@naviyra/cloud-panel 0.0.0-stage → 0.0.2

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 (56) hide show
  1. package/.env.example +40 -0
  2. package/README.md +145 -2
  3. package/apps/agent/package.json +13 -0
  4. package/apps/agent/src/cloudflare.mjs +733 -0
  5. package/apps/agent/src/native-worker.mjs +52 -0
  6. package/apps/agent/src/native.mjs +457 -0
  7. package/apps/agent/src/runtime.mjs +760 -0
  8. package/apps/agent/src/server.mjs +195 -0
  9. package/apps/agent/src/static-server.mjs +53 -0
  10. package/apps/panel/AGENTS.md +9 -0
  11. package/apps/panel/CLAUDE.md +1 -0
  12. package/apps/panel/app/api/[...path]/route.js +445 -0
  13. package/apps/panel/app/globals.css +2057 -0
  14. package/apps/panel/app/icon.png +0 -0
  15. package/apps/panel/app/layout.jsx +18 -0
  16. package/apps/panel/app/login/page.jsx +108 -0
  17. package/apps/panel/app/page.jsx +33 -0
  18. package/apps/panel/app/ui/cloudflare.jsx +926 -0
  19. package/apps/panel/app/ui/dashboard.jsx +1487 -0
  20. package/apps/panel/app/ui/databases.jsx +293 -0
  21. package/apps/panel/app/ui/skeleton.jsx +196 -0
  22. package/apps/panel/app/ui/theme.jsx +35 -0
  23. package/apps/panel/lib/agent.mjs +83 -0
  24. package/apps/panel/lib/auth.mjs +48 -0
  25. package/apps/panel/lib/database-runtime.mjs +243 -0
  26. package/apps/panel/lib/databases.mjs +292 -0
  27. package/apps/panel/lib/db.mjs +6 -0
  28. package/apps/panel/next.config.mjs +8 -0
  29. package/apps/panel/package.json +22 -0
  30. package/apps/panel/public/naviyra-logo.png +0 -0
  31. package/bin/naviyra.mjs +215 -0
  32. package/db/001_init.sql +28 -0
  33. package/db/002_native_runtimes.sql +3 -0
  34. package/db/003_databases.sql +8 -0
  35. package/db/004_database_engines.sql +4 -0
  36. package/deploy/naviyra-agent.service +17 -0
  37. package/docker-compose.yml +18 -0
  38. package/docs/managed-runtime.md +52 -0
  39. package/docs/native-hosts.md +48 -0
  40. package/package.json +61 -4
  41. package/packages/runtime/artifacts.json +32 -0
  42. package/packages/runtime/index.cjs +526 -0
  43. package/packages/runtime/index.mjs +10 -0
  44. package/packages/runtime/package.json +6 -0
  45. package/packages/shared/index.mjs +85 -0
  46. package/packages/shared/package.json +9 -0
  47. package/scripts/migrate.mjs +18 -0
  48. package/scripts/panel-control.mjs +195 -0
  49. package/scripts/postgres-local.mjs +97 -0
  50. package/scripts/runtime-download-manifest.mjs +30 -0
  51. package/scripts/runtime.mjs +20 -0
  52. package/scripts/seed.mjs +35 -0
  53. package/scripts/service-supervisor.mjs +164 -0
  54. package/scripts/setup-local.mjs +215 -0
  55. package/scripts/start-naviyra.mjs +303 -0
  56. package/scripts/windows-boot.mjs +259 -0
Binary file
@@ -0,0 +1,18 @@
1
+ import "./globals.css";
2
+ import { ThemeSync } from "./ui/theme";
3
+ export const metadata = {
4
+ title: "Naviyra · Cloudflare hosting",
5
+ description: "Your applications. Your infrastructure. One panel.",
6
+ };
7
+ const themeScript = `(function(){try{var saved=localStorage.getItem("naviyra-theme");var theme=saved==="dark"||saved==="light"?saved:(matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light");document.documentElement.dataset.theme=theme;}catch(e){}})();`;
8
+ export default function Layout({ children }) {
9
+ return (
10
+ <html lang="en" suppressHydrationWarning>
11
+ <body>
12
+ <script dangerouslySetInnerHTML={{ __html: themeScript }} />
13
+ <ThemeSync />
14
+ {children}
15
+ </body>
16
+ </html>
17
+ );
18
+ }
@@ -0,0 +1,108 @@
1
+ "use client";
2
+ import { useEffect, useState } from "react";
3
+ import { ArrowRight, ShieldCheck, Cloud, Terminal } from "lucide-react";
4
+ import { ThemeToggle } from "../ui/theme";
5
+ export default function Login() {
6
+ const [error, setError] = useState("");
7
+ const [busy, setBusy] = useState(false);
8
+ const [ready, setReady] = useState(false);
9
+ useEffect(() => setReady(true), []);
10
+ async function submit(event) {
11
+ event.preventDefault();
12
+ setBusy(true);
13
+ setError("");
14
+ const values = Object.fromEntries(new FormData(event.currentTarget));
15
+ try {
16
+ const response = await fetch("/api/auth/login", {
17
+ method: "POST",
18
+ headers: { "Content-Type": "application/json" },
19
+ body: JSON.stringify(values),
20
+ });
21
+ const body = await response.json();
22
+ if (!response.ok) throw Error(body.error);
23
+ window.location.href = "/";
24
+ } catch (error) {
25
+ setError(error.message);
26
+ setBusy(false);
27
+ }
28
+ }
29
+ return (
30
+ <main className="login">
31
+ <section className="login-story">
32
+ <a className="brand" href="/">
33
+ <img src="/naviyra-logo.png" alt="Naviyra" className="brand-logo" />
34
+ </a>
35
+ <div>
36
+ <span className="eyebrow">YOUR INFRASTRUCTURE, SIMPLIFIED</span>
37
+ <h1>
38
+ A home for
39
+ <br />
40
+ what you build.
41
+ </h1>
42
+ <p>
43
+ Deploy your applications on Windows or Linux. Connect them to the
44
+ world with Cloudflare.
45
+ </p>
46
+ <div className="login-features">
47
+ <span>
48
+ <Cloud size={18} /> Automatic tunnels
49
+ </span>
50
+ <span>
51
+ <Terminal size={18} /> Managed services
52
+ </span>
53
+ <span>
54
+ <ShieldCheck size={18} /> Secure by design
55
+ </span>
56
+ </div>
57
+ </div>
58
+ <small>
59
+ Naviyra Panel <span>Native · Multiple runtimes</span>
60
+ </small>
61
+ </section>
62
+ <section className="login-form">
63
+ <ThemeToggle className="login-theme" />
64
+ <div>
65
+ <span className="eyebrow">CONTROL PANEL</span>
66
+ <h2>Welcome back</h2>
67
+ <p className="muted">Sign in to manage your applications.</p>
68
+ <form method="post" onSubmit={submit}>
69
+ <label>
70
+ Email address
71
+ <input
72
+ name="email"
73
+ type="email"
74
+ autoComplete="username"
75
+ placeholder="you@example.com"
76
+ required
77
+ />
78
+ </label>
79
+ <label>
80
+ Password
81
+ <input
82
+ name="password"
83
+ type="password"
84
+ autoComplete="current-password"
85
+ placeholder="Enter your password"
86
+ required
87
+ />
88
+ </label>
89
+ {error && (
90
+ <div role="alert" className="error">
91
+ {error}
92
+ </div>
93
+ )}
94
+ <button className="primary" disabled={busy || !ready}>
95
+ {busy ? "Signing in…" : "Sign in"}
96
+ <ArrowRight size={17} />
97
+ </button>
98
+ </form>
99
+ <p className="login-note">
100
+ <ShieldCheck size={16} /> Access is restricted to registered users.
101
+ <br />
102
+ Contact your server administrator for an account.
103
+ </p>
104
+ </div>
105
+ </section>
106
+ </main>
107
+ );
108
+ }
@@ -0,0 +1,33 @@
1
+ import { redirect } from "next/navigation";
2
+ import { session } from "../lib/auth.mjs";
3
+ import Dashboard from "./ui/dashboard";
4
+ export const dynamic = "force-dynamic";
5
+ const views = new Set([
6
+ "projects",
7
+ "infrastructure",
8
+ "activity",
9
+ "databases",
10
+ "dns",
11
+ "email",
12
+ ]);
13
+ const tabs = new Set(["overview", "logs", "deployments"]);
14
+ const projectId = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
15
+ function one(value) {
16
+ return (Array.isArray(value) ? value[0] : value) || "";
17
+ }
18
+ export default async function Page({ searchParams }) {
19
+ const user = await session();
20
+ if (!user) redirect("/login");
21
+ const params = await searchParams;
22
+ const view = views.has(one(params?.view)) ? one(params.view) : "projects";
23
+ const project = projectId.test(one(params?.project)) ? one(params.project) : null;
24
+ const tab = tabs.has(one(params?.tab)) ? one(params.tab) : "overview";
25
+ return (
26
+ <Dashboard
27
+ user={user}
28
+ initialView={view}
29
+ initialProject={project}
30
+ initialTab={tab}
31
+ />
32
+ );
33
+ }