omniroute 3.2.6 → 3.2.7
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/README.ar.md +15 -13
- package/README.bg.md +3 -0
- package/README.cs.md +3 -0
- package/README.da.md +3 -0
- package/README.fi.md +3 -0
- package/README.he.md +40 -37
- package/README.hu.md +12 -9
- package/README.id.md +3 -0
- package/README.in.md +3 -0
- package/README.ja.md +3 -0
- package/README.ko.md +40 -37
- package/README.md +25 -22
- package/README.ms.md +18 -15
- package/README.nl.md +3 -0
- package/README.no.md +3 -0
- package/README.phi.md +3 -0
- package/README.pl.md +3 -0
- package/README.pt.md +3 -0
- package/README.ro.md +3 -0
- package/README.sk.md +3 -0
- package/README.sv.md +3 -0
- package/README.th.md +12 -9
- package/README.uk-UA.md +3 -0
- package/README.vi.md +3 -0
- package/app/.next/BUILD_ID +1 -1
- package/app/.next/build-manifest.json +2 -2
- package/app/.next/prerender-manifest.json +3 -3
- package/app/.next/server/app/(dashboard)/dashboard/a2a/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/agents/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/analytics/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/api-manager/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/audit-log/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/auto-combo/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/cache/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/costs/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/health/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/limits/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/logs/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/mcp/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/media/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/onboarding/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/playground/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/search-tools/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/settings/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/400/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/401/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/403/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/408/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/429/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/500/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/502/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/503/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/_global-error.html +2 -2
- package/app/.next/server/app/_global-error.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/callback/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/docs/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/forbidden/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/forgot-password/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/landing/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/maintenance/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/offline/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/privacy/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/status/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/terms/page_client-reference-manifest.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__0891af92._.js +3 -1
- package/app/.next/server/chunks/[root-of-the-server]__1f27646b._.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__46e00e59._.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__6e52619e._.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__950558b8._.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__a32d3818._.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__d5a064d5._.js +2 -2
- package/app/.next/server/chunks/_05c48915._.js +1 -1
- package/app/.next/server/chunks/_06515a8a._.js +1 -1
- package/app/.next/server/chunks/_2115d8de._.js +1 -1
- package/app/.next/server/chunks/_3ac953eb._.js +1 -1
- package/app/.next/server/chunks/_4b8fd853._.js +1 -1
- package/app/.next/server/chunks/_68683848._.js +1 -1
- package/app/.next/server/chunks/_ee9b677b._.js +1 -1
- package/app/.next/server/chunks/ssr/[root-of-the-server]__9ef96d20._.js +1 -1
- package/app/.next/server/chunks/ssr/[root-of-the-server]__a6942102._.js +1 -1
- package/app/.next/server/chunks/ssr/src_app_(dashboard)_dashboard_3666f2bd._.js +1 -1
- package/app/.next/server/pages/500.html +2 -2
- package/app/.next/server/server-reference-manifest.js +1 -1
- package/app/.next/server/server-reference-manifest.json +1 -1
- package/app/.next/static/chunks/8a7e69530366d349.js +1 -0
- package/app/.next/static/chunks/ced99e799397dd8f.css +1 -0
- package/app/.next/static/chunks/{a505e70878b9cc4b.js → e0bc7c9ae396f60a.js} +1 -1
- package/app/CHANGELOG.md +6 -0
- package/app/README.ar.md +15 -13
- package/app/README.bg.md +3 -0
- package/app/README.cs.md +3 -0
- package/app/README.da.md +3 -0
- package/app/README.fi.md +3 -0
- package/app/README.he.md +40 -37
- package/app/README.hu.md +12 -9
- package/app/README.id.md +3 -0
- package/app/README.in.md +3 -0
- package/app/README.ja.md +3 -0
- package/app/README.ko.md +40 -37
- package/app/README.md +25 -22
- package/app/README.ms.md +18 -15
- package/app/README.nl.md +3 -0
- package/app/README.no.md +3 -0
- package/app/README.phi.md +3 -0
- package/app/README.pl.md +3 -0
- package/app/README.pt.md +3 -0
- package/app/README.ro.md +3 -0
- package/app/README.sk.md +3 -0
- package/app/README.sv.md +3 -0
- package/app/README.th.md +12 -9
- package/app/README.uk-UA.md +3 -0
- package/app/README.vi.md +3 -0
- package/app/docs/FEATURES.md +1 -1
- package/app/docs/i18n/ar/FEATURES.md +1 -1
- package/app/docs/i18n/ar/README.md +23 -20
- package/app/docs/i18n/bg/FEATURES.md +1 -1
- package/app/docs/i18n/bg/README.md +13 -10
- package/app/docs/i18n/cs/README.md +13 -10
- package/app/docs/i18n/da/FEATURES.md +1 -1
- package/app/docs/i18n/da/README.md +13 -10
- package/app/docs/i18n/de/FEATURES.md +1 -1
- package/app/docs/i18n/de/README.md +13 -10
- package/app/docs/i18n/es/FEATURES.md +1 -1
- package/app/docs/i18n/es/README.md +32 -34
- package/app/docs/i18n/fi/FEATURES.md +1 -1
- package/app/docs/i18n/fi/README.md +13 -10
- package/app/docs/i18n/fr/FEATURES.md +1 -1
- package/app/docs/i18n/fr/README.md +21 -23
- package/app/docs/i18n/he/FEATURES.md +1 -1
- package/app/docs/i18n/he/README.md +26 -23
- package/app/docs/i18n/hu/FEATURES.md +1 -1
- package/app/docs/i18n/hu/README.md +13 -10
- package/app/docs/i18n/id/FEATURES.md +1 -1
- package/app/docs/i18n/id/README.md +26 -23
- package/app/docs/i18n/in/FEATURES.md +1 -1
- package/app/docs/i18n/in/README.md +26 -23
- package/app/docs/i18n/it/FEATURES.md +1 -1
- package/app/docs/i18n/it/README.md +32 -34
- package/app/docs/i18n/ja/FEATURES.md +1 -1
- package/app/docs/i18n/ja/README.md +26 -23
- package/app/docs/i18n/ko/FEATURES.md +1 -1
- package/app/docs/i18n/ko/README.md +26 -23
- package/app/docs/i18n/ms/FEATURES.md +1 -1
- package/app/docs/i18n/ms/README.md +13 -10
- package/app/docs/i18n/nl/FEATURES.md +1 -1
- package/app/docs/i18n/nl/README.md +13 -10
- package/app/docs/i18n/no/FEATURES.md +1 -1
- package/app/docs/i18n/no/README.md +26 -23
- package/app/docs/i18n/phi/FEATURES.md +1 -1
- package/app/docs/i18n/phi/README.md +26 -23
- package/app/docs/i18n/pl/FEATURES.md +1 -1
- package/app/docs/i18n/pl/README.md +13 -10
- package/app/docs/i18n/pt/FEATURES.md +1 -1
- package/app/docs/i18n/pt/README.md +13 -10
- package/app/docs/i18n/pt-BR/FEATURES.md +1 -1
- package/app/docs/i18n/pt-BR/README.md +13 -10
- package/app/docs/i18n/ro/FEATURES.md +1 -1
- package/app/docs/i18n/ro/README.md +13 -10
- package/app/docs/i18n/ru/FEATURES.md +1 -1
- package/app/docs/i18n/ru/README.md +32 -34
- package/app/docs/i18n/sk/FEATURES.md +1 -1
- package/app/docs/i18n/sk/README.md +13 -10
- package/app/docs/i18n/sv/FEATURES.md +1 -1
- package/app/docs/i18n/sv/README.md +26 -23
- package/app/docs/i18n/th/FEATURES.md +1 -1
- package/app/docs/i18n/th/README.md +26 -23
- package/app/docs/i18n/uk-UA/FEATURES.md +1 -1
- package/app/docs/i18n/uk-UA/README.md +13 -10
- package/app/docs/i18n/vi/FEATURES.md +1 -1
- package/app/docs/i18n/vi/README.md +13 -10
- package/app/docs/i18n/zh-CN/FEATURES.md +1 -1
- package/app/docs/i18n/zh-CN/README.md +32 -34
- package/app/docs/openapi.yaml +1 -1
- package/app/package-lock.json +2 -2
- package/app/package.json +1 -1
- package/app/src/app/(dashboard)/dashboard/HomePageClient.tsx +217 -13
- package/app/src/app/api/system/version/route.ts +69 -22
- package/package.json +1 -1
- package/app/.next/static/chunks/2e25e28a804c74cb.css +0 -1
- package/app/.next/static/chunks/786bb016b73be366.js +0 -1
- /package/app/.next/static/{y0yR5YnNvU8dlWh7MSaaO → V1AhcZllvKyXSF7QBcufd}/_buildManifest.js +0 -0
- /package/app/.next/static/{y0yR5YnNvU8dlWh7MSaaO → V1AhcZllvKyXSF7QBcufd}/_clientMiddlewareManifest.json +0 -0
- /package/app/.next/static/{y0yR5YnNvU8dlWh7MSaaO → V1AhcZllvKyXSF7QBcufd}/_ssgManifest.js +0 -0
|
@@ -26,6 +26,10 @@ export default function HomePageClient({ machineId }) {
|
|
|
26
26
|
|
|
27
27
|
const [versionInfo, setVersionInfo] = useState<any>(null);
|
|
28
28
|
const [updating, setUpdating] = useState(false);
|
|
29
|
+
const [updateSteps, setUpdateSteps] = useState<
|
|
30
|
+
Array<{ step: string; status: string; message: string }>
|
|
31
|
+
>([]);
|
|
32
|
+
const [updatePhase, setUpdatePhase] = useState<"idle" | "running" | "done" | "failed">("idle");
|
|
29
33
|
|
|
30
34
|
useEffect(() => {
|
|
31
35
|
if (typeof window !== "undefined") {
|
|
@@ -89,7 +93,6 @@ export default function HomePageClient({ machineId }) {
|
|
|
89
93
|
const providerKeys = new Set([providerId, providerInfo.alias].filter(Boolean));
|
|
90
94
|
const providerModels = models.filter((m) => providerKeys.has(m.provider));
|
|
91
95
|
|
|
92
|
-
// Determine auth type
|
|
93
96
|
const authType = FREE_PROVIDERS[providerId]
|
|
94
97
|
? "free"
|
|
95
98
|
: OAUTH_PROVIDERS[providerId]
|
|
@@ -108,7 +111,6 @@ export default function HomePageClient({ machineId }) {
|
|
|
108
111
|
});
|
|
109
112
|
}, [providerConnections, models]);
|
|
110
113
|
|
|
111
|
-
// Models for selected provider
|
|
112
114
|
const selectedProviderModels = useMemo(() => {
|
|
113
115
|
if (!selectedProvider) return [];
|
|
114
116
|
const providerKeys = new Set(
|
|
@@ -135,24 +137,112 @@ export default function HomePageClient({ machineId }) {
|
|
|
135
137
|
const handleUpdate = async () => {
|
|
136
138
|
const notify = useNotificationStore.getState();
|
|
137
139
|
setUpdating(true);
|
|
140
|
+
setUpdatePhase("running");
|
|
141
|
+
setUpdateSteps([]);
|
|
142
|
+
|
|
138
143
|
try {
|
|
139
|
-
notify.info(t("updateStarted") || "Update process started...");
|
|
140
144
|
const res = await fetch("/api/system/version", { method: "POST" });
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
|
|
145
|
+
|
|
146
|
+
// If response is JSON (error/already up to date)
|
|
147
|
+
const contentType = res.headers.get("content-type") || "";
|
|
148
|
+
if (contentType.includes("application/json")) {
|
|
149
|
+
const data = await res.json();
|
|
150
|
+
if (!res.ok || !data.success) {
|
|
151
|
+
notify.error(data.error || "Failed to start update.");
|
|
152
|
+
setUpdating(false);
|
|
153
|
+
setUpdatePhase("idle");
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// SSE stream — read progress events
|
|
159
|
+
if (!res.body) {
|
|
160
|
+
notify.error("No response stream received.");
|
|
148
161
|
setUpdating(false);
|
|
162
|
+
setUpdatePhase("idle");
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const reader = res.body.getReader();
|
|
167
|
+
const decoder = new TextDecoder();
|
|
168
|
+
let buffer = "";
|
|
169
|
+
|
|
170
|
+
while (true) {
|
|
171
|
+
const { done, value } = await reader.read();
|
|
172
|
+
if (done) break;
|
|
173
|
+
buffer += decoder.decode(value, { stream: true });
|
|
174
|
+
|
|
175
|
+
const lines = buffer.split("\n");
|
|
176
|
+
buffer = lines.pop() || "";
|
|
177
|
+
|
|
178
|
+
for (const line of lines) {
|
|
179
|
+
if (!line.startsWith("data: ")) continue;
|
|
180
|
+
try {
|
|
181
|
+
const event = JSON.parse(line.slice(6));
|
|
182
|
+
|
|
183
|
+
setUpdateSteps((prev) => {
|
|
184
|
+
// Replace existing step entry or add new one
|
|
185
|
+
const idx = prev.findIndex((s) => s.step === event.step);
|
|
186
|
+
if (idx >= 0) {
|
|
187
|
+
const next = [...prev];
|
|
188
|
+
next[idx] = event;
|
|
189
|
+
return next;
|
|
190
|
+
}
|
|
191
|
+
return [...prev, event];
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
if (event.step === "complete") {
|
|
195
|
+
setUpdatePhase("done");
|
|
196
|
+
notify.success(event.message || "Update complete!");
|
|
197
|
+
} else if (event.step === "error") {
|
|
198
|
+
setUpdatePhase("failed");
|
|
199
|
+
notify.error(event.message || "Update failed.");
|
|
200
|
+
setUpdating(false);
|
|
201
|
+
}
|
|
202
|
+
} catch {
|
|
203
|
+
// ignore parse errors
|
|
204
|
+
}
|
|
205
|
+
}
|
|
149
206
|
}
|
|
150
207
|
} catch {
|
|
151
|
-
|
|
208
|
+
setUpdatePhase("failed");
|
|
209
|
+
setUpdateSteps((prev) => [
|
|
210
|
+
...prev,
|
|
211
|
+
{
|
|
212
|
+
step: "error",
|
|
213
|
+
status: "failed",
|
|
214
|
+
message: "Network error — connection lost during update.",
|
|
215
|
+
},
|
|
216
|
+
]);
|
|
152
217
|
setUpdating(false);
|
|
153
218
|
}
|
|
154
219
|
};
|
|
155
220
|
|
|
221
|
+
// Auto-reload after successful update (service restarts, need new page)
|
|
222
|
+
useEffect(() => {
|
|
223
|
+
if (updatePhase !== "done") return;
|
|
224
|
+
const timer = setTimeout(() => {
|
|
225
|
+
window.location.reload();
|
|
226
|
+
}, 8000);
|
|
227
|
+
return () => clearTimeout(timer);
|
|
228
|
+
}, [updatePhase]);
|
|
229
|
+
|
|
230
|
+
const stepIcons: Record<string, string> = {
|
|
231
|
+
install: "download",
|
|
232
|
+
rebuild: "build",
|
|
233
|
+
restart: "restart_alt",
|
|
234
|
+
complete: "check_circle",
|
|
235
|
+
error: "error",
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
const stepLabels: Record<string, string> = {
|
|
239
|
+
install: "Install Package",
|
|
240
|
+
rebuild: "Rebuild Native Modules",
|
|
241
|
+
restart: "Restart Service",
|
|
242
|
+
complete: "Complete",
|
|
243
|
+
error: "Error",
|
|
244
|
+
};
|
|
245
|
+
|
|
156
246
|
if (loading) {
|
|
157
247
|
return (
|
|
158
248
|
<div className="flex flex-col gap-8">
|
|
@@ -166,8 +256,122 @@ export default function HomePageClient({ machineId }) {
|
|
|
166
256
|
|
|
167
257
|
return (
|
|
168
258
|
<div className="flex flex-col gap-8">
|
|
259
|
+
{/* Update Progress Overlay */}
|
|
260
|
+
{updating && (
|
|
261
|
+
<div className="fixed inset-0 z-[999] bg-black/60 backdrop-blur-sm flex items-center justify-center p-4">
|
|
262
|
+
<div className="bg-bg-main border border-border rounded-2xl shadow-2xl max-w-md w-full p-6">
|
|
263
|
+
<div className="flex items-center gap-3 mb-5">
|
|
264
|
+
<span className="material-symbols-outlined text-primary text-[28px] animate-spin">
|
|
265
|
+
progress_activity
|
|
266
|
+
</span>
|
|
267
|
+
<div>
|
|
268
|
+
<h3 className="text-lg font-bold">
|
|
269
|
+
{updatePhase === "done"
|
|
270
|
+
? "Update Complete!"
|
|
271
|
+
: updatePhase === "failed"
|
|
272
|
+
? "Update Failed"
|
|
273
|
+
: "Updating OmniRoute..."}
|
|
274
|
+
</h3>
|
|
275
|
+
<p className="text-xs text-text-muted mt-0.5">
|
|
276
|
+
{updatePhase === "done"
|
|
277
|
+
? "The page will reload automatically in a few seconds."
|
|
278
|
+
: updatePhase === "failed"
|
|
279
|
+
? "Please try again or update manually via the CLI."
|
|
280
|
+
: "Do not close this page. The system will restart automatically."}
|
|
281
|
+
</p>
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
|
|
285
|
+
{/* Step list */}
|
|
286
|
+
<div className="flex flex-col gap-2">
|
|
287
|
+
{updateSteps
|
|
288
|
+
.filter((s) => s.step !== "complete" && s.step !== "error")
|
|
289
|
+
.map((s) => (
|
|
290
|
+
<div
|
|
291
|
+
key={s.step}
|
|
292
|
+
className={`flex items-center gap-3 px-3 py-2.5 rounded-lg border transition-all ${
|
|
293
|
+
s.status === "running"
|
|
294
|
+
? "border-primary/40 bg-primary/5"
|
|
295
|
+
: s.status === "done"
|
|
296
|
+
? "border-green-500/30 bg-green-500/5"
|
|
297
|
+
: s.status === "failed"
|
|
298
|
+
? "border-red-500/30 bg-red-500/5"
|
|
299
|
+
: "border-border bg-bg-subtle"
|
|
300
|
+
}`}
|
|
301
|
+
>
|
|
302
|
+
{s.status === "running" ? (
|
|
303
|
+
<span className="material-symbols-outlined text-primary text-[18px] animate-spin">
|
|
304
|
+
progress_activity
|
|
305
|
+
</span>
|
|
306
|
+
) : s.status === "done" ? (
|
|
307
|
+
<span className="material-symbols-outlined text-green-500 text-[18px]">
|
|
308
|
+
check_circle
|
|
309
|
+
</span>
|
|
310
|
+
) : s.status === "failed" ? (
|
|
311
|
+
<span className="material-symbols-outlined text-red-500 text-[18px]">
|
|
312
|
+
error
|
|
313
|
+
</span>
|
|
314
|
+
) : (
|
|
315
|
+
<span className="material-symbols-outlined text-yellow-500 text-[18px]">
|
|
316
|
+
warning
|
|
317
|
+
</span>
|
|
318
|
+
)}
|
|
319
|
+
<div className="min-w-0 flex-1">
|
|
320
|
+
<p className="text-sm font-medium">{stepLabels[s.step] || s.step}</p>
|
|
321
|
+
<p className="text-xs text-text-muted truncate">{s.message}</p>
|
|
322
|
+
</div>
|
|
323
|
+
</div>
|
|
324
|
+
))}
|
|
325
|
+
|
|
326
|
+
{/* Error message */}
|
|
327
|
+
{updateSteps.find((s) => s.step === "error") && (
|
|
328
|
+
<div className="mt-1 px-3 py-2.5 rounded-lg border border-red-500/30 bg-red-500/5 text-red-500">
|
|
329
|
+
<p className="text-xs font-mono break-all">
|
|
330
|
+
{updateSteps.find((s) => s.step === "error")?.message}
|
|
331
|
+
</p>
|
|
332
|
+
</div>
|
|
333
|
+
)}
|
|
334
|
+
|
|
335
|
+
{/* Completion message */}
|
|
336
|
+
{updatePhase === "done" && (
|
|
337
|
+
<div className="mt-1 px-3 py-2.5 rounded-lg border border-green-500/30 bg-green-500/5">
|
|
338
|
+
<p className="text-sm font-semibold text-green-500 flex items-center gap-2">
|
|
339
|
+
<span className="material-symbols-outlined text-[18px]">check_circle</span>
|
|
340
|
+
{updateSteps.find((s) => s.step === "complete")?.message || "Update complete!"}
|
|
341
|
+
</p>
|
|
342
|
+
<p className="text-xs text-text-muted mt-1">Reloading page automatically...</p>
|
|
343
|
+
</div>
|
|
344
|
+
)}
|
|
345
|
+
</div>
|
|
346
|
+
|
|
347
|
+
{/* Actions */}
|
|
348
|
+
{(updatePhase === "failed" || updatePhase === "done") && (
|
|
349
|
+
<div className="flex gap-2 mt-4">
|
|
350
|
+
<Button
|
|
351
|
+
size="sm"
|
|
352
|
+
fullWidth
|
|
353
|
+
onClick={() => {
|
|
354
|
+
setUpdating(false);
|
|
355
|
+
setUpdatePhase("idle");
|
|
356
|
+
setUpdateSteps([]);
|
|
357
|
+
if (updatePhase === "done") window.location.reload();
|
|
358
|
+
}}
|
|
359
|
+
>
|
|
360
|
+
{updatePhase === "done" ? "Reload Now" : "Close"}
|
|
361
|
+
</Button>
|
|
362
|
+
{updatePhase === "failed" && (
|
|
363
|
+
<Button size="sm" variant="secondary" fullWidth onClick={handleUpdate}>
|
|
364
|
+
Retry
|
|
365
|
+
</Button>
|
|
366
|
+
)}
|
|
367
|
+
</div>
|
|
368
|
+
)}
|
|
369
|
+
</div>
|
|
370
|
+
</div>
|
|
371
|
+
)}
|
|
372
|
+
|
|
169
373
|
{/* Update Notification Banner */}
|
|
170
|
-
{versionInfo?.updateAvailable && (
|
|
374
|
+
{versionInfo?.updateAvailable && !updating && (
|
|
171
375
|
<div className="bg-primary/10 border border-primary/20 text-primary px-5 py-4 rounded-xl flex items-center justify-between min-h-[64px]">
|
|
172
376
|
<div className="flex items-center gap-4">
|
|
173
377
|
<span className="material-symbols-outlined text-[24px]">system_update_alt</span>
|
|
@@ -185,7 +389,7 @@ export default function HomePageClient({ machineId }) {
|
|
|
185
389
|
disabled={updating}
|
|
186
390
|
className="shrink-0 ml-4 font-semibold"
|
|
187
391
|
>
|
|
188
|
-
{
|
|
392
|
+
{t("updateNow") || "Update Now"}
|
|
189
393
|
</Button>
|
|
190
394
|
</div>
|
|
191
395
|
)}
|
|
@@ -30,7 +30,6 @@ async function getLatestNpmVersion(): Promise<string | null> {
|
|
|
30
30
|
/** Current installed version from package.json */
|
|
31
31
|
function getCurrentVersion(): string {
|
|
32
32
|
try {
|
|
33
|
-
|
|
34
33
|
return require("../../../../../package.json").version as string;
|
|
35
34
|
} catch {
|
|
36
35
|
return "unknown";
|
|
@@ -89,27 +88,75 @@ export async function POST(req: NextRequest) {
|
|
|
89
88
|
});
|
|
90
89
|
}
|
|
91
90
|
|
|
92
|
-
//
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
await execFileAsync("pm2", ["restart", "omniroute"]).catch(() => null);
|
|
100
|
-
console.log(`[AutoUpdate] Successfully updated to v${latest}`);
|
|
101
|
-
} catch (err) {
|
|
102
|
-
console.error(`[AutoUpdate] Update failed:`, err);
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
// Fire-and-forget
|
|
107
|
-
install();
|
|
91
|
+
// Stream progress events so the frontend can show real-time status
|
|
92
|
+
const encoder = new TextEncoder();
|
|
93
|
+
const stream = new ReadableStream({
|
|
94
|
+
async start(controller) {
|
|
95
|
+
const send = (data: Record<string, unknown>) => {
|
|
96
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`));
|
|
97
|
+
};
|
|
108
98
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
99
|
+
try {
|
|
100
|
+
// Step 1: Install
|
|
101
|
+
send({ step: "install", status: "running", message: `Installing omniroute@${latest}...` });
|
|
102
|
+
await execFileAsync("npm", ["install", "-g", `omniroute@${latest}`, "--ignore-scripts"], {
|
|
103
|
+
timeout: 300000,
|
|
104
|
+
});
|
|
105
|
+
send({ step: "install", status: "done", message: `Installed omniroute@${latest}` });
|
|
106
|
+
|
|
107
|
+
// Step 2: Rebuild native modules (critical for better-sqlite3)
|
|
108
|
+
send({
|
|
109
|
+
step: "rebuild",
|
|
110
|
+
status: "running",
|
|
111
|
+
message: "Rebuilding native modules (better-sqlite3)...",
|
|
112
|
+
});
|
|
113
|
+
const globalRoot = (
|
|
114
|
+
await execFileAsync("npm", ["root", "-g"], { timeout: 10000 })
|
|
115
|
+
).stdout.trim();
|
|
116
|
+
const omniPath = `${globalRoot}/omniroute/app`;
|
|
117
|
+
await execFileAsync("npm", ["rebuild", "better-sqlite3"], {
|
|
118
|
+
cwd: omniPath,
|
|
119
|
+
timeout: 120000,
|
|
120
|
+
});
|
|
121
|
+
send({ step: "rebuild", status: "done", message: "Native modules rebuilt" });
|
|
122
|
+
|
|
123
|
+
// Step 3: Restart PM2
|
|
124
|
+
send({ step: "restart", status: "running", message: "Restarting service via PM2..." });
|
|
125
|
+
try {
|
|
126
|
+
await execFileAsync("pm2", ["restart", "omniroute", "--update-env"], { timeout: 30000 });
|
|
127
|
+
send({ step: "restart", status: "done", message: "Service restarted" });
|
|
128
|
+
} catch {
|
|
129
|
+
// PM2 may not be available (Docker/manual setups)
|
|
130
|
+
send({
|
|
131
|
+
step: "restart",
|
|
132
|
+
status: "skipped",
|
|
133
|
+
message: "PM2 not available — manual restart needed",
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
send({
|
|
138
|
+
step: "complete",
|
|
139
|
+
status: "done",
|
|
140
|
+
from: current,
|
|
141
|
+
to: latest,
|
|
142
|
+
message: `Update to v${latest} complete!`,
|
|
143
|
+
});
|
|
144
|
+
console.log(`[AutoUpdate] Successfully updated to v${latest}`);
|
|
145
|
+
} catch (err: any) {
|
|
146
|
+
const errMsg = err?.stderr || err?.message || String(err);
|
|
147
|
+
send({ step: "error", status: "failed", message: errMsg });
|
|
148
|
+
console.error(`[AutoUpdate] Update failed:`, err);
|
|
149
|
+
} finally {
|
|
150
|
+
controller.close();
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
return new Response(stream, {
|
|
156
|
+
headers: {
|
|
157
|
+
"Content-Type": "text/event-stream",
|
|
158
|
+
"Cache-Control": "no-cache",
|
|
159
|
+
Connection: "keep-alive",
|
|
160
|
+
},
|
|
114
161
|
});
|
|
115
162
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omniroute",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.7",
|
|
4
4
|
"description": "Smart AI Router with auto fallback — route to FREE & cheap models, zero downtime. Works with Cursor, Cline, Claude Desktop, Codex, and any OpenAI-compatible tool.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|