/**
* π°οΈ Nodeloc Remote β Cloudflare Worker (v10)
*
* - Token TIDAK ada di kode Worker
* - Multi-akun di localStorage browser
* - Single Add + Bulk Add DNS record (1 target untuk banyak name)
*/
const NODELOC_BASE = "https://domain.nodeloc.com";
const corsHeaders = {
"access-control-allow-origin": "*",
"access-control-allow-headers": "content-type, x-nodeloc-token",
"access-control-allow-methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
};
const json = (data, status = 200) =>
new Response(JSON.stringify(data, null, 2), {
status,
headers: { "content-type": "application/json; charset=utf-8", ...corsHeaders },
});
const html = (body, status = 200) =>
new Response(body, { status, headers: { "content-type": "text/html; charset=utf-8" } });
const cors = () => new Response(null, { status: 204, headers: corsHeaders });
async function nodeloc(method, path, body, token) {
const init = {
method,
headers: {
Accept: "application/json, text/plain, */*",
Authorization: `Bearer ${token}`,
"User-Agent": "nodeloc-cf-worker/1.0",
},
};
if (body !== undefined && body !== null) {
init.headers["content-type"] = "application/json";
init.body = typeof body === "string" ? body : JSON.stringify(body);
}
const r = await fetch(`${NODELOC_BASE}${path}`, init);
const text = await r.text();
let data;
try { data = JSON.parse(text); } catch { data = text; }
return { status: r.status, data };
}
// βββββββββββββββββββββββββ HTML SHELL βββββββββββββββββββββββββ
const SHELL = `
Nodeloc Remote
β Tambah Akun
Simpan token JWT beberapa akun Nodeloc. Semua token hanya disimpan di
localStorage browser kamu.
π₯ Kelola Akun
Pilih akun aktif, ganti nama, atau hapus.
π°οΈ Nodeloc Remote
β
β³ Memuatβ¦
`;
// βββββββββββββββββββββββββ Router βββββββββββββββββββββββββ
export default {
async fetch(request) {
const url = new URL(request.url);
const path = url.pathname;
if (request.method === "OPTIONS") return cors();
if (path === "/" && request.method === "GET") return html(SHELL);
if (path === "/health") return json({ ok: true, base: NODELOC_BASE });
const token = (request.headers.get("x-nodeloc-token") || "").trim();
if (!token) return json({ error: "Unauthorized: header x-nodeloc-token kosong" }, 401);
try {
if (path === "/api/domains" && request.method === "GET") {
const { status, data } = await nodeloc("GET", "/api/domains", null, token);
return json(data, status);
}
let m = path.match(/^\/api\/domains\/(\d+)\/dnssec$/);
if (m && request.method === "GET") {
const { status, data } = await nodeloc("GET", `/api/domains/${m[1]}/dnssec`, null, token);
return json(data, status);
}
m = path.match(/^\/api\/domains\/(\d+)$/);
if (m && request.method === "GET") {
const { status, data } = await nodeloc("GET", `/api/domains/${m[1]}`, null, token);
return json(data, status);
}
if (path === "/api/cyberpanel/accounts" && request.method === "GET") {
const { status, data } = await nodeloc("GET", "/api/cyberpanel/accounts", null, token);
return json(data, status);
}
m = path.match(/^\/api\/dns\/(\d+)\/records$/);
if (m && request.method === "GET") {
const { status, data } = await nodeloc("GET", `/api/dns/${m[1]}/records`, null, token);
return json(data, status);
}
if (m && request.method === "POST") {
const body = await request.json();
if (!body.name || !body.type || !body.content) {
return json({ error: "field wajib: name, type, content" }, 400);
}
const payload = {
name: body.name,
type: body.type.toUpperCase(),
content: body.content,
ttl: body.ttl ?? 3600,
priority: body.priority ?? null,
is_active: body.is_active ?? true,
};
const { status, data } = await nodeloc("POST", `/api/dns/${m[1]}/records`, payload, token);
return json(data, status);
}
m = path.match(/^\/api\/dns\/(\d+)\/records\/(\d+)$/);
if (m && request.method === "DELETE") {
const { status, data } = await nodeloc("DELETE", `/api/dns/${m[1]}/records/${m[2]}`, null, token);
return json(data, status);
}
if (m && (request.method === "PATCH" || request.method === "PUT")) {
const body = await request.json();
const { status, data } = await nodeloc(request.method, `/api/dns/${m[1]}/records/${m[2]}`, body, token);
return json(data, status);
}
if (path === "/api/proxy" && request.method === "POST") {
const { method = "GET", path: p, body } = await request.json();
if (!p) return json({ error: "path wajib diisi" }, 400);
const { status, data } = await nodeloc(method.toUpperCase(), p, body, token);
return json(data, status);
}
return json({ error: "Not found", path }, 404);
} catch (e) {
return json({ error: e.message }, 500);
}
},
};