orator-static-server 2.0.0 → 2.0.3

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.
@@ -0,0 +1,50 @@
1
+ # Contributing to Retold
2
+
3
+ We welcome contributions to Retold and its modules. This guide covers the expectations and process for contributing.
4
+
5
+ ## Code of Conduct
6
+
7
+ The Retold community values **empathy**, **equity**, **kindness**, and **thoughtfulness**. We expect all participants to treat each other with respect, assume good intent, and engage constructively. These values apply to all interactions: pull requests, issues, discussions, and code review.
8
+
9
+ ## How to Contribute
10
+
11
+ ### Pull Requests
12
+
13
+ Pull requests are the preferred method for contributing changes. To submit one:
14
+
15
+ 1. Fork the module repository you want to change
16
+ 2. Create a branch for your work
17
+ 3. Make your changes, following the code style of the module you are editing
18
+ 4. Ensure your changes have test coverage (see below)
19
+ 5. Open a pull request against the module's main branch
20
+
21
+ **Submitting a pull request does not guarantee it will be accepted.** Maintainers review contributions for fit, quality, and alignment with the project's direction. A PR may be declined, or you may be asked to revise it. This is normal and not a reflection on the quality of your effort.
22
+
23
+ ### Reporting Issues
24
+
25
+ If you find a bug or have a feature suggestion, open an issue on the relevant module's repository. Include enough detail to reproduce the problem or understand the proposal.
26
+
27
+ ## Test Coverage
28
+
29
+ Every commit must include test coverage for the changes it introduces. Retold modules use Mocha in TDD style. Before submitting:
30
+
31
+ - **Write tests** for any new functionality or bug fixes
32
+ - **Run the existing test suite** with `npm test` and confirm all tests pass
33
+ - **Check coverage** with `npm run coverage` if the module supports it
34
+
35
+ Pull requests that break existing tests or lack coverage for new code will not be merged.
36
+
37
+ ## Code Style
38
+
39
+ Follow the conventions of the module you are working in. The general Retold style is:
40
+
41
+ - **Tabs** for indentation, never spaces
42
+ - **Plain JavaScript** only (no TypeScript)
43
+ - **Allman-style braces** (opening brace on its own line)
44
+ - **Variable naming:** `pVariable` for parameters, `tmpVariable` for temporaries, `libSomething` for imports
45
+
46
+ When in doubt, match what the surrounding code does.
47
+
48
+ ## Repository Structure
49
+
50
+ Each module is its own git repository. The [retold](https://github.com/stevenvelozo/retold) repository tracks module organization but does not contain module source code. Direct your pull request to the specific module repository where your change belongs.
package/README.md CHANGED
@@ -99,6 +99,14 @@ npx docsify-cli serve docs
99
99
 
100
100
  ## Related Packages
101
101
 
102
- - [orator](https://github.com/stevenvelozo/orator) - Main Orator service (includes addStaticRoute)
103
- - [orator-serviceserver-restify](https://github.com/stevenvelozo/orator-serviceserver-restify) - Restify service server
104
- - [fable](https://github.com/stevenvelozo/fable) - Service provider framework
102
+ - [orator](https://github.com/stevenvelozo/orator) - API server abstraction
103
+ - [orator-serviceserver-restify](https://github.com/stevenvelozo/orator-serviceserver-restify) - Restify service server implementation
104
+ - [fable](https://github.com/stevenvelozo/fable) - Application services framework
105
+
106
+ ## License
107
+
108
+ MIT
109
+
110
+ ## Contributing
111
+
112
+ Pull requests are welcome. For details on our code of conduct, contribution process, and testing requirements, see the [Retold Contributing Guide](https://github.com/stevenvelozo/retold/blob/main/docs/contributing.md).
@@ -0,0 +1,73 @@
1
+ /* ============================================================================
2
+ Pict Docuserve - Base Styles
3
+ ============================================================================ */
4
+
5
+ /* Reset and base */
6
+ *, *::before, *::after {
7
+ box-sizing: border-box;
8
+ }
9
+
10
+ html, body {
11
+ margin: 0;
12
+ padding: 0;
13
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
14
+ font-size: 16px;
15
+ line-height: 1.5;
16
+ color: #423D37;
17
+ background-color: #fff;
18
+ -webkit-font-smoothing: antialiased;
19
+ -moz-osx-font-smoothing: grayscale;
20
+ }
21
+
22
+ /* Typography */
23
+ h1, h2, h3, h4, h5, h6 {
24
+ margin-top: 0;
25
+ line-height: 1.3;
26
+ }
27
+
28
+ a {
29
+ color: #2E7D74;
30
+ text-decoration: none;
31
+ }
32
+
33
+ a:hover {
34
+ color: #256861;
35
+ }
36
+
37
+ /* Application container */
38
+ #Docuserve-Application-Container {
39
+ min-height: 100vh;
40
+ }
41
+
42
+ /* Utility: scrollbar styling */
43
+ ::-webkit-scrollbar {
44
+ width: 8px;
45
+ }
46
+
47
+ ::-webkit-scrollbar-track {
48
+ background: #F5F0E8;
49
+ }
50
+
51
+ ::-webkit-scrollbar-thumb {
52
+ background: #D4CCBE;
53
+ border-radius: 4px;
54
+ }
55
+
56
+ ::-webkit-scrollbar-thumb:hover {
57
+ background: #B5AA9A;
58
+ }
59
+
60
+ /* Responsive adjustments */
61
+ @media (max-width: 768px) {
62
+ html {
63
+ font-size: 14px;
64
+ }
65
+
66
+ #Docuserve-Sidebar-Container {
67
+ display: none;
68
+ }
69
+
70
+ .docuserve-body {
71
+ flex-direction: column;
72
+ }
73
+ }
package/docs/index.html CHANGED
@@ -9,7 +9,7 @@
9
9
  <title>Documentation</title>
10
10
 
11
11
  <!-- Application Stylesheet -->
12
- <link href="https://cdn.jsdelivr.net/npm/pict-docuserve@0/dist/css/docuserve.css" rel="stylesheet">
12
+ <link href="css/docuserve.css" rel="stylesheet">
13
13
  <!-- KaTeX stylesheet for LaTeX equation rendering -->
14
14
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.css">
15
15
  <!-- PICT Dynamic View CSS Container -->
@@ -0,0 +1,41 @@
1
+ {
2
+ "Generated": "2026-02-18T03:41:38.903Z",
3
+ "GitHubOrg": "stevenvelozo",
4
+ "DefaultBranch": "master",
5
+ "Groups": [
6
+ {
7
+ "Name": "Dist",
8
+ "Key": "dist",
9
+ "Description": "",
10
+ "Modules": [
11
+ {
12
+ "Name": "indoctrinate_content_staging",
13
+ "Repo": "indoctrinate_content_staging",
14
+ "Group": "dist",
15
+ "Branch": "master",
16
+ "HasDocs": false,
17
+ "HasCover": false,
18
+ "Sidebar": [],
19
+ "DocFiles": []
20
+ }
21
+ ]
22
+ },
23
+ {
24
+ "Name": "Test",
25
+ "Key": "test",
26
+ "Description": "",
27
+ "Modules": [
28
+ {
29
+ "Name": "static_content",
30
+ "Repo": "static_content",
31
+ "Group": "test",
32
+ "Branch": "master",
33
+ "HasDocs": false,
34
+ "HasCover": false,
35
+ "Sidebar": [],
36
+ "DocFiles": []
37
+ }
38
+ ]
39
+ }
40
+ ]
41
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "Generated": "2026-02-18T03:41:38.985Z",
3
+ "DocumentCount": 0,
4
+ "LunrIndex": {
5
+ "version": "2.3.9",
6
+ "fields": [
7
+ "title",
8
+ "module",
9
+ "group",
10
+ "body"
11
+ ],
12
+ "fieldVectors": [],
13
+ "invertedIndex": [],
14
+ "pipeline": [
15
+ "stemmer"
16
+ ]
17
+ },
18
+ "Documents": {}
19
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orator-static-server",
3
- "version": "2.0.0",
3
+ "version": "2.0.3",
4
4
  "description": "Static file serving for Orator API servers.",
5
5
  "main": "source/Orator-Static-Server.js",
6
6
  "scripts": {
@@ -38,17 +38,17 @@
38
38
  },
39
39
  "homepage": "https://github.com/stevenvelozo/orator-static-server#readme",
40
40
  "dependencies": {
41
- "fable-serviceproviderbase": "^3.0.15",
41
+ "fable-serviceproviderbase": "^3.0.18",
42
42
  "finalhandler": "^1.3.1",
43
43
  "mime": "^3.0.0",
44
44
  "serve-static": "^1.16.2"
45
45
  },
46
46
  "devDependencies": {
47
47
  "chai": "^4.3.7",
48
- "fable": "^3.1.51",
48
+ "fable": "^3.1.57",
49
49
  "mocha": "^10.2.0",
50
- "orator": "^5.0.1",
51
- "orator-serviceserver-restify": "^2.0.5",
52
- "quackage": "^1.0.45"
50
+ "orator": "^6.0.1",
51
+ "orator-serviceserver-restify": "^2.0.7",
52
+ "quackage": "^1.0.51"
53
53
  }
54
54
  }
@@ -161,15 +161,12 @@ class OratorStaticServer extends libFableServiceProviderBase
161
161
  return pRequest.url;
162
162
  };
163
163
 
164
- // When the URL is a directory (e.g. '/' or '/docs/'), use the default file for MIME detection
165
- // so the browser gets text/html instead of application/octet-stream
166
- let tmpMimeTarget = pRequest.url;
167
- if (tmpMimeTarget.endsWith('/') || tmpMimeTarget.indexOf('.') < 0)
168
- {
169
- tmpMimeTarget = tmpDefaultFile;
170
- }
171
- this.setMimeHeader(tmpMimeTarget, pResponse);
172
-
164
+ // Let serve-static handle Content-Type detection. It resolves
165
+ // the actual file path first (e.g. / → /index.html) and then
166
+ // sets the correct MIME type with charset. Pre-setting the
167
+ // header here would prevent serve-static from overriding it
168
+ // because the underlying `send` library skips Content-Type
169
+ // when the header is already present.
173
170
  const tmpServe = libServeStatic(servePath, Object.assign({ index: tmpDefaultFile }, pParams));
174
171
  tmpServe(pRequest, pResponse, libFinalHandler(pRequest, pResponse));
175
172
  // TODO: This may break things if a post request send handler is setup...
@@ -1308,6 +1308,175 @@ suite
1308
1308
  }
1309
1309
  );
1310
1310
 
1311
+ suite
1312
+ (
1313
+ 'MIME Type Resolution by serve-static',
1314
+ () =>
1315
+ {
1316
+ test
1317
+ (
1318
+ 'serve-static should set content-type with charset for HTML files',
1319
+ (fDone) =>
1320
+ {
1321
+ let tmpPort = getNextTestPort();
1322
+ let tmpHarness = createHarness(tmpPort);
1323
+
1324
+ startHarness(tmpHarness,
1325
+ (pError) =>
1326
+ {
1327
+ tmpHarness.orator.addStaticRoute(_StaticContentPath, 'index.html', '/mime/*', '/mime/');
1328
+
1329
+ makeRequest(tmpPort, '/mime/index.html',
1330
+ (pError, pStatusCode, pHeaders, pBody) =>
1331
+ {
1332
+ Expect(pError).to.equal(null);
1333
+ Expect(pStatusCode).to.equal(200);
1334
+ // serve-static sets charset on text types; a manual setMimeHeader would not
1335
+ Expect(pHeaders['content-type']).to.equal('text/html; charset=UTF-8');
1336
+ tmpHarness.orator.log.info(`HTML content-type with charset: ${pHeaders['content-type']}`);
1337
+ tmpHarness.orator.stopService(
1338
+ () =>
1339
+ {
1340
+ return fDone();
1341
+ });
1342
+ });
1343
+ });
1344
+ }
1345
+ );
1346
+
1347
+ test
1348
+ (
1349
+ 'serve-static should set content-type with charset for CSS files',
1350
+ (fDone) =>
1351
+ {
1352
+ let tmpPort = getNextTestPort();
1353
+ let tmpHarness = createHarness(tmpPort);
1354
+
1355
+ startHarness(tmpHarness,
1356
+ (pError) =>
1357
+ {
1358
+ tmpHarness.orator.addStaticRoute(_StaticContentPath, 'index.html', '/mimecss/*', '/mimecss/');
1359
+
1360
+ makeRequest(tmpPort, '/mimecss/style.css',
1361
+ (pError, pStatusCode, pHeaders, pBody) =>
1362
+ {
1363
+ Expect(pError).to.equal(null);
1364
+ Expect(pStatusCode).to.equal(200);
1365
+ // serve-static adds charset for text/* types
1366
+ Expect(pHeaders['content-type']).to.equal('text/css; charset=UTF-8');
1367
+ tmpHarness.orator.log.info(`CSS content-type with charset: ${pHeaders['content-type']}`);
1368
+ tmpHarness.orator.stopService(
1369
+ () =>
1370
+ {
1371
+ return fDone();
1372
+ });
1373
+ });
1374
+ });
1375
+ }
1376
+ );
1377
+
1378
+ test
1379
+ (
1380
+ 'directory request to / should get text/html from serve-static not application/octet-stream',
1381
+ (fDone) =>
1382
+ {
1383
+ let tmpPort = getNextTestPort();
1384
+ let tmpHarness = createHarness(tmpPort);
1385
+
1386
+ startHarness(tmpHarness,
1387
+ (pError) =>
1388
+ {
1389
+ tmpHarness.orator.addStaticRoute(_StaticContentPath, 'index.html', '/*', '/');
1390
+
1391
+ makeRequest(tmpPort, '/',
1392
+ (pError, pStatusCode, pHeaders, pBody) =>
1393
+ {
1394
+ Expect(pError).to.equal(null);
1395
+ Expect(pStatusCode).to.equal(200);
1396
+ // The core bug: mime.getType('/') returns null, falling back to
1397
+ // application/octet-stream. serve-static resolves / to /index.html
1398
+ // and correctly determines text/html with charset.
1399
+ Expect(pHeaders['content-type']).to.equal('text/html; charset=UTF-8');
1400
+ Expect(pHeaders['content-type']).to.not.contain('octet-stream');
1401
+ Expect(pBody).to.contain('Test Index');
1402
+ tmpHarness.orator.log.info(`Root / content-type: ${pHeaders['content-type']}`);
1403
+ tmpHarness.orator.stopService(
1404
+ () =>
1405
+ {
1406
+ return fDone();
1407
+ });
1408
+ });
1409
+ });
1410
+ }
1411
+ );
1412
+
1413
+ test
1414
+ (
1415
+ 'directory request to /subdir/ should get text/html from serve-static',
1416
+ (fDone) =>
1417
+ {
1418
+ let tmpPort = getNextTestPort();
1419
+ let tmpHarness = createHarness(tmpPort);
1420
+
1421
+ startHarness(tmpHarness,
1422
+ (pError) =>
1423
+ {
1424
+ tmpHarness.orator.addStaticRoute(_StaticContentPath, 'index.html', '/app/*', '/app/');
1425
+
1426
+ makeRequest(tmpPort, '/app/subsite/',
1427
+ (pError, pStatusCode, pHeaders, pBody) =>
1428
+ {
1429
+ Expect(pError).to.equal(null);
1430
+ Expect(pStatusCode).to.equal(200);
1431
+ // serve-static resolves /subsite/ to /subsite/index.html
1432
+ Expect(pHeaders['content-type']).to.equal('text/html; charset=UTF-8');
1433
+ Expect(pBody).to.contain('Subsite');
1434
+ tmpHarness.orator.log.info(`Subdir / content-type: ${pHeaders['content-type']}`);
1435
+ tmpHarness.orator.stopService(
1436
+ () =>
1437
+ {
1438
+ return fDone();
1439
+ });
1440
+ });
1441
+ });
1442
+ }
1443
+ );
1444
+
1445
+ test
1446
+ (
1447
+ 'JSON file should get application/json content-type from serve-static',
1448
+ (fDone) =>
1449
+ {
1450
+ let tmpPort = getNextTestPort();
1451
+ let tmpHarness = createHarness(tmpPort);
1452
+
1453
+ startHarness(tmpHarness,
1454
+ (pError) =>
1455
+ {
1456
+ tmpHarness.orator.addStaticRoute(_StaticContentPath, 'index.html', '/mj/*', '/mj/');
1457
+
1458
+ makeRequest(tmpPort, '/mj/data.json',
1459
+ (pError, pStatusCode, pHeaders, pBody) =>
1460
+ {
1461
+ Expect(pError).to.equal(null);
1462
+ Expect(pStatusCode).to.equal(200);
1463
+ // JSON should not have charset added by serve-static
1464
+ Expect(pHeaders['content-type']).to.contain('application/json');
1465
+ let tmpParsed = JSON.parse(pBody);
1466
+ Expect(tmpParsed.TestKey).to.equal('TestValue');
1467
+ tmpHarness.orator.log.info(`JSON content-type: ${pHeaders['content-type']}`);
1468
+ tmpHarness.orator.stopService(
1469
+ () =>
1470
+ {
1471
+ return fDone();
1472
+ });
1473
+ });
1474
+ });
1475
+ }
1476
+ );
1477
+ }
1478
+ );
1479
+
1311
1480
  suite
1312
1481
  (
1313
1482
  'addStaticRoute Parameter Defaults',