23 Commits

Author SHA1 Message Date
9aa4d5b438 docs: collect refreshed mongo-ops wiki site (UC 17 Related cross-links + themed index map) 2026-09-14 21:02:19 +05:30
be1a5abe25 docs: collect mongo-ops wiki with Use Cases promoted to its own tab (themed groups) 2026-09-14 20:20:29 +05:30
1e560f9a35 docs: collect refreshed mongo-ops wiki site (UC17 populate/depopulate worked examples) 2026-09-14 20:19:22 +05:30
317fd128bf docs: collect refreshed mongo-ops wiki site (UC15/16 deep dives, UC10 cache-miss fix, corrected cache imports) 2026-09-14 14:37:23 +05:30
f406aa2f21 docs: collect refreshed mongo-ops wiki site (API-correct overhaul, v0.1.5) 2026-09-14 13:46:11 +05:30
bbd9863d23 refresh collected sites/mcp for docstring changes in dagpipe, mail-intake, openapi-first 2026-09-14 00:18:17 +05:30
9516e0b4cb docs: refresh collected sites after per-kind mkdocs config standardisation 2026-09-13 18:26:26 +05:30
e272527b88 docs: refresh collected sites and MCP bundles after GSDFC docstring conformance 2026-09-13 16:24:16 +05:30
754255166f refactored view docs to view api 2026-09-12 15:01:55 +05:30
6124d8c1e8 docs: add auth-server lib and wiki sites and refresh collections 2026-09-12 14:58:43 +05:30
bf83538136 docs: refresh doc-forge split sites (lib + wiki) 2026-09-12 14:23:24 +05:30
167d44fcfe docs: refresh doc-forge library and MCP bundle
- collect regenerated doc-forge combined site (wiki + lib)
- drop stale lib/docforge duplicate subtree
- mcp bundle now uses docs:// module resources
2026-09-12 13:12:55 +05:30
bd8ba6e67c feat: regroup homepage into apps/tutorial/services/libraries cards
- assign each repo a section via config.yml (blog -> apps,
  media-manager -> tutorial, auth-server -> services, rest -> libraries)
- render one card per repo with a bottom-justified action row containing
  one link per available kind (view docs / view wiki / view lib /
  view tutorial)
- switch card grid to three columns with responsive breakpoints and
  taller cards
2026-09-11 23:49:59 +05:30
42e5ed290e feat: list each declared doc kind as its own homepage card
- compute per-kind home URLs (lib/, api/, wiki/) via _find_home_for_kind
- emit one card per declared kind so multi-kind repos (e.g. doc-forge
  with lib + wiki) appear in each matching homepage section
- declare the doc-forge wiki kind and refresh its vendored site with the
  combined lib + wiki build
2026-09-11 23:38:31 +05:30
a32eeaf2b4 feat: serve docs flat at /<repo>/ with no redirects
- collect.py copies each repo's built site contents directly to a
  top-level <repo>/ dir (was libs|apis|wiki/<repo>/site nesting)
- nginx uses `index index.html lib/index.html api/index.html` so
  /dagpipe/ -> lib/index.html, /auth-server/ -> api/index.html are
  served internally with no redirects
- _index regenerates links against the flat layout
  (/dagpipe/lib/, /auth-server/api/, /mongo-ops/, /blog/...)
- config.yml static entries point at vendored blog/ + media-manager/
- Dockerfile copies per-repo dirs flat into the nginx html root
- removed stale libs/, apis/, wiki/, tutorials/ category trees
2026-09-11 21:32:30 +05:30
0c25cbb19f feat: unify docs portal and MCP servers into one config-driven service
- add config.yml as single source of truth for collected repos/categories
- add collect.py CLI to pull lib/api/wiki site builds and mcp bundles from
  source repos and regenerate nginx.conf + _index/index.html
- port mcp runtime (main.py/core.py/config.py): nginx + health + FastMCP
  servers started from config.yml
- docker: python:3.13-slim + nginx, expose 8000-8006 + 9000 (html portal)
- drone: publish html (6007:9000) and MCP ports 8000-8006
- move mongo-ops docs to wiki/, add auth-server (api) and hexa (lib)
- refresh lib site builds (lib/ prefix) and collect mcp bundles
2026-09-11 15:14:51 +05:30
0e49f02c4c updated mcp
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-08 17:57:34 +05:30
9191de9dff Build: 0.1.8
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-08 01:01:39 +05:30
8701bf92ac updated doc forge docs
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-07 16:24:14 +05:30
91baa41bee fixed missing indexes
All checks were successful
continuous-integration/drone/push Build is passing
2026-02-21 22:21:10 +05:30
24ecde4222 added more libs
All checks were successful
continuous-integration/drone/push Build is passing
2026-01-22 17:20:17 +05:30
239064f088 bumped up to 0.1.6
All checks were successful
continuous-integration/drone/push Build is passing
2025-12-10 16:21:37 +05:30
03de5cd2b4 ## Commit Message
**Restructure documentation layout, update entrypoint links, and migrate folders**

This commit introduces a consistent and modular documentation structure by
grouping related documentation under `libs`, `apis`, and `tutorials`. The
Dockerfile now reflects the new paths, and the index page links have been
adjusted accordingly.

### Folder Migrations
The following documentation directories were moved:

- `./mongo-ops/site` → `./libs/mongo-ops/site`
- `./blog-api/site` → `./apis/blog/site`
- `./tutorials/media-manager/site` (unchanged, retained under tutorials)

These changes improve namespace clarity and reflect the logical separation
between libraries, APIs, and tutorials.

### Additional Changes
- Updated URLs in `_index/index.html` to point to `/libs/mongo-ops/` and `/apis/blog/`.
- Removed outdated root-level documentation folders.
2025-12-10 16:17:29 +05:30
1618 changed files with 622056 additions and 6030 deletions

View File

@@ -16,25 +16,17 @@ volumes:
path: /var/run/docker.sock
steps:
# # 🏗️ Step 1: Build static docs for all projects
# - name: build-docs
# image: squidfunk/mkdocs-material
# commands:
# - echo "🧱 Building documentation for all projects..."
# - cd mongo-ops && mkdocs build --clean && cd ..
# - echo "✅ All docs built successfully."
# 🐳 Step 2: Build Docker image for docs site
# 🐳 Step 1: Build Docker image
- name: build-image
image: docker:24
volumes:
- name: dockersock
path: /var/run/docker.sock
commands:
- echo "🔨 Building Docker image for docs..."
- echo "🔨 Building Docker image for aetos-docs..."
- docker build -t aetos/docs:latest .
# 📤 Step 3: Push image to private registry
# 📤 Step 2: Push image to private registry
- name: push-image
image: docker:24
environment:
@@ -69,12 +61,18 @@ steps:
- name: dockersock
path: /var/run/docker.sock
commands:
- echo "🚀 Starting container aetos/docs:latest ..."
- echo "🚀 Starting aetos/docs:latest ..."
- |
docker run -d \
--name docs \
-p 6007:80 \
-e NODE_ENV=production \
-p 6007:9000 \
-p 8000:8000 \
-p 8001:8001 \
-p 8002:8002 \
-p 8003:8003 \
-p 8004:8004 \
-p 8005:8005 \
-p 8006:8006 \
--restart always \
aetos/docs:latest

2
.gitignore vendored
View File

@@ -1,2 +1,4 @@
.venv
.idea
__pycache__/
*.pyc

View File

@@ -1,25 +1,51 @@
# Stage 1: Base Nginx static server
FROM nginx:1.27-alpine
# ---------------------------------------------------------------------------
# aetos-docs — serves both the HTML documentation portal (nginx) and the
# per-library MCP servers (FastMCP streamable-http).
# ---------------------------------------------------------------------------
FROM python:3.13-slim
# Metadata
LABEL maintainer="Aetoskia <dev@aetoskia.com>"
LABEL description="Static documentation host for Aetoskia projects"
LABEL description="Unified documentation portal and MCP server for Aetoskia projects"
# Copy custom Nginx configuration
# --- system deps -----------------------------------------------------------
RUN apt-get update && \
apt-get install -y --no-install-recommends nginx && \
rm -rf /var/lib/apt/lists/*
# --- python deps -----------------------------------------------------------
WORKDIR /app
ARG PIP_USERNAME
ARG PIP_PASSWORD
ARG PIP_REPO_URL
COPY requirements.txt .
RUN pip install --no-cache-dir uv && \
uv pip install --system -r requirements.txt
# --- application files -----------------------------------------------------
COPY main.py core.py config.py collect.py config.yml ./
COPY nginx.conf /etc/nginx/conf.d/default.conf
RUN rm -f /etc/nginx/sites-enabled/default
# Copy all project docs
# Expected folder layout (on build context):
COPY ./_index /usr/share/nginx/html/
COPY ./mongo-ops/site /usr/share/nginx/html/mongo-ops/
COPY ./blog-api/site /usr/share/nginx/html/api/blog/
COPY ./tutorials/media-manager/site /usr/share/nginx/html/tutorials/media-manager/
# --- collected documentation tree (flat, one dir per repo) -----------------
COPY _index /usr/share/nginx/html/
COPY openapi-first /usr/share/nginx/html/openapi-first
COPY doc-forge /usr/share/nginx/html/doc-forge
COPY dagpipe /usr/share/nginx/html/dagpipe
COPY mail-intake /usr/share/nginx/html/mail-intake
COPY omniread /usr/share/nginx/html/omniread
COPY py-jwt /usr/share/nginx/html/py-jwt
COPY hexa /usr/share/nginx/html/hexa
COPY mongo-ops /usr/share/nginx/html/mongo-ops
COPY auth-server /usr/share/nginx/html/auth-server
COPY blog /usr/share/nginx/html/blog
COPY media-manager /usr/share/nginx/html/media-manager
# Expose HTTP port
EXPOSE 80
# --- MCP bundles -----------------------------------------------------------
COPY mcp /app/mcp
# Healthcheck
HEALTHCHECK --interval=30s --timeout=5s CMD wget -qO- http://localhost/ || exit 1
EXPOSE 8000 8001 8002 8003 8004 8005 8006 9000
# Start Nginx
CMD ["nginx", "-g", "daemon off;"]
CMD ["python", "main.py"]

View File

@@ -16,148 +16,175 @@
--font-main: 'Inter', 'Roboto', sans-serif;
--font-code: 'JetBrains Mono', monospace;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
* { margin:0; padding:0; box-sizing:border-box; }
body {
background: var(--bg);
color: var(--text);
font-family: var(--font-main);
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
padding: 3rem 1.5rem;
background:var(--bg); color:var(--text); font-family:var(--font-main);
min-height:100vh; display:flex; flex-direction:column;
align-items:center; justify-content:flex-start; padding:3rem 1.5rem;
}
header {
text-align: center;
margin-bottom: 3rem;
header { text-align:center; margin-bottom:3rem; }
h1 { font-size:2.5rem; color:var(--accent); letter-spacing:0.5px; margin-bottom:0.5rem; }
.subtitle { color:var(--muted); font-size:1rem; }
.badge {
display:inline-block; margin-top:0.8rem; background:#30363d; color:#fff;
padding:3px 8px; border-radius:6px; font-size:0.85rem; font-weight:600;
border:1px solid #484f58;
}
h1 {
font-size: 2.5rem;
color: var(--accent);
letter-spacing: 0.5px;
margin-bottom: 0.5rem;
.section { width:100%; max-width:1200px; margin-bottom:2.5rem; }
.section h2 {
font-size:1.2rem; color:var(--muted); text-transform:uppercase;
letter-spacing:1.5px; margin-bottom:1rem; border-bottom:1px solid var(--border);
padding-bottom:0.4rem;
}
p {
color: var(--muted);
font-size: 1rem;
margin-bottom: 0.5rem;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1.5rem;
width: 100%;
max-width: 900px;
display:grid; grid-template-columns:repeat(3, 1fr); gap:1.5rem; width:100%;
}
@media (max-width: 1024px) {
.grid { grid-template-columns:repeat(2, 1fr); }
}
@media (max-width: 640px) {
.grid { grid-template-columns:1fr; }
}
.card {
background: var(--card);
border: 1px solid var(--border);
border-radius: 12px;
padding: 1.8rem;
text-align: left;
transition: transform 0.15s ease, box-shadow 0.15s ease;
background:var(--card); border:1px solid var(--border); border-radius:12px;
padding:1.6rem; text-align:left; display:flex; flex-direction:column;
height:100%; min-height:200px;
transition:transform 0.15s ease,box-shadow 0.15s ease;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 0 20px rgba(45, 212, 191, 0.2);
border-color: var(--accent);
transform:translateY(-4px); box-shadow:0 0 20px rgba(45,212,191,0.2);
border-color:var(--accent);
}
.card h2 {
color: var(--accent);
font-size: 1.4rem;
margin-bottom: 0.4rem;
.card h3 { color:var(--accent); font-size:1.4rem; margin-bottom:0.4rem; }
.card p { color:var(--muted); font-size:0.95rem; line-height:1.6; }
.card-actions {
margin-top:auto; padding-top:1.2rem; display:flex; flex-wrap:wrap; gap:0.6rem;
}
.card p {
color: var(--muted);
font-size: 0.95rem;
line-height: 1.6;
.card-actions a {
color:var(--accent); text-decoration:none; font-size:0.85rem; font-weight:600;
padding:0.45rem 0.9rem; border:1px solid var(--border); border-radius:999px;
background:rgba(45,212,191,0.06);
transition:border-color 0.15s ease,background 0.15s ease,color 0.15s ease;
}
.card a {
color: var(--accent);
text-decoration: none;
display: inline-block;
margin-top: 0.8rem;
font-weight: 500;
}
.card a:hover {
color: var(--accent-dim);
text-decoration: underline;
}
footer {
margin-top: 4rem;
text-align: center;
color: var(--muted);
font-size: 0.9rem;
.card-actions a:hover {
color:var(--accent-dim); border-color:var(--accent);
background:rgba(45,212,191,0.14);
}
footer { margin-top:4rem; text-align:center; color:var(--muted); font-size:0.9rem; }
</style>
</head>
<body>
<header>
<h1>Aetoskia Developer Docs</h1>
<p>Central documentation hub for Aetoskia projects</p>
<span style="
background: #30363d;
color: #fff;
padding: 3px 8px;
border-radius: 6px;
font-size: 0.85rem;
font-weight: 600;
border: 1px solid #484f58;
">
Build: 0.1.5
</span>
<p class="subtitle">Central documentation hub for Aetoskia projects</p>
</header>
<div class="grid">
<div class="card">
<h2>Mongo Ops</h2>
<p>
A modular, async MongoDB operations layer for FastAPI microservices.
Simplifies CRUD, transactions, and model management.
</p>
<a href="/mongo-ops/" target="_blank">View Documentation →</a>
</div>
<div class="card">
<h2>Blog API</h2>
<p>
A modular, async Blog API backend for FastAPI microservices.
Provides streamlined CRUD operations for articles and authors, supports nested author details within article endpoints, and enables simple association management between content and contributors.
</p>
<a href="/api/blog/" target="_blank">View Documentation →</a>
</div>
<div class="card">
<h2>Media Manager Tutorial</h2>
<p>
Step-by-step guide to the Media Manager architecture, ingestion pipeline,
automation workflows, and integration with Radarr, Sonarr, and your custom
dashboard services.
</p>
<a href="/tutorials/media-manager/" target="_blank">View Tutorial →</a>
<section class="section">
<h2>Apps</h2>
<div class="grid">
<div class="card">
<h3>Blog API</h3>
<p>A modular, async Blog API backend for FastAPI microservices. Provides streamlined CRUD operations for articles and authors.</p>
<div class="card-actions">
<a href="/blog/" target="_blank">view docs</a>
</div>
</div>
</div>
</section>
<section class="section">
<h2>Tutorial</h2>
<div class="grid">
<div class="card">
<h3>Media Manager Tutorial</h3>
<p>Step-by-step guide to the Media Manager architecture, ingestion pipeline, automation workflows, and integrations.</p>
<div class="card-actions">
<a href="/media-manager/" target="_blank">view tutorial</a>
</div>
</div>
</div>
</section>
<section class="section">
<h2>Services</h2>
<div class="grid">
<div class="card">
<h3>Auth Server</h3>
<p>Aetoskia authentication service. OpenAPI-driven, FastAPI backend for auth flows.</p>
<div class="card-actions">
<a href="/auth-server/api/" target="_blank">view api</a>
<a href="/auth-server/wiki/" target="_blank">view wiki</a>
<a href="/auth-server/lib/" target="_blank">view lib</a>
</div>
</div>
</div>
</section>
<section class="section">
<h2>Libraries</h2>
<div class="grid">
<div class="card">
<h3>OpenAPI First</h3>
<p>Design-first API development toolkit enforcing OpenAPI contracts as the single source of truth.</p>
<div class="card-actions">
<a href="/openapi-first/lib/" target="_blank">view lib</a>
</div>
</div>
<div class="card">
<h3>Doc Forge</h3>
<p>Renderer-agnostic Python documentation compiler powering MkDocs and MCP generation across Aetoskia projects.</p>
<div class="card-actions">
<a href="/doc-forge/wiki/" target="_blank">view wiki</a>
<a href="/doc-forge/lib/" target="_blank">view lib</a>
</div>
</div>
<div class="card">
<h3>DAG Pipe</h3>
<p>Deterministic pipeline framework for executing state transformations through a directed acyclic graph (DAG).</p>
<div class="card-actions">
<a href="/dagpipe/lib/" target="_blank">view lib</a>
</div>
</div>
<div class="card">
<h3>Mail Intake</h3>
<p>High-performance email ingestion and processing framework with pluggable adapters and automation workflows.</p>
<div class="card-actions">
<a href="/mail-intake/lib/" target="_blank">view lib</a>
</div>
</div>
<div class="card">
<h3>Omniread</h3>
<p>Unified ingestion and normalization layer for structured and unstructured data sources.</p>
<div class="card-actions">
<a href="/omniread/lib/" target="_blank">view lib</a>
</div>
</div>
<div class="card">
<h3>Py JWT</h3>
<p>Lightweight, explicit JWT utilities for Python services with strong validation and minimal magic.</p>
<div class="card-actions">
<a href="/py-jwt/lib/" target="_blank">view lib</a>
</div>
</div>
<div class="card">
<h3>Hexa</h3>
<p>Hexagonal architecture framework and toolbox for Python services.</p>
<div class="card-actions">
<a href="/hexa/lib/" target="_blank">view lib</a>
</div>
</div>
<div class="card">
<h3>Mongo Ops</h3>
<p>A modular, async MongoDB operations layer for FastAPI microservices. Simplifies CRUD, transactions, and model management.</p>
<div class="card-actions">
<a href="/mongo-ops/" target="_blank">view wiki</a>
</div>
</div>
</div>
</section>
<footer>
© 2025 Aetoskia Developer Network — Built with ❤️ on Raspberry Pi
&copy; 2025 Aetoskia Developer Network
</footer>
</body>
</html>
</html>

309
auth-server/404.html Normal file
View File

@@ -0,0 +1,309 @@
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="
The Aetoskia Authentication Service.
Provides identity, access control, and JWT token issuance for the Aetoskia
ecosystem. Fully async, built with FastAPI and MongoDB.
">
<meta name="author" content="Aetoskia Dev Team">
<link rel="icon" href="/assets/images/favicon.png">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.23">
<title>Aetoskia Auth Server</title>
<link rel="stylesheet" href="/assets/stylesheets/main.84d31ad4.min.css">
<link rel="stylesheet" href="/assets/stylesheets/palette.06af60db.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Inter";--md-code-font:"JetBrains Mono"}</style>
<link rel="stylesheet" href="https://unpkg.com/dracula-prism/dist/css/dracula-prism.css">
<script>__md_scope=new URL("/",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr" data-md-color-scheme="slate" data-md-color-primary="deep-purple" data-md-color-accent="cyan">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="/." title="Aetoskia Auth Server" class="md-header__button md-logo" aria-label="Aetoskia Auth Server" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 3C7.58 3 4 4.79 4 7s3.58 4 8 4 8-1.79 8-4-3.58-4-8-4M4 9v3c0 2.21 3.58 4 8 4s8-1.79 8-4V9c0 2.21-3.58 4-8 4s-8-1.79-8-4m0 5v3c0 2.21 3.58 4 8 4s8-1.79 8-4v-3c0 2.21-3.58 4-8 4s-8-1.79-8-4"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Aetoskia Auth Server
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="" data-md-color-scheme="slate" data-md-color-primary="deep-purple" data-md-color-accent="cyan" aria-hidden="true" type="radio" name="__palette" id="__palette_0">
</form>
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<a href="javascript:void(0)" class="md-search__icon md-icon" title="Share" aria-label="Share" data-clipboard data-clipboard-text="" data-md-component="search-share" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91s2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08"/></svg>
</a>
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary md-nav--integrated" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="/." title="Aetoskia Auth Server" class="md-nav__button md-logo" aria-label="Aetoskia Auth Server" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 3C7.58 3 4 4.79 4 7s3.58 4 8 4 8-1.79 8-4-3.58-4-8-4M4 9v3c0 2.21 3.58 4 8 4s8-1.79 8-4V9c0 2.21-3.58 4-8 4s-8-1.79-8-4m0 5v3c0 2.21 3.58 4 8 4s8-1.79 8-4v-3c0 2.21-3.58 4-8 4s-8-1.79-8-4"/></svg>
</a>
Aetoskia Auth Server
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="/api/" class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1>404 - Not found</h1>
</article>
</div>
<script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "/", "features": ["navigation.sections", "navigation.expand", "navigation.top", "navigation.instant", "navigation.tracking", "navigation.indexes", "content.code.copy", "content.code.annotate", "content.tabs.link", "content.action.edit", "search.highlight", "search.share", "search.suggest", "toc.integrate", "header.autohide", "announce.dismiss", "footer.social", "content.code.select", "content.code.line_numbers", "content.tooltips"], "search": "/assets/javascripts/workers/search.973d3a69.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
<script src="/assets/javascripts/bundle.f55a23d4.min.js"></script>
</body>
</html>

309
auth-server/api/404.html Normal file
View File

@@ -0,0 +1,309 @@
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="
The Aetoskia Authentication Service.
Provides identity, access control, and JWT token issuance for the Aetoskia
ecosystem. Fully async, built with FastAPI and MongoDB.
">
<meta name="author" content="Aetoskia Dev Team">
<link rel="icon" href="/assets/images/favicon.png">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.23">
<title>Aetoskia Auth Server</title>
<link rel="stylesheet" href="/assets/stylesheets/main.84d31ad4.min.css">
<link rel="stylesheet" href="/assets/stylesheets/palette.06af60db.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Inter";--md-code-font:"JetBrains Mono"}</style>
<link rel="stylesheet" href="https://unpkg.com/dracula-prism/dist/css/dracula-prism.css">
<script>__md_scope=new URL("/",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr" data-md-color-scheme="slate" data-md-color-primary="deep-purple" data-md-color-accent="cyan">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="/." title="Aetoskia Auth Server" class="md-header__button md-logo" aria-label="Aetoskia Auth Server" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7 14c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2m5.6-4c-.8-2.3-3-4-5.6-4-3.3 0-6 2.7-6 6s2.7 6 6 6c2.6 0 4.8-1.7 5.6-4H16v4h4v-4h3v-4z"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Aetoskia Auth Server
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="" data-md-color-scheme="slate" data-md-color-primary="deep-purple" data-md-color-accent="cyan" aria-hidden="true" type="radio" name="__palette" id="__palette_0">
</form>
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<a href="javascript:void(0)" class="md-search__icon md-icon" title="Share" aria-label="Share" data-clipboard data-clipboard-text="" data-md-component="search-share" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91s2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08"/></svg>
</a>
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary md-nav--integrated" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="/." title="Aetoskia Auth Server" class="md-nav__button md-logo" aria-label="Aetoskia Auth Server" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7 14c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2m5.6-4c-.8-2.3-3-4-5.6-4-3.3 0-6 2.7-6 6s2.7 6 6 6c2.6 0 4.8-1.7 5.6-4H16v4h4v-4h3v-4z"/></svg>
</a>
Aetoskia Auth Server
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="/." class="md-nav__link">
<span class="md-ellipsis">
API Reference
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1>404 - Not found</h1>
</article>
</div>
<script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "/", "features": ["navigation.sections", "navigation.expand", "navigation.top", "navigation.instant", "navigation.tracking", "navigation.indexes", "content.code.copy", "content.code.annotate", "content.tabs.link", "content.action.edit", "search.highlight", "search.share", "search.suggest", "toc.integrate", "header.autohide", "announce.dismiss", "footer.social", "content.code.select", "content.code.line_numbers", "content.tooltips"], "search": "/assets/javascripts/workers/search.973d3a69.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
<script src="/assets/javascripts/bundle.f55a23d4.min.js"></script>
</body>
</html>

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,6 @@
<!doctype html>
<html lang="en-US">
<body>
<script src="oauth2-redirect.js"></script>
</body>
</html>

View File

@@ -0,0 +1 @@
"use strict";function run(){var e,r,t,a=window.opener.swaggerUIRedirectOauth2,o=a.state,n=a.redirectUrl;if((t=(r=/code|token|error/.test(window.location.hash)?window.location.hash.substring(1).replace("?","&"):location.search.substring(1)).split("&")).forEach((function(e,r,t){t[r]='"'+e.replace("=",'":"')+'"'})),e=(r=r?JSON.parse("{"+t.join()+"}",(function(e,r){return""===e?r:decodeURIComponent(r)})):{}).state===o,"accessCode"!==a.auth.schema.get("flow")&&"authorizationCode"!==a.auth.schema.get("flow")&&"authorization_code"!==a.auth.schema.get("flow")||a.auth.code)a.callback({auth:a.auth,token:r,isValid:e,redirectUrl:n});else if(e||a.errCb({authId:a.auth.name,source:"auth",level:"warning",message:"Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"}),r.code)delete a.state,a.auth.code=r.code,a.callback({auth:a.auth,redirectUrl:n});else{let e;r.error&&(e="["+r.error+"]: "+(r.error_description?r.error_description+". ":"no accessCode received from the server. ")+(r.error_uri?"More info: "+r.error_uri:"")),a.errCb({authId:a.auth.name,source:"auth",level:"error",message:e||"[Authorization failed]: no accessCode received from the server"})}window.close()}"loading"!==document.readyState?run():document.addEventListener("DOMContentLoaded",(function(){run()}));

234
auth-server/api/index.html Normal file
View File

@@ -0,0 +1,234 @@
<!DOCTYPE html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8"/>
<meta content="width=device-width,initial-scale=1" name="viewport"/>
<meta content="
The Aetoskia Authentication Service.
Provides identity, access control, and JWT token issuance for the Aetoskia
ecosystem. Fully async, built with FastAPI and MongoDB.
" name="description"/>
<meta content="Aetoskia Dev Team" name="author"/>
<link href="assets/images/favicon.png" rel="icon"/>
<meta content="mkdocs-1.6.1, mkdocs-material-9.6.23" name="generator"/>
<title>Aetoskia Auth Server</title>
<link href="assets/stylesheets/main.84d31ad4.min.css" rel="stylesheet"/>
<link href="assets/stylesheets/palette.06af60db.min.css" rel="stylesheet"/>
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/>
<link href="https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i%7CJetBrains+Mono:400,400i,700,700i&amp;display=fallback" rel="stylesheet"/>
<style>:root{--md-text-font:"Inter";--md-code-font:"JetBrains Mono"}</style>
<link href="https://unpkg.com/dracula-prism/dist/css/dracula-prism.css" rel="stylesheet"/>
<script>__md_scope=new URL(".",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body data-md-color-accent="cyan" data-md-color-primary="deep-purple" data-md-color-scheme="slate" dir="ltr">
<input autocomplete="off" class="md-toggle" data-md-toggle="drawer" id="__drawer" type="checkbox"/>
<input autocomplete="off" class="md-toggle" data-md-toggle="search" id="__search" type="checkbox"/>
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a class="md-skip" href="#api-reference">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow" data-md-component="header">
<nav aria-label="Header" class="md-header__inner md-grid">
<a aria-label="Aetoskia Auth Server" class="md-header__button md-logo" data-md-component="logo" href="." title="Aetoskia Auth Server">
<svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M7 14c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2m5.6-4c-.8-2.3-3-4-5.6-4-3.3 0-6 2.7-6 6s2.7 6 6 6c2.6 0 4.8-1.7 5.6-4H16v4h4v-4h3v-4z"></path></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"></path></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Aetoskia Auth Server
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
API Reference
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input aria-hidden="true" class="md-option" data-md-color-accent="cyan" data-md-color-media="" data-md-color-primary="deep-purple" data-md-color-scheme="slate" id="__palette_0" name="__palette" type="radio"/>
</form>
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"></path></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input aria-label="Search" autocapitalize="off" autocomplete="off" autocorrect="off" class="md-search__input" data-md-component="search-query" name="query" placeholder="Search" required="" spellcheck="false" type="text"/>
<label class="md-search__icon md-icon" for="__search">
<svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"></path></svg>
<svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"></path></svg>
</label>
<nav aria-label="Search" class="md-search__options">
<a aria-label="Share" class="md-search__icon md-icon" data-clipboard="" data-clipboard-text="" data-md-component="search-share" href="javascript:void(0)" tabindex="-1" title="Share">
<svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91s2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08"></path></svg>
</a>
<button aria-label="Clear" class="md-search__icon md-icon" tabindex="-1" title="Clear" type="reset">
<svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix="" tabindex="0">
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav aria-label="Navigation" class="md-nav md-nav--primary md-nav--integrated" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a aria-label="Aetoskia Auth Server" class="md-nav__button md-logo" data-md-component="logo" href="." title="Aetoskia Auth Server">
<svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M7 14c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2m5.6-4c-.8-2.3-3-4-5.6-4-3.3 0-6 2.7-6 6s2.7 6 6 6c2.6 0 4.8-1.7 5.6-4H16v4h4v-4h3v-4z"></path></svg>
</a>
Aetoskia Auth Server
</label>
<ul class="md-nav__list" data-md-scrollfix="">
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" id="__toc" type="checkbox"/>
<a class="md-nav__link md-nav__link--active" href=".">
<span class="md-ellipsis">
API Reference
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="api-reference">API Reference</h1>
<p><iframe class="swagger-ui-iframe" frameborder="0" id="4f4c9641" onload="this.style.display = 'block'; this.style.overflow = 'hidden'; this.style.width = '100%';" src="swagger-4f4c9641.html" style="display:none;" width="100%"></iframe></p>
</article>
</div>
<script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button class="md-top md-icon" data-md-component="top" hidden="" type="button">
<svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"></path></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" rel="noopener" target="_blank">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": ".", "features": ["navigation.sections", "navigation.expand", "navigation.top", "navigation.instant", "navigation.tracking", "navigation.indexes", "content.code.copy", "content.code.annotate", "content.tabs.link", "content.action.edit", "search.highlight", "search.share", "search.suggest", "toc.integrate", "header.autohide", "announce.dismiss", "footer.social", "content.code.select", "content.code.line_numbers", "content.tooltips"], "search": "assets/javascripts/workers/search.973d3a69.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
<script src="assets/javascripts/bundle.f55a23d4.min.js"></script>
<script>document$.subscribe(() => {
window.update_swagger_ui_iframe_height = function (id) {
var iFrameID = document.getElementById(id);
if (iFrameID) {
full_height = (iFrameID.contentWindow.document.body.scrollHeight + 80) + "px";
iFrameID.height = full_height;
iFrameID.style.height = full_height;
}
}
let iframe_id_list = []
var iframes = document.getElementsByClassName("swagger-ui-iframe");
for (var i = 0; i < iframes.length; i++) {
iframe_id_list.push(iframes[i].getAttribute("id"))
}
let ticking = false;
document.addEventListener('scroll', function(e) {
if (!ticking) {
window.requestAnimationFrame(()=> {
let half_vh = window.innerHeight/2;
for(var i = 0; i < iframe_id_list.length; i++) {
let element = document.getElementById(iframe_id_list[i])
if(element==null){
return
}
let diff = element.getBoundingClientRect().top
if(element.contentWindow.update_top_val){
element.contentWindow.update_top_val(half_vh - diff)
}
}
ticking = false;
});
ticking = true;
}
});
const dark_scheme_name = "slate"
const schemeAttr = document.body.getAttribute("data-md-color-scheme");
const isMediaPrefersScheme = document.body.getAttribute("data-md-color-media") === "(prefers-color-scheme: dark)";
if (!isMediaPrefersScheme) {
window.__init_is_dark_mode = (schemeAttr === dark_scheme_name);
} else {
const computedScheme = window.getComputedStyle(document.body).getPropertyValue('color-scheme');
window.__init_is_dark_mode = computedScheme === "dark";
}
const options = {
attributeFilter: ['data-md-color-scheme'],
};
function color_scheme_callback(mutations) {
for (let mutation of mutations) {
if (mutation.attributeName === "data-md-color-scheme") {
scheme = document.body.getAttribute("data-md-color-scheme")
var iframe_list = document.getElementsByClassName("swagger-ui-iframe")
for(var i = 0; i < iframe_list.length; i++) {
var ele = iframe_list.item(i);
if (ele) {
if (scheme === dark_scheme_name) {
ele.contentWindow.enable_dark_mode();
} else {
ele.contentWindow.disable_dark_mode();
}
}
}
}
}
}
observer = new MutationObserver(color_scheme_callback);
observer.observe(document.body, options);
})</script></body>
</html>

View File

@@ -0,0 +1,563 @@
{
"openapi": "3.1.0",
"info": {
"title": "Aetoskia Auth Server",
"description": "\n The Aetoskia Authentication Service.\n\n Provides identity, access control, and JWT token issuance for the Aetoskia\n ecosystem. Fully async, built with FastAPI and MongoDB.\n ",
"termsOfService": "https://aetoskia.com/terms",
"contact": {
"name": "Aetoskia Dev Team",
"url": "https://dev.aetoskia.com/contact",
"email": "dev@aetoskia.com"
},
"license": {
"name": "MIT License",
"url": "https://opensource.org/licenses/MIT"
},
"version": "0.0.5"
},
"servers": [
{
"url": "https://auth.aetoskia.com",
"description": "Production Authentication Service"
},
{
"url": "http://server-pi:9002",
"description": "Internal staging environment"
},
{
"url": "http://localhost:8000",
"description": "Local development server"
}
],
"paths": {
"/register": {
"post": {
"tags": [
"Auth"
],
"summary": "Register a new user",
"description": "Creates a new user account and returns the public user profile.",
"operationId": "create_user_register_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RegisterRequest"
}
}
},
"required": true
},
"responses": {
"201": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PublicUser"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/login": {
"post": {
"tags": [
"Auth"
],
"summary": "Login user",
"description": "Authenticates a user and issues a JWT access token.",
"operationId": "login_login_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginResponse"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/me": {
"get": {
"tags": [
"Auth"
],
"summary": "Get current user",
"description": "Returns the currently authenticated user's public profile.",
"operationId": "read_users_me_me_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PublicUser"
}
}
}
}
},
"security": [
{
"HTTPBearer": []
}
]
}
},
"/logout": {
"post": {
"tags": [
"Auth"
],
"summary": "Logout user",
"description": "Stateless logout endpoint. The client must discard the JWT access token.",
"operationId": "logout_logout_post",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LogoutResponse"
}
}
}
}
},
"security": [
{
"HTTPBearer": []
}
]
}
},
"/introspect": {
"post": {
"tags": [
"Auth",
"Internal"
],
"summary": "Token introspection (internal)",
"description": "Internal service-to-service endpoint for verifying JWTs. Not intended for direct client use.",
"operationId": "introspect_introspect_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/IntrospectRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/IntrospectResponse"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/health": {
"get": {
"tags": [
"Health"
],
"summary": "Health Check",
"description": "Report service health.\n\nReturns:\n dict:\n A simple ``{\"status\": \"ok\"}`` payload used by load balancers and\n the container health check.",
"operationId": "health_check_health_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
}
}
}
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
},
"IntrospectRequest": {
"properties": {
"token": {
"type": "string",
"title": "Token",
"description": "JWT access token to introspect",
"examples": [
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
]
}
},
"type": "object",
"required": [
"token"
],
"title": "IntrospectRequest",
"description": "Payload for requesting token introspection.\n\nUsed by internal services to verify the validity of a JWT and retrieve\nthe associated public user information.\n\nFields:\n token: JWT access token to introspect.\n\nNotes:\n - Intended for service-to-service communication.\n - Not meant for direct end-user consumption.",
"example": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
},
"IntrospectResponse": {
"properties": {
"active": {
"type": "boolean",
"title": "Active",
"description": "Indicates whether the provided token is valid and active",
"examples": [
true,
false
]
},
"user": {
"anyOf": [
{
"$ref": "#/components/schemas/PublicUser"
},
{
"type": "null"
}
],
"description": "Public user details if the token is valid; null otherwise"
}
},
"type": "object",
"required": [
"active"
],
"title": "IntrospectResponse",
"description": "Result of a token introspection operation.\n\nThis model communicates whether a JWT is valid and, if so, provides\nthe associated public user information.\n\nFields:\n active: Indicates whether the token is valid and active.\n user: Public user details if the token is valid; otherwise null.\n\nNotes:\n - This model is designed to avoid raising exceptions.\n - All introspection outcomes are represented as data.",
"example": {
"active": true,
"user": {
"email": "tester@example.com",
"is_active": true,
"username": "tester"
}
}
},
"LoginRequest": {
"properties": {
"password": {
"type": "string",
"minLength": 6,
"title": "Password",
"description": "User password (minimum 6 characters). Stored only as a hash.",
"examples": [
"SuperSecure123"
]
},
"username": {
"type": "string",
"maxLength": 50,
"minLength": 3,
"title": "Username",
"description": "Unique username used for authentication and display",
"examples": [
"tester"
]
},
"email": {
"anyOf": [
{
"type": "string",
"format": "email"
},
{
"type": "null"
}
],
"title": "Email",
"description": "Primary email address associated with the account",
"examples": [
"tester@example.com"
]
}
},
"type": "object",
"required": [
"password",
"username"
],
"title": "LoginRequest",
"description": "Payload for authenticating a user and issuing a JWT.\n\nThis model is used to verify user credentials and request an access token.\n\nFields:\n username: Username identifier.\n password: Plain-text password to be verified.\n\nNotes:\n - Successful authentication results in a LoginResponse.\n - Failed authentication raises an AuthError.",
"example": {
"password": "SuperSecure123",
"username": "tester"
}
},
"LoginResponse": {
"properties": {
"access_token": {
"type": "string",
"title": "Access Token",
"description": "JWT access token to be used for authenticated requests",
"examples": [
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
]
},
"user": {
"$ref": "#/components/schemas/PublicUser",
"description": "Authenticated user's public profile"
}
},
"type": "object",
"required": [
"access_token",
"user"
],
"title": "LoginResponse",
"description": "Response returned after successful authentication.\n\nContains the issued JWT access token and the authenticated user's\npublic profile.\n\nFields:\n access_token: JWT access token for authenticated requests.\n user: Public profile of the authenticated user.\n\nNotes:\n - The token is stateless and must be stored client-side.\n - Token expiration and validation are handled elsewhere.",
"example": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"email": "tester@example.com",
"is_active": true,
"username": "tester"
}
}
},
"LogoutResponse": {
"properties": {
"message": {
"type": "string",
"title": "Message",
"description": "Human-readable logout confirmation message",
"examples": [
"Successfully logged out"
]
}
},
"type": "object",
"required": [
"message"
],
"title": "LogoutResponse",
"description": "Response returned after a logout operation.\n\nSince logout is stateless, this response serves only as a confirmation\nmessage instructing the client to discard its token.\n\nFields:\n message: Human-readable logout confirmation.",
"example": {
"message": "Successfully logged out"
}
},
"PublicUser": {
"properties": {
"is_active": {
"type": "boolean",
"title": "Is Active",
"description": "Indicates whether the account is active and allowed to authenticate",
"default": true,
"examples": [
true
]
},
"username": {
"type": "string",
"maxLength": 50,
"minLength": 3,
"title": "Username",
"description": "Unique username used for authentication and display",
"examples": [
"tester"
]
},
"email": {
"anyOf": [
{
"type": "string",
"format": "email"
},
{
"type": "null"
}
],
"title": "Email",
"description": "Primary email address associated with the account",
"examples": [
"tester@example.com"
]
}
},
"type": "object",
"required": [
"username"
],
"title": "PublicUser",
"description": "Public-facing user representation returned by authentication APIs.\n\nThis model represents a user profile that is safe to expose outside\nthe authentication system.\n\nFields:\n username: Unique username identifier.\n email: User's email address.\n is_active: Whether the user account is active.\n\nNotes:\n - Contains no sensitive data.\n - Can be constructed from persistence models via `from_attributes`.",
"example": {
"email": "tester@example.com",
"is_active": true,
"username": "tester"
}
},
"RegisterRequest": {
"properties": {
"password": {
"type": "string",
"minLength": 6,
"title": "Password",
"description": "User password (minimum 6 characters). Stored only as a hash.",
"examples": [
"SuperSecure123"
]
},
"username": {
"type": "string",
"maxLength": 50,
"minLength": 3,
"title": "Username",
"description": "Unique username used for authentication and display",
"examples": [
"tester"
]
},
"email": {
"anyOf": [
{
"type": "string",
"format": "email"
},
{
"type": "null"
}
],
"title": "Email",
"description": "Primary email address associated with the account",
"examples": [
"tester@example.com"
]
}
},
"type": "object",
"required": [
"password",
"username"
],
"title": "RegisterRequest",
"description": "Payload for registering a new user account.\n\nThis model contains the minimum required identity and credential\ninformation to create a new user.\n\nFields:\n username: Unique username identifier.\n email: User's email address.\n password: Plain-text password (to be hashed by the repository layer).\n\nNotes:\n - Validation and normalization handled by mixins.\n - This model is never returned in responses.",
"example": {
"email": "tester@example.com",
"password": "SuperSecure123",
"username": "tester"
}
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
}
},
"securitySchemes": {
"HTTPBearer": {
"type": "http",
"scheme": "bearer"
}
}
},
"tags": [
{
"name": "Auth",
"description": "Login, registration, token issuance, refresh, and identity operations."
},
{
"name": "Health",
"description": "Service health and diagnostics."
}
]
}

View File

@@ -0,0 +1 @@
{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"API Reference","text":""}]}

View File

@@ -0,0 +1,125 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="assets/stylesheets/swagger-ui.css" />
</head>
<body style="overflow:hidden;">
<div id="swagger-ui"></div>
<script src="assets/javascripts/swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="assets/javascripts/swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script>
window.onload = function () {
var url = "openapi.json";
window.ui = SwaggerUIBundle({
dom_id: "#swagger-ui",
onComplete: onComplete,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
url,
"oauth2RedirectUrl": "assets/swagger-ui/oauth2-redirect.html",
"validatorUrl": "none",
"docExpansion": "list",
"filter": false,
"tryItOutEnabled": false,
"supportedSubmitMethods": [
"get",
"put",
"post",
"delete",
"options",
"head",
"patch",
"trace"
],
"validatorUrl": "none",
"extra_css": [],
"dark_scheme_name": "slate",
"filter_files": [],
"syntaxHighlight": {
"theme": "agate"
}
})
if (parent.__init_is_dark_mode) {
enable_dark_mode();
}
}
enable_dark_mode = function(){
document.documentElement.classList.add("dark-mode");
}
disable_dark_mode = function(){
document.documentElement.classList.remove("dark-mode");
}
const resize_ob = new ResizeObserver(function(entries) {
parent.update_swagger_ui_iframe_height("4f4c9641");
});
// start observing for resizing
resize_ob.observe(document.querySelector("body"));
// authorize modal position
var modal_top = 0;
const mutation_ob = new MutationObserver(function (mutations) {
if(mutations && mutations[0].addedNodes && mutations[0].addedNodes.length > 0){
update_modal_top()
}
});
onComplete = function(){
// start observing for auth-wrapper after Swagger UI loaded
const div = document.querySelector("div.auth-wrapper");
if(div){
mutation_ob.observe(div, {
childList: true,
});
}
}
update_top_val = function(top){
modal_top = top
update_modal_top()
}
update_modal_top = function(){
let modal_list = document.getElementsByClassName('modal-ux')
if(modal_list.length > 0){
let modal = modal_list.item(0)
const modal_height = modal.offsetHeight
const padding = 60
min = parseInt(modal_height/2 + padding)
max = document.body.scrollHeight - min + padding
if (modal_top < min) {
modal.style.top = `${min}px`
} else if (modal_top > max) {
modal.style.top = `${max}px`
} else {
modal.style.top = `${modal_top}px`
}
}
}
</script>
</body>
</html>

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Some files were not shown because too many files have changed in this diff Show More