horizon-code 0.3.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/app.ts +2 -6
- package/src/chat/renderer.ts +1 -1
- package/src/components/footer.ts +0 -1
- package/src/components/input-bar.ts +0 -2
- package/src/components/splash.ts +0 -1
- package/src/components/tab-bar.ts +0 -1
- package/src/platform/supabase.ts +35 -28
- package/src/theme/colors.ts +8 -8
package/package.json
CHANGED
package/src/app.ts
CHANGED
|
@@ -907,7 +907,8 @@ export class App {
|
|
|
907
907
|
this.authenticated = loggedIn;
|
|
908
908
|
|
|
909
909
|
const cfg = loadConfig();
|
|
910
|
-
const
|
|
910
|
+
const rawEmail = cfg.user_email || getUser()?.email;
|
|
911
|
+
const email = typeof rawEmail === "string" ? rawEmail : undefined;
|
|
911
912
|
|
|
912
913
|
if (!loggedIn) {
|
|
913
914
|
this.splash.setAuthStatus(false);
|
|
@@ -939,11 +940,6 @@ export class App {
|
|
|
939
940
|
|
|
940
941
|
if (!live) {
|
|
941
942
|
this.splash.setAuthStatus(true, email);
|
|
942
|
-
// Only warn about expired session if they actually had one before
|
|
943
|
-
// Don't warn if they just have an api_key (chat still works fine)
|
|
944
|
-
if (config.supabase_session) {
|
|
945
|
-
this.showSystemMsg("Supabase session expired — chat sync disabled. Type /login to reconnect.");
|
|
946
|
-
}
|
|
947
943
|
} else {
|
|
948
944
|
this.splash.setAuthStatus(true, email, firstTime);
|
|
949
945
|
}
|
package/src/chat/renderer.ts
CHANGED
package/src/components/footer.ts
CHANGED
|
@@ -31,7 +31,6 @@ export class InputBar {
|
|
|
31
31
|
width: "100%",
|
|
32
32
|
flexDirection: "column",
|
|
33
33
|
paddingLeft: 4,
|
|
34
|
-
backgroundColor: COLORS.bgSecondary,
|
|
35
34
|
});
|
|
36
35
|
this.acBox.visible = false;
|
|
37
36
|
this.container.add(this.acBox);
|
|
@@ -52,7 +51,6 @@ export class InputBar {
|
|
|
52
51
|
width: "100%",
|
|
53
52
|
flexDirection: "row",
|
|
54
53
|
alignItems: "center",
|
|
55
|
-
backgroundColor: COLORS.bgDarker,
|
|
56
54
|
paddingLeft: 2,
|
|
57
55
|
});
|
|
58
56
|
this.container.add(inputRow);
|
package/src/components/splash.ts
CHANGED
package/src/platform/supabase.ts
CHANGED
|
@@ -115,34 +115,37 @@ export async function restoreSession(): Promise<boolean> {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
// Try setSession first (works if access token still valid)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
|
|
118
|
+
try {
|
|
119
|
+
const { data, error } = await sb.auth.setSession({
|
|
120
|
+
access_token: accessToken,
|
|
121
|
+
refresh_token: refreshToken,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
if (!error && data.session) {
|
|
125
|
+
if (config.api_key) platform.setApiKey(config.api_key);
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
} catch {}
|
|
127
129
|
|
|
128
130
|
// Access token expired — try refreshing with just the refresh token
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
131
|
+
try {
|
|
132
|
+
const { data: refreshData, error: refreshError } = await sb.auth.refreshSession({
|
|
133
|
+
refresh_token: refreshToken,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
if (!refreshError && refreshData.session) {
|
|
137
|
+
// Save the new tokens
|
|
138
|
+
saveSessionTokens(config, refreshData.session.access_token, refreshData.session.refresh_token);
|
|
139
|
+
config.user_email = refreshData.session.user.email ?? config.user_email;
|
|
140
|
+
config.user_id = refreshData.session.user.id;
|
|
141
|
+
saveConfig(config);
|
|
142
|
+
if (config.api_key) platform.setApiKey(config.api_key);
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
} catch {}
|
|
142
146
|
|
|
143
|
-
// Both failed —
|
|
144
|
-
|
|
145
|
-
saveConfig(config);
|
|
147
|
+
// Both failed — don't delete the session, it might work next time
|
|
148
|
+
// (network issue, Supabase outage, etc.). The API key still works for chat.
|
|
146
149
|
}
|
|
147
150
|
|
|
148
151
|
// API key still works for the LLM proxy even without a Supabase session
|
|
@@ -211,7 +214,10 @@ export async function loginWithBrowser(): Promise<{ success: boolean; error?: st
|
|
|
211
214
|
// Save everything
|
|
212
215
|
const config = loadConfig();
|
|
213
216
|
saveSessionTokens(config, sd.session.access_token, sd.session.refresh_token);
|
|
214
|
-
|
|
217
|
+
// Defensively extract email — server might return string or object
|
|
218
|
+
const rawEmail = data.email ?? sd.session.user.email ?? sd.session.user?.user_metadata?.email;
|
|
219
|
+
const email = typeof rawEmail === "string" ? rawEmail : typeof rawEmail === "object" && rawEmail !== null ? (rawEmail as any).address ?? (rawEmail as any).email ?? String(rawEmail) : "";
|
|
220
|
+
config.user_email = email;
|
|
215
221
|
config.user_id = sd.session.user.id;
|
|
216
222
|
|
|
217
223
|
if (!config.api_key) {
|
|
@@ -224,7 +230,7 @@ export async function loginWithBrowser(): Promise<{ success: boolean; error?: st
|
|
|
224
230
|
}
|
|
225
231
|
|
|
226
232
|
saveConfig(config);
|
|
227
|
-
return { success: true, email
|
|
233
|
+
return { success: true, email };
|
|
228
234
|
}
|
|
229
235
|
}
|
|
230
236
|
if (res.status === 410) return { success: false, error: "Session expired. Type /login to sign in again." };
|
|
@@ -246,7 +252,8 @@ export async function loginWithPassword(email: string, password: string): Promis
|
|
|
246
252
|
|
|
247
253
|
const config = loadConfig();
|
|
248
254
|
saveSessionTokens(config, data.session.access_token, data.session.refresh_token);
|
|
249
|
-
|
|
255
|
+
const userEmail = data.session.user.email;
|
|
256
|
+
config.user_email = typeof userEmail === "string" ? userEmail : email;
|
|
250
257
|
config.user_id = data.session.user.id;
|
|
251
258
|
|
|
252
259
|
if (!config.api_key) {
|
package/src/theme/colors.ts
CHANGED
|
@@ -19,18 +19,18 @@ interface Colors {
|
|
|
19
19
|
|
|
20
20
|
const THEMES: Record<ThemeName, Colors> = {
|
|
21
21
|
dark: {
|
|
22
|
-
bg: "#
|
|
23
|
-
text: "#
|
|
24
|
-
border: "#4b4c5c", borderDim: "#
|
|
25
|
-
primary: "#fab283", primaryDim: "#c48a62", secondary: "#
|
|
26
|
-
success: "#7fd88f", error: "#e06c75", warning: "#f5a742", info: "#
|
|
22
|
+
bg: "#1a1a1a", bgSecondary: "#1e1e1e", bgDarker: "#141414", selection: "#252525",
|
|
23
|
+
text: "#d4d4d4", textMuted: "#808080", textEmphasized: "#ffffff",
|
|
24
|
+
border: "#4b4c5c", borderDim: "#3a3a3a", borderFocus: "#fab283",
|
|
25
|
+
primary: "#fab283", primaryDim: "#c48a62", secondary: "#4d8ef7", accent: "#9d7cd8",
|
|
26
|
+
success: "#7fd88f", error: "#e06c75", warning: "#f5a742", info: "#5bb8d0",
|
|
27
27
|
},
|
|
28
28
|
midnight: {
|
|
29
|
-
bg: "#0d1117", bgSecondary: "#
|
|
29
|
+
bg: "#0d1117", bgSecondary: "#131920", bgDarker: "#080c12", selection: "#182030",
|
|
30
30
|
text: "#c9d1d9", textMuted: "#636e7b", textEmphasized: "#f0f6fc",
|
|
31
31
|
border: "#30363d", borderDim: "#2d333b", borderFocus: "#8be9fd",
|
|
32
|
-
primary: "#ff79c6", primaryDim: "#cc5f9e", secondary: "#
|
|
33
|
-
success: "#50fa7b", error: "#ff5555", warning: "#f1fa8c", info: "#
|
|
32
|
+
primary: "#ff79c6", primaryDim: "#cc5f9e", secondary: "#79b8ff", accent: "#bd93f9",
|
|
33
|
+
success: "#50fa7b", error: "#ff5555", warning: "#f1fa8c", info: "#79b8ff",
|
|
34
34
|
},
|
|
35
35
|
nord: {
|
|
36
36
|
bg: "#2e3440", bgSecondary: "#3b4252", bgDarker: "#272c36", selection: "#434c5e",
|