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.
Files changed (89) hide show
  1. package/README.md +1250 -283
  2. package/documentation/config/db.js +25 -0
  3. package/documentation/config/middleware.js +44 -0
  4. package/documentation/config/tls.js +12 -0
  5. package/documentation/controllers/cookies.js +34 -0
  6. package/documentation/controllers/tasks.js +108 -0
  7. package/documentation/full-server.js +28 -177
  8. package/documentation/models/Task.js +21 -0
  9. package/documentation/public/data/api.json +404 -24
  10. package/documentation/public/data/docs.json +1139 -0
  11. package/documentation/public/data/examples.json +80 -2
  12. package/documentation/public/data/options.json +23 -8
  13. package/documentation/public/index.html +138 -99
  14. package/documentation/public/scripts/app.js +1 -3
  15. package/documentation/public/scripts/custom-select.js +189 -0
  16. package/documentation/public/scripts/data-sections.js +233 -250
  17. package/documentation/public/scripts/playground.js +270 -0
  18. package/documentation/public/scripts/ui.js +4 -3
  19. package/documentation/public/styles.css +56 -5
  20. package/documentation/public/vendor/icons/compress.svg +17 -17
  21. package/documentation/public/vendor/icons/database.svg +21 -0
  22. package/documentation/public/vendor/icons/env.svg +21 -0
  23. package/documentation/public/vendor/icons/fetch.svg +11 -14
  24. package/documentation/public/vendor/icons/security.svg +15 -0
  25. package/documentation/public/vendor/icons/sse.svg +12 -13
  26. package/documentation/public/vendor/icons/static.svg +12 -26
  27. package/documentation/public/vendor/icons/stream.svg +7 -13
  28. package/documentation/public/vendor/icons/validate.svg +17 -0
  29. package/documentation/routes/api.js +41 -0
  30. package/documentation/routes/core.js +20 -0
  31. package/documentation/routes/playground.js +29 -0
  32. package/documentation/routes/realtime.js +49 -0
  33. package/documentation/routes/uploads.js +71 -0
  34. package/index.js +62 -1
  35. package/lib/app.js +200 -8
  36. package/lib/body/json.js +28 -5
  37. package/lib/body/multipart.js +29 -1
  38. package/lib/body/raw.js +1 -1
  39. package/lib/body/sendError.js +1 -0
  40. package/lib/body/text.js +1 -1
  41. package/lib/body/typeMatch.js +6 -2
  42. package/lib/body/urlencoded.js +5 -2
  43. package/lib/debug.js +345 -0
  44. package/lib/env/index.js +440 -0
  45. package/lib/errors.js +231 -0
  46. package/lib/http/request.js +219 -1
  47. package/lib/http/response.js +410 -6
  48. package/lib/middleware/compress.js +39 -6
  49. package/lib/middleware/cookieParser.js +237 -0
  50. package/lib/middleware/cors.js +13 -2
  51. package/lib/middleware/csrf.js +135 -0
  52. package/lib/middleware/errorHandler.js +90 -0
  53. package/lib/middleware/helmet.js +176 -0
  54. package/lib/middleware/index.js +7 -2
  55. package/lib/middleware/rateLimit.js +12 -1
  56. package/lib/middleware/requestId.js +54 -0
  57. package/lib/middleware/static.js +95 -11
  58. package/lib/middleware/timeout.js +72 -0
  59. package/lib/middleware/validator.js +257 -0
  60. package/lib/orm/adapters/json.js +215 -0
  61. package/lib/orm/adapters/memory.js +383 -0
  62. package/lib/orm/adapters/mongo.js +444 -0
  63. package/lib/orm/adapters/mysql.js +272 -0
  64. package/lib/orm/adapters/postgres.js +394 -0
  65. package/lib/orm/adapters/sql-base.js +142 -0
  66. package/lib/orm/adapters/sqlite.js +311 -0
  67. package/lib/orm/index.js +276 -0
  68. package/lib/orm/model.js +895 -0
  69. package/lib/orm/query.js +807 -0
  70. package/lib/orm/schema.js +172 -0
  71. package/lib/router/index.js +136 -47
  72. package/lib/sse/stream.js +15 -3
  73. package/lib/ws/connection.js +19 -3
  74. package/lib/ws/handshake.js +3 -0
  75. package/lib/ws/index.js +3 -1
  76. package/lib/ws/room.js +222 -0
  77. package/package.json +15 -5
  78. package/types/app.d.ts +120 -0
  79. package/types/env.d.ts +80 -0
  80. package/types/errors.d.ts +147 -0
  81. package/types/fetch.d.ts +43 -0
  82. package/types/index.d.ts +135 -0
  83. package/types/middleware.d.ts +292 -0
  84. package/types/orm.d.ts +610 -0
  85. package/types/request.d.ts +99 -0
  86. package/types/response.d.ts +142 -0
  87. package/types/router.d.ts +78 -0
  88. package/types/sse.d.ts +78 -0
  89. 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
+ }