orator 5.0.2 → 6.0.0

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/index.html CHANGED
@@ -1,51 +1,39 @@
1
1
  <!doctype html>
2
2
  <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <title>Orator Documentation</title>
6
- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
7
- <meta name="description" content="Documentation for Orator - An unopinionated API server abstraction for REST and IPC services" />
8
- <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
9
- <meta name="keywords" content="orator, javascript, api, rest, ipc, server, restify, fable" />
10
- <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css" />
11
- <style>
12
- :root {
13
- --theme-color: #42b983;
14
- }
15
- </style>
16
- </head>
17
- <body>
18
- <div id="app"></div>
19
- <script>
20
- window.$docsify = {
21
- name: 'Orator',
22
- repo: 'https://github.com/stevenvelozo/orator',
23
- loadSidebar: '_sidebar.md',
24
- subMaxLevel: 3,
25
- auto2top: true,
26
- coverpage: 'cover.md',
27
- onlyCover: false,
28
- search: {
29
- placeholder: 'Search',
30
- noData: 'No results found',
31
- depth: 3
32
- },
33
- copyCode: {
34
- buttonText: 'Copy',
35
- successText: 'Copied'
36
- }
37
- };
38
- </script>
39
- <!-- Docsify v4 -->
40
- <script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
41
- <!-- Syntax highlighting -->
42
- <script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-javascript.min.js"></script>
43
- <script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-json.min.js"></script>
44
- <script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-bash.min.js"></script>
45
- <script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-markdown.min.js"></script>
46
- <!-- Search plugin -->
47
- <script src="//cdn.jsdelivr.net/npm/docsify@4/lib/plugins/search.min.js"></script>
48
- <!-- Copy code plugin -->
49
- <script src="//cdn.jsdelivr.net/npm/docsify-copy-code@2"></script>
50
- </body>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
7
+ <meta name="description" content="Documentation powered by pict-docuserve">
8
+
9
+ <title>Documentation</title>
10
+
11
+ <!-- Application Stylesheet -->
12
+ <link href="https://cdn.jsdelivr.net/npm/pict-docuserve@0/dist/css/docuserve.css" rel="stylesheet">
13
+ <!-- KaTeX stylesheet for LaTeX equation rendering -->
14
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.css">
15
+ <!-- PICT Dynamic View CSS Container -->
16
+ <style id="PICT-CSS"></style>
17
+
18
+ <!-- Load the PICT library from jsDelivr CDN -->
19
+ <script src="https://cdn.jsdelivr.net/npm/pict@1/dist/pict.min.js" type="text/javascript"></script>
20
+ <!-- Bootstrap the Application -->
21
+ <script type="text/javascript">
22
+ //<![CDATA[
23
+ Pict.safeOnDocumentReady(() => { Pict.safeLoadPictApplication(PictDocuserve, 2)});
24
+ //]]>
25
+ </script>
26
+ </head>
27
+ <body>
28
+ <!-- The root container for the Pict application -->
29
+ <div id="Docuserve-Application-Container"></div>
30
+
31
+ <!-- Mermaid diagram rendering -->
32
+ <script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
33
+ <script>mermaid.initialize({ startOnLoad: false, theme: 'default' });</script>
34
+ <!-- KaTeX for LaTeX equation rendering -->
35
+ <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.js"></script>
36
+ <!-- Load the Docuserve PICT Application Bundle from jsDelivr CDN -->
37
+ <script src="https://cdn.jsdelivr.net/npm/pict-docuserve@0/dist/pict-docuserve.min.js" type="text/javascript"></script>
38
+ </body>
51
39
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orator",
3
- "version": "5.0.2",
3
+ "version": "6.0.0",
4
4
  "description": "Unopinionated API http server abstraction - REST or IPC",
5
5
  "main": "source/Orator.js",
6
6
  "scripts": {
@@ -51,14 +51,13 @@
51
51
  },
52
52
  "homepage": "https://github.com/stevenvelozo/orator",
53
53
  "devDependencies": {
54
- "fable": "^3.1.51",
55
- "quackage": "^1.0.45"
54
+ "fable": "^3.1.53",
55
+ "quackage": "^1.0.48"
56
56
  },
57
57
  "dependencies": {
58
- "fable-serviceproviderbase": "^3.0.15",
59
- "finalhandler": "^1.3.1",
58
+ "fable-serviceproviderbase": "^3.0.17",
60
59
  "find-my-way": "^9.1.0",
61
- "orator-serviceserver-base": "^1.0.1",
62
- "serve-static": "^1.16.2"
60
+ "orator-serviceserver-base": "^1.0.2",
61
+ "orator-static-server": "^2.0.0"
63
62
  }
64
63
  }
package/source/Orator.js CHANGED
@@ -11,9 +11,7 @@ const libFableServiceProviderBase = require('fable-serviceproviderbase');
11
11
 
12
12
  const libDefaultOratorServiceServer = require('./Orator-Default-ServiceServer.js');
13
13
 
14
- const libServeStatic = require('serve-static');
15
- const libFinalHandler = require('finalhandler');
16
- const libMime = require('mime');
14
+ const libOratorStaticServer = require('orator-static-server');
17
15
 
18
16
  const defaultOratorConfiguration = require('./Orator-Default-Configuration.js');
19
17
 
@@ -59,21 +57,6 @@ class Orator extends libFableServiceProviderBase
59
57
  {
60
58
  this.options.Product = defaultOratorConfiguration.Product;
61
59
  }
62
-
63
- // This is here because libMime has a breaking change from v1 to v2 and the lookup function was update to be getType per https://stackoverflow.com/a/60741078
64
- // We don't want to introspect properties on this library every single time we need to check mime types.
65
- // Therefore we are setting this boolean here and using it to branch.
66
- this.oldLibMime = false;
67
- if ('lookup' in libMime)
68
- {
69
- this.oldLibMime = true;
70
- }
71
-
72
- // Ensure FilePersistence is available for the magic subdomain subfolder check in addStaticRoute
73
- if (!this.fable.FilePersistence)
74
- {
75
- this.fable.serviceManager.instantiateServiceProvider('FilePersistence');
76
- }
77
60
  }
78
61
 
79
62
  /**
@@ -368,29 +351,46 @@ class Orator extends libFableServiceProviderBase
368
351
  * End of Legacy Orator Functions
369
352
  */
370
353
 
371
- setMimeHeader(pFileName, pResponse)
354
+ /*
355
+ * Backwards Compatibility: setMimeHeader and oldLibMime
356
+ *
357
+ * These used to live directly on Orator but now live on OratorStaticServer.
358
+ * These thin wrappers delegate to the OratorStaticServer instance so that
359
+ * any code calling orator.setMimeHeader() or reading orator.oldLibMime
360
+ * continues to work without changes.
361
+ *************************************************************************/
362
+ /**
363
+ * @deprecated Use fable.OratorStaticServer.oldLibMime instead.
364
+ */
365
+ get oldLibMime()
372
366
  {
373
- let tmpHeader;
374
-
375
- if (this.oldLibMime)
376
- {
377
- tmpHeader = libMime.lookup(pFileName);
378
- }
379
- else
367
+ if (this.fable.OratorStaticServer)
380
368
  {
381
- tmpHeader = libMime.getType(pFileName);
369
+ return this.fable.OratorStaticServer.oldLibMime;
382
370
  }
371
+ return false;
372
+ }
383
373
 
384
- if (!tmpHeader)
374
+ /**
375
+ * @deprecated Use fable.OratorStaticServer.setMimeHeader() instead.
376
+ */
377
+ setMimeHeader(pFileName, pResponse)
378
+ {
379
+ if (!this.fable.OratorStaticServer)
385
380
  {
386
- tmpHeader = 'application/octet-stream';
381
+ // Force auto-registration so the method is available
382
+ if (!this.fable.serviceManager.servicesMap.hasOwnProperty('OratorStaticServer'))
383
+ {
384
+ this.fable.serviceManager.addServiceType('OratorStaticServer', libOratorStaticServer);
385
+ }
386
+ this.fable.serviceManager.instantiateServiceProvider('OratorStaticServer', {}, 'OratorStaticServer-AutoInit');
387
387
  }
388
-
389
- pResponse.setHeader('Content-Type', tmpHeader);
388
+ return this.fable.OratorStaticServer.setMimeHeader(pFileName, pResponse);
390
389
  }
391
390
 
392
391
  /**
393
392
  * Serve a static folder, optionally with magic subdomain masking.
393
+ * Delegates to the OratorStaticServer service provider.
394
394
  *
395
395
  * @param {string} pFilePath The path on disk that we are serving files from.
396
396
  * @param {string?} pDefaultFile (optional) The default file served if no specific file is requested.
@@ -401,78 +401,19 @@ class Orator extends libFableServiceProviderBase
401
401
  */
402
402
  addStaticRoute(pFilePath, pDefaultFile, pRoute, pRouteStrip, pParams)
403
403
  {
404
- if (typeof(pFilePath) !== 'string')
404
+ // Auto-register the OratorStaticServer service type if it hasn't been registered yet
405
+ if (!this.fable.serviceManager.servicesMap.hasOwnProperty('OratorStaticServer'))
405
406
  {
406
- this.fable.log.error('A file path must be passed in as part of the server.');
407
- return false;
407
+ this.fable.serviceManager.addServiceType('OratorStaticServer', libOratorStaticServer);
408
408
  }
409
409
 
410
- // Default to just serving from root
411
- const tmpRoute = (typeof(pRoute) === 'undefined') ? '/*' : pRoute;
412
- const tmpRouteStrip = (typeof(pRouteStrip) === 'undefined') ? '/' : pRouteStrip;
413
-
414
- // Default to serving index.html
415
- const tmpDefaultFile = (typeof(pDefaultFile) === 'undefined') ? 'index.html' : pDefaultFile;
416
-
417
- this.fable.log.info('Orator mapping static route to files: '+tmpRoute+' ==> '+pFilePath+' '+tmpDefaultFile);
418
-
419
- // Try the service server's built-in serveStatic first (e.g. restify's serveStaticFiles plugin).
420
- // This handles MIME types, caching headers, and streaming correctly without our manual intervention.
421
- if (typeof(this.serviceServer.serveStatic) === 'function')
410
+ // Auto-instantiate a default OratorStaticServer instance if none exists
411
+ if (!this.fable.OratorStaticServer)
422
412
  {
423
- let tmpServeStaticOptions = Object.assign({ directory: pFilePath, default: tmpDefaultFile }, pParams);
424
- if (this.serviceServer.serveStatic(tmpRoute, tmpServeStaticOptions))
425
- {
426
- return true;
427
- }
413
+ this.fable.serviceManager.instantiateServiceProvider('OratorStaticServer', {}, 'OratorStaticServer-AutoInit');
428
414
  }
429
415
 
430
- // Fall back to the serve-static library approach (used by the IPC service server and other
431
- // service servers that don't have a built-in serveStatic implementation).
432
- this.serviceServer.get(tmpRoute,
433
- (pRequest, pResponse, fNext) =>
434
- {
435
- // See if there is a magic subdomain put at the beginning of a request.
436
- // If there is, then we need to see if there is a subfolder and add that to the file path
437
- let tmpHostSet = pRequest.headers.host.split('.');
438
- let tmpPotentialSubfolderMagicHost = false;
439
- let servePath = pFilePath;
440
- // Check if there are more than one host in the host header (this will be 127 a lot)
441
- if (tmpHostSet.length > 1)
442
- {
443
- tmpPotentialSubfolderMagicHost = tmpHostSet[0];
444
- }
445
- if (tmpPotentialSubfolderMagicHost)
446
- {
447
- // Check if the subfolder exists -- this is only one dimensional for now
448
- let tmpPotentialSubfolder = servePath + tmpPotentialSubfolderMagicHost;
449
- if (this.fable.FilePersistence.libFS.existsSync(tmpPotentialSubfolder))
450
- {
451
- // If it does, then we need to add it to the file path
452
- servePath = `${tmpPotentialSubfolder}/`;
453
- }
454
- }
455
- pRequest.url = pRequest.url.split('?')[0].substr(tmpRouteStrip.length) || '/';
456
- pRequest.path = function()
457
- {
458
- return pRequest.url;
459
- };
460
-
461
- // When the URL is a directory (e.g. '/' or '/docs/'), use the default file for MIME detection
462
- // so the browser gets text/html instead of application/octet-stream
463
- let tmpMimeTarget = pRequest.url;
464
- if (tmpMimeTarget.endsWith('/') || tmpMimeTarget.indexOf('.') < 0)
465
- {
466
- tmpMimeTarget = tmpDefaultFile;
467
- }
468
- this.setMimeHeader(tmpMimeTarget, pResponse);
469
-
470
- const tmpServe = libServeStatic(servePath, Object.assign({ index: tmpDefaultFile }, pParams));
471
- tmpServe(pRequest, pResponse, libFinalHandler(pRequest, pResponse));
472
- // TODO: This may break things if a post request send handler is setup...
473
- //fNext();
474
- });
475
- return true;
416
+ return this.fable.OratorStaticServer.addStaticRoute(pFilePath, pDefaultFile, pRoute, pRouteStrip, pParams);
476
417
  }
477
418
  }
478
419
 
@@ -264,13 +264,17 @@ suite
264
264
  tmpOrator.initialize(
265
265
  () =>
266
266
  {
267
+ // Trigger auto-registration of OratorStaticServer
268
+ tmpOrator.addStaticRoute(_StaticContentPath);
269
+ let tmpStaticServer = tmpFable.OratorStaticServer;
270
+
267
271
  let tmpCapturedHeaders = {};
268
272
  let tmpMockResponse = { setHeader: function(pName, pValue) { tmpCapturedHeaders[pName] = pValue; } };
269
273
 
270
- tmpOrator.setMimeHeader('index.html', tmpMockResponse);
274
+ tmpStaticServer.setMimeHeader('index.html', tmpMockResponse);
271
275
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('text/html');
272
276
 
273
- tmpOrator.setMimeHeader('/path/to/page.html', tmpMockResponse);
277
+ tmpStaticServer.setMimeHeader('/path/to/page.html', tmpMockResponse);
274
278
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('text/html');
275
279
 
276
280
  tmpOrator.log.info('HTML MIME type correctly detected');
@@ -290,10 +294,13 @@ suite
290
294
  tmpOrator.initialize(
291
295
  () =>
292
296
  {
297
+ tmpOrator.addStaticRoute(_StaticContentPath);
298
+ let tmpStaticServer = tmpFable.OratorStaticServer;
299
+
293
300
  let tmpCapturedHeaders = {};
294
301
  let tmpMockResponse = { setHeader: function(pName, pValue) { tmpCapturedHeaders[pName] = pValue; } };
295
302
 
296
- tmpOrator.setMimeHeader('style.css', tmpMockResponse);
303
+ tmpStaticServer.setMimeHeader('style.css', tmpMockResponse);
297
304
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('text/css');
298
305
 
299
306
  tmpOrator.log.info('CSS MIME type correctly detected');
@@ -313,10 +320,13 @@ suite
313
320
  tmpOrator.initialize(
314
321
  () =>
315
322
  {
323
+ tmpOrator.addStaticRoute(_StaticContentPath);
324
+ let tmpStaticServer = tmpFable.OratorStaticServer;
325
+
316
326
  let tmpCapturedHeaders = {};
317
327
  let tmpMockResponse = { setHeader: function(pName, pValue) { tmpCapturedHeaders[pName] = pValue; } };
318
328
 
319
- tmpOrator.setMimeHeader('data.json', tmpMockResponse);
329
+ tmpStaticServer.setMimeHeader('data.json', tmpMockResponse);
320
330
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('application/json');
321
331
 
322
332
  tmpOrator.log.info('JSON MIME type correctly detected');
@@ -336,10 +346,13 @@ suite
336
346
  tmpOrator.initialize(
337
347
  () =>
338
348
  {
349
+ tmpOrator.addStaticRoute(_StaticContentPath);
350
+ let tmpStaticServer = tmpFable.OratorStaticServer;
351
+
339
352
  let tmpCapturedHeaders = {};
340
353
  let tmpMockResponse = { setHeader: function(pName, pValue) { tmpCapturedHeaders[pName] = pValue; } };
341
354
 
342
- tmpOrator.setMimeHeader('app.js', tmpMockResponse);
355
+ tmpStaticServer.setMimeHeader('app.js', tmpMockResponse);
343
356
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('application/javascript');
344
357
 
345
358
  tmpOrator.log.info('JavaScript MIME type correctly detected');
@@ -359,19 +372,22 @@ suite
359
372
  tmpOrator.initialize(
360
373
  () =>
361
374
  {
375
+ tmpOrator.addStaticRoute(_StaticContentPath);
376
+ let tmpStaticServer = tmpFable.OratorStaticServer;
377
+
362
378
  let tmpCapturedHeaders = {};
363
379
  let tmpMockResponse = { setHeader: function(pName, pValue) { tmpCapturedHeaders[pName] = pValue; } };
364
380
 
365
- tmpOrator.setMimeHeader('photo.png', tmpMockResponse);
381
+ tmpStaticServer.setMimeHeader('photo.png', tmpMockResponse);
366
382
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('image/png');
367
383
 
368
- tmpOrator.setMimeHeader('logo.jpg', tmpMockResponse);
384
+ tmpStaticServer.setMimeHeader('logo.jpg', tmpMockResponse);
369
385
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('image/jpeg');
370
386
 
371
- tmpOrator.setMimeHeader('icon.gif', tmpMockResponse);
387
+ tmpStaticServer.setMimeHeader('icon.gif', tmpMockResponse);
372
388
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('image/gif');
373
389
 
374
- tmpOrator.setMimeHeader('vector.svg', tmpMockResponse);
390
+ tmpStaticServer.setMimeHeader('vector.svg', tmpMockResponse);
375
391
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('image/svg+xml');
376
392
 
377
393
  tmpOrator.log.info('Image MIME types correctly detected');
@@ -391,19 +407,22 @@ suite
391
407
  tmpOrator.initialize(
392
408
  () =>
393
409
  {
410
+ tmpOrator.addStaticRoute(_StaticContentPath);
411
+ let tmpStaticServer = tmpFable.OratorStaticServer;
412
+
394
413
  let tmpCapturedHeaders = {};
395
414
  let tmpMockResponse = { setHeader: function(pName, pValue) { tmpCapturedHeaders[pName] = pValue; } };
396
415
 
397
- tmpOrator.setMimeHeader('document.pdf', tmpMockResponse);
416
+ tmpStaticServer.setMimeHeader('document.pdf', tmpMockResponse);
398
417
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('application/pdf');
399
418
 
400
- tmpOrator.setMimeHeader('archive.zip', tmpMockResponse);
419
+ tmpStaticServer.setMimeHeader('archive.zip', tmpMockResponse);
401
420
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('application/zip');
402
421
 
403
- tmpOrator.setMimeHeader('data.xml', tmpMockResponse);
422
+ tmpStaticServer.setMimeHeader('data.xml', tmpMockResponse);
404
423
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('application/xml');
405
424
 
406
- tmpOrator.setMimeHeader('readme.txt', tmpMockResponse);
425
+ tmpStaticServer.setMimeHeader('readme.txt', tmpMockResponse);
407
426
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('text/plain');
408
427
 
409
428
  tmpOrator.log.info('Document and archive MIME types correctly detected');
@@ -423,13 +442,16 @@ suite
423
442
  tmpOrator.initialize(
424
443
  () =>
425
444
  {
445
+ tmpOrator.addStaticRoute(_StaticContentPath);
446
+ let tmpStaticServer = tmpFable.OratorStaticServer;
447
+
426
448
  let tmpCapturedHeaders = {};
427
449
  let tmpMockResponse = { setHeader: function(pName, pValue) { tmpCapturedHeaders[pName] = pValue; } };
428
450
 
429
- tmpOrator.setMimeHeader('mystery.xyz123', tmpMockResponse);
451
+ tmpStaticServer.setMimeHeader('mystery.xyz123', tmpMockResponse);
430
452
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('application/octet-stream');
431
453
 
432
- tmpOrator.setMimeHeader('noextension', tmpMockResponse);
454
+ tmpStaticServer.setMimeHeader('noextension', tmpMockResponse);
433
455
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('application/octet-stream');
434
456
 
435
457
  tmpOrator.log.info('Unknown MIME types fall back to application/octet-stream');
@@ -449,13 +471,16 @@ suite
449
471
  tmpOrator.initialize(
450
472
  () =>
451
473
  {
474
+ tmpOrator.addStaticRoute(_StaticContentPath);
475
+ let tmpStaticServer = tmpFable.OratorStaticServer;
476
+
452
477
  let tmpCapturedHeaders = {};
453
478
  let tmpMockResponse = { setHeader: function(pName, pValue) { tmpCapturedHeaders[pName] = pValue; } };
454
479
 
455
- tmpOrator.setMimeHeader('/assets/css/main.css', tmpMockResponse);
480
+ tmpStaticServer.setMimeHeader('/assets/css/main.css', tmpMockResponse);
456
481
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('text/css');
457
482
 
458
- tmpOrator.setMimeHeader('/deep/nested/path/to/image.png', tmpMockResponse);
483
+ tmpStaticServer.setMimeHeader('/deep/nested/path/to/image.png', tmpMockResponse);
459
484
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('image/png');
460
485
 
461
486
  tmpOrator.log.info('MIME type detected correctly from paths with directories');
@@ -645,6 +670,10 @@ suite
645
670
  tmpOrator.initialize(
646
671
  () =>
647
672
  {
673
+ // Trigger auto-registration of OratorStaticServer
674
+ tmpOrator.addStaticRoute(_StaticContentPath);
675
+ let tmpStaticServer = tmpFable.OratorStaticServer;
676
+
648
677
  // Test the MIME detection logic directly with a mock response
649
678
  let tmpCapturedHeaders = {};
650
679
  let tmpMockResponse = { setHeader: function(pName, pValue) { tmpCapturedHeaders[pName] = pValue; } };
@@ -657,7 +686,7 @@ suite
657
686
  {
658
687
  tmpMimeTarget = 'index.html';
659
688
  }
660
- tmpOrator.setMimeHeader(tmpMimeTarget, tmpMockResponse);
689
+ tmpStaticServer.setMimeHeader(tmpMimeTarget, tmpMockResponse);
661
690
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('text/html');
662
691
 
663
692
  // A URL like '/somepath' (no extension, no slash) should also fall back
@@ -667,7 +696,7 @@ suite
667
696
  {
668
697
  tmpMimeTarget = 'index.html';
669
698
  }
670
- tmpOrator.setMimeHeader(tmpMimeTarget, tmpMockResponse);
699
+ tmpStaticServer.setMimeHeader(tmpMimeTarget, tmpMockResponse);
671
700
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('text/html');
672
701
 
673
702
  // A URL with an extension should use its own extension
@@ -677,7 +706,7 @@ suite
677
706
  {
678
707
  tmpMimeTarget = 'index.html';
679
708
  }
680
- tmpOrator.setMimeHeader(tmpMimeTarget, tmpMockResponse);
709
+ tmpStaticServer.setMimeHeader(tmpMimeTarget, tmpMockResponse);
681
710
  Expect(tmpCapturedHeaders['Content-Type']).to.equal('text/css');
682
711
 
683
712
  tmpOrator.log.info('Directory and extensionless MIME detection verified');
@@ -695,7 +724,7 @@ suite
695
724
  {
696
725
  test
697
726
  (
698
- 'Orator constructor should auto-instantiate FilePersistence if not present',
727
+ 'addStaticRoute should auto-instantiate FilePersistence if not present',
699
728
  (fDone) =>
700
729
  {
701
730
  let tmpFable = new libFable(defaultFableSettings);
@@ -704,19 +733,24 @@ suite
704
733
 
705
734
  tmpFable.serviceManager.addServiceType('Orator', libOrator);
706
735
  let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {});
736
+ tmpOrator.initialize(
737
+ () =>
738
+ {
739
+ // FilePersistence is auto-instantiated by OratorStaticServer.addStaticRoute
740
+ tmpOrator.addStaticRoute(_StaticContentPath);
707
741
 
708
- // After constructing Orator, FilePersistence should now be available
709
- Expect(tmpFable.FilePersistence).to.be.an('object');
710
- Expect(tmpFable.FilePersistence.libFS).to.be.an('object');
711
- Expect(tmpFable.FilePersistence.libFS.existsSync).to.be.a('function');
712
- tmpOrator.log.info('FilePersistence auto-instantiated by Orator constructor');
713
- return fDone();
742
+ Expect(tmpFable.FilePersistence).to.be.an('object');
743
+ Expect(tmpFable.FilePersistence.libFS).to.be.an('object');
744
+ Expect(tmpFable.FilePersistence.libFS.existsSync).to.be.a('function');
745
+ tmpOrator.log.info('FilePersistence auto-instantiated by addStaticRoute');
746
+ return fDone();
747
+ });
714
748
  }
715
749
  );
716
750
 
717
751
  test
718
752
  (
719
- 'Orator constructor should not re-instantiate FilePersistence if already present',
753
+ 'addStaticRoute should not re-instantiate FilePersistence if already present',
720
754
  (fDone) =>
721
755
  {
722
756
  let tmpFable = new libFable(defaultFableSettings);
@@ -726,11 +760,16 @@ suite
726
760
 
727
761
  tmpFable.serviceManager.addServiceType('Orator', libOrator);
728
762
  let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {});
763
+ tmpOrator.initialize(
764
+ () =>
765
+ {
766
+ tmpOrator.addStaticRoute(_StaticContentPath);
729
767
 
730
- // Should still be the same instance, not a new one
731
- Expect(tmpFable.FilePersistence).to.equal(tmpOriginal);
732
- tmpOrator.log.info('FilePersistence preserved when already present');
733
- return fDone();
768
+ // Should still be the same instance, not a new one
769
+ Expect(tmpFable.FilePersistence).to.equal(tmpOriginal);
770
+ tmpOrator.log.info('FilePersistence preserved when already present');
771
+ return fDone();
772
+ });
734
773
  }
735
774
  );
736
775
  }
@@ -1089,7 +1128,7 @@ suite
1089
1128
  (fDone) =>
1090
1129
  {
1091
1130
  let tmpFable = new libFable(defaultFableSettings);
1092
- // FilePersistence is now auto-instantiated by Orator's constructor
1131
+ // FilePersistence is now auto-instantiated by OratorStaticServer.addStaticRoute
1093
1132
  tmpFable.serviceManager.addServiceType('Orator', libOrator);
1094
1133
  let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {});
1095
1134
  tmpOrator.startService();
@@ -1123,7 +1162,7 @@ suite
1123
1162
  (fDone) =>
1124
1163
  {
1125
1164
  let tmpFable = new libFable(defaultFableSettings);
1126
- // FilePersistence is now auto-instantiated by Orator's constructor
1165
+ // FilePersistence is now auto-instantiated by OratorStaticServer.addStaticRoute
1127
1166
  tmpFable.serviceManager.addServiceType('Orator', libOrator);
1128
1167
  let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {});
1129
1168
  tmpOrator.startService();
@@ -1299,19 +1338,13 @@ suite
1299
1338
  tmpOrator.initialize(
1300
1339
  () =>
1301
1340
  {
1341
+ // Trigger auto-registration of OratorStaticServer
1342
+ tmpOrator.addStaticRoute(_StaticContentPath);
1343
+ let tmpStaticServer = tmpFable.OratorStaticServer;
1344
+
1302
1345
  // The oldLibMime flag should be a boolean
1303
- Expect(tmpOrator.oldLibMime).to.be.a('boolean');
1304
- // With the current version of the mime library, it should use the lookup function
1305
- let libMime = require('mime');
1306
- if ('lookup' in libMime)
1307
- {
1308
- Expect(tmpOrator.oldLibMime).to.equal(true);
1309
- }
1310
- else
1311
- {
1312
- Expect(tmpOrator.oldLibMime).to.equal(false);
1313
- }
1314
- tmpOrator.log.info(`oldLibMime flag is ${tmpOrator.oldLibMime}`);
1346
+ Expect(tmpStaticServer.oldLibMime).to.be.a('boolean');
1347
+ tmpOrator.log.info(`oldLibMime flag is ${tmpStaticServer.oldLibMime}`);
1315
1348
  return fDone();
1316
1349
  });
1317
1350
  }