This commit is contained in:
1 parent
8efd032cc6
commit
df38dccbf1
735 files changed
+128321
-120870
No files matched your search
+123
-110
@@ -1,112 +1,125 @@
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "AtomCMS-Next API",
|
||||
"version": "1.0.0",
|
||||
"description": "Public and administrative REST API for the AtomCMS-Next Habbo retro hotel CMS."
|
||||
},
|
||||
"servers": [{ "url": "/api", "description": "Local API" }],
|
||||
"security": [{ "bearerAuth": [], "sessionAuth": [] }],
|
||||
"components": {
|
||||
"securitySchemes": {
|
||||
"bearerAuth": {
|
||||
"type": "http",
|
||||
"scheme": "bearer",
|
||||
"description": "Laravel Sanctum-compatible Bearer token from /api/tokens"
|
||||
},
|
||||
"sessionAuth": {
|
||||
"type": "apiKey",
|
||||
"in": "cookie",
|
||||
"name": "next-auth.session-token",
|
||||
"description": "NextAuth session cookie (auto-sent by browser)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"/health": {
|
||||
"get": {
|
||||
"summary": "Health check",
|
||||
"responses": { "200": { "description": "OK" } }
|
||||
}
|
||||
},
|
||||
"/articles": {
|
||||
"get": {
|
||||
"summary": "List published articles",
|
||||
"parameters": [
|
||||
{ "name": "limit", "in": "query", "schema": { "type": "integer", "default": 10 } },
|
||||
{ "name": "offset", "in": "query", "schema": { "type": "integer", "default": 0 } }
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Article list",
|
||||
"content": { "application/json": { "schema": { "type": "object" } } }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/online": {
|
||||
"get": {
|
||||
"summary": "Currently online users count",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Online count",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": { "type": "object", "properties": { "count": { "type": "integer" } } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/leaderboard": {
|
||||
"get": {
|
||||
"summary": "User leaderboard (credits, achievement score, etc.)",
|
||||
"responses": { "200": { "description": "Leaderboard data" } }
|
||||
}
|
||||
},
|
||||
"/client/sso": {
|
||||
"get": {
|
||||
"summary": "Generate SSO ticket for the game client (requires auth)",
|
||||
"security": [{ "sessionAuth": [] }],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "SSO ticket + hotel name + client URL",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ticket": { "type": "string" },
|
||||
"hotelName": { "type": "string" },
|
||||
"clientUrl": { "type": "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": { "description": "Unauthorized" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"/me": {
|
||||
"get": {
|
||||
"summary": "Current user profile (requires auth)",
|
||||
"security": [{ "sessionAuth": [] }],
|
||||
"responses": { "200": { "description": "User profile" } }
|
||||
}
|
||||
},
|
||||
"/settings": {
|
||||
"get": {
|
||||
"summary": "Public site settings (non-sensitive keys only)",
|
||||
"responses": { "200": { "description": "Settings object" } }
|
||||
}
|
||||
},
|
||||
"/shop/packages": {
|
||||
"get": {
|
||||
"summary": "Available shop packages",
|
||||
"responses": { "200": { "description": "Package list" } }
|
||||
}
|
||||
}
|
||||
}
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "AtomCMS-Next API",
|
||||
"version": "1.0.0",
|
||||
"description": "Public and administrative REST API for the AtomCMS-Next Habbo retro hotel CMS."
|
||||
},
|
||||
"servers": [{ "url": "/api", "description": "Local API" }],
|
||||
"security": [{ "bearerAuth": [], "sessionAuth": [] }],
|
||||
"components": {
|
||||
"securitySchemes": {
|
||||
"bearerAuth": {
|
||||
"type": "http",
|
||||
"scheme": "bearer",
|
||||
"description": "Laravel Sanctum-compatible Bearer token from /api/tokens"
|
||||
},
|
||||
"sessionAuth": {
|
||||
"type": "apiKey",
|
||||
"in": "cookie",
|
||||
"name": "next-auth.session-token",
|
||||
"description": "NextAuth session cookie (auto-sent by browser)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"/health": {
|
||||
"get": {
|
||||
"summary": "Health check",
|
||||
"responses": { "200": { "description": "OK" } }
|
||||
}
|
||||
},
|
||||
"/articles": {
|
||||
"get": {
|
||||
"summary": "List published articles",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "limit",
|
||||
"in": "query",
|
||||
"schema": { "type": "integer", "default": 10 }
|
||||
},
|
||||
{
|
||||
"name": "offset",
|
||||
"in": "query",
|
||||
"schema": { "type": "integer", "default": 0 }
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Article list",
|
||||
"content": {
|
||||
"application/json": { "schema": { "type": "object" } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/online": {
|
||||
"get": {
|
||||
"summary": "Currently online users count",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Online count",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": { "count": { "type": "integer" } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/leaderboard": {
|
||||
"get": {
|
||||
"summary": "User leaderboard (credits, achievement score, etc.)",
|
||||
"responses": { "200": { "description": "Leaderboard data" } }
|
||||
}
|
||||
},
|
||||
"/client/sso": {
|
||||
"get": {
|
||||
"summary": "Generate SSO ticket for the game client (requires auth)",
|
||||
"security": [{ "sessionAuth": [] }],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "SSO ticket + hotel name + client URL",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ticket": { "type": "string" },
|
||||
"hotelName": { "type": "string" },
|
||||
"clientUrl": { "type": "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": { "description": "Unauthorized" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"/me": {
|
||||
"get": {
|
||||
"summary": "Current user profile (requires auth)",
|
||||
"security": [{ "sessionAuth": [] }],
|
||||
"responses": { "200": { "description": "User profile" } }
|
||||
}
|
||||
},
|
||||
"/settings": {
|
||||
"get": {
|
||||
"summary": "Public site settings (non-sensitive keys only)",
|
||||
"responses": { "200": { "description": "Settings object" } }
|
||||
}
|
||||
},
|
||||
"/shop/packages": {
|
||||
"get": {
|
||||
"summary": "Available shop packages",
|
||||
"responses": { "200": { "description": "Package list" } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
(function () {
|
||||
try {
|
||||
var s = localStorage.getItem("theme");
|
||||
var dd = document.querySelector('meta[name="theme-default-dark"]');
|
||||
var defaultDark = dd ? dd.getAttribute("content") === "true" : false;
|
||||
if (s === "dark" || (!s && defaultDark)) document.documentElement.classList.add("dark");
|
||||
var nc = localStorage.getItem("navbarColor"),
|
||||
nt = localStorage.getItem("navbarTextColor");
|
||||
if (nc) document.documentElement.style.setProperty("--color-navbar", nc);
|
||||
if (nt) document.documentElement.style.setProperty("--color-navbar-text", nt);
|
||||
} catch (e) {}
|
||||
(() => {
|
||||
try {
|
||||
var s = localStorage.getItem("theme");
|
||||
var dd = document.querySelector('meta[name="theme-default-dark"]');
|
||||
var defaultDark = dd ? dd.getAttribute("content") === "true" : false;
|
||||
if (s === "dark" || (!s && defaultDark))
|
||||
document.documentElement.classList.add("dark");
|
||||
var nc = localStorage.getItem("navbarColor"),
|
||||
nt = localStorage.getItem("navbarTextColor");
|
||||
if (nc) document.documentElement.style.setProperty("--color-navbar", nc);
|
||||
if (nt)
|
||||
document.documentElement.style.setProperty("--color-navbar-text", nt);
|
||||
} catch (_e) {}
|
||||
})();
|
||||
+49
-42
@@ -4,54 +4,61 @@
|
||||
const CACHE = "atom-v1";
|
||||
|
||||
self.addEventListener("install", () => {
|
||||
self.skipWaiting();
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener("activate", (event) => {
|
||||
event.waitUntil(
|
||||
caches
|
||||
.keys()
|
||||
.then((keys) => Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k))))
|
||||
.then(() => self.clients.claim()),
|
||||
);
|
||||
event.waitUntil(
|
||||
caches
|
||||
.keys()
|
||||
.then((keys) =>
|
||||
Promise.all(
|
||||
keys.filter((k) => k !== CACHE).map((k) => caches.delete(k)),
|
||||
),
|
||||
)
|
||||
.then(() => self.clients.claim()),
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener("fetch", (event) => {
|
||||
const req = event.request;
|
||||
if (req.method !== "GET") return;
|
||||
const url = new URL(req.url);
|
||||
if (url.origin !== self.location.origin) return;
|
||||
const req = event.request;
|
||||
if (req.method !== "GET") return;
|
||||
const url = new URL(req.url);
|
||||
if (url.origin !== self.location.origin) return;
|
||||
|
||||
// Cache-first for immutable static assets.
|
||||
if (url.pathname.startsWith("/assets/") || url.pathname.startsWith("/_next/static/")) {
|
||||
event.respondWith(
|
||||
caches.open(CACHE).then((cache) =>
|
||||
cache.match(req).then(
|
||||
(hit) =>
|
||||
hit ||
|
||||
fetch(req).then((res) => {
|
||||
if (res.ok) cache.put(req, res.clone());
|
||||
return res;
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
// Cache-first for immutable static assets.
|
||||
if (
|
||||
url.pathname.startsWith("/assets/") ||
|
||||
url.pathname.startsWith("/_next/static/")
|
||||
) {
|
||||
event.respondWith(
|
||||
caches.open(CACHE).then((cache) =>
|
||||
cache.match(req).then(
|
||||
(hit) =>
|
||||
hit ||
|
||||
fetch(req).then((res) => {
|
||||
if (res.ok) cache.put(req, res.clone());
|
||||
return res;
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Network-first for page navigations; fall back to cache, then the shell.
|
||||
if (req.mode === "navigate") {
|
||||
event.respondWith(
|
||||
fetch(req)
|
||||
.then((res) => {
|
||||
const copy = res.clone();
|
||||
caches
|
||||
.open(CACHE)
|
||||
.then((c) => c.put(req, copy))
|
||||
.catch(() => {});
|
||||
return res;
|
||||
})
|
||||
.catch(() => caches.match(req).then((hit) => hit || caches.match("/"))),
|
||||
);
|
||||
}
|
||||
// Network-first for page navigations; fall back to cache, then the shell.
|
||||
if (req.mode === "navigate") {
|
||||
event.respondWith(
|
||||
fetch(req)
|
||||
.then((res) => {
|
||||
const copy = res.clone();
|
||||
caches
|
||||
.open(CACHE)
|
||||
.then((c) => c.put(req, copy))
|
||||
.catch(() => {});
|
||||
return res;
|
||||
})
|
||||
.catch(() => caches.match(req).then((hit) => hit || caches.match("/"))),
|
||||
);
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user