zero-http 0.2.4 → 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 +28 -177
- 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
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* custom-select.js
|
|
3
|
+
* Replaces every native <select> with a styled dropdown.
|
|
4
|
+
* The native element stays in the DOM (hidden) so .value, change events,
|
|
5
|
+
* and form submission keep working with zero changes to existing JS.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const ARROW_SVG = '<svg class="cs-arrow" viewBox="0 0 10 6" fill="none"><path d="M1 1l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
9
|
+
|
|
10
|
+
function initCustomSelects()
|
|
11
|
+
{
|
|
12
|
+
const selects = document.querySelectorAll('select');
|
|
13
|
+
selects.forEach(wrapSelect);
|
|
14
|
+
|
|
15
|
+
// Close all dropdowns when clicking outside
|
|
16
|
+
document.addEventListener('click', (e) =>
|
|
17
|
+
{
|
|
18
|
+
if (!e.target.closest('.custom-select'))
|
|
19
|
+
{
|
|
20
|
+
document.querySelectorAll('.custom-select.open').forEach(el => el.classList.remove('open'));
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Close on Escape
|
|
25
|
+
document.addEventListener('keydown', (e) =>
|
|
26
|
+
{
|
|
27
|
+
if (e.key === 'Escape')
|
|
28
|
+
{
|
|
29
|
+
document.querySelectorAll('.custom-select.open').forEach(el => el.classList.remove('open'));
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function wrapSelect(native)
|
|
35
|
+
{
|
|
36
|
+
// Build wrapper
|
|
37
|
+
const wrapper = document.createElement('div');
|
|
38
|
+
wrapper.className = 'custom-select';
|
|
39
|
+
|
|
40
|
+
// Build trigger button
|
|
41
|
+
const trigger = document.createElement('div');
|
|
42
|
+
trigger.className = 'cs-trigger';
|
|
43
|
+
trigger.setAttribute('tabindex', '0');
|
|
44
|
+
trigger.setAttribute('role', 'combobox');
|
|
45
|
+
trigger.setAttribute('aria-haspopup', 'listbox');
|
|
46
|
+
trigger.setAttribute('aria-expanded', 'false');
|
|
47
|
+
|
|
48
|
+
// Build dropdown
|
|
49
|
+
const dropdown = document.createElement('div');
|
|
50
|
+
dropdown.className = 'cs-dropdown';
|
|
51
|
+
dropdown.setAttribute('role', 'listbox');
|
|
52
|
+
|
|
53
|
+
// Populate options
|
|
54
|
+
function buildOptions()
|
|
55
|
+
{
|
|
56
|
+
dropdown.innerHTML = '';
|
|
57
|
+
const options = native.querySelectorAll('option');
|
|
58
|
+
options.forEach((opt) =>
|
|
59
|
+
{
|
|
60
|
+
const item = document.createElement('div');
|
|
61
|
+
item.className = 'cs-option' + (opt.selected ? ' selected' : '');
|
|
62
|
+
item.textContent = opt.textContent;
|
|
63
|
+
item.dataset.value = opt.value;
|
|
64
|
+
item.setAttribute('role', 'option');
|
|
65
|
+
item.addEventListener('click', (e) =>
|
|
66
|
+
{
|
|
67
|
+
e.stopPropagation();
|
|
68
|
+
selectOption(native, wrapper, opt.value);
|
|
69
|
+
});
|
|
70
|
+
dropdown.appendChild(item);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
buildOptions();
|
|
75
|
+
|
|
76
|
+
// Set initial label
|
|
77
|
+
const selected = native.options[native.selectedIndex];
|
|
78
|
+
trigger.innerHTML = (selected ? selected.textContent : '') + ' ' + ARROW_SVG;
|
|
79
|
+
|
|
80
|
+
// Insert into DOM
|
|
81
|
+
native.parentNode.insertBefore(wrapper, native);
|
|
82
|
+
wrapper.appendChild(trigger);
|
|
83
|
+
wrapper.appendChild(dropdown);
|
|
84
|
+
wrapper.appendChild(native);
|
|
85
|
+
native.classList.add('cs-hidden');
|
|
86
|
+
|
|
87
|
+
// If select is inside a <label>, intercept label click to open dropdown
|
|
88
|
+
const parentLabel = wrapper.closest('label');
|
|
89
|
+
if (parentLabel)
|
|
90
|
+
{
|
|
91
|
+
parentLabel.addEventListener('click', (e) =>
|
|
92
|
+
{
|
|
93
|
+
if (e.target === parentLabel || e.target.nodeType === 3)
|
|
94
|
+
{
|
|
95
|
+
e.preventDefault();
|
|
96
|
+
trigger.click();
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Toggle dropdown
|
|
102
|
+
trigger.addEventListener('click', (e) =>
|
|
103
|
+
{
|
|
104
|
+
e.stopPropagation();
|
|
105
|
+
// Close other open selects
|
|
106
|
+
document.querySelectorAll('.custom-select.open').forEach(el =>
|
|
107
|
+
{
|
|
108
|
+
if (el !== wrapper) el.classList.remove('open');
|
|
109
|
+
});
|
|
110
|
+
const isOpen = wrapper.classList.toggle('open');
|
|
111
|
+
trigger.setAttribute('aria-expanded', isOpen);
|
|
112
|
+
|
|
113
|
+
// Scroll selected into view
|
|
114
|
+
if (isOpen)
|
|
115
|
+
{
|
|
116
|
+
const sel = dropdown.querySelector('.cs-option.selected');
|
|
117
|
+
if (sel) sel.scrollIntoView({ block: 'nearest' });
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Keyboard navigation
|
|
122
|
+
trigger.addEventListener('keydown', (e) =>
|
|
123
|
+
{
|
|
124
|
+
const isOpen = wrapper.classList.contains('open');
|
|
125
|
+
|
|
126
|
+
if (e.key === 'Enter' || e.key === ' ')
|
|
127
|
+
{
|
|
128
|
+
e.preventDefault();
|
|
129
|
+
if (!isOpen)
|
|
130
|
+
{
|
|
131
|
+
wrapper.classList.add('open');
|
|
132
|
+
trigger.setAttribute('aria-expanded', 'true');
|
|
133
|
+
}
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (e.key === 'ArrowDown' || e.key === 'ArrowUp')
|
|
138
|
+
{
|
|
139
|
+
e.preventDefault();
|
|
140
|
+
const opts = Array.from(native.options);
|
|
141
|
+
let idx = native.selectedIndex;
|
|
142
|
+
idx += e.key === 'ArrowDown' ? 1 : -1;
|
|
143
|
+
idx = Math.max(0, Math.min(idx, opts.length - 1));
|
|
144
|
+
selectOption(native, wrapper, opts[idx].value);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// If native select changes programmatically, sync UI
|
|
149
|
+
const observer = new MutationObserver(() =>
|
|
150
|
+
{
|
|
151
|
+
buildOptions();
|
|
152
|
+
syncTriggerLabel(native, trigger);
|
|
153
|
+
});
|
|
154
|
+
observer.observe(native, { childList: true, subtree: true, attributes: true });
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function selectOption(native, wrapper, value)
|
|
158
|
+
{
|
|
159
|
+
native.value = value;
|
|
160
|
+
native.dispatchEvent(new Event('change', { bubbles: true }));
|
|
161
|
+
|
|
162
|
+
const trigger = wrapper.querySelector('.cs-trigger');
|
|
163
|
+
const dropdown = wrapper.querySelector('.cs-dropdown');
|
|
164
|
+
|
|
165
|
+
// Update selected state
|
|
166
|
+
dropdown.querySelectorAll('.cs-option').forEach(o =>
|
|
167
|
+
{
|
|
168
|
+
o.classList.toggle('selected', o.dataset.value === value);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
syncTriggerLabel(native, trigger);
|
|
172
|
+
wrapper.classList.remove('open');
|
|
173
|
+
trigger.setAttribute('aria-expanded', 'false');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function syncTriggerLabel(native, trigger)
|
|
177
|
+
{
|
|
178
|
+
const selected = native.options[native.selectedIndex];
|
|
179
|
+
trigger.innerHTML = (selected ? selected.textContent : '') + ' ' + ARROW_SVG;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Auto-init when DOM is ready
|
|
183
|
+
if (document.readyState === 'loading')
|
|
184
|
+
{
|
|
185
|
+
document.addEventListener('DOMContentLoaded', initCustomSelects);
|
|
186
|
+
} else
|
|
187
|
+
{
|
|
188
|
+
initCustomSelects();
|
|
189
|
+
}
|