pavedb 0.9.0__py3-none-any.whl
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.
- pave/__init__.py +6 -0
- pave/assets/__init__.py +4 -0
- pave/assets/config.yml.example +229 -0
- pave/assets/favicon.ico +0 -0
- pave/assets/pavedb_icon_192.png +0 -0
- pave/assets/tenants.yml.example +19 -0
- pave/assets/ui.html +366 -0
- pave/auth.py +271 -0
- pave/backends/__init__.py +13 -0
- pave/backends/base.py +29 -0
- pave/backends/faiss.py +153 -0
- pave/backends/qdrant.py +46 -0
- pave/cli.py +522 -0
- pave/config.py +289 -0
- pave/embedders/__init__.py +7 -0
- pave/embedders/base.py +21 -0
- pave/embedders/factory.py +69 -0
- pave/embedders/openai.py +47 -0
- pave/embedders/sbert.py +74 -0
- pave/embedders/sbert_worker.py +269 -0
- pave/filters.py +164 -0
- pave/log.py +289 -0
- pave/main.py +503 -0
- pave/metadb.py +1477 -0
- pave/metrics.py +202 -0
- pave/preprocess.py +153 -0
- pave/routes/__init__.py +16 -0
- pave/routes/admin.py +305 -0
- pave/routes/collections.py +205 -0
- pave/routes/documents.py +386 -0
- pave/routes/health.py +113 -0
- pave/routes/search.py +364 -0
- pave/runtime_paths.py +89 -0
- pave/schemas.py +287 -0
- pave/service.py +897 -0
- pave/stores/__init__.py +6 -0
- pave/stores/base.py +241 -0
- pave/stores/local.py +1400 -0
- pave/ui.py +341 -0
- pave/version.py +4 -0
- pavedb-0.9.0.dist-info/METADATA +157 -0
- pavedb-0.9.0.dist-info/RECORD +46 -0
- pavedb-0.9.0.dist-info/WHEEL +5 -0
- pavedb-0.9.0.dist-info/entry_points.txt +3 -0
- pavedb-0.9.0.dist-info/licenses/LICENSE +235 -0
- pavedb-0.9.0.dist-info/top_level.txt +1 -0
pave/__init__.py
ADDED
pave/assets/__init__.py
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# PaveDB sample configuration
|
|
2
|
+
# Copy to config.yml and adjust.
|
|
3
|
+
# Secrets (API keys) should live in a separate untracked file — see tenants.yml.example.
|
|
4
|
+
#
|
|
5
|
+
# Default user-install paths:
|
|
6
|
+
# config: ~/pavedb/config.yml
|
|
7
|
+
# tenants: ~/pavedb/tenants.yml
|
|
8
|
+
# data: ~/pavedb/data
|
|
9
|
+
#
|
|
10
|
+
# Distro-like install example:
|
|
11
|
+
# config: /etc/pavedb/config.yml
|
|
12
|
+
# tenants: /var/pavedb/tenants.yml
|
|
13
|
+
# data: /var/pavedb/data
|
|
14
|
+
#
|
|
15
|
+
# Config file location override:
|
|
16
|
+
# PAVEDB_CONFIG=/etc/pavedb/config.yml
|
|
17
|
+
#
|
|
18
|
+
# In Docker/systemd deployments always set PAVEDB_CONFIG explicitly — the
|
|
19
|
+
# default path expands ~ relative to the process user, which may not be what
|
|
20
|
+
# you expect inside a container. Example compose snippet:
|
|
21
|
+
#
|
|
22
|
+
# environment:
|
|
23
|
+
# PAVEDB_CONFIG: /etc/pavedb/config.yml
|
|
24
|
+
# volumes:
|
|
25
|
+
# - ./config.yml:/etc/pavedb/config.yml:ro
|
|
26
|
+
#
|
|
27
|
+
# All keys can also be overridden inline via environment variables:
|
|
28
|
+
# PAVEDB_<KEY>=value (top-level, e.g. PAVEDB_DATA_DIR)
|
|
29
|
+
# PAVEDB_<SECTION>__<KEY>=val (nested, e.g. PAVEDB_LOG__LEVEL=debug)
|
|
30
|
+
# `auth.tenants_file` is optional. If unset, its default is `None` and no
|
|
31
|
+
# tenants sidecar file is loaded.
|
|
32
|
+
# If set, PaveDB loads that sidecar first. Then inline tenant config is
|
|
33
|
+
# applied with precedence:
|
|
34
|
+
# env vars > config.yml > tenants.yml > defaults
|
|
35
|
+
# Example: define tenant "acme" entirely from env:
|
|
36
|
+
# PAVEDB_AUTH__API_KEYS__acme=change-me
|
|
37
|
+
# PAVEDB_TENANTS__acme__MAX_CONCURRENT=5
|
|
38
|
+
|
|
39
|
+
# ---------------------------------------------------------------------------
|
|
40
|
+
# Storage
|
|
41
|
+
# ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
# Data directory — ~ is expanded at startup.
|
|
44
|
+
# Default (library/dev): ~/pavedb/data
|
|
45
|
+
# For distro-like installs use an absolute path, e.g. /var/pavedb/data.
|
|
46
|
+
data_dir: ~/pavedb/data
|
|
47
|
+
|
|
48
|
+
# ---------------------------------------------------------------------------
|
|
49
|
+
# Common collection
|
|
50
|
+
# ---------------------------------------------------------------------------
|
|
51
|
+
# When enabled, every tenant search also queries a shared "common" collection
|
|
52
|
+
# and merges the results. Useful for org-wide reference data (e.g. a shared
|
|
53
|
+
# code/term dictionary) that should be visible to all tenants.
|
|
54
|
+
# The common collection is owned by common_tenant and is never rate-limited.
|
|
55
|
+
|
|
56
|
+
common_enabled: false
|
|
57
|
+
common_tenant: global # tenant that owns the common collection
|
|
58
|
+
common_collection: common # collection name within that tenant
|
|
59
|
+
|
|
60
|
+
# ---------------------------------------------------------------------------
|
|
61
|
+
# Authentication
|
|
62
|
+
# ---------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
auth:
|
|
65
|
+
# none — no auth; all requests accepted. Dev/private deployments only.
|
|
66
|
+
# enforce_policy() will reject auth=none on non-loopback interfaces.
|
|
67
|
+
# static — Bearer token per tenant; keys defined below or in tenants_file.
|
|
68
|
+
mode: static
|
|
69
|
+
|
|
70
|
+
# Default tenant name when auth.mode=none (no key required).
|
|
71
|
+
default_access_tenant: public
|
|
72
|
+
|
|
73
|
+
# Global admin key — grants access to all tenants and admin routes.
|
|
74
|
+
# Always read from the environment; never hardcode in committed files.
|
|
75
|
+
global_key: ${PAVEDB_GLOBAL_KEY}
|
|
76
|
+
|
|
77
|
+
# External tenant→key mapping file.
|
|
78
|
+
# Keep the same key paths there (`auth.api_keys`, `tenants.*`).
|
|
79
|
+
# User install default: ~/pavedb/tenants.yml
|
|
80
|
+
# Distro-like install: /var/pavedb/tenants.yml
|
|
81
|
+
# tenants_file: ~/pavedb/tenants.yml
|
|
82
|
+
|
|
83
|
+
# Inline tenant→key mapping (fallback; keep empty in the repo).
|
|
84
|
+
api_keys: {}
|
|
85
|
+
|
|
86
|
+
# ---------------------------------------------------------------------------
|
|
87
|
+
# Vector store
|
|
88
|
+
# ---------------------------------------------------------------------------
|
|
89
|
+
|
|
90
|
+
vector_store:
|
|
91
|
+
# faiss — local FAISS index (built-in, no extra services required).
|
|
92
|
+
type: faiss
|
|
93
|
+
|
|
94
|
+
# Options for type=faiss.
|
|
95
|
+
faiss:
|
|
96
|
+
embed_model: sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2
|
|
97
|
+
max_query_chars: 4000
|
|
98
|
+
|
|
99
|
+
# ---------------------------------------------------------------------------
|
|
100
|
+
# Embedder
|
|
101
|
+
# ---------------------------------------------------------------------------
|
|
102
|
+
# Controls how text is converted to vectors before indexing and querying.
|
|
103
|
+
# The embedder is shared across all collections (per-collection config: v0.6).
|
|
104
|
+
|
|
105
|
+
embedder:
|
|
106
|
+
# sbert — direct sentence-transformers (recommended local default).
|
|
107
|
+
# openai — OpenAI embeddings API (requires API key, adds latency).
|
|
108
|
+
type: sbert
|
|
109
|
+
|
|
110
|
+
# Used by type=sbert.
|
|
111
|
+
sbert:
|
|
112
|
+
runtime: auto # auto | process | direct
|
|
113
|
+
model: sentence-transformers/all-MiniLM-L6-v2
|
|
114
|
+
batch_size: 64
|
|
115
|
+
device: auto # cpu | cuda | mps | auto
|
|
116
|
+
|
|
117
|
+
# Used by type=openai.
|
|
118
|
+
openai:
|
|
119
|
+
model: text-embedding-3-small
|
|
120
|
+
batch_size: 256
|
|
121
|
+
api_key: ${PAVEDB_OPENAI_API_KEY}
|
|
122
|
+
dim: 1536
|
|
123
|
+
|
|
124
|
+
# ---------------------------------------------------------------------------
|
|
125
|
+
# Ingest limits
|
|
126
|
+
# ---------------------------------------------------------------------------
|
|
127
|
+
|
|
128
|
+
ingest:
|
|
129
|
+
# Reject uploads larger than this (MB). 0 = unlimited.
|
|
130
|
+
# Also set your reverse proxy: e.g. nginx client_max_body_size >= this value.
|
|
131
|
+
max_file_size_mb: 500
|
|
132
|
+
|
|
133
|
+
# Max parallel ingests; excess requests get 503 immediately.
|
|
134
|
+
# Ingest is CPU/memory heavy — keep this well below your core count.
|
|
135
|
+
# In-code default is 7 (conservative floor); 10 below is a typical-dev-host
|
|
136
|
+
# value. Rule of thumb: ~1× core count on dedicated hosts (e.g. 10 on a
|
|
137
|
+
# 10-core M-series, 16 on a 16-vCPU VM).
|
|
138
|
+
# 0 = unlimited (not recommended in production).
|
|
139
|
+
max_concurrent: 10
|
|
140
|
+
|
|
141
|
+
# Reverse-proxy timeout guidance for ingest endpoints:
|
|
142
|
+
# Ingest embeds the entire document before responding; large files can take
|
|
143
|
+
# tens of seconds. Raise these nginx directives accordingly:
|
|
144
|
+
#
|
|
145
|
+
# proxy_read_timeout 300; # wait up to 5 min for upstream response
|
|
146
|
+
# client_body_timeout 120; # wait up to 2 min for client to send body
|
|
147
|
+
#
|
|
148
|
+
# Your HTTP client read timeout should also be at least 300 s for ingest.
|
|
149
|
+
|
|
150
|
+
# ---------------------------------------------------------------------------
|
|
151
|
+
# Search limits
|
|
152
|
+
# ---------------------------------------------------------------------------
|
|
153
|
+
|
|
154
|
+
search:
|
|
155
|
+
# Max parallel searches; excess requests get 503 immediately.
|
|
156
|
+
# In-code default is 42 (conservative floor); 48 below is a typical-dev-host
|
|
157
|
+
# value. Rule of thumb: ~4–5× core count on dedicated hosts; throughput
|
|
158
|
+
# plateaus past that and only latency grows.
|
|
159
|
+
# 0 = unlimited (not recommended in production).
|
|
160
|
+
max_concurrent: 48
|
|
161
|
+
|
|
162
|
+
# Per-search timeout in ms; returns 503 on expiry. 0 = no timeout.
|
|
163
|
+
timeout_ms: 30000
|
|
164
|
+
|
|
165
|
+
# ---------------------------------------------------------------------------
|
|
166
|
+
# Per-tenant concurrency limits
|
|
167
|
+
# ---------------------------------------------------------------------------
|
|
168
|
+
# Applies to all tenant-scoped routes (search, ingest, collection ops).
|
|
169
|
+
# Admin requests and global-key requests bypass these limits.
|
|
170
|
+
# Per-tenant overrides can be set in tenants.yml (see tenants.yml.example).
|
|
171
|
+
# Moving-window limits (max_rpm, max_rph) require SQLite — post-v0.5.8.
|
|
172
|
+
|
|
173
|
+
tenants:
|
|
174
|
+
default_max_concurrent: 10 # applies to every tenant; 0 = unlimited
|
|
175
|
+
|
|
176
|
+
# ---------------------------------------------------------------------------
|
|
177
|
+
# Text preprocessing
|
|
178
|
+
# ---------------------------------------------------------------------------
|
|
179
|
+
# Controls how plain-text (.txt) files are split into chunks before embedding.
|
|
180
|
+
# Overlap ensures context is preserved across chunk boundaries.
|
|
181
|
+
|
|
182
|
+
preprocess:
|
|
183
|
+
txt_chunk_size: 1000 # characters per chunk
|
|
184
|
+
txt_chunk_overlap: 200 # characters of overlap between adjacent chunks
|
|
185
|
+
|
|
186
|
+
# ---------------------------------------------------------------------------
|
|
187
|
+
# Server
|
|
188
|
+
# ---------------------------------------------------------------------------
|
|
189
|
+
# These defaults are overridden by env vars HOST / PORT / RELOAD / WORKERS.
|
|
190
|
+
|
|
191
|
+
server:
|
|
192
|
+
host: 0.0.0.0
|
|
193
|
+
port: 8086
|
|
194
|
+
reload: false
|
|
195
|
+
workers: 1
|
|
196
|
+
|
|
197
|
+
# Keep-alive timeout in seconds (passed to uvicorn --timeout-keep-alive).
|
|
198
|
+
# Must be lower than your reverse proxy's keepalive_timeout.
|
|
199
|
+
# nginx default is 75 s — set this to 65 when behind nginx.
|
|
200
|
+
timeout_keep_alive: 75
|
|
201
|
+
|
|
202
|
+
# ---------------------------------------------------------------------------
|
|
203
|
+
# Logging
|
|
204
|
+
# ---------------------------------------------------------------------------
|
|
205
|
+
|
|
206
|
+
log:
|
|
207
|
+
# Dev log level (stderr). DEBUG | INFO | WARNING | ERROR — default INFO.
|
|
208
|
+
# Overridden by PAVEDB_LOG__LEVEL env var (e.g. in Makefile: debug).
|
|
209
|
+
# Per-namespace overrides: log.debug / log.watch / log.quiet (list of loggers).
|
|
210
|
+
level: INFO
|
|
211
|
+
|
|
212
|
+
# Ops log — one structured JSON line per operation (search, ingest, delete…).
|
|
213
|
+
# Fields: ts, op, tenant, collection, latency_ms, status, error_code, hits.
|
|
214
|
+
# null (off) | stdout | /path/to/ops.jsonl
|
|
215
|
+
# stdout is recommended for Docker/12-factor; pave uses stderr for the dev log.
|
|
216
|
+
# File paths suit traditional deployments; no rotation is provided here.
|
|
217
|
+
ops_log: null
|
|
218
|
+
|
|
219
|
+
# Uvicorn access log destination.
|
|
220
|
+
# null (use uvicorn default) | stdout | /path/to/access.log
|
|
221
|
+
access_log: null
|
|
222
|
+
|
|
223
|
+
# ---------------------------------------------------------------------------
|
|
224
|
+
# Instance branding (optional)
|
|
225
|
+
# ---------------------------------------------------------------------------
|
|
226
|
+
|
|
227
|
+
instance:
|
|
228
|
+
name: PaveDB
|
|
229
|
+
desc: Vector Search Microservice (pluggable, functional)
|
pave/assets/favicon.ico
ADDED
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Untracked secrets file with tenant API keys and per-tenant limits.
|
|
2
|
+
# Name it 'tenants.yml', adjust and DO NOT commit.
|
|
3
|
+
# The installed default should be innocuous; uncomment the examples you need.
|
|
4
|
+
#
|
|
5
|
+
# auth:
|
|
6
|
+
# api_keys:
|
|
7
|
+
# acme: change-me
|
|
8
|
+
# umbrella: change-me
|
|
9
|
+
|
|
10
|
+
# Per-tenant concurrency overrides.
|
|
11
|
+
# Omit a tenant entry to fall back to tenants.default_max_concurrent in config.yml.
|
|
12
|
+
# 0 = unlimited for that tenant.
|
|
13
|
+
# Moving-window limits (max_rpm, max_rph) will be added here after SQLite lands.
|
|
14
|
+
#
|
|
15
|
+
# tenants:
|
|
16
|
+
# acme:
|
|
17
|
+
# max_concurrent: 5 # overrides global default for acme; 0 = unlimited
|
|
18
|
+
# umbrella:
|
|
19
|
+
# max_concurrent: 20
|
pave/assets/ui.html
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<!-- (C) 2025 Rodrigo Rodrigues da Silva <rodrigo@flowlexi.com> -->
|
|
3
|
+
<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
|
|
4
|
+
|
|
5
|
+
<html lang="en">
|
|
6
|
+
<head>
|
|
7
|
+
<meta charset="utf-8" />
|
|
8
|
+
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
9
|
+
<!-- favicon robusto -->
|
|
10
|
+
<link rel="icon" type="image/png" sizes="32x32"
|
|
11
|
+
href="/assets/pavedb_icon_192.png?v=__VERSION__" />
|
|
12
|
+
<link rel="icon" type="image/png" sizes="192x192"
|
|
13
|
+
href="/assets/pavedb_icon_192.png?v=__VERSION__" />
|
|
14
|
+
<link rel="icon" href="/favicon.ico?v=__VERSION__" />
|
|
15
|
+
<title>__INST_NAME__ • Search</title>
|
|
16
|
+
<style>
|
|
17
|
+
/* Flowlexi docs palette with restrained PaveDB accents */
|
|
18
|
+
:root{
|
|
19
|
+
--bg:#F4F2ED; --panel:#FFFFFF; --text:#1E1E1E; --muted:#4B5563;
|
|
20
|
+
--accent:#2ECC71; --border:#E5E7EB; --link:#11957D;
|
|
21
|
+
--link-accent:#0B7769;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
*{ box-sizing:border-box }
|
|
25
|
+
html,body{ height:100% }
|
|
26
|
+
body{
|
|
27
|
+
min-height:100vh; display:flex; flex-direction:column; overflow:hidden;
|
|
28
|
+
margin:0; font:16px/1.45 system-ui,Segoe UI,Roboto,Inter,Arial;
|
|
29
|
+
background:var(--bg); color:var(--text);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.bar{
|
|
33
|
+
flex:0 0 auto; display:flex; gap:10px; align-items:center;
|
|
34
|
+
padding:12px; border-bottom:1px solid var(--border); background:var(--bg);
|
|
35
|
+
}
|
|
36
|
+
.left{ display:flex; gap:8px; align-items:center }
|
|
37
|
+
.right{
|
|
38
|
+
margin-left:auto; color:var(--muted); white-space:nowrap;
|
|
39
|
+
overflow:hidden; text-overflow:ellipsis;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.tab{
|
|
43
|
+
padding:8px 12px; border-radius:10px; border:1px solid var(--border);
|
|
44
|
+
cursor:pointer; background:var(--panel); color:var(--text);
|
|
45
|
+
}
|
|
46
|
+
.tab:hover{
|
|
47
|
+
background:#F1F3F4; color:var(--link-accent);
|
|
48
|
+
}
|
|
49
|
+
.tab.active{
|
|
50
|
+
background:#D9E3E2; color:var(--link-accent);
|
|
51
|
+
border-color:var(--link-accent);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.frames{ flex:1 1 auto; min-height:0; background:var(--bg) }
|
|
55
|
+
.frame{ display:none; width:100%; height:100%; border:0; background:var(--bg) }
|
|
56
|
+
.frame.active{ display:block }
|
|
57
|
+
|
|
58
|
+
.footer{
|
|
59
|
+
flex:0 0 auto; position:sticky; bottom:0;
|
|
60
|
+
display:flex; gap:12px; align-items:center; justify-content:center;
|
|
61
|
+
padding:10px; color:var(--muted); border-top:1px solid var(--border);
|
|
62
|
+
background:var(--bg);
|
|
63
|
+
}
|
|
64
|
+
.footer a{ color:var(--link); text-decoration:none }
|
|
65
|
+
.footer a:hover{ color:var(--link-accent) }
|
|
66
|
+
</style>
|
|
67
|
+
</head>
|
|
68
|
+
<body>
|
|
69
|
+
<div class="bar">
|
|
70
|
+
<div class="left">
|
|
71
|
+
<button class="tab active" data-target="search"
|
|
72
|
+
data-title="__INST_NAME__ • Search">Search</button>
|
|
73
|
+
<button class="tab" data-target="data"
|
|
74
|
+
data-title="__INST_NAME__ • Data">Data</button>
|
|
75
|
+
<button class="tab" data-target="admin"
|
|
76
|
+
data-title="__INST_NAME__ • Admin">Admin</button>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="right">
|
|
79
|
+
<strong>__INST_NAME__</strong> — <small>__INST_DESC__</small>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<div class="frames">
|
|
84
|
+
<iframe id="search" class="frame active" src="/ui/search" title="Search"></iframe>
|
|
85
|
+
<iframe id="data" class="frame" src="/ui/data" title="Data"></iframe>
|
|
86
|
+
<iframe id="admin" class="frame" src="/ui/admin" title="Admin"></iframe>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<div class="footer">
|
|
90
|
+
© 2025, 2026
|
|
91
|
+
<a href="https://flowlexi.com" target="_blank"
|
|
92
|
+
rel="noopener">Flowlexi</a> •
|
|
93
|
+
<a href="__REPO_URL__" target="_blank"
|
|
94
|
+
rel="noopener">🛣️ PaveDB __VERSION__</a> •
|
|
95
|
+
<a href="__LICENSE_URL__" target="_blank" rel="noopener">__LICENSE_NAME__</a>
|
|
96
|
+
</div>
|
|
97
|
+
<script>
|
|
98
|
+
function activeFrame(){ return document.querySelector('.frame.active'); }
|
|
99
|
+
|
|
100
|
+
function scrubSwagger(frame){
|
|
101
|
+
const win = frame?.contentWindow;
|
|
102
|
+
const doc = win?.document;
|
|
103
|
+
if(!doc) return;
|
|
104
|
+
if(!doc.querySelector('.swagger-ui')){
|
|
105
|
+
setTimeout(()=>scrubSwagger(frame), 80);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// CSS: remove topo/infos
|
|
110
|
+
const STYLE_ID = 'pv-clean';
|
|
111
|
+
if(!doc.getElementById(STYLE_ID)){
|
|
112
|
+
const s = doc.createElement('style');
|
|
113
|
+
s.id = STYLE_ID;
|
|
114
|
+
s.textContent = `
|
|
115
|
+
:root{
|
|
116
|
+
--bg:#F4F2ED; --panel:#FFFFFF; --text:#1E1E1E;
|
|
117
|
+
--muted:#4B5563; --accent:#2ECC71; --border:#E5E7EB;
|
|
118
|
+
--link:#11957D; --link-accent:#0B7769;
|
|
119
|
+
}
|
|
120
|
+
#operations-tag-default,
|
|
121
|
+
.swagger-ui .topbar,
|
|
122
|
+
.swagger-ui .download-url-wrapper,
|
|
123
|
+
.swagger-ui .information-container,
|
|
124
|
+
.swagger-ui .info,
|
|
125
|
+
.swagger-ui .servers { display:none !important; }
|
|
126
|
+
html, body {
|
|
127
|
+
background: var(--bg) !important;
|
|
128
|
+
color: var(--text) !important;
|
|
129
|
+
}
|
|
130
|
+
.swagger-ui {
|
|
131
|
+
color: var(--text) !important;
|
|
132
|
+
}
|
|
133
|
+
.swagger-ui .wrapper {
|
|
134
|
+
margin:0 !important; padding:0 0 8px !important;
|
|
135
|
+
max-width:none !important;
|
|
136
|
+
}
|
|
137
|
+
.swagger-ui a,
|
|
138
|
+
.swagger-ui .opblock-summary-path,
|
|
139
|
+
.swagger-ui .link {
|
|
140
|
+
color: var(--link) !important;
|
|
141
|
+
}
|
|
142
|
+
.swagger-ui a:hover,
|
|
143
|
+
.swagger-ui .opblock-summary-path:hover,
|
|
144
|
+
.swagger-ui .link:hover {
|
|
145
|
+
color: var(--link-accent) !important;
|
|
146
|
+
}
|
|
147
|
+
.swagger-ui section.models,
|
|
148
|
+
.swagger-ui .model-box {
|
|
149
|
+
background: var(--panel) !important;
|
|
150
|
+
border:1px solid var(--border) !important;
|
|
151
|
+
box-shadow:none !important;
|
|
152
|
+
}
|
|
153
|
+
.swagger-ui .scheme-container {
|
|
154
|
+
margin:8px 0 0 !important;
|
|
155
|
+
padding:0 16px 8px !important;
|
|
156
|
+
background: transparent !important;
|
|
157
|
+
border:0 !important;
|
|
158
|
+
box-shadow:none !important;
|
|
159
|
+
}
|
|
160
|
+
.swagger-ui .scheme-container .schemes,
|
|
161
|
+
.swagger-ui .scheme-container .auth-wrapper {
|
|
162
|
+
background: transparent !important;
|
|
163
|
+
border:0 !important;
|
|
164
|
+
box-shadow:none !important;
|
|
165
|
+
}
|
|
166
|
+
.swagger-ui .opblock {
|
|
167
|
+
background: var(--panel) !important;
|
|
168
|
+
border:1px solid var(--border) !important;
|
|
169
|
+
box-shadow:none !important;
|
|
170
|
+
}
|
|
171
|
+
.swagger-ui .opblock .opblock-summary,
|
|
172
|
+
.swagger-ui .responses-inner,
|
|
173
|
+
.swagger-ui table tbody tr td,
|
|
174
|
+
.swagger-ui .parameters-col_description input,
|
|
175
|
+
.swagger-ui .parameters-col_description textarea,
|
|
176
|
+
.swagger-ui .model-example {
|
|
177
|
+
border-color: var(--border) !important;
|
|
178
|
+
}
|
|
179
|
+
.swagger-ui .opblock-tag,
|
|
180
|
+
.swagger-ui .opblock-summary-description,
|
|
181
|
+
.swagger-ui .response-col_description__inner p,
|
|
182
|
+
.swagger-ui .parameter__type,
|
|
183
|
+
.swagger-ui .parameter__name,
|
|
184
|
+
.swagger-ui .responses-inner h4,
|
|
185
|
+
.swagger-ui .responses-inner h5,
|
|
186
|
+
.swagger-ui .model-title,
|
|
187
|
+
.swagger-ui label,
|
|
188
|
+
.swagger-ui .prop-name {
|
|
189
|
+
color: var(--text) !important;
|
|
190
|
+
}
|
|
191
|
+
.swagger-ui .opblock-description-wrapper p,
|
|
192
|
+
.swagger-ui .response-col_links,
|
|
193
|
+
.swagger-ui .responses-inner .markdown p,
|
|
194
|
+
.swagger-ui .renderedMarkdown p,
|
|
195
|
+
.swagger-ui .parameter__deprecated,
|
|
196
|
+
.swagger-ui .tab li,
|
|
197
|
+
.swagger-ui .model-title small,
|
|
198
|
+
.swagger-ui .prop-type {
|
|
199
|
+
color: var(--muted) !important;
|
|
200
|
+
}
|
|
201
|
+
.swagger-ui .copy-to-clipboard,
|
|
202
|
+
.swagger-ui .model-hint {
|
|
203
|
+
color: #6B7280 !important;
|
|
204
|
+
}
|
|
205
|
+
.swagger-ui .opblock-body pre.microlight,
|
|
206
|
+
.swagger-ui .highlight-code,
|
|
207
|
+
.swagger-ui textarea,
|
|
208
|
+
.swagger-ui input[type=text],
|
|
209
|
+
.swagger-ui input[type=password],
|
|
210
|
+
.swagger-ui select {
|
|
211
|
+
background: #F1F3F4 !important;
|
|
212
|
+
border:1px solid var(--border) !important;
|
|
213
|
+
color: var(--text) !important;
|
|
214
|
+
box-shadow:none !important;
|
|
215
|
+
}
|
|
216
|
+
.swagger-ui textarea:focus,
|
|
217
|
+
.swagger-ui input[type=text]:focus,
|
|
218
|
+
.swagger-ui input[type=password]:focus,
|
|
219
|
+
.swagger-ui select:focus {
|
|
220
|
+
border-color: var(--link) !important;
|
|
221
|
+
outline:none !important;
|
|
222
|
+
}
|
|
223
|
+
.swagger-ui .tab li.active {
|
|
224
|
+
background: #D9E3E2 !important;
|
|
225
|
+
color: var(--text) !important;
|
|
226
|
+
}
|
|
227
|
+
.swagger-ui .btn {
|
|
228
|
+
border-radius:8px !important;
|
|
229
|
+
box-shadow:none !important;
|
|
230
|
+
}
|
|
231
|
+
.swagger-ui .btn.authorize,
|
|
232
|
+
.swagger-ui .btn.execute,
|
|
233
|
+
.swagger-ui .btn.try-out__btn {
|
|
234
|
+
background: var(--link) !important;
|
|
235
|
+
border-color: var(--link) !important;
|
|
236
|
+
color: #FFFFFF !important;
|
|
237
|
+
}
|
|
238
|
+
.swagger-ui .btn.authorize:hover,
|
|
239
|
+
.swagger-ui .btn.execute:hover,
|
|
240
|
+
.swagger-ui .btn.try-out__btn:hover,
|
|
241
|
+
.swagger-ui .btn.authorize:focus,
|
|
242
|
+
.swagger-ui .btn.execute:focus,
|
|
243
|
+
.swagger-ui .btn.try-out__btn:focus {
|
|
244
|
+
background: var(--link-accent) !important;
|
|
245
|
+
border-color: var(--link-accent) !important;
|
|
246
|
+
color: #FFFFFF !important;
|
|
247
|
+
}
|
|
248
|
+
.swagger-ui .btn.cancel {
|
|
249
|
+
background: var(--panel) !important;
|
|
250
|
+
border-color: var(--border) !important;
|
|
251
|
+
color: var(--muted) !important;
|
|
252
|
+
}
|
|
253
|
+
.swagger-ui .btn.cancel:hover,
|
|
254
|
+
.swagger-ui .btn.cancel:focus {
|
|
255
|
+
background: #F1F3F4 !important;
|
|
256
|
+
color: var(--text) !important;
|
|
257
|
+
}
|
|
258
|
+
.swagger-ui .btn.authorize svg,
|
|
259
|
+
.swagger-ui .btn.execute svg {
|
|
260
|
+
fill: currentColor !important;
|
|
261
|
+
}
|
|
262
|
+
.swagger-ui .opblock.opblock-get .opblock-summary {
|
|
263
|
+
background: rgba(91,141,184,.08) !important;
|
|
264
|
+
}
|
|
265
|
+
.swagger-ui .opblock.opblock-post .opblock-summary {
|
|
266
|
+
background: rgba(17,149,125,.08) !important;
|
|
267
|
+
}
|
|
268
|
+
.swagger-ui .opblock.opblock-put .opblock-summary {
|
|
269
|
+
background: rgba(201,130,58,.08) !important;
|
|
270
|
+
}
|
|
271
|
+
.swagger-ui .opblock.opblock-patch .opblock-summary {
|
|
272
|
+
background: rgba(68,191,152,.08) !important;
|
|
273
|
+
}
|
|
274
|
+
.swagger-ui .opblock.opblock-delete .opblock-summary {
|
|
275
|
+
background: rgba(176,82,74,.08) !important;
|
|
276
|
+
}
|
|
277
|
+
.swagger-ui .opblock.opblock-head .opblock-summary {
|
|
278
|
+
background: rgba(122,107,152,.08) !important;
|
|
279
|
+
}
|
|
280
|
+
.swagger-ui .opblock.opblock-options .opblock-summary {
|
|
281
|
+
background: rgba(79,111,143,.08) !important;
|
|
282
|
+
}
|
|
283
|
+
.swagger-ui .opblock.opblock-get .opblock-summary-method {
|
|
284
|
+
background:#5B8DB8 !important;
|
|
285
|
+
}
|
|
286
|
+
.swagger-ui .opblock.opblock-post .opblock-summary-method {
|
|
287
|
+
background:#11957D !important;
|
|
288
|
+
}
|
|
289
|
+
.swagger-ui .opblock.opblock-put .opblock-summary-method {
|
|
290
|
+
background:#C9823A !important;
|
|
291
|
+
}
|
|
292
|
+
.swagger-ui .opblock.opblock-patch .opblock-summary-method {
|
|
293
|
+
background:#44BF98 !important;
|
|
294
|
+
}
|
|
295
|
+
.swagger-ui .opblock.opblock-delete .opblock-summary-method {
|
|
296
|
+
background:#B0524A !important;
|
|
297
|
+
}
|
|
298
|
+
.swagger-ui .opblock.opblock-head .opblock-summary-method {
|
|
299
|
+
background:#7A6B98 !important;
|
|
300
|
+
}
|
|
301
|
+
.swagger-ui .opblock.opblock-options .opblock-summary-method {
|
|
302
|
+
background:#4F6F8F !important;
|
|
303
|
+
}
|
|
304
|
+
`;
|
|
305
|
+
doc.head.appendChild(s);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const TAB_KEY = 'pavedb.ui.tab';
|
|
310
|
+
const tabs = document.querySelectorAll('.tab');
|
|
311
|
+
const frames = document.querySelectorAll('.frame');
|
|
312
|
+
|
|
313
|
+
function tabNames(){
|
|
314
|
+
return Array.from(tabs).map(function(tab){ return tab.dataset.target; });
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function tabFromLocation(){
|
|
318
|
+
const qs = new URLSearchParams(window.location.search);
|
|
319
|
+
const queryTab = qs.get('tab');
|
|
320
|
+
if(queryTab) return queryTab;
|
|
321
|
+
const hash = window.location.hash.replace(/^#\/?/, '');
|
|
322
|
+
return hash || '';
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function rememberedTab(){
|
|
326
|
+
try { return window.localStorage.getItem(TAB_KEY) || ''; }
|
|
327
|
+
catch (_err) { return ''; }
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function writeTab(name){
|
|
331
|
+
try { window.localStorage.setItem(TAB_KEY, name); }
|
|
332
|
+
catch (_err) {}
|
|
333
|
+
const url = new URL(window.location.href);
|
|
334
|
+
url.searchParams.set('tab', name);
|
|
335
|
+
url.hash = '/' + name;
|
|
336
|
+
window.history.replaceState(null, '', url);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function activateTab(name, updateUrl){
|
|
340
|
+
if(tabNames().indexOf(name) === -1) name = 'search';
|
|
341
|
+
tabs.forEach(function(tab){ tab.classList.remove('active'); });
|
|
342
|
+
frames.forEach(function(frame){ frame.classList.remove('active'); });
|
|
343
|
+
const tab = document.querySelector('.tab[data-target="' + name + '"]');
|
|
344
|
+
const frame = document.getElementById(name);
|
|
345
|
+
if(tab) tab.classList.add('active');
|
|
346
|
+
if(frame) frame.classList.add('active');
|
|
347
|
+
if(tab && tab.dataset.title) document.title = tab.dataset.title;
|
|
348
|
+
if(frame) scrubSwagger(frame);
|
|
349
|
+
if(updateUrl) writeTab(name);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
tabs.forEach(function(tab){
|
|
353
|
+
tab.addEventListener('click', function(){
|
|
354
|
+
activateTab(tab.dataset.target, true);
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
frames.forEach(function(frame){
|
|
359
|
+
frame.addEventListener('load', function(){ scrubSwagger(frame); });
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
const initialTab = tabFromLocation() || rememberedTab() || 'search';
|
|
363
|
+
activateTab(initialTab, false);
|
|
364
|
+
</script>
|
|
365
|
+
</body>
|
|
366
|
+
</html>
|