fluxy-bot 0.7.4 → 0.7.5

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.
@@ -1 +1 @@
1
- import{e as o,j as e,R as n,O as r}from"./globals-C0DMRzvx.js";function a(){const t=()=>{window.parent?.postMessage({type:"fluxy:onboard-complete"},"*")};return e.jsx(r,{onComplete:t,isInitialSetup:!0})}o.createRoot(document.getElementById("root")).render(e.jsx(n.StrictMode,{children:e.jsx(a,{})}));
1
+ import{e as o,j as e,R as n,O as r}from"./globals-DxeORYnQ.js";function a(){const t=()=>{window.parent?.postMessage({type:"fluxy:onboard-complete"},"*")};return e.jsx(r,{onComplete:t,isInitialSetup:!0})}o.createRoot(document.getElementById("root")).render(e.jsx(n.StrictMode,{children:e.jsx(a,{})}));
@@ -4,9 +4,9 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, interactive-widget=resizes-content" />
6
6
  <title>Fluxy Chat</title>
7
- <script type="module" crossorigin src="/fluxy/assets/fluxy-C2_hZ0e0.js"></script>
8
- <link rel="modulepreload" crossorigin href="/fluxy/assets/globals-C0DMRzvx.js">
9
- <link rel="stylesheet" crossorigin href="/fluxy/assets/globals-DZhBbtf8.css">
7
+ <script type="module" crossorigin src="/fluxy/assets/fluxy-CR6Sg8AD.js"></script>
8
+ <link rel="modulepreload" crossorigin href="/fluxy/assets/globals-DxeORYnQ.js">
9
+ <link rel="stylesheet" crossorigin href="/fluxy/assets/globals-Bs_wR6rP.css">
10
10
  </head>
11
11
  <body class="bg-background text-foreground">
12
12
  <div id="root"></div>
@@ -4,9 +4,9 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, interactive-widget=resizes-content" />
6
6
  <title>Fluxy Setup</title>
7
- <script type="module" crossorigin src="/fluxy/assets/onboard-LzOfScdU.js"></script>
8
- <link rel="modulepreload" crossorigin href="/fluxy/assets/globals-C0DMRzvx.js">
9
- <link rel="stylesheet" crossorigin href="/fluxy/assets/globals-DZhBbtf8.css">
7
+ <script type="module" crossorigin src="/fluxy/assets/onboard-ChgrXiME.js"></script>
8
+ <link rel="modulepreload" crossorigin href="/fluxy/assets/globals-DxeORYnQ.js">
9
+ <link rel="stylesheet" crossorigin href="/fluxy/assets/globals-Bs_wR6rP.css">
10
10
  </head>
11
11
  <body class="bg-background text-foreground">
12
12
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxy-bot",
3
- "version": "0.7.4",
3
+ "version": "0.7.5",
4
4
  "releaseNotes": [
5
5
  "Fixed some bugs to iOs ",
6
6
  "2. ",
@@ -174,11 +174,47 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
174
174
  // Sub-phase within step 3: 'password' | 'totp-setup' | 'recovery'
175
175
  const [step3Phase, setStep3Phase] = useState<'password' | 'totp-setup' | 'recovery'>('password');
176
176
 
177
+ // Clipboard feedback for TOTP secret copy
178
+ const [totpSecretCopied, setTotpSecretCopied] = useState(false);
179
+
177
180
  // Pre-fill guard
178
181
  const prefillDone = useRef(false);
179
182
 
180
183
  const isConnected = authState[provider] === 'connected';
181
184
 
185
+ // Persist/restore TOTP setup state across page reloads (mobile deep link → authenticator → return)
186
+ const TOTP_STORAGE_KEY = 'fluxy_totp_setup';
187
+
188
+ function saveTotpState() {
189
+ try {
190
+ sessionStorage.setItem(TOTP_STORAGE_KEY, JSON.stringify({
191
+ secret: totpSecret, qrUri: totpQrUri, otpauthUri: totpOtpauthUri, phase: step3Phase,
192
+ }));
193
+ } catch {}
194
+ }
195
+
196
+ function restoreTotpState() {
197
+ try {
198
+ const raw = sessionStorage.getItem(TOTP_STORAGE_KEY);
199
+ if (!raw) return false;
200
+ const saved = JSON.parse(raw);
201
+ if (saved.secret && saved.phase === 'totp-setup') {
202
+ setTotpSecret(saved.secret);
203
+ setTotpQrUri(saved.qrUri || '');
204
+ setTotpOtpauthUri(saved.otpauthUri || '');
205
+ setTotpEnabled(true);
206
+ setStep3Phase('totp-setup');
207
+ setStep(3);
208
+ return true;
209
+ }
210
+ } catch {}
211
+ return false;
212
+ }
213
+
214
+ function clearTotpStorage() {
215
+ try { sessionStorage.removeItem(TOTP_STORAGE_KEY); } catch {}
216
+ }
217
+
182
218
  // Pre-fill from existing settings (re-run wizard)
183
219
  useEffect(() => {
184
220
  fetch('/api/onboard/status')
@@ -204,6 +240,9 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
204
240
  // If user has existing handle, default to 'relay'; otherwise default to 'tunnel'
205
241
  if (!data.handle) setHandleChoice('tunnel');
206
242
  prefillDone.current = true;
243
+
244
+ // Restore TOTP setup state if returning from authenticator app
245
+ if (!data.totpEnabled) restoreTotpState();
207
246
  })
208
247
  .catch(() => { prefillDone.current = true; });
209
248
  }, []);
@@ -1258,6 +1297,7 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
1258
1297
  setTotpCode('');
1259
1298
  setTotpError('');
1260
1299
  setStep3Phase('password');
1300
+ clearTotpStorage();
1261
1301
  }}
1262
1302
  className="w-7 h-7 rounded-full bg-white/[0.04] flex items-center justify-center text-white/40 hover:text-white/70 transition-colors shrink-0"
1263
1303
  >
@@ -1280,20 +1320,39 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
1280
1320
  <p className="text-white/40 text-[13px] leading-relaxed mb-4">
1281
1321
  Add Fluxy to your authenticator app, then enter the 6-digit code below to confirm.
1282
1322
  </p>
1323
+
1324
+ {/* Primary: copy secret key (doesn't leave the app) */}
1325
+ <button
1326
+ onClick={() => {
1327
+ navigator.clipboard.writeText(totpSecret);
1328
+ setTotpSecretCopied(true);
1329
+ setTimeout(() => setTotpSecretCopied(false), 3000);
1330
+ }}
1331
+ className={`w-full py-3 text-[14px] font-medium rounded-xl transition-colors flex items-center justify-center gap-2 ${
1332
+ totpSecretCopied
1333
+ ? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20'
1334
+ : 'bg-white/[0.05] text-white/70 hover:bg-white/[0.08] border border-white/[0.08]'
1335
+ }`}
1336
+ >
1337
+ {totpSecretCopied ? (
1338
+ <><Check className="h-4 w-4" />Secret key copied</>
1339
+ ) : (
1340
+ <><Copy className="h-4 w-4" />Copy secret key</>
1341
+ )}
1342
+ </button>
1343
+ <p className="text-[11px] text-white/20 text-center mt-2">
1344
+ Paste it in your authenticator app → Add account → Enter key
1345
+ </p>
1346
+
1347
+ {/* Secondary: deep link (saves state before leaving) */}
1283
1348
  <a
1284
1349
  href={totpOtpauthUri}
1285
- className="w-full py-3 bg-[#AF27E3]/10 hover:bg-[#AF27E3]/20 text-[#AF27E3] text-[14px] font-medium rounded-xl transition-colors flex items-center justify-center gap-2"
1350
+ onClick={() => saveTotpState()}
1351
+ className="w-full mt-3 py-2.5 text-[13px] text-white/30 hover:text-white/50 flex items-center justify-center gap-1.5 transition-colors"
1286
1352
  >
1287
- <Smartphone className="h-4 w-4" />
1288
- Open in Authenticator
1353
+ <Smartphone className="h-3.5 w-3.5" />
1354
+ Or open directly in authenticator
1289
1355
  </a>
1290
- <button
1291
- onClick={() => { navigator.clipboard.writeText(totpSecret); }}
1292
- className="w-full mt-2 text-[11px] text-white/25 hover:text-white/40 flex items-center justify-center gap-1 py-1 transition-colors"
1293
- >
1294
- <Copy className="h-3 w-3" />
1295
- Or copy secret key manually
1296
- </button>
1297
1356
  </div>
1298
1357
  ) : (
1299
1358
  <div className="mt-4 flex gap-4 items-start">
@@ -1353,6 +1412,7 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
1353
1412
  setTotpVerified(true);
1354
1413
  setRecoveryCodes(data.recoveryCodes || []);
1355
1414
  setStep3Phase('recovery');
1415
+ clearTotpStorage();
1356
1416
  } else {
1357
1417
  setTotpError(data.error || 'Verification failed');
1358
1418
  }
@@ -1427,6 +1487,7 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
1427
1487
  onClick={() => {
1428
1488
  setRecoveryCodes([]);
1429
1489
  setStep3Phase('password');
1490
+ clearTotpStorage();
1430
1491
  }}
1431
1492
  disabled={!recoveryCodesCopied}
1432
1493
  className="w-full mt-3 py-3 bg-gradient-brand hover:opacity-90 text-white text-[14px] font-semibold rounded-full transition-colors flex items-center justify-center gap-2 disabled:opacity-40"