@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.
- package/.env.example +40 -0
- package/README.md +145 -2
- package/apps/agent/package.json +13 -0
- package/apps/agent/src/cloudflare.mjs +733 -0
- package/apps/agent/src/native-worker.mjs +52 -0
- package/apps/agent/src/native.mjs +457 -0
- package/apps/agent/src/runtime.mjs +760 -0
- package/apps/agent/src/server.mjs +195 -0
- package/apps/agent/src/static-server.mjs +53 -0
- package/apps/panel/AGENTS.md +9 -0
- package/apps/panel/CLAUDE.md +1 -0
- package/apps/panel/app/api/[...path]/route.js +445 -0
- package/apps/panel/app/globals.css +2057 -0
- package/apps/panel/app/icon.png +0 -0
- package/apps/panel/app/layout.jsx +18 -0
- package/apps/panel/app/login/page.jsx +108 -0
- package/apps/panel/app/page.jsx +33 -0
- package/apps/panel/app/ui/cloudflare.jsx +926 -0
- package/apps/panel/app/ui/dashboard.jsx +1487 -0
- package/apps/panel/app/ui/databases.jsx +293 -0
- package/apps/panel/app/ui/skeleton.jsx +196 -0
- package/apps/panel/app/ui/theme.jsx +35 -0
- package/apps/panel/lib/agent.mjs +83 -0
- package/apps/panel/lib/auth.mjs +48 -0
- package/apps/panel/lib/database-runtime.mjs +243 -0
- package/apps/panel/lib/databases.mjs +292 -0
- package/apps/panel/lib/db.mjs +6 -0
- package/apps/panel/next.config.mjs +8 -0
- package/apps/panel/package.json +22 -0
- package/apps/panel/public/naviyra-logo.png +0 -0
- package/bin/naviyra.mjs +215 -0
- package/db/001_init.sql +28 -0
- package/db/002_native_runtimes.sql +3 -0
- package/db/003_databases.sql +8 -0
- package/db/004_database_engines.sql +4 -0
- package/deploy/naviyra-agent.service +17 -0
- package/docker-compose.yml +18 -0
- package/docs/managed-runtime.md +52 -0
- package/docs/native-hosts.md +48 -0
- package/package.json +61 -4
- package/packages/runtime/artifacts.json +32 -0
- package/packages/runtime/index.cjs +526 -0
- package/packages/runtime/index.mjs +10 -0
- package/packages/runtime/package.json +6 -0
- package/packages/shared/index.mjs +85 -0
- package/packages/shared/package.json +9 -0
- package/scripts/migrate.mjs +18 -0
- package/scripts/panel-control.mjs +195 -0
- package/scripts/postgres-local.mjs +97 -0
- package/scripts/runtime-download-manifest.mjs +30 -0
- package/scripts/runtime.mjs +20 -0
- package/scripts/seed.mjs +35 -0
- package/scripts/service-supervisor.mjs +164 -0
- package/scripts/setup-local.mjs +215 -0
- package/scripts/start-naviyra.mjs +303 -0
- 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
|
+
}
|