orator-static-server 2.0.3 → 2.1.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/docs/{cover.md → _cover.md} +1 -1
- package/docs/_version.json +7 -0
- package/docs/css/docuserve.css +277 -23
- package/docs/index.html +2 -2
- package/docs/retold-catalog.json +20 -1
- package/docs/retold-keyword-index.json +1 -1
- package/docs/subdomain-routing.md +5 -5
- package/package.json +13 -14
- package/source/Orator-Static-Server.js +121 -0
package/docs/css/docuserve.css
CHANGED
|
@@ -1,73 +1,327 @@
|
|
|
1
1
|
/* ============================================================================
|
|
2
|
-
Pict Docuserve - Base Styles
|
|
2
|
+
Pict Docuserve - Base Styles & Theme Variables
|
|
3
3
|
============================================================================ */
|
|
4
4
|
|
|
5
|
-
/*
|
|
6
|
-
|
|
5
|
+
/* ----------------------------------------------------------------------------
|
|
6
|
+
Theme variables — light defaults on :root.
|
|
7
|
+
Dark mode applies when either:
|
|
8
|
+
(a) the user explicitly selected dark via <html data-theme="dark">
|
|
9
|
+
(b) the user hasn't chosen anything AND the system prefers dark
|
|
10
|
+
An explicit <html data-theme="light"> pins the light palette regardless.
|
|
11
|
+
---------------------------------------------------------------------------- */
|
|
12
|
+
|
|
13
|
+
:root
|
|
14
|
+
{
|
|
15
|
+
/* Surfaces */
|
|
16
|
+
--docuserve-bg: #FDFBF7;
|
|
17
|
+
--docuserve-bg-elevated: #FFFFFF;
|
|
18
|
+
--docuserve-border: #DDD6CA;
|
|
19
|
+
--docuserve-border-soft: #EAE3D8;
|
|
20
|
+
|
|
21
|
+
/* Text */
|
|
22
|
+
--docuserve-text: #2A241E;
|
|
23
|
+
--docuserve-text-strong: #3D3229;
|
|
24
|
+
--docuserve-text-muted: #5E5549;
|
|
25
|
+
--docuserve-text-dim: #8A7F72;
|
|
26
|
+
|
|
27
|
+
/* Accent / links */
|
|
28
|
+
--docuserve-accent: #2E7D74;
|
|
29
|
+
--docuserve-accent-hover: #236660;
|
|
30
|
+
|
|
31
|
+
/* Top bar */
|
|
32
|
+
--docuserve-topbar-bg: #3D3229;
|
|
33
|
+
--docuserve-topbar-text: #E8E0D4;
|
|
34
|
+
--docuserve-topbar-text-muted: #B5AA9A;
|
|
35
|
+
--docuserve-topbar-text-dim: #8A7F72;
|
|
36
|
+
--docuserve-topbar-hover-bg: #524438;
|
|
37
|
+
--docuserve-topbar-version-bg: rgba(255, 255, 255, 0.06);
|
|
38
|
+
--docuserve-topbar-version-border: rgba(255, 255, 255, 0.08);
|
|
39
|
+
--docuserve-topbar-version-text: #B5AA9A;
|
|
40
|
+
|
|
41
|
+
/* Sidebar */
|
|
42
|
+
--docuserve-sidebar-bg: #FAF7F1;
|
|
43
|
+
--docuserve-sidebar-border: #DDD6CA;
|
|
44
|
+
--docuserve-sidebar-border-soft: #E5DED1;
|
|
45
|
+
--docuserve-sidebar-text: #423D37;
|
|
46
|
+
--docuserve-sidebar-group-title: #3D3229;
|
|
47
|
+
--docuserve-sidebar-module-text: #5E5549;
|
|
48
|
+
--docuserve-sidebar-hover-bg: #EAE3D8;
|
|
49
|
+
--docuserve-sidebar-hover-text: #2E7D74;
|
|
50
|
+
--docuserve-sidebar-active-bg: #E5DED1;
|
|
51
|
+
--docuserve-sidebar-active-text: #2E7D74;
|
|
52
|
+
--docuserve-sidebar-search-bg: #FFFFFF;
|
|
53
|
+
--docuserve-sidebar-search-border: #DDD6CA;
|
|
54
|
+
|
|
55
|
+
/* Inline code */
|
|
56
|
+
--docuserve-inline-code-bg: #F0ECE4;
|
|
57
|
+
--docuserve-inline-code-text: #9E3A50;
|
|
58
|
+
|
|
59
|
+
/* Code block panel */
|
|
60
|
+
--docuserve-code-bg: #F6F3EE;
|
|
61
|
+
--docuserve-code-border: #E5DED1;
|
|
62
|
+
--docuserve-code-gutter-bg: #EFEAE0;
|
|
63
|
+
--docuserve-code-gutter-border: #DDD6CA;
|
|
64
|
+
--docuserve-code-gutter-text: #A59986;
|
|
65
|
+
--docuserve-code-text: #2A241E;
|
|
66
|
+
|
|
67
|
+
/* Syntax tokens — low-chroma dark-on-light palette */
|
|
68
|
+
--docuserve-tok-keyword: #A03472;
|
|
69
|
+
--docuserve-tok-string: #1A6640;
|
|
70
|
+
--docuserve-tok-number: #B25A00;
|
|
71
|
+
--docuserve-tok-comment: #8A7F72;
|
|
72
|
+
--docuserve-tok-operator: #2E7D74;
|
|
73
|
+
--docuserve-tok-punctuation: #2A241E;
|
|
74
|
+
--docuserve-tok-function: #2A5DB0;
|
|
75
|
+
--docuserve-tok-property: #9E3A50;
|
|
76
|
+
--docuserve-tok-tag: #9E3A50;
|
|
77
|
+
--docuserve-tok-attr-name: #B25A00;
|
|
78
|
+
--docuserve-tok-attr-value: #1A6640;
|
|
79
|
+
|
|
80
|
+
/* Tables, blockquotes, mermaid */
|
|
81
|
+
--docuserve-table-header-bg: #F5F0E8;
|
|
82
|
+
--docuserve-table-row-alt-bg: #F9F6F0;
|
|
83
|
+
--docuserve-blockquote-bg: #F7F5F0;
|
|
84
|
+
--docuserve-blockquote-border: #2E7D74;
|
|
85
|
+
--docuserve-blockquote-text: #5E5549;
|
|
86
|
+
--docuserve-mermaid-bg: #FFFFFF;
|
|
87
|
+
|
|
88
|
+
/* Scrollbars */
|
|
89
|
+
--docuserve-scrollbar-track: #F5F0E8;
|
|
90
|
+
--docuserve-scrollbar-thumb: #D4CCBE;
|
|
91
|
+
--docuserve-scrollbar-thumb-hover: #B5AA9A;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@media (prefers-color-scheme: dark)
|
|
95
|
+
{
|
|
96
|
+
:root:not([data-theme="light"])
|
|
97
|
+
{
|
|
98
|
+
--docuserve-bg: #15120F;
|
|
99
|
+
--docuserve-bg-elevated: #1B1814;
|
|
100
|
+
--docuserve-border: #2F2823;
|
|
101
|
+
--docuserve-border-soft: #26211C;
|
|
102
|
+
|
|
103
|
+
--docuserve-text: #E8E0D4;
|
|
104
|
+
--docuserve-text-strong: #F2ECE0;
|
|
105
|
+
--docuserve-text-muted: #B5AA9A;
|
|
106
|
+
--docuserve-text-dim: #7A6F62;
|
|
107
|
+
|
|
108
|
+
--docuserve-accent: #5DB8A8;
|
|
109
|
+
--docuserve-accent-hover: #7FCCB8;
|
|
110
|
+
|
|
111
|
+
--docuserve-topbar-bg: #1A1612;
|
|
112
|
+
--docuserve-topbar-text: #E8E0D4;
|
|
113
|
+
--docuserve-topbar-text-muted: #B5AA9A;
|
|
114
|
+
--docuserve-topbar-text-dim: #7A6F62;
|
|
115
|
+
--docuserve-topbar-hover-bg: #2A241E;
|
|
116
|
+
--docuserve-topbar-version-bg: rgba(255, 255, 255, 0.05);
|
|
117
|
+
--docuserve-topbar-version-border: rgba(255, 255, 255, 0.09);
|
|
118
|
+
--docuserve-topbar-version-text: #B5AA9A;
|
|
119
|
+
|
|
120
|
+
--docuserve-sidebar-bg: #1B1814;
|
|
121
|
+
--docuserve-sidebar-border: #2F2823;
|
|
122
|
+
--docuserve-sidebar-border-soft: #26211C;
|
|
123
|
+
--docuserve-sidebar-text: #C9C0B3;
|
|
124
|
+
--docuserve-sidebar-group-title: #F2ECE0;
|
|
125
|
+
--docuserve-sidebar-module-text: #B5AA9A;
|
|
126
|
+
--docuserve-sidebar-hover-bg: #2A241E;
|
|
127
|
+
--docuserve-sidebar-hover-text: #7FCCB8;
|
|
128
|
+
--docuserve-sidebar-active-bg: #2F2823;
|
|
129
|
+
--docuserve-sidebar-active-text: #7FCCB8;
|
|
130
|
+
--docuserve-sidebar-search-bg: #26211C;
|
|
131
|
+
--docuserve-sidebar-search-border: #2F2823;
|
|
132
|
+
|
|
133
|
+
--docuserve-inline-code-bg: #2A241E;
|
|
134
|
+
--docuserve-inline-code-text: #E8B07A;
|
|
135
|
+
|
|
136
|
+
--docuserve-code-bg: #1E1A17;
|
|
137
|
+
--docuserve-code-border: #2F2823;
|
|
138
|
+
--docuserve-code-gutter-bg: #17130F;
|
|
139
|
+
--docuserve-code-gutter-border: #2F2823;
|
|
140
|
+
--docuserve-code-gutter-text: #6A6052;
|
|
141
|
+
--docuserve-code-text: #E8E0D4;
|
|
142
|
+
|
|
143
|
+
--docuserve-tok-keyword: #C678DD;
|
|
144
|
+
--docuserve-tok-string: #98C379;
|
|
145
|
+
--docuserve-tok-number: #D19A66;
|
|
146
|
+
--docuserve-tok-comment: #7F848E;
|
|
147
|
+
--docuserve-tok-operator: #56B6C2;
|
|
148
|
+
--docuserve-tok-punctuation: #E8E0D4;
|
|
149
|
+
--docuserve-tok-function: #61AFEF;
|
|
150
|
+
--docuserve-tok-property: #E06C75;
|
|
151
|
+
--docuserve-tok-tag: #E06C75;
|
|
152
|
+
--docuserve-tok-attr-name: #D19A66;
|
|
153
|
+
--docuserve-tok-attr-value: #98C379;
|
|
154
|
+
|
|
155
|
+
--docuserve-table-header-bg: #26211C;
|
|
156
|
+
--docuserve-table-row-alt-bg: #1F1B17;
|
|
157
|
+
--docuserve-blockquote-bg: #1F1B17;
|
|
158
|
+
--docuserve-blockquote-border: #5DB8A8;
|
|
159
|
+
--docuserve-blockquote-text: #C9C0B3;
|
|
160
|
+
--docuserve-mermaid-bg: #E8E0D4;
|
|
161
|
+
|
|
162
|
+
--docuserve-scrollbar-track: #1B1814;
|
|
163
|
+
--docuserve-scrollbar-thumb: #3A322B;
|
|
164
|
+
--docuserve-scrollbar-thumb-hover: #524438;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
:root[data-theme="dark"]
|
|
169
|
+
{
|
|
170
|
+
--docuserve-bg: #15120F;
|
|
171
|
+
--docuserve-bg-elevated: #1B1814;
|
|
172
|
+
--docuserve-border: #2F2823;
|
|
173
|
+
--docuserve-border-soft: #26211C;
|
|
174
|
+
|
|
175
|
+
--docuserve-text: #E8E0D4;
|
|
176
|
+
--docuserve-text-strong: #F2ECE0;
|
|
177
|
+
--docuserve-text-muted: #B5AA9A;
|
|
178
|
+
--docuserve-text-dim: #7A6F62;
|
|
179
|
+
|
|
180
|
+
--docuserve-accent: #5DB8A8;
|
|
181
|
+
--docuserve-accent-hover: #7FCCB8;
|
|
182
|
+
|
|
183
|
+
--docuserve-topbar-bg: #1A1612;
|
|
184
|
+
--docuserve-topbar-text: #E8E0D4;
|
|
185
|
+
--docuserve-topbar-text-muted: #B5AA9A;
|
|
186
|
+
--docuserve-topbar-text-dim: #7A6F62;
|
|
187
|
+
--docuserve-topbar-hover-bg: #2A241E;
|
|
188
|
+
--docuserve-topbar-version-bg: rgba(255, 255, 255, 0.05);
|
|
189
|
+
--docuserve-topbar-version-border: rgba(255, 255, 255, 0.09);
|
|
190
|
+
--docuserve-topbar-version-text: #B5AA9A;
|
|
191
|
+
|
|
192
|
+
--docuserve-sidebar-bg: #1B1814;
|
|
193
|
+
--docuserve-sidebar-border: #2F2823;
|
|
194
|
+
--docuserve-sidebar-border-soft: #26211C;
|
|
195
|
+
--docuserve-sidebar-text: #C9C0B3;
|
|
196
|
+
--docuserve-sidebar-group-title: #F2ECE0;
|
|
197
|
+
--docuserve-sidebar-module-text: #B5AA9A;
|
|
198
|
+
--docuserve-sidebar-hover-bg: #2A241E;
|
|
199
|
+
--docuserve-sidebar-hover-text: #7FCCB8;
|
|
200
|
+
--docuserve-sidebar-active-bg: #2F2823;
|
|
201
|
+
--docuserve-sidebar-active-text: #7FCCB8;
|
|
202
|
+
--docuserve-sidebar-search-bg: #26211C;
|
|
203
|
+
--docuserve-sidebar-search-border: #2F2823;
|
|
204
|
+
|
|
205
|
+
--docuserve-inline-code-bg: #2A241E;
|
|
206
|
+
--docuserve-inline-code-text: #E8B07A;
|
|
207
|
+
|
|
208
|
+
--docuserve-code-bg: #1E1A17;
|
|
209
|
+
--docuserve-code-border: #2F2823;
|
|
210
|
+
--docuserve-code-gutter-bg: #17130F;
|
|
211
|
+
--docuserve-code-gutter-border: #2F2823;
|
|
212
|
+
--docuserve-code-gutter-text: #6A6052;
|
|
213
|
+
--docuserve-code-text: #E8E0D4;
|
|
214
|
+
|
|
215
|
+
--docuserve-tok-keyword: #C678DD;
|
|
216
|
+
--docuserve-tok-string: #98C379;
|
|
217
|
+
--docuserve-tok-number: #D19A66;
|
|
218
|
+
--docuserve-tok-comment: #7F848E;
|
|
219
|
+
--docuserve-tok-operator: #56B6C2;
|
|
220
|
+
--docuserve-tok-punctuation: #E8E0D4;
|
|
221
|
+
--docuserve-tok-function: #61AFEF;
|
|
222
|
+
--docuserve-tok-property: #E06C75;
|
|
223
|
+
--docuserve-tok-tag: #E06C75;
|
|
224
|
+
--docuserve-tok-attr-name: #D19A66;
|
|
225
|
+
--docuserve-tok-attr-value: #98C379;
|
|
226
|
+
|
|
227
|
+
--docuserve-table-header-bg: #26211C;
|
|
228
|
+
--docuserve-table-row-alt-bg: #1F1B17;
|
|
229
|
+
--docuserve-blockquote-bg: #1F1B17;
|
|
230
|
+
--docuserve-blockquote-border: #5DB8A8;
|
|
231
|
+
--docuserve-blockquote-text: #C9C0B3;
|
|
232
|
+
--docuserve-mermaid-bg: #E8E0D4;
|
|
233
|
+
|
|
234
|
+
--docuserve-scrollbar-track: #1B1814;
|
|
235
|
+
--docuserve-scrollbar-thumb: #3A322B;
|
|
236
|
+
--docuserve-scrollbar-thumb-hover: #524438;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/* ----------------------------------------------------------------------------
|
|
240
|
+
Reset and base
|
|
241
|
+
---------------------------------------------------------------------------- */
|
|
242
|
+
|
|
243
|
+
*, *::before, *::after
|
|
244
|
+
{
|
|
7
245
|
box-sizing: border-box;
|
|
8
246
|
}
|
|
9
247
|
|
|
10
|
-
html, body
|
|
248
|
+
html, body
|
|
249
|
+
{
|
|
11
250
|
margin: 0;
|
|
12
251
|
padding: 0;
|
|
13
252
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
14
253
|
font-size: 16px;
|
|
15
254
|
line-height: 1.5;
|
|
16
|
-
color:
|
|
17
|
-
background-color:
|
|
255
|
+
color: var(--docuserve-text);
|
|
256
|
+
background-color: var(--docuserve-bg);
|
|
18
257
|
-webkit-font-smoothing: antialiased;
|
|
19
258
|
-moz-osx-font-smoothing: grayscale;
|
|
259
|
+
transition: background-color 0.15s ease, color 0.15s ease;
|
|
20
260
|
}
|
|
21
261
|
|
|
22
262
|
/* Typography */
|
|
23
|
-
h1, h2, h3, h4, h5, h6
|
|
263
|
+
h1, h2, h3, h4, h5, h6
|
|
264
|
+
{
|
|
24
265
|
margin-top: 0;
|
|
25
266
|
line-height: 1.3;
|
|
267
|
+
color: var(--docuserve-text-strong);
|
|
26
268
|
}
|
|
27
269
|
|
|
28
|
-
a
|
|
29
|
-
|
|
270
|
+
a
|
|
271
|
+
{
|
|
272
|
+
color: var(--docuserve-accent);
|
|
30
273
|
text-decoration: none;
|
|
31
274
|
}
|
|
32
275
|
|
|
33
|
-
a:hover
|
|
34
|
-
|
|
276
|
+
a:hover
|
|
277
|
+
{
|
|
278
|
+
color: var(--docuserve-accent-hover);
|
|
35
279
|
}
|
|
36
280
|
|
|
37
281
|
/* Application container */
|
|
38
|
-
#Docuserve-Application-Container
|
|
282
|
+
#Docuserve-Application-Container
|
|
283
|
+
{
|
|
39
284
|
min-height: 100vh;
|
|
40
285
|
}
|
|
41
286
|
|
|
42
287
|
/* Utility: scrollbar styling */
|
|
43
|
-
::-webkit-scrollbar
|
|
288
|
+
::-webkit-scrollbar
|
|
289
|
+
{
|
|
44
290
|
width: 8px;
|
|
291
|
+
height: 8px;
|
|
45
292
|
}
|
|
46
293
|
|
|
47
|
-
::-webkit-scrollbar-track
|
|
48
|
-
|
|
294
|
+
::-webkit-scrollbar-track
|
|
295
|
+
{
|
|
296
|
+
background: var(--docuserve-scrollbar-track);
|
|
49
297
|
}
|
|
50
298
|
|
|
51
|
-
::-webkit-scrollbar-thumb
|
|
52
|
-
|
|
299
|
+
::-webkit-scrollbar-thumb
|
|
300
|
+
{
|
|
301
|
+
background: var(--docuserve-scrollbar-thumb);
|
|
53
302
|
border-radius: 4px;
|
|
54
303
|
}
|
|
55
304
|
|
|
56
|
-
::-webkit-scrollbar-thumb:hover
|
|
57
|
-
|
|
305
|
+
::-webkit-scrollbar-thumb:hover
|
|
306
|
+
{
|
|
307
|
+
background: var(--docuserve-scrollbar-thumb-hover);
|
|
58
308
|
}
|
|
59
309
|
|
|
60
310
|
/* Responsive adjustments */
|
|
61
|
-
@media (max-width: 768px)
|
|
62
|
-
|
|
311
|
+
@media (max-width: 768px)
|
|
312
|
+
{
|
|
313
|
+
html
|
|
314
|
+
{
|
|
63
315
|
font-size: 14px;
|
|
64
316
|
}
|
|
65
317
|
|
|
66
|
-
#Docuserve-Sidebar-Container
|
|
318
|
+
#Docuserve-Sidebar-Container
|
|
319
|
+
{
|
|
67
320
|
display: none;
|
|
68
321
|
}
|
|
69
322
|
|
|
70
|
-
.docuserve-body
|
|
323
|
+
.docuserve-body
|
|
324
|
+
{
|
|
71
325
|
flex-direction: column;
|
|
72
326
|
}
|
|
73
327
|
}
|
package/docs/index.html
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
7
|
-
<meta name="description" content="Documentation
|
|
7
|
+
<meta name="description" content="Orator Static Server v2.0.4 Documentation — Static file serving for Orator API servers.">
|
|
8
8
|
|
|
9
|
-
<title>Documentation</title>
|
|
9
|
+
<title>Orator Static Server v2.0.4 Documentation</title>
|
|
10
10
|
|
|
11
11
|
<!-- Application Stylesheet -->
|
|
12
12
|
<link href="css/docuserve.css" rel="stylesheet">
|
package/docs/retold-catalog.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"Generated": "2026-
|
|
2
|
+
"Generated": "2026-04-10T17:23:24.205Z",
|
|
3
3
|
"GitHubOrg": "stevenvelozo",
|
|
4
4
|
"DefaultBranch": "master",
|
|
5
5
|
"Groups": [
|
|
@@ -20,6 +20,25 @@
|
|
|
20
20
|
}
|
|
21
21
|
]
|
|
22
22
|
},
|
|
23
|
+
{
|
|
24
|
+
"Name": "Docs",
|
|
25
|
+
"Key": "docs",
|
|
26
|
+
"Description": "",
|
|
27
|
+
"Modules": [
|
|
28
|
+
{
|
|
29
|
+
"Name": "css",
|
|
30
|
+
"Repo": "css",
|
|
31
|
+
"Group": "docs",
|
|
32
|
+
"Branch": "master",
|
|
33
|
+
"HasDocs": true,
|
|
34
|
+
"HasCover": false,
|
|
35
|
+
"Sidebar": [],
|
|
36
|
+
"DocFiles": [
|
|
37
|
+
"css/docuserve.css"
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
},
|
|
23
42
|
{
|
|
24
43
|
"Name": "Test",
|
|
25
44
|
"Key": "test",
|
|
@@ -14,8 +14,8 @@ Split host: ["clienta", "example", "com"]
|
|
|
14
14
|
First segment: "clienta"
|
|
15
15
|
↓
|
|
16
16
|
Check: does ./sites/clienta/ exist?
|
|
17
|
-
├── Yes
|
|
18
|
-
└── No
|
|
17
|
+
├── Yes -> Serve from ./sites/clienta/page.html
|
|
18
|
+
└── No -> Serve from ./sites/page.html
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
## Setup
|
|
@@ -29,13 +29,13 @@ _Fable.Orator.addStaticRoute('./sites/');
|
|
|
29
29
|
|
|
30
30
|
```
|
|
31
31
|
sites/
|
|
32
|
-
├── index.html
|
|
32
|
+
├── index.html <- Served for requests without subdomain match
|
|
33
33
|
├── styles.css
|
|
34
34
|
├── clienta/
|
|
35
|
-
│ ├── index.html
|
|
35
|
+
│ ├── index.html <- Served for clienta.example.com
|
|
36
36
|
│ └── styles.css
|
|
37
37
|
├── clientb/
|
|
38
|
-
│ ├── index.html
|
|
38
|
+
│ ├── index.html <- Served for clientb.example.com
|
|
39
39
|
│ └── styles.css
|
|
40
40
|
└── shared/
|
|
41
41
|
└── logo.png
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "orator-static-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Static file serving for Orator API servers.",
|
|
5
5
|
"main": "source/Orator-Static-Server.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "
|
|
8
|
-
"coverage": "
|
|
7
|
+
"test": "npx quack test",
|
|
8
|
+
"coverage": "npx quack coverage",
|
|
9
9
|
"start": "node debug/Harness.js",
|
|
10
|
-
"tests": "npx
|
|
10
|
+
"tests": "npx quack test -g"
|
|
11
11
|
},
|
|
12
12
|
"mocha": {
|
|
13
13
|
"diff": true,
|
|
@@ -38,17 +38,16 @@
|
|
|
38
38
|
},
|
|
39
39
|
"homepage": "https://github.com/stevenvelozo/orator-static-server#readme",
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"fable-serviceproviderbase": "^3.0.
|
|
42
|
-
"finalhandler": "^1.
|
|
43
|
-
"mime": "^
|
|
44
|
-
"serve-static": "^
|
|
41
|
+
"fable-serviceproviderbase": "^3.0.19",
|
|
42
|
+
"finalhandler": "^2.1.1",
|
|
43
|
+
"mime": "^4.1.0",
|
|
44
|
+
"serve-static": "^2.2.1"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"quackage": "^1.0.51"
|
|
47
|
+
"fable": "^3.1.71",
|
|
48
|
+
"orator": "^6.0.4",
|
|
49
|
+
"orator-serviceserver-restify": "^2.0.10",
|
|
50
|
+
"pict-docuserve": "^0.1.5",
|
|
51
|
+
"quackage": "^1.1.2"
|
|
53
52
|
}
|
|
54
53
|
}
|
|
@@ -183,6 +183,127 @@ class OratorStaticServer extends libFableServiceProviderBase
|
|
|
183
183
|
});
|
|
184
184
|
return true;
|
|
185
185
|
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Like addStaticRoute, but any file listed in pFallbackMap that isn't
|
|
189
|
+
* present on disk produces a 302 redirect to the mapped URL instead of
|
|
190
|
+
* a 404. Useful for offering CDN fallbacks on runtime assets that are
|
|
191
|
+
* optionally committed alongside the build output.
|
|
192
|
+
*
|
|
193
|
+
* addStaticRouteWithFallbacks(
|
|
194
|
+
* './web-application/', null, '/pict/*', '/pict/', null,
|
|
195
|
+
* { 'pict.min.js': 'https://unpkg.com/pict/dist/pict.min.js' });
|
|
196
|
+
*
|
|
197
|
+
* Files present locally are served normally (MIME types, caching, etc.
|
|
198
|
+
* all via serve-static). Files absent locally that ARE in the map are
|
|
199
|
+
* redirected. Files absent locally that are NOT in the map 404 as usual.
|
|
200
|
+
*
|
|
201
|
+
* This variant does not use the service server's built-in serveStatic
|
|
202
|
+
* plugin (e.g. restify.plugins.serveStatic) because that plugin does
|
|
203
|
+
* not expose a "not found" hook; it always finalises the response.
|
|
204
|
+
*
|
|
205
|
+
* @param {string} pFilePath - The path on disk to serve files from.
|
|
206
|
+
* @param {string} [pDefaultFile='index.html'] - The default file for directory requests.
|
|
207
|
+
* @param {string} [pRoute='/*'] - The route pattern to match.
|
|
208
|
+
* @param {string} [pRouteStrip='/'] - URL prefix to strip before filesystem lookup.
|
|
209
|
+
* @param {object} [pParams={}] - Additional parameters passed to serve-static.
|
|
210
|
+
* @param {Object<string,string>} [pFallbackMap={}] - Map of relative-path (under the route prefix) to absolute URL.
|
|
211
|
+
* @returns {boolean} true if the route was successfully installed.
|
|
212
|
+
*/
|
|
213
|
+
addStaticRouteWithFallbacks(pFilePath, pDefaultFile, pRoute, pRouteStrip, pParams, pFallbackMap)
|
|
214
|
+
{
|
|
215
|
+
if (!this.fable.Orator)
|
|
216
|
+
{
|
|
217
|
+
this.log.error('OratorStaticServer requires an Orator instance to be registered with Fable.');
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
if (typeof(pFilePath) !== 'string')
|
|
221
|
+
{
|
|
222
|
+
this.fable.log.error('A file path must be passed in as part of the server.');
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const tmpRoute = (typeof(pRoute) === 'undefined') ? '/*' : pRoute;
|
|
227
|
+
const tmpRouteStrip = (typeof(pRouteStrip) === 'undefined') ? '/' : pRouteStrip;
|
|
228
|
+
const tmpDefaultFile = (typeof(pDefaultFile) === 'undefined') ? 'index.html' : pDefaultFile;
|
|
229
|
+
const tmpFallbackMap = pFallbackMap || {};
|
|
230
|
+
|
|
231
|
+
let tmpOrator = this.fable.Orator;
|
|
232
|
+
|
|
233
|
+
this.fable.log.info('Orator mapping static+fallback route to files: '
|
|
234
|
+
+ tmpRoute + ' ==> ' + pFilePath + ' ' + tmpDefaultFile
|
|
235
|
+
+ ' (fallback entries: ' + Object.keys(tmpFallbackMap).length + ')');
|
|
236
|
+
|
|
237
|
+
if (!this.fable.FilePersistence)
|
|
238
|
+
{
|
|
239
|
+
this.fable.serviceManager.instantiateServiceProvider('FilePersistence');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
tmpOrator.serviceServer.get(tmpRoute,
|
|
243
|
+
(pRequest, pResponse, fNext) =>
|
|
244
|
+
{
|
|
245
|
+
// Capture the relative path BEFORE the URL rewrite so we can
|
|
246
|
+
// look it up in the fallback map on a miss.
|
|
247
|
+
let tmpRelative = (pRequest.url || '').split('?')[0];
|
|
248
|
+
if (tmpRelative.indexOf(tmpRouteStrip) === 0)
|
|
249
|
+
{
|
|
250
|
+
tmpRelative = tmpRelative.slice(tmpRouteStrip.length);
|
|
251
|
+
}
|
|
252
|
+
try { tmpRelative = decodeURIComponent(tmpRelative); }
|
|
253
|
+
catch (pError) { /* non-fatal; will fall through to 404 */ }
|
|
254
|
+
|
|
255
|
+
// Magic subdomain subfolder check (mirrors addStaticRoute)
|
|
256
|
+
let tmpHostSet = pRequest.headers.host.split('.');
|
|
257
|
+
let tmpPotentialSubfolderMagicHost = false;
|
|
258
|
+
let servePath = pFilePath;
|
|
259
|
+
if (tmpHostSet.length > 1)
|
|
260
|
+
{
|
|
261
|
+
tmpPotentialSubfolderMagicHost = tmpHostSet[0];
|
|
262
|
+
}
|
|
263
|
+
if (tmpPotentialSubfolderMagicHost)
|
|
264
|
+
{
|
|
265
|
+
let tmpPotentialSubfolder = servePath + tmpPotentialSubfolderMagicHost;
|
|
266
|
+
if (this.fable.FilePersistence.libFS.existsSync(tmpPotentialSubfolder))
|
|
267
|
+
{
|
|
268
|
+
servePath = `${tmpPotentialSubfolder}/`;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
pRequest.url = pRequest.url.split('?')[0].substr(tmpRouteStrip.length) || '/';
|
|
273
|
+
pRequest.path = function() { return pRequest.url; };
|
|
274
|
+
|
|
275
|
+
const tmpServe = libServeStatic(servePath, Object.assign({ index: tmpDefaultFile }, pParams));
|
|
276
|
+
tmpServe(pRequest, pResponse,
|
|
277
|
+
(pError) =>
|
|
278
|
+
{
|
|
279
|
+
// serve-static invokes this when it cannot serve a local
|
|
280
|
+
// file (missing, method not allowed, etc.). We get a
|
|
281
|
+
// chance to redirect before the default final handler
|
|
282
|
+
// would otherwise 404.
|
|
283
|
+
if (!pError && Object.prototype.hasOwnProperty.call(tmpFallbackMap, tmpRelative))
|
|
284
|
+
{
|
|
285
|
+
let tmpTarget = tmpFallbackMap[tmpRelative];
|
|
286
|
+
pResponse.statusCode = 302;
|
|
287
|
+
pResponse.setHeader('Location', tmpTarget);
|
|
288
|
+
pResponse.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
|
289
|
+
pResponse.end('Redirecting to ' + tmpTarget + '\n');
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
return libFinalHandler(pRequest, pResponse)(pError);
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
this.routes.push(
|
|
297
|
+
{
|
|
298
|
+
filePath: pFilePath,
|
|
299
|
+
defaultFile: tmpDefaultFile,
|
|
300
|
+
route: tmpRoute,
|
|
301
|
+
routeStrip: tmpRouteStrip,
|
|
302
|
+
params: pParams || {},
|
|
303
|
+
fallbackMap: tmpFallbackMap,
|
|
304
|
+
});
|
|
305
|
+
return true;
|
|
306
|
+
}
|
|
186
307
|
}
|
|
187
308
|
|
|
188
309
|
module.exports = OratorStaticServer;
|