zero-http 0.2.5 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1250 -283
- package/documentation/config/db.js +25 -0
- package/documentation/config/middleware.js +44 -0
- package/documentation/config/tls.js +12 -0
- package/documentation/controllers/cookies.js +34 -0
- package/documentation/controllers/tasks.js +108 -0
- package/documentation/full-server.js +25 -184
- package/documentation/models/Task.js +21 -0
- package/documentation/public/data/api.json +404 -24
- package/documentation/public/data/docs.json +1139 -0
- package/documentation/public/data/examples.json +80 -2
- package/documentation/public/data/options.json +23 -8
- package/documentation/public/index.html +138 -99
- package/documentation/public/scripts/app.js +1 -3
- package/documentation/public/scripts/custom-select.js +189 -0
- package/documentation/public/scripts/data-sections.js +233 -250
- package/documentation/public/scripts/playground.js +270 -0
- package/documentation/public/scripts/ui.js +4 -3
- package/documentation/public/styles.css +56 -5
- package/documentation/public/vendor/icons/compress.svg +17 -17
- package/documentation/public/vendor/icons/database.svg +21 -0
- package/documentation/public/vendor/icons/env.svg +21 -0
- package/documentation/public/vendor/icons/fetch.svg +11 -14
- package/documentation/public/vendor/icons/security.svg +15 -0
- package/documentation/public/vendor/icons/sse.svg +12 -13
- package/documentation/public/vendor/icons/static.svg +12 -26
- package/documentation/public/vendor/icons/stream.svg +7 -13
- package/documentation/public/vendor/icons/validate.svg +17 -0
- package/documentation/routes/api.js +41 -0
- package/documentation/routes/core.js +20 -0
- package/documentation/routes/playground.js +29 -0
- package/documentation/routes/realtime.js +49 -0
- package/documentation/routes/uploads.js +71 -0
- package/index.js +62 -1
- package/lib/app.js +200 -8
- package/lib/body/json.js +28 -5
- package/lib/body/multipart.js +29 -1
- package/lib/body/raw.js +1 -1
- package/lib/body/sendError.js +1 -0
- package/lib/body/text.js +1 -1
- package/lib/body/typeMatch.js +6 -2
- package/lib/body/urlencoded.js +5 -2
- package/lib/debug.js +345 -0
- package/lib/env/index.js +440 -0
- package/lib/errors.js +231 -0
- package/lib/http/request.js +219 -1
- package/lib/http/response.js +410 -6
- package/lib/middleware/compress.js +39 -6
- package/lib/middleware/cookieParser.js +237 -0
- package/lib/middleware/cors.js +13 -2
- package/lib/middleware/csrf.js +135 -0
- package/lib/middleware/errorHandler.js +90 -0
- package/lib/middleware/helmet.js +176 -0
- package/lib/middleware/index.js +7 -2
- package/lib/middleware/rateLimit.js +12 -1
- package/lib/middleware/requestId.js +54 -0
- package/lib/middleware/static.js +95 -11
- package/lib/middleware/timeout.js +72 -0
- package/lib/middleware/validator.js +257 -0
- package/lib/orm/adapters/json.js +215 -0
- package/lib/orm/adapters/memory.js +383 -0
- package/lib/orm/adapters/mongo.js +444 -0
- package/lib/orm/adapters/mysql.js +272 -0
- package/lib/orm/adapters/postgres.js +394 -0
- package/lib/orm/adapters/sql-base.js +142 -0
- package/lib/orm/adapters/sqlite.js +311 -0
- package/lib/orm/index.js +276 -0
- package/lib/orm/model.js +895 -0
- package/lib/orm/query.js +807 -0
- package/lib/orm/schema.js +172 -0
- package/lib/router/index.js +136 -47
- package/lib/sse/stream.js +15 -3
- package/lib/ws/connection.js +19 -3
- package/lib/ws/handshake.js +3 -0
- package/lib/ws/index.js +3 -1
- package/lib/ws/room.js +222 -0
- package/package.json +15 -5
- package/types/app.d.ts +120 -0
- package/types/env.d.ts +80 -0
- package/types/errors.d.ts +147 -0
- package/types/fetch.d.ts +43 -0
- package/types/index.d.ts +135 -0
- package/types/middleware.d.ts +292 -0
- package/types/orm.d.ts +610 -0
- package/types/request.d.ts +99 -0
- package/types/response.d.ts +142 -0
- package/types/router.d.ts +78 -0
- package/types/sse.d.ts +78 -0
- package/types/websocket.d.ts +119 -0
|
@@ -1,319 +1,302 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* data-sections.js
|
|
3
|
-
* Fetches and renders
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* - Code Examples (/data/examples.json)
|
|
3
|
+
* Fetches the unified docs.json and renders hierarchical documentation sections
|
|
4
|
+
* with sidebar TOC population. Each section becomes a top-level sidebar category
|
|
5
|
+
* with expandable sub-items.
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
* examples sections.
|
|
10
|
-
*
|
|
11
|
-
* Depends on: helpers.js (provides $, escapeHtml, slugify, showJsonResult,
|
|
12
|
-
* highlightAllPre)
|
|
7
|
+
* Depends on: helpers.js (provides $, escapeHtml, slugify, highlightAllPre)
|
|
13
8
|
*/
|
|
14
9
|
|
|
15
|
-
/* --
|
|
10
|
+
/* -- Section icon map -------------------------------------------------------- */
|
|
11
|
+
const SECTION_ICONS = {
|
|
12
|
+
rocket: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z"/><path d="M12 15l-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"/><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0"/><path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/></svg>',
|
|
13
|
+
box: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>',
|
|
14
|
+
parse: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 3H7a2 2 0 0 0-2 2v4a2 2 0 0 1-2 2 2 2 0 0 1 2 2v4a2 2 0 0 0 2 2h2"/><path d="M15 3h2a2 2 0 0 1 2 2v4a2 2 0 0 0 2 2 2 2 0 0 0-2 2v4a2 2 0 0 1-2 2h-2"/></svg>',
|
|
15
|
+
layers: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>',
|
|
16
|
+
shield: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>',
|
|
17
|
+
settings: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>',
|
|
18
|
+
database: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>',
|
|
19
|
+
zap: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>',
|
|
20
|
+
globe: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/* -- Rendering helpers ------------------------------------------------------- */
|
|
24
|
+
|
|
25
|
+
function sectionSlug(sectionName)
|
|
26
|
+
{
|
|
27
|
+
return 'section-' + slugify(sectionName);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function itemSlug(sectionName, itemName)
|
|
31
|
+
{
|
|
32
|
+
return slugify(sectionName) + '-' + slugify(itemName);
|
|
33
|
+
}
|
|
16
34
|
|
|
17
35
|
/**
|
|
18
|
-
*
|
|
19
|
-
* href, then append a sub-list of items beneath it.
|
|
20
|
-
* @param {string} href - Hash href to match (e.g. "#api-reference").
|
|
21
|
-
* @param {Object[]} items - Array of `{ slug, label }` objects.
|
|
36
|
+
* Render a single documentation item as a <details> accordion.
|
|
22
37
|
*/
|
|
23
|
-
function
|
|
38
|
+
function renderDocItem(item, section)
|
|
24
39
|
{
|
|
25
|
-
const
|
|
26
|
-
|
|
40
|
+
const slug = itemSlug(section, item.name);
|
|
41
|
+
const d = document.createElement('details');
|
|
42
|
+
d.className = 'acc nested doc-item';
|
|
43
|
+
d.id = slug;
|
|
27
44
|
|
|
28
|
-
const
|
|
29
|
-
{
|
|
30
|
-
|
|
31
|
-
return !!a;
|
|
32
|
-
});
|
|
33
|
-
if (!parentLi) return;
|
|
45
|
+
const s = document.createElement('summary');
|
|
46
|
+
s.innerHTML = `<strong>${escapeHtml(item.name)}</strong>`;
|
|
47
|
+
d.appendChild(s);
|
|
34
48
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (existing) existing.remove();
|
|
49
|
+
const body = document.createElement('div');
|
|
50
|
+
body.className = 'acc-body';
|
|
38
51
|
|
|
39
|
-
/*
|
|
40
|
-
if (
|
|
52
|
+
/* Description */
|
|
53
|
+
if (item.description)
|
|
41
54
|
{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const toggle = document.createElement('button');
|
|
46
|
-
toggle.className = 'toc-collapse-btn';
|
|
47
|
-
toggle.setAttribute('aria-label', 'Toggle section');
|
|
48
|
-
toggle.innerHTML = '<svg width="10" height="10" viewBox="0 0 10 10" fill="none"><path d="M3 1l4 4-4 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
49
|
-
toggle.addEventListener('click', (e) =>
|
|
50
|
-
{
|
|
51
|
-
e.preventDefault();
|
|
52
|
-
e.stopPropagation();
|
|
53
|
-
parentLi.classList.toggle('toc-collapsed');
|
|
54
|
-
});
|
|
55
|
-
parentLi.insertBefore(toggle, parentLi.firstChild);
|
|
55
|
+
const p = document.createElement('p');
|
|
56
|
+
p.textContent = item.description;
|
|
57
|
+
body.appendChild(p);
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
for (const { slug, label } of items)
|
|
60
|
+
/* Options table */
|
|
61
|
+
if (Array.isArray(item.options) && item.options.length)
|
|
62
62
|
{
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const a = document.createElement('a');
|
|
67
|
-
a.href = '#' + slug;
|
|
68
|
-
a.textContent = label;
|
|
69
|
-
a.addEventListener('click', () => document.body.classList.remove('toc-open'));
|
|
63
|
+
const h6 = document.createElement('h6');
|
|
64
|
+
h6.textContent = 'Options';
|
|
65
|
+
body.appendChild(h6);
|
|
70
66
|
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
const table = document.createElement('table');
|
|
68
|
+
table.innerHTML = '<thead><tr><th>Option</th><th>Type</th><th>Default</th><th>Notes</th></tr></thead>';
|
|
69
|
+
const tbody = document.createElement('tbody');
|
|
70
|
+
for (const opt of item.options)
|
|
71
|
+
{
|
|
72
|
+
const tr = document.createElement('tr');
|
|
73
|
+
tr.innerHTML =
|
|
74
|
+
`<td><code>${escapeHtml(opt.option)}</code></td>` +
|
|
75
|
+
`<td>${escapeHtml(opt.type || '')}</td>` +
|
|
76
|
+
`<td>${escapeHtml(opt.default != null ? String(opt.default) : '—')}</td>` +
|
|
77
|
+
`<td>${escapeHtml(opt.notes || '')}</td>`;
|
|
78
|
+
tbody.appendChild(tr);
|
|
79
|
+
}
|
|
80
|
+
table.appendChild(tbody);
|
|
81
|
+
body.appendChild(table);
|
|
73
82
|
}
|
|
74
83
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
/* -- API Reference ----------------------------------------------------------- */
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Render a list of API items into the `#api-items` container and Prism-highlight
|
|
82
|
-
* any code examples.
|
|
83
|
-
* @param {HTMLElement} container - Target element.
|
|
84
|
-
* @param {Object[]} list - API item descriptors.
|
|
85
|
-
*/
|
|
86
|
-
function renderApiList(container, list)
|
|
87
|
-
{
|
|
88
|
-
container.innerHTML = '';
|
|
89
|
-
if (!list || !list.length) { container.textContent = 'No API items'; return; }
|
|
90
|
-
|
|
91
|
-
for (const it of list)
|
|
84
|
+
/* Methods table */
|
|
85
|
+
if (Array.isArray(item.methods) && item.methods.length)
|
|
92
86
|
{
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const s = document.createElement('summary');
|
|
98
|
-
s.innerHTML = `<strong>${escapeHtml(it.name)}</strong>`;
|
|
99
|
-
d.appendChild(s);
|
|
100
|
-
|
|
101
|
-
const body = document.createElement('div');
|
|
102
|
-
body.className = 'acc-body';
|
|
87
|
+
const h6 = document.createElement('h6');
|
|
88
|
+
h6.textContent = 'Methods';
|
|
89
|
+
body.appendChild(h6);
|
|
103
90
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
p.innerHTML = escapeHtml(it.description);
|
|
109
|
-
body.appendChild(p);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/* Options table */
|
|
113
|
-
if (Array.isArray(it.options) && it.options.length)
|
|
91
|
+
const table = document.createElement('table');
|
|
92
|
+
table.innerHTML = '<thead><tr><th>Method</th><th>Signature</th><th>Description</th></tr></thead>';
|
|
93
|
+
const tbody = document.createElement('tbody');
|
|
94
|
+
for (const m of item.methods)
|
|
114
95
|
{
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
tr.innerHTML =
|
|
122
|
-
`<td><code>${escapeHtml(opt.option)}</code></td>` +
|
|
123
|
-
`<td>${escapeHtml(opt.type || '')}</td>` +
|
|
124
|
-
`<td>${escapeHtml(opt.default || '')}</td>` +
|
|
125
|
-
`<td>${escapeHtml(opt.notes || '')}</td>`;
|
|
126
|
-
tbody.appendChild(tr);
|
|
127
|
-
}
|
|
128
|
-
table.appendChild(tbody);
|
|
129
|
-
body.appendChild(table);
|
|
96
|
+
const tr = document.createElement('tr');
|
|
97
|
+
tr.innerHTML =
|
|
98
|
+
`<td><code>${escapeHtml(m.method || '')}</code></td>` +
|
|
99
|
+
`<td><code>${escapeHtml(m.signature || '')}</code></td>` +
|
|
100
|
+
`<td>${escapeHtml(m.description || '')}</td>`;
|
|
101
|
+
tbody.appendChild(tr);
|
|
130
102
|
}
|
|
103
|
+
table.appendChild(tbody);
|
|
104
|
+
body.appendChild(table);
|
|
105
|
+
}
|
|
131
106
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
body.appendChild(table);
|
|
149
|
-
}
|
|
107
|
+
/* Example code block */
|
|
108
|
+
if (item.example)
|
|
109
|
+
{
|
|
110
|
+
const h6 = document.createElement('h6');
|
|
111
|
+
h6.textContent = 'Example';
|
|
112
|
+
body.appendChild(h6);
|
|
113
|
+
|
|
114
|
+
const lang = item.exampleLang || 'javascript';
|
|
115
|
+
const pre = document.createElement('pre');
|
|
116
|
+
pre.className = 'language-' + lang + ' code';
|
|
117
|
+
const code = document.createElement('code');
|
|
118
|
+
code.className = 'language-' + lang;
|
|
119
|
+
code.textContent = item.example;
|
|
120
|
+
pre.appendChild(code);
|
|
121
|
+
body.appendChild(pre);
|
|
122
|
+
}
|
|
150
123
|
|
|
151
|
-
|
|
152
|
-
|
|
124
|
+
/* Tips */
|
|
125
|
+
if (Array.isArray(item.tips) && item.tips.length)
|
|
126
|
+
{
|
|
127
|
+
const tipsDiv = document.createElement('div');
|
|
128
|
+
tipsDiv.className = 'doc-tips';
|
|
129
|
+
const h6 = document.createElement('h6');
|
|
130
|
+
h6.className = 'doc-tips-heading';
|
|
131
|
+
h6.textContent = 'Tips';
|
|
132
|
+
tipsDiv.appendChild(h6);
|
|
133
|
+
|
|
134
|
+
const ul = document.createElement('ul');
|
|
135
|
+
ul.className = 'tips-list';
|
|
136
|
+
for (const tip of item.tips)
|
|
153
137
|
{
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
pre.className = 'language-javascript code';
|
|
158
|
-
const code = document.createElement('code');
|
|
159
|
-
code.className = 'language-javascript';
|
|
160
|
-
code.textContent = it.example;
|
|
161
|
-
pre.appendChild(code);
|
|
162
|
-
body.appendChild(h6);
|
|
163
|
-
body.appendChild(pre);
|
|
138
|
+
const li = document.createElement('li');
|
|
139
|
+
li.textContent = tip;
|
|
140
|
+
ul.appendChild(li);
|
|
164
141
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
container.appendChild(d);
|
|
142
|
+
tipsDiv.appendChild(ul);
|
|
143
|
+
body.appendChild(tipsDiv);
|
|
168
144
|
}
|
|
169
145
|
|
|
170
|
-
|
|
146
|
+
d.appendChild(body);
|
|
147
|
+
return d;
|
|
171
148
|
}
|
|
172
149
|
|
|
173
150
|
/**
|
|
174
|
-
*
|
|
175
|
-
* the search / clear filter controls.
|
|
151
|
+
* Render a full documentation section (section heading card + item accordions).
|
|
176
152
|
*/
|
|
177
|
-
|
|
153
|
+
function renderSection(section)
|
|
178
154
|
{
|
|
179
|
-
|
|
155
|
+
const slug = sectionSlug(section.section);
|
|
156
|
+
const wrapper = document.createElement('div');
|
|
157
|
+
wrapper.className = 'doc-section';
|
|
158
|
+
wrapper.id = slug;
|
|
159
|
+
|
|
160
|
+
/* Section header */
|
|
161
|
+
const header = document.createElement('div');
|
|
162
|
+
header.className = 'doc-section-header';
|
|
163
|
+
|
|
164
|
+
const iconHtml = SECTION_ICONS[section.icon] || '';
|
|
165
|
+
header.innerHTML = `<span class="doc-section-icon">${iconHtml}</span><h4 class="doc-section-title">${escapeHtml(section.section)}</h4>`;
|
|
166
|
+
wrapper.appendChild(header);
|
|
167
|
+
|
|
168
|
+
/* Section divider line */
|
|
169
|
+
const divider = document.createElement('div');
|
|
170
|
+
divider.className = 'doc-section-divider';
|
|
171
|
+
wrapper.appendChild(divider);
|
|
172
|
+
|
|
173
|
+
/* Items */
|
|
174
|
+
if (Array.isArray(section.items))
|
|
180
175
|
{
|
|
181
|
-
const
|
|
182
|
-
if (!res.ok) return;
|
|
183
|
-
|
|
184
|
-
const items = await res.json();
|
|
185
|
-
const container = document.getElementById('api-items');
|
|
186
|
-
if (!container) return;
|
|
187
|
-
|
|
188
|
-
window._apiItems = items;
|
|
189
|
-
renderApiList(container, items);
|
|
190
|
-
|
|
191
|
-
/* Sidebar TOC sub-items */
|
|
192
|
-
populateTocSub('#api-reference', items.map(it => ({
|
|
193
|
-
slug: 'api-' + slugify(it.name),
|
|
194
|
-
label: it.name || '',
|
|
195
|
-
})));
|
|
196
|
-
|
|
197
|
-
/* Search / clear filter */
|
|
198
|
-
const search = document.getElementById('api-search');
|
|
199
|
-
const clearBtn = document.getElementById('api-clear');
|
|
200
|
-
|
|
201
|
-
const doFilter = () =>
|
|
176
|
+
for (const item of section.items)
|
|
202
177
|
{
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
JSON.stringify(it.options || []).toLowerCase().includes(q)
|
|
209
|
-
);
|
|
210
|
-
renderApiList(container, filtered);
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
if (search) search.addEventListener('input', doFilter);
|
|
214
|
-
if (clearBtn) clearBtn.addEventListener('click', () => { if (search) search.value = ''; renderApiList(container, window._apiItems); });
|
|
215
|
-
} catch (e) { }
|
|
178
|
+
wrapper.appendChild(renderDocItem(item, section.section));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return wrapper;
|
|
216
183
|
}
|
|
217
184
|
|
|
218
|
-
/* --
|
|
185
|
+
/* -- TOC population ---------------------------------------------------------- */
|
|
219
186
|
|
|
220
187
|
/**
|
|
221
|
-
*
|
|
188
|
+
* Build the full sidebar TOC from the docs sections array.
|
|
222
189
|
*/
|
|
223
|
-
|
|
190
|
+
function populateToc(sections)
|
|
224
191
|
{
|
|
225
|
-
|
|
192
|
+
const nav = document.querySelector('.toc-sidebar nav ul');
|
|
193
|
+
if (!nav) return;
|
|
194
|
+
|
|
195
|
+
/* Keep static items (features, quickstart, playground) */
|
|
196
|
+
const staticItems = nav.querySelectorAll(':scope > li[data-static]');
|
|
197
|
+
const playgroundLi = nav.querySelector(':scope > li[data-static="playground"]');
|
|
198
|
+
|
|
199
|
+
/* Remove all non-static items */
|
|
200
|
+
Array.from(nav.children).forEach(li =>
|
|
226
201
|
{
|
|
227
|
-
|
|
228
|
-
|
|
202
|
+
if (!li.hasAttribute('data-static')) li.remove();
|
|
203
|
+
});
|
|
229
204
|
|
|
230
|
-
|
|
231
|
-
|
|
205
|
+
/* Insert section TOC items before playground */
|
|
206
|
+
for (const section of sections)
|
|
207
|
+
{
|
|
208
|
+
const sSlug = sectionSlug(section.section);
|
|
209
|
+
const li = document.createElement('li');
|
|
210
|
+
li.className = 'toc-collapsible toc-collapsed';
|
|
232
211
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
212
|
+
const a = document.createElement('a');
|
|
213
|
+
a.href = '#' + sSlug;
|
|
214
|
+
a.textContent = section.section;
|
|
215
|
+
a.addEventListener('click', () => document.body.classList.remove('toc-open'));
|
|
216
|
+
li.appendChild(a);
|
|
236
217
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
218
|
+
/* Sub-items */
|
|
219
|
+
if (Array.isArray(section.items) && section.items.length)
|
|
220
|
+
{
|
|
221
|
+
const sub = document.createElement('ul');
|
|
222
|
+
sub.className = 'toc-sub';
|
|
223
|
+
|
|
224
|
+
for (const item of section.items)
|
|
225
|
+
{
|
|
226
|
+
const subLi = document.createElement('li');
|
|
227
|
+
subLi.className = 'toc-sub-item';
|
|
228
|
+
const subA = document.createElement('a');
|
|
229
|
+
subA.href = '#' + itemSlug(section.section, item.name);
|
|
230
|
+
subA.textContent = item.name;
|
|
231
|
+
subA.addEventListener('click', () => document.body.classList.remove('toc-open'));
|
|
232
|
+
subLi.appendChild(subA);
|
|
233
|
+
sub.appendChild(subLi);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
li.appendChild(sub);
|
|
237
|
+
}
|
|
240
238
|
|
|
241
|
-
|
|
239
|
+
if (playgroundLi)
|
|
242
240
|
{
|
|
243
|
-
|
|
244
|
-
tr.innerHTML =
|
|
245
|
-
`<td><strong>${escapeHtml(it.option || '')}</strong></td>` +
|
|
246
|
-
`<td>${escapeHtml(it.type || '')}</td>` +
|
|
247
|
-
`<td>${escapeHtml(it.default || '')}</td>` +
|
|
248
|
-
`<td>${escapeHtml(it.notes || it.description || '')}</td>`;
|
|
249
|
-
tbody.appendChild(tr);
|
|
241
|
+
nav.insertBefore(li, playgroundLi);
|
|
250
242
|
}
|
|
243
|
+
else
|
|
244
|
+
{
|
|
245
|
+
nav.appendChild(li);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
251
248
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
container.appendChild(table);
|
|
255
|
-
} catch (e) { console.error('loadOptions error', e); }
|
|
249
|
+
/* Re-init collapsible toggles for new items */
|
|
250
|
+
if (typeof initTocCollapsible === 'function') initTocCollapsible();
|
|
256
251
|
}
|
|
257
252
|
|
|
258
|
-
/* --
|
|
253
|
+
/* -- Main loader ------------------------------------------------------------- */
|
|
259
254
|
|
|
260
255
|
/**
|
|
261
|
-
* Fetch
|
|
262
|
-
* populate the sidebar TOC.
|
|
256
|
+
* Fetch docs.json and render all sections + populate sidebar.
|
|
263
257
|
*/
|
|
264
|
-
async function
|
|
258
|
+
async function loadDocs()
|
|
265
259
|
{
|
|
266
260
|
try
|
|
267
261
|
{
|
|
268
|
-
const
|
|
269
|
-
if (!
|
|
262
|
+
const res = await fetch('/data/docs.json', { cache: 'no-store' });
|
|
263
|
+
if (!res.ok) return;
|
|
270
264
|
|
|
271
|
-
const
|
|
272
|
-
|
|
265
|
+
const sections = await res.json();
|
|
266
|
+
window._docSections = sections;
|
|
267
|
+
|
|
268
|
+
const container = document.getElementById('doc-sections');
|
|
269
|
+
if (!container) return;
|
|
273
270
|
|
|
274
|
-
const items = await res.json();
|
|
275
271
|
container.innerHTML = '';
|
|
276
272
|
|
|
277
|
-
for (const
|
|
273
|
+
for (const section of sections)
|
|
278
274
|
{
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
d.className = 'acc nested';
|
|
282
|
-
d.id = id;
|
|
275
|
+
container.appendChild(renderSection(section));
|
|
276
|
+
}
|
|
283
277
|
|
|
284
|
-
|
|
285
|
-
s.innerHTML = `<strong>${escapeHtml(it.title || '')}</strong>`;
|
|
286
|
-
d.appendChild(s);
|
|
278
|
+
try { highlightAllPre(); } catch (e) { }
|
|
287
279
|
|
|
288
|
-
|
|
289
|
-
|
|
280
|
+
/* Populate sidebar */
|
|
281
|
+
populateToc(sections);
|
|
290
282
|
|
|
291
|
-
|
|
283
|
+
/* Wire accordion click handling for new items */
|
|
284
|
+
container.querySelectorAll('details.acc summary').forEach(summary =>
|
|
285
|
+
{
|
|
286
|
+
if (summary.dataset.wired === '1') return;
|
|
287
|
+
summary.dataset.wired = '1';
|
|
288
|
+
summary.addEventListener('click', (ev) =>
|
|
292
289
|
{
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const pre = document.createElement('pre');
|
|
300
|
-
pre.className = it.language ? 'language-' + it.language + ' code' : 'code';
|
|
301
|
-
const code = document.createElement('code');
|
|
302
|
-
if (it.language) code.className = 'language-' + it.language;
|
|
303
|
-
code.textContent = it.code || '';
|
|
304
|
-
pre.appendChild(code);
|
|
305
|
-
body.appendChild(pre);
|
|
306
|
-
|
|
307
|
-
d.appendChild(body);
|
|
308
|
-
container.appendChild(d);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
try { highlightAllPre(); } catch (e) { }
|
|
290
|
+
ev.preventDefault();
|
|
291
|
+
const details = summary.parentElement;
|
|
292
|
+
if (details) details.open = !details.open;
|
|
293
|
+
});
|
|
294
|
+
});
|
|
312
295
|
|
|
313
|
-
|
|
314
|
-
populateTocSub('#simple-examples', items.map(it => ({
|
|
315
|
-
slug: 'example-' + slugify(it.title),
|
|
316
|
-
label: it.title || '',
|
|
317
|
-
})));
|
|
318
|
-
} catch (e) { console.error('loadExamples error', e); }
|
|
296
|
+
} catch (e) { console.error('loadDocs error', e); }
|
|
319
297
|
}
|
|
298
|
+
|
|
299
|
+
/* Legacy stubs for backwards compat (app.js may still call these) */
|
|
300
|
+
async function loadApiReference() { }
|
|
301
|
+
async function loadOptions() { }
|
|
302
|
+
async function loadExamples() { }
|