fluxy-bot 0.7.5 → 0.7.6

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-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,{})}));
1
+ import{e as o,j as e,R as n,O as r}from"./globals-CMrTFJSE.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,8 +4,8 @@
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-CR6Sg8AD.js"></script>
8
- <link rel="modulepreload" crossorigin href="/fluxy/assets/globals-DxeORYnQ.js">
7
+ <script type="module" crossorigin src="/fluxy/assets/fluxy-Bcd5tJrt.js"></script>
8
+ <link rel="modulepreload" crossorigin href="/fluxy/assets/globals-CMrTFJSE.js">
9
9
  <link rel="stylesheet" crossorigin href="/fluxy/assets/globals-Bs_wR6rP.css">
10
10
  </head>
11
11
  <body class="bg-background text-foreground">
@@ -4,8 +4,8 @@
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-ChgrXiME.js"></script>
8
- <link rel="modulepreload" crossorigin href="/fluxy/assets/globals-DxeORYnQ.js">
7
+ <script type="module" crossorigin src="/fluxy/assets/onboard-BSlNrxVH.js"></script>
8
+ <link rel="modulepreload" crossorigin href="/fluxy/assets/globals-CMrTFJSE.js">
9
9
  <link rel="stylesheet" crossorigin href="/fluxy/assets/globals-Bs_wR6rP.css">
10
10
  </head>
11
11
  <body class="bg-background text-foreground">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxy-bot",
3
- "version": "0.7.5",
3
+ "version": "0.7.6",
4
4
  "releaseNotes": [
5
5
  "Fixed some bugs to iOs ",
6
6
  "2. ",
@@ -182,13 +182,15 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
182
182
 
183
183
  const isConnected = authState[provider] === 'connected';
184
184
 
185
- // Persist/restore TOTP setup state across page reloads (mobile deep link authenticator → return)
185
+ // Persist/restore TOTP setup state across page reloads (mobile: OS suspends PWA on app-switch)
186
186
  const TOTP_STORAGE_KEY = 'fluxy_totp_setup';
187
187
 
188
188
  function saveTotpState() {
189
189
  try {
190
190
  sessionStorage.setItem(TOTP_STORAGE_KEY, JSON.stringify({
191
191
  secret: totpSecret, qrUri: totpQrUri, otpauthUri: totpOtpauthUri, phase: step3Phase,
192
+ // Also persist password fields so user doesn't re-type after returning
193
+ portalPass, portalPassConfirm,
192
194
  }));
193
195
  } catch {}
194
196
  }
@@ -205,6 +207,7 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
205
207
  setTotpEnabled(true);
206
208
  setStep3Phase('totp-setup');
207
209
  setStep(3);
210
+ if (saved.portalPass) { setPortalPass(saved.portalPass); setPortalPassConfirm(saved.portalPassConfirm || ''); }
208
211
  return true;
209
212
  }
210
213
  } catch {}
@@ -2,6 +2,8 @@ import { useState, useRef, useEffect, type KeyboardEvent } from 'react';
2
2
  import { Lock, LoaderCircle, ArrowRight, ArrowLeft, Shield, Check } from 'lucide-react';
3
3
  import { motion, AnimatePresence } from 'framer-motion';
4
4
 
5
+ const LOGIN_STORAGE_KEY = 'fluxy_login_totp';
6
+
5
7
  interface Props {
6
8
  onLogin: (token: string) => void;
7
9
  totpEnabled?: boolean;
@@ -20,6 +22,21 @@ export default function LoginScreen({ onLogin, totpEnabled }: Props) {
20
22
  const [useRecovery, setUseRecovery] = useState(false);
21
23
  const totpInputRef = useRef<HTMLInputElement>(null);
22
24
 
25
+ // Restore TOTP phase after page reload (mobile: OS suspends PWA on app-switch)
26
+ useEffect(() => {
27
+ try {
28
+ const raw = sessionStorage.getItem(LOGIN_STORAGE_KEY);
29
+ if (!raw) return;
30
+ const saved = JSON.parse(raw);
31
+ if (saved.pendingToken && saved.expiresAt > Date.now()) {
32
+ setPendingToken(saved.pendingToken);
33
+ setPhase('totp');
34
+ } else {
35
+ sessionStorage.removeItem(LOGIN_STORAGE_KEY);
36
+ }
37
+ } catch {}
38
+ }, []);
39
+
23
40
  // Auto-focus TOTP input when switching to TOTP phase
24
41
  useEffect(() => {
25
42
  if (phase === 'totp') {
@@ -27,6 +44,20 @@ export default function LoginScreen({ onLogin, totpEnabled }: Props) {
27
44
  }
28
45
  }, [phase]);
29
46
 
47
+ function saveLoginState(token: string) {
48
+ try {
49
+ // Pending token has 5min server expiry — save with matching client expiry
50
+ sessionStorage.setItem(LOGIN_STORAGE_KEY, JSON.stringify({
51
+ pendingToken: token,
52
+ expiresAt: Date.now() + 4.5 * 60 * 1000,
53
+ }));
54
+ } catch {}
55
+ }
56
+
57
+ function clearLoginState() {
58
+ try { sessionStorage.removeItem(LOGIN_STORAGE_KEY); } catch {}
59
+ }
60
+
30
61
  const handleSubmit = async () => {
31
62
  if (!password.trim() || loading) return;
32
63
  setLoading(true);
@@ -41,9 +72,11 @@ export default function LoginScreen({ onLogin, totpEnabled }: Props) {
41
72
  const data = await res.json();
42
73
 
43
74
  if (res.ok && data.token) {
75
+ clearLoginState();
44
76
  onLogin(data.token);
45
77
  } else if (res.ok && data.requiresTOTP) {
46
78
  setPendingToken(data.pendingToken);
79
+ saveLoginState(data.pendingToken);
47
80
  setPhase('totp');
48
81
  setError('');
49
82
  } else {
@@ -69,6 +102,7 @@ export default function LoginScreen({ onLogin, totpEnabled }: Props) {
69
102
  const data = await res.json();
70
103
 
71
104
  if (res.ok && data.token) {
105
+ clearLoginState();
72
106
  onLogin(data.token);
73
107
  } else {
74
108
  setError(data.error || 'Invalid code');
@@ -87,6 +121,14 @@ export default function LoginScreen({ onLogin, totpEnabled }: Props) {
87
121
  }
88
122
  };
89
123
 
124
+ const handleBackToPassword = () => {
125
+ setPhase('password');
126
+ setError('');
127
+ setTotpCode('');
128
+ setUseRecovery(false);
129
+ clearLoginState();
130
+ };
131
+
90
132
  const inputCls = 'w-full bg-white/[0.05] border border-white/[0.08] text-white rounded-xl px-4 py-3 text-base outline-none input-glow placeholder:text-white/20 transition-all';
91
133
 
92
134
  return (
@@ -183,6 +225,7 @@ export default function LoginScreen({ onLogin, totpEnabled }: Props) {
183
225
  }}
184
226
  onKeyDown={handleKeyDown}
185
227
  placeholder={useRecovery ? 'Recovery code' : '000000'}
228
+ autoFocus
186
229
  className={inputCls + (useRecovery ? '' : ' tracking-[0.3em] text-center font-mono')}
187
230
  />
188
231
 
@@ -215,7 +258,7 @@ export default function LoginScreen({ onLogin, totpEnabled }: Props) {
215
258
 
216
259
  <div className="flex items-center gap-4 mt-4">
217
260
  <button
218
- onClick={() => { setPhase('password'); setError(''); setTotpCode(''); setUseRecovery(false); }}
261
+ onClick={handleBackToPassword}
219
262
  className="text-[12px] text-white/30 hover:text-white/50 flex items-center gap-1 transition-colors"
220
263
  >
221
264
  <ArrowLeft className="h-3 w-3" />