@medialane/ui 0.257.0 → 0.258.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 (89) 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/drop/create/launch-dialog.cjs +1 -1
  18. package/dist/components/drop/create/launch-dialog.cjs.map +1 -1
  19. package/dist/components/drop/create/launch-dialog.js +1 -1
  20. package/dist/components/drop/create/launch-dialog.js.map +1 -1
  21. package/dist/components/drop/page/drop-manage.cjs +1 -1
  22. package/dist/components/drop/page/drop-manage.cjs.map +1 -1
  23. package/dist/components/drop/page/drop-manage.js +1 -1
  24. package/dist/components/drop/page/drop-manage.js.map +1 -1
  25. package/dist/components/drop/page/drop-mint-dialog.cjs +1 -1
  26. package/dist/components/drop/page/drop-mint-dialog.cjs.map +1 -1
  27. package/dist/components/drop/page/drop-mint-dialog.js +1 -1
  28. package/dist/components/drop/page/drop-mint-dialog.js.map +1 -1
  29. package/dist/components/empty-or-error.cjs +2 -2
  30. package/dist/components/empty-or-error.cjs.map +1 -1
  31. package/dist/components/empty-or-error.js +2 -2
  32. package/dist/components/empty-or-error.js.map +1 -1
  33. package/dist/components/fast-mint/fast-mint.cjs +2 -1
  34. package/dist/components/fast-mint/fast-mint.cjs.map +1 -1
  35. package/dist/components/fast-mint/fast-mint.js +2 -1
  36. package/dist/components/fast-mint/fast-mint.js.map +1 -1
  37. package/dist/components/license-request-page.cjs +1 -1
  38. package/dist/components/license-request-page.cjs.map +1 -1
  39. package/dist/components/license-request-page.js +1 -1
  40. package/dist/components/license-request-page.js.map +1 -1
  41. package/dist/components/media-wallet/activate-card.cjs +1 -1
  42. package/dist/components/media-wallet/activate-card.cjs.map +1 -1
  43. package/dist/components/media-wallet/activate-card.js +1 -1
  44. package/dist/components/media-wallet/activate-card.js.map +1 -1
  45. package/dist/components/media-wallet/media-wallet-activity.cjs +1 -1
  46. package/dist/components/media-wallet/media-wallet-activity.cjs.map +1 -1
  47. package/dist/components/media-wallet/media-wallet-activity.js +1 -1
  48. package/dist/components/media-wallet/media-wallet-activity.js.map +1 -1
  49. package/dist/components/media-wallet/media-wallet-send.cjs +2 -6
  50. package/dist/components/media-wallet/media-wallet-send.cjs.map +1 -1
  51. package/dist/components/media-wallet/media-wallet-send.js +2 -6
  52. package/dist/components/media-wallet/media-wallet-send.js.map +1 -1
  53. package/dist/components/transaction-dialog.cjs +4 -4
  54. package/dist/components/transaction-dialog.cjs.map +1 -1
  55. package/dist/components/transaction-dialog.d.cts +3 -1
  56. package/dist/components/transaction-dialog.d.ts +3 -1
  57. package/dist/components/transaction-dialog.js +4 -4
  58. package/dist/components/transaction-dialog.js.map +1 -1
  59. package/dist/components/wallet/export-key-section.cjs +3 -3
  60. package/dist/components/wallet/export-key-section.cjs.map +1 -1
  61. package/dist/components/wallet/export-key-section.d.cts +1 -2
  62. package/dist/components/wallet/export-key-section.d.ts +1 -2
  63. package/dist/components/wallet/export-key-section.js +3 -3
  64. package/dist/components/wallet/export-key-section.js.map +1 -1
  65. package/dist/index.cjs +0 -2
  66. package/dist/index.cjs.map +1 -1
  67. package/dist/index.d.cts +1 -1
  68. package/dist/index.d.ts +1 -1
  69. package/dist/index.js +0 -2
  70. package/dist/index.js.map +1 -1
  71. package/dist/utils/describe-error.cjs +16 -11
  72. package/dist/utils/describe-error.cjs.map +1 -1
  73. package/dist/utils/describe-error.d.cts +4 -4
  74. package/dist/utils/describe-error.d.ts +4 -4
  75. package/dist/utils/describe-error.js +16 -10
  76. package/dist/utils/describe-error.js.map +1 -1
  77. package/dist/utils/media-wallet/use-erc20-balance.d.cts +1 -1
  78. package/dist/utils/media-wallet/use-erc20-balance.d.ts +1 -1
  79. package/dist/utils/use-email-code.cjs +2 -2
  80. package/dist/utils/use-email-code.cjs.map +1 -1
  81. package/dist/utils/use-email-code.js +2 -2
  82. package/dist/utils/use-email-code.js.map +1 -1
  83. package/dist/utils/use-transaction.cjs +16 -2
  84. package/dist/utils/use-transaction.cjs.map +1 -1
  85. package/dist/utils/use-transaction.d.cts +1 -0
  86. package/dist/utils/use-transaction.d.ts +1 -0
  87. package/dist/utils/use-transaction.js +17 -3
  88. package/dist/utils/use-transaction.js.map +1 -1
  89. package/package.json +3 -3
@@ -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":"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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":";;;;;;;;;;;;;;;;;;;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,CAAC,EAAE,OAAO;AAAA,IACnC;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,CAAC,EAAE,OAAO;AAAA,IACnC,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":[]}
@@ -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":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA8DQ;AA5DR,mBAAiD;AACjD,0BAAuC;AACvC,sBAAmE;AACnE,oBAAuB;AACvB,mBAAsB;AACtB,4BAA8B;AAC9B,oCAAqC;AAGrC,MAAM,QAAQ,CAAC,MAAc,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC,SAAI,EAAE,MAAM,EAAE,CAAC;AAQtD,SAAS,eAAe,EAAE,eAAe,QAAQ,WAAW,GAAwB;AACzF,QAAM,CAAC,SAAS,UAAU,QAAI,uBAA+B,IAAI;AACjE,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAC5C,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAwB,IAAI;AAC5D,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAwB,IAAI;AAEtD,QAAM,cAAU,0BAAY,MAAM;AAChC,UAAM,SAAS,WAAW;AAC1B,QAAI,CAAC,OAAQ;AACb,WACG,UAAU,aAAa,EACvB,KAAK,CAAC,WAAW,eAAW,iCAAgB,QAAQ,OAAO,WAAW,CAAC,CAAC,EACxE,MAAM,MAAM,WAAW,CAAC,CAAC,CAAC;AAAA,EAC/B,GAAG,CAAC,eAAe,QAAQ,UAAU,CAAC;AAEtC,8BAAU,MAAM;AACd,YAAQ;AAAA,EACV,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,eAAe,OAAO,WAAwB;AAClD,UAAM,SAAS,WAAW;AAC1B,QAAI,CAAC,UAAU,CAAC,QAAS;AAEzB,UAAM,YAAY,OAAO;AAAA,MACvB;AAAA,IACF;AACA,QAAI,CAAC,UAAW;AAEhB,gBAAY,OAAO,IAAI;AACvB,aAAS,IAAI;AACb,QAAI;AACF,YAAM,OAAO,aAAa,QAAQ,OAAO,IAAI;AAC7C,cAAQ;AAAA,IACV,SAAS,GAAG;AACV,mBAAS,qCAAc,GAAG,mDAAmD,EAAE,OAAO;AAAA,IACxF,UAAE;AACA,kBAAY,IAAI;AAAA,IAClB;AAAA,EACF;AAEA,SACE,6CAAC,SAAI,WAAU,oEACb;AAAA,iDAAC,SAAI,WAAU,0CACb;AAAA,mDAAC,SACC;AAAA,oDAAC,QAAG,WAAU,uCAAsC,0BAAY;AAAA,QAChE,4CAAC,OAAE,WAAU,wCAAuC,uFAEpD;AAAA,SACF;AAAA,MACA,6CAAC,wBAAO,MAAK,MAAK,SAAQ,WAAU,SAAS,MAAM,WAAW,IAAI,GAChE;AAAA,oDAAC,4BAAK,WAAU,gBAAe;AAAA,QAAE;AAAA,SAEnC;AAAA,OACF;AAAA,IAEC,YAAY,OACX,4CAAC,+BAAQ,WAAU,8CAA6C,IAC9D,QAAQ,WAAW,IACrB,4CAAC,OAAE,WAAU,iCAAgC,gDAAkC,IAE/E,4CAAC,QAAG,WAAU,aACX,kBAAQ,IAAI,CAAC,WACZ;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAEV;AAAA,uDAAC,SAAI,WAAU,mCACb;AAAA,wDAAC,+BAAQ,WAAU,0CAAyC;AAAA,YAC5D,4CAAC,UAAK,WAAU,oDACb,gBAAM,OAAO,IAAI,GACpB;AAAA,YACC,OAAO,eAAe,4CAAC,sBAAM,SAAQ,aAAY,yBAAW,IAAW;AAAA,aAC1E;AAAA,UACC,OAAO,eAAe,OACrB;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,UAAU,KAAC,iCAAgB,SAAS,OAAO,IAAI,KAAK,aAAa;AAAA,cACjE,SAAS,MAAM,aAAa,MAAM;AAAA,cAEjC,uBAAa,OAAO,OAAO,4CAAC,+BAAQ,WAAU,wBAAuB,IAAK;AAAA;AAAA,UAC7E;AAAA;AAAA;AAAA,MAlBG,OAAO;AAAA,IAoBd,CACD,GACH;AAAA,IAGD,QAAQ,4CAAC,OAAE,WAAU,4BAA4B,iBAAM,IAAO;AAAA,IAE/D;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,cAAc;AAAA,QACd,YAAY;AAAA,QACZ;AAAA,QACA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;","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":"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","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"]}
@@ -108,7 +108,7 @@ function LaunchDialog({ open, onClose, draft }) {
108
108
  }
109
109
  setStep({ kind: "done", collection, links: list ? (0, import_starknet.dropClaimLinks)(window.location.origin, collection, list) : [], warning });
110
110
  } catch (err) {
111
- setStep({ kind: "error", message: (0, import_describe_error.describeError)(err, "We couldn't launch your drop. Please try again.").message });
111
+ setStep({ kind: "error", message: (0, import_describe_error.describeError)(err).message });
112
112
  }
113
113
  };
114
114
  const close = () => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/drop/create/launch-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useMemo, useState } from \"react\";\nimport { CheckCircle2, Loader2, RotateCcw, XCircle } from \"lucide-react\";\nimport { dropHref } from \"@medialane/sdk\";\nimport { buildPopAllowlist, dropClaimLinks, popClaimLinksCsv, type PopClaimLink } from \"@medialane/sdk/starknet\";\nimport { ActionDialog } from \"../../action-dialog.js\";\nimport { GradientButton } from \"../../gradient-button.js\";\nimport { Button } from \"../../button.js\";\nimport { ShareButton } from \"../../share-button.js\";\nimport { describeError } from \"../../../utils/describe-error.js\";\nimport { uploadDirectoryToIpfs, uploadFileToIpfs } from \"../../../utils/ipfs-upload.js\";\nimport { parseAllowlist } from \"../../../utils/drop/allowlist.js\";\nimport { buildDropMetadataFiles, metadataBytes, MAX_DROP_METADATA_BYTES } from \"../../../utils/drop/metadata.js\";\nimport { toDropTerms, priceLabel } from \"../../../utils/drop/sale.js\";\nimport { draftSupply, type DropDraft } from \"../../../utils/drop/draft.js\";\nimport { uploadAll, type UploadTask } from \"../../../utils/drop/upload.js\";\nimport { launchDrop, saveExclusiveContent } from \"../../../utils/drop/actions.js\";\nimport { useMedialaneApp } from \"../../medialane-app.js\";\n\ntype Step =\n | { kind: \"review\" }\n | { kind: \"uploading\" }\n | { kind: \"launching\" }\n | { kind: \"done\"; collection: string; links: PopClaimLink[]; warning: string | null }\n | { kind: \"error\"; message: string };\n\nexport function LaunchDialog({ open, onClose, draft }: { open: boolean; onClose: () => void; draft: DropDraft }) {\n const app = useMedialaneApp();\n const [step, setStep] = useState<Step>({ kind: \"review\" });\n const [tasks, setTasks] = useState<UploadTask[]>([]);\n const [baseUri, setBaseUri] = useState<string | null>(null);\n const client = app.getClient();\n const files = draft.kind === \"edition\" ? (draft.edition ? [draft.edition] : []) : draft.items.map((i) => i.file);\n const terms = toDropTerms(draft.sale);\n const list = useMemo(\n () => (draft.listOnly ? buildPopAllowlist(parseAllowlist(draft.allowlist).addresses) : null),\n [draft.listOnly, draft.allowlist],\n );\n\n const run = async () => {\n try {\n let uri = baseUri;\n if (!uri) {\n setStep({ kind: \"uploading\" });\n const initial = tasks.length > 0 ? tasks : [\n ...files.map((file, i) => ({ id: `art-${i}`, file, status: \"pending\" as const, uri: null, error: null })),\n ...(draft.cover ? [{ id: \"cover\", file: draft.cover, status: \"pending\" as const, uri: null, error: null }] : []),\n ];\n const done = await uploadAll(initial, async (f) => (await uploadFileToIpfs(client.api, f, \"image\")).uri, setTasks);\n setTasks(done);\n if (done.some((t) => t.status !== \"done\")) {\n setStep({ kind: \"error\", message: \"Some files didn't upload. Retry to send only those.\" });\n return;\n }\n const art = done.filter((t) => t.id.startsWith(\"art-\"));\n const metadata = buildDropMetadataFiles({\n kind: draft.kind,\n name: draft.name.trim(),\n description: draft.description.trim(),\n creator: app.walletAddress!,\n coverUri: done.find((t) => t.id === \"cover\")?.uri ?? null,\n license: draft.license,\n items: draft.kind === \"edition\"\n ? [{ name: \"\", description: \"\", imageUri: art[0]!.uri! }]\n : draft.items.map((it, i) => ({ name: it.name, description: it.description, imageUri: art[i]!.uri! })),\n supply: draftSupply(draft),\n });\n if (metadataBytes(metadata) > MAX_DROP_METADATA_BYTES) {\n setStep({ kind: \"error\", message: \"The descriptions are too long for this many tokens. Shorten them and try again.\" });\n return;\n }\n uri = (await uploadDirectoryToIpfs(client.api, metadata)).baseUri;\n setBaseUri(uri);\n }\n setStep({ kind: \"launching\" });\n const signer = await app.getSigner();\n const { collection } = await launchDrop({ client, signer }, {\n owner: app.walletAddress!,\n name: draft.name.trim(),\n symbol: draft.symbol,\n baseUri: uri!,\n maxSupply: draftSupply(draft),\n terms,\n allowlistRoot: list?.root,\n description: draft.description.trim() || undefined,\n });\n let warning: string | null = null;\n if (draft.gated.enabled) {\n try {\n await saveExclusiveContent(client, collection, draft.gated);\n } catch {\n warning = \"Your drop launched, but the exclusive content wasn't saved. You can add it from Manage.\";\n }\n }\n setStep({ kind: \"done\", collection, links: list ? dropClaimLinks(window.location.origin, collection, list) : [], warning });\n } catch (err) {\n setStep({ kind: \"error\", message: describeError(err, \"We couldn't launch your drop. Please try again.\").message });\n }\n };\n\n const close = () => {\n if (step.kind === \"uploading\" || step.kind === \"launching\") return;\n onClose();\n };\n\n return (\n <ActionDialog open={open} onClose={close}>\n <div className=\"space-y-5 p-6\">\n {step.kind === \"review\" && (\n <>\n <h2 className=\"text-lg font-semibold\">Review and launch</h2>\n <div className=\"space-y-2 rounded-xl border border-border p-4 text-sm\">\n <p className=\"font-semibold\">{draft.name}</p>\n <p className=\"text-xs font-semibold uppercase tracking-widest text-muted-foreground\">Fixed after launch</p>\n <Row label=\"Price\" value={priceLabel(terms.price, terms.paymentToken)} />\n <Row label=\"Supply\" value={`${draftSupply(draft).toLocaleString(\"en-US\")} ${draft.kind === \"edition\" ? (draftSupply(draft) === 1 ? \"copy\" : \"copies\") : draftSupply(draft) === 1 ? \"item\" : \"items\"}`} />\n <Row label=\"Starts\" value={terms.startTime === 0 ? \"At launch\" : new Date(terms.startTime * 1000).toLocaleString()} />\n <Row label=\"Ends\" value={terms.endTime === 0 ? \"No end date\" : new Date(terms.endTime * 1000).toLocaleString()} />\n <Row label=\"Per wallet\" value={terms.maxPerWallet === \"0\" ? \"No limit\" : terms.maxPerWallet} />\n <Row label=\"Who can mint\" value={list ? `${Object.keys(list.proofs).length} wallets on a list` : \"Everyone\"} />\n <p className=\"pt-1 text-xs text-muted-foreground\">The artwork and these terms can't be changed after launch. You can change the list later.</p>\n </div>\n <GradientButton big onClick={() => void run()}>Launch drop</GradientButton>\n </>\n )}\n {step.kind === \"uploading\" && (\n <>\n <h2 className=\"flex items-center gap-2 text-lg font-semibold\"><Loader2 className=\"h-4 w-4 animate-spin\" />Uploading</h2>\n <p className=\"text-sm text-muted-foreground\">{tasks.filter((t) => t.status === \"done\").length} of {tasks.length} files</p>\n </>\n )}\n {step.kind === \"launching\" && (\n <h2 className=\"flex items-center gap-2 text-lg font-semibold\"><Loader2 className=\"h-4 w-4 animate-spin\" />Launching your drop…</h2>\n )}\n {step.kind === \"error\" && (\n <>\n <h2 className=\"flex items-center gap-2 text-lg font-semibold\"><XCircle className=\"h-4 w-4 text-destructive\" />Not launched</h2>\n <p className=\"text-sm text-muted-foreground\">{step.message}</p>\n {tasks.some((t) => t.status === \"failed\") && (\n <ul className=\"space-y-1 text-xs text-muted-foreground\">\n {tasks.filter((t) => t.status === \"failed\").map((t) => <li key={t.id}>{t.file.name}: {t.error}</li>)}\n </ul>\n )}\n <Button onClick={() => void run()} className=\"gap-1.5\"><RotateCcw className=\"h-3.5 w-3.5\" />Try again</Button>\n </>\n )}\n {step.kind === \"done\" && (\n <>\n <h2 className=\"flex items-center gap-2 text-lg font-semibold\"><CheckCircle2 className=\"h-5 w-5 text-green-500\" />Your drop is live</h2>\n {step.warning && <p className=\"text-sm text-brand-orange\">{step.warning}</p>}\n <div className=\"flex flex-wrap gap-2\">\n <ShareButton title={draft.name} url={`${window.location.origin}${dropHref(step.collection)}`} variant=\"outline\" />\n <Button asChild variant=\"outline\"><a href={dropHref(step.collection)}>View drop</a></Button>\n {step.links.length > 0 && (\n <Button variant=\"outline\" onClick={() => downloadCsv(popClaimLinksCsv(step.links), \"claim-links.csv\")}>Download claim links</Button>\n )}\n </div>\n {step.links.length > 0 && <p className=\"text-xs text-muted-foreground\">Send each wallet its link — the link is what lets it mint.</p>}\n </>\n )}\n </div>\n </ActionDialog>\n );\n}\n\nfunction Row({ label, value }: { label: string; value: string }) {\n return <div className=\"flex justify-between gap-3\"><span className=\"text-muted-foreground\">{label}</span><span className=\"text-right font-medium\">{value}</span></div>;\n}\n\nexport function downloadCsv(csv: string, name: string) {\n const href = URL.createObjectURL(new Blob([csv], { type: \"text/csv\" }));\n Object.assign(document.createElement(\"a\"), { href, download: name }).click();\n URL.revokeObjectURL(href);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/components/drop/create/launch-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useMemo, useState } from \"react\";\nimport { CheckCircle2, Loader2, RotateCcw, XCircle } from \"lucide-react\";\nimport { dropHref } from \"@medialane/sdk\";\nimport { buildPopAllowlist, dropClaimLinks, popClaimLinksCsv, type PopClaimLink } from \"@medialane/sdk/starknet\";\nimport { ActionDialog } from \"../../action-dialog.js\";\nimport { GradientButton } from \"../../gradient-button.js\";\nimport { Button } from \"../../button.js\";\nimport { ShareButton } from \"../../share-button.js\";\nimport { describeError } from \"../../../utils/describe-error.js\";\nimport { uploadDirectoryToIpfs, uploadFileToIpfs } from \"../../../utils/ipfs-upload.js\";\nimport { parseAllowlist } from \"../../../utils/drop/allowlist.js\";\nimport { buildDropMetadataFiles, metadataBytes, MAX_DROP_METADATA_BYTES } from \"../../../utils/drop/metadata.js\";\nimport { toDropTerms, priceLabel } from \"../../../utils/drop/sale.js\";\nimport { draftSupply, type DropDraft } from \"../../../utils/drop/draft.js\";\nimport { uploadAll, type UploadTask } from \"../../../utils/drop/upload.js\";\nimport { launchDrop, saveExclusiveContent } from \"../../../utils/drop/actions.js\";\nimport { useMedialaneApp } from \"../../medialane-app.js\";\n\ntype Step =\n | { kind: \"review\" }\n | { kind: \"uploading\" }\n | { kind: \"launching\" }\n | { kind: \"done\"; collection: string; links: PopClaimLink[]; warning: string | null }\n | { kind: \"error\"; message: string };\n\nexport function LaunchDialog({ open, onClose, draft }: { open: boolean; onClose: () => void; draft: DropDraft }) {\n const app = useMedialaneApp();\n const [step, setStep] = useState<Step>({ kind: \"review\" });\n const [tasks, setTasks] = useState<UploadTask[]>([]);\n const [baseUri, setBaseUri] = useState<string | null>(null);\n const client = app.getClient();\n const files = draft.kind === \"edition\" ? (draft.edition ? [draft.edition] : []) : draft.items.map((i) => i.file);\n const terms = toDropTerms(draft.sale);\n const list = useMemo(\n () => (draft.listOnly ? buildPopAllowlist(parseAllowlist(draft.allowlist).addresses) : null),\n [draft.listOnly, draft.allowlist],\n );\n\n const run = async () => {\n try {\n let uri = baseUri;\n if (!uri) {\n setStep({ kind: \"uploading\" });\n const initial = tasks.length > 0 ? tasks : [\n ...files.map((file, i) => ({ id: `art-${i}`, file, status: \"pending\" as const, uri: null, error: null })),\n ...(draft.cover ? [{ id: \"cover\", file: draft.cover, status: \"pending\" as const, uri: null, error: null }] : []),\n ];\n const done = await uploadAll(initial, async (f) => (await uploadFileToIpfs(client.api, f, \"image\")).uri, setTasks);\n setTasks(done);\n if (done.some((t) => t.status !== \"done\")) {\n setStep({ kind: \"error\", message: \"Some files didn't upload. Retry to send only those.\" });\n return;\n }\n const art = done.filter((t) => t.id.startsWith(\"art-\"));\n const metadata = buildDropMetadataFiles({\n kind: draft.kind,\n name: draft.name.trim(),\n description: draft.description.trim(),\n creator: app.walletAddress!,\n coverUri: done.find((t) => t.id === \"cover\")?.uri ?? null,\n license: draft.license,\n items: draft.kind === \"edition\"\n ? [{ name: \"\", description: \"\", imageUri: art[0]!.uri! }]\n : draft.items.map((it, i) => ({ name: it.name, description: it.description, imageUri: art[i]!.uri! })),\n supply: draftSupply(draft),\n });\n if (metadataBytes(metadata) > MAX_DROP_METADATA_BYTES) {\n setStep({ kind: \"error\", message: \"The descriptions are too long for this many tokens. Shorten them and try again.\" });\n return;\n }\n uri = (await uploadDirectoryToIpfs(client.api, metadata)).baseUri;\n setBaseUri(uri);\n }\n setStep({ kind: \"launching\" });\n const signer = await app.getSigner();\n const { collection } = await launchDrop({ client, signer }, {\n owner: app.walletAddress!,\n name: draft.name.trim(),\n symbol: draft.symbol,\n baseUri: uri!,\n maxSupply: draftSupply(draft),\n terms,\n allowlistRoot: list?.root,\n description: draft.description.trim() || undefined,\n });\n let warning: string | null = null;\n if (draft.gated.enabled) {\n try {\n await saveExclusiveContent(client, collection, draft.gated);\n } catch {\n warning = \"Your drop launched, but the exclusive content wasn't saved. You can add it from Manage.\";\n }\n }\n setStep({ kind: \"done\", collection, links: list ? dropClaimLinks(window.location.origin, collection, list) : [], warning });\n } catch (err) {\n setStep({ kind: \"error\", message: describeError(err).message });\n }\n };\n\n const close = () => {\n if (step.kind === \"uploading\" || step.kind === \"launching\") return;\n onClose();\n };\n\n return (\n <ActionDialog open={open} onClose={close}>\n <div className=\"space-y-5 p-6\">\n {step.kind === \"review\" && (\n <>\n <h2 className=\"text-lg font-semibold\">Review and launch</h2>\n <div className=\"space-y-2 rounded-xl border border-border p-4 text-sm\">\n <p className=\"font-semibold\">{draft.name}</p>\n <p className=\"text-xs font-semibold uppercase tracking-widest text-muted-foreground\">Fixed after launch</p>\n <Row label=\"Price\" value={priceLabel(terms.price, terms.paymentToken)} />\n <Row label=\"Supply\" value={`${draftSupply(draft).toLocaleString(\"en-US\")} ${draft.kind === \"edition\" ? (draftSupply(draft) === 1 ? \"copy\" : \"copies\") : draftSupply(draft) === 1 ? \"item\" : \"items\"}`} />\n <Row label=\"Starts\" value={terms.startTime === 0 ? \"At launch\" : new Date(terms.startTime * 1000).toLocaleString()} />\n <Row label=\"Ends\" value={terms.endTime === 0 ? \"No end date\" : new Date(terms.endTime * 1000).toLocaleString()} />\n <Row label=\"Per wallet\" value={terms.maxPerWallet === \"0\" ? \"No limit\" : terms.maxPerWallet} />\n <Row label=\"Who can mint\" value={list ? `${Object.keys(list.proofs).length} wallets on a list` : \"Everyone\"} />\n <p className=\"pt-1 text-xs text-muted-foreground\">The artwork and these terms can't be changed after launch. You can change the list later.</p>\n </div>\n <GradientButton big onClick={() => void run()}>Launch drop</GradientButton>\n </>\n )}\n {step.kind === \"uploading\" && (\n <>\n <h2 className=\"flex items-center gap-2 text-lg font-semibold\"><Loader2 className=\"h-4 w-4 animate-spin\" />Uploading</h2>\n <p className=\"text-sm text-muted-foreground\">{tasks.filter((t) => t.status === \"done\").length} of {tasks.length} files</p>\n </>\n )}\n {step.kind === \"launching\" && (\n <h2 className=\"flex items-center gap-2 text-lg font-semibold\"><Loader2 className=\"h-4 w-4 animate-spin\" />Launching your drop…</h2>\n )}\n {step.kind === \"error\" && (\n <>\n <h2 className=\"flex items-center gap-2 text-lg font-semibold\"><XCircle className=\"h-4 w-4 text-destructive\" />Not launched</h2>\n <p className=\"text-sm text-muted-foreground\">{step.message}</p>\n {tasks.some((t) => t.status === \"failed\") && (\n <ul className=\"space-y-1 text-xs text-muted-foreground\">\n {tasks.filter((t) => t.status === \"failed\").map((t) => <li key={t.id}>{t.file.name}: {t.error}</li>)}\n </ul>\n )}\n <Button onClick={() => void run()} className=\"gap-1.5\"><RotateCcw className=\"h-3.5 w-3.5\" />Try again</Button>\n </>\n )}\n {step.kind === \"done\" && (\n <>\n <h2 className=\"flex items-center gap-2 text-lg font-semibold\"><CheckCircle2 className=\"h-5 w-5 text-green-500\" />Your drop is live</h2>\n {step.warning && <p className=\"text-sm text-brand-orange\">{step.warning}</p>}\n <div className=\"flex flex-wrap gap-2\">\n <ShareButton title={draft.name} url={`${window.location.origin}${dropHref(step.collection)}`} variant=\"outline\" />\n <Button asChild variant=\"outline\"><a href={dropHref(step.collection)}>View drop</a></Button>\n {step.links.length > 0 && (\n <Button variant=\"outline\" onClick={() => downloadCsv(popClaimLinksCsv(step.links), \"claim-links.csv\")}>Download claim links</Button>\n )}\n </div>\n {step.links.length > 0 && <p className=\"text-xs text-muted-foreground\">Send each wallet its link — the link is what lets it mint.</p>}\n </>\n )}\n </div>\n </ActionDialog>\n );\n}\n\nfunction Row({ label, value }: { label: string; value: string }) {\n return <div className=\"flex justify-between gap-3\"><span className=\"text-muted-foreground\">{label}</span><span className=\"text-right font-medium\">{value}</span></div>;\n}\n\nexport function downloadCsv(csv: string, name: string) {\n const href = URL.createObjectURL(new Blob([csv], { type: \"text/csv\" }));\n Object.assign(document.createElement(\"a\"), { href, download: name }).click();\n URL.revokeObjectURL(href);\n}\n"],"mappings":"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","names":[]}
@@ -84,7 +84,7 @@ function LaunchDialog({ open, onClose, draft }) {
84
84
  }
85
85
  setStep({ kind: "done", collection, links: list ? dropClaimLinks(window.location.origin, collection, list) : [], warning });
86
86
  } catch (err) {
87
- setStep({ kind: "error", message: describeError(err, "We couldn't launch your drop. Please try again.").message });
87
+ setStep({ kind: "error", message: describeError(err).message });
88
88
  }
89
89
  };
90
90
  const close = () => {