orator-static-server 1.0.1 → 2.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023 Steven Velozo
3
+ Copyright (c) 2024 Steven Velozo
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,5 +1,104 @@
1
- # Orator Static File Server
1
+ # Orator Static Server
2
2
 
3
- Very basic static file server for local development and lightweight tasks.
3
+ > Static file serving for Orator API servers
4
4
 
5
- Leverages restify static server.
5
+ Orator Static Server provides static file serving capabilities for Orator. The core static file serving functionality is built directly into the main [orator](https://github.com/stevenvelozo/orator) module via the `addStaticRoute` method, which serves files from disk with MIME type detection and subdomain-based folder routing.
6
+
7
+ ## Features
8
+
9
+ - **File Serving** - Serve static files from any directory on disk
10
+ - **MIME Detection** - Automatic Content-Type headers based on file extension
11
+ - **Default Files** - Configurable default file (e.g., `index.html`) for directory requests
12
+ - **Route Stripping** - Strip URL prefixes before mapping to the filesystem
13
+ - **Subdomain Routing** - Serve different folders based on request subdomain
14
+
15
+ ## Usage
16
+
17
+ Static file serving is available through the main Orator module's `addStaticRoute` method:
18
+
19
+ ```javascript
20
+ const libFable = require('fable');
21
+ const libOrator = require('orator');
22
+ const libOratorServiceServerRestify = require('orator-serviceserver-restify');
23
+
24
+ const _Fable = new libFable({
25
+ Product: 'MyStaticServer',
26
+ ServicePort: 8080
27
+ });
28
+
29
+ _Fable.serviceManager.addServiceType('Orator', libOrator);
30
+ _Fable.serviceManager.addServiceType('OratorServiceServer', libOratorServiceServerRestify);
31
+ _Fable.serviceManager.instantiateServiceProvider('Orator');
32
+ _Fable.serviceManager.instantiateServiceProvider('OratorServiceServer');
33
+
34
+ // Serve static files from ./public
35
+ _Fable.Orator.addStaticRoute('./public/');
36
+
37
+ _Fable.Orator.startService();
38
+ ```
39
+
40
+ ## API
41
+
42
+ ### addStaticRoute(pFilePath, pDefaultFile, pRoute, pRouteStrip, pParams)
43
+
44
+ | Parameter | Type | Default | Description |
45
+ |-----------|------|---------|-------------|
46
+ | `pFilePath` | string | *required* | Path to the directory to serve files from |
47
+ | `pDefaultFile` | string | `"index.html"` | Default file for directory requests |
48
+ | `pRoute` | string | `"/*"` | Route pattern to match |
49
+ | `pRouteStrip` | string | `"/"` | URL prefix to strip before filesystem lookup |
50
+ | `pParams` | object | `{}` | Options passed to `serve-static` |
51
+
52
+ ## Examples
53
+
54
+ ### Single Page Application
55
+
56
+ ```javascript
57
+ // All routes fall back to index.html
58
+ _Fable.Orator.addStaticRoute('./dist/', 'index.html', '/*');
59
+ ```
60
+
61
+ ### Serving Under a Subpath
62
+
63
+ ```javascript
64
+ // /app/styles.css serves ./dist/styles.css
65
+ _Fable.Orator.addStaticRoute('./dist/', 'index.html', '/app/*', '/app/');
66
+ ```
67
+
68
+ ### API Server with Static Frontend
69
+
70
+ ```javascript
71
+ // API routes first
72
+ _Fable.Orator.serviceServer.get('/api/data',
73
+ (pRequest, pResponse, fNext) =>
74
+ {
75
+ pResponse.send({ value: 42 });
76
+ return fNext();
77
+ });
78
+
79
+ // Static files for everything else
80
+ _Fable.Orator.addStaticRoute('./public/', 'index.html', '/*');
81
+ ```
82
+
83
+ ## Subdomain Folder Routing
84
+
85
+ When a request arrives with a subdomain, Orator checks if a matching subfolder exists in the serve directory. If it does, files are served from that subfolder.
86
+
87
+ For a serve path of `./sites/`:
88
+ - `http://clienta.example.com/page.html` checks for `./sites/clienta/page.html`
89
+ - If `./sites/clienta/` exists, it serves from there
90
+ - Otherwise, falls back to `./sites/page.html`
91
+
92
+ ## Documentation
93
+
94
+ Full documentation is available in the [`docs`](./docs) folder, or served locally:
95
+
96
+ ```bash
97
+ npx docsify-cli serve docs
98
+ ```
99
+
100
+ ## Related Packages
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
package/docs/.nojekyll ADDED
File without changes
package/docs/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # Orator Static Server
2
+
3
+ > Static file serving for Orator API servers
4
+
5
+ Orator Static Server provides static file serving capabilities for Orator-based applications. The core functionality lives in the main `orator` module's `addStaticRoute` method -- this documentation covers how to use it effectively for development servers, single page applications, and multi-tenant hosting.
6
+
7
+ ## Features
8
+
9
+ - **File Serving** - Serve static files from any directory on disk
10
+ - **MIME Detection** - Automatic Content-Type headers based on file extension
11
+ - **Default Files** - Configurable default file (e.g., `index.html`) for directory requests
12
+ - **Route Stripping** - Strip URL prefixes before mapping to the filesystem
13
+ - **Subdomain Routing** - Serve different folders based on request subdomain
14
+
15
+ ## Quick Start
16
+
17
+ ```javascript
18
+ const libFable = require('fable');
19
+ const libOrator = require('orator');
20
+ const libOratorServiceServerRestify = require('orator-serviceserver-restify');
21
+
22
+ const _Fable = new libFable({
23
+ Product: 'MyStaticServer',
24
+ ServicePort: 8080
25
+ });
26
+
27
+ _Fable.serviceManager.addServiceType('Orator', libOrator);
28
+ _Fable.serviceManager.addServiceType('OratorServiceServer', libOratorServiceServerRestify);
29
+ _Fable.serviceManager.instantiateServiceProvider('Orator');
30
+ _Fable.serviceManager.instantiateServiceProvider('OratorServiceServer');
31
+
32
+ _Fable.Orator.addStaticRoute('./public/');
33
+ _Fable.Orator.startService();
34
+ ```
35
+
36
+ ## How It Works
37
+
38
+ When `addStaticRoute` is called, Orator registers a GET route handler on the service server that:
39
+
40
+ 1. Checks for subdomain-based folder routing
41
+ 2. Strips the configured URL prefix from the request path
42
+ 3. Sets the appropriate MIME type Content-Type header
43
+ 4. Serves the file from disk using `serve-static`
44
+
45
+ ## Related Packages
46
+
47
+ - [orator](https://github.com/stevenvelozo/orator) - Main Orator service (includes addStaticRoute)
48
+ - [orator-serviceserver-restify](https://github.com/stevenvelozo/orator-serviceserver-restify) - Restify service server
49
+ - [fable](https://github.com/stevenvelozo/fable) - Service provider framework
@@ -0,0 +1,9 @@
1
+ - Getting Started
2
+
3
+ - [Introduction](/)
4
+ - [Getting Started](getting-started.md)
5
+
6
+ - Reference
7
+
8
+ - [API Reference](api-reference.md)
9
+ - [Subdomain Routing](subdomain-routing.md)
@@ -0,0 +1,68 @@
1
+ # API Reference
2
+
3
+ ## addStaticRoute(pFilePath, pDefaultFile, pRoute, pRouteStrip, pParams)
4
+
5
+ Registers a GET route handler that serves static files from a directory on disk.
6
+
7
+ ### Parameters
8
+
9
+ | Parameter | Type | Default | Required | Description |
10
+ |-----------|------|---------|----------|-------------|
11
+ | `pFilePath` | string | - | Yes | Path to the directory to serve files from |
12
+ | `pDefaultFile` | string | `"index.html"` | No | Default file when no specific file is requested |
13
+ | `pRoute` | string | `"/*"` | No | Route pattern to match for static file requests |
14
+ | `pRouteStrip` | string | `"/"` | No | Prefix to strip from URL paths before filesystem lookup |
15
+ | `pParams` | object | `{}` | No | Additional options passed to the `serve-static` library |
16
+
17
+ ### Returns
18
+
19
+ `true` if the route was successfully installed, `false` if `pFilePath` is not a string.
20
+
21
+ ### Examples
22
+
23
+ **Minimal:**
24
+ ```javascript
25
+ _Fable.Orator.addStaticRoute('./public/');
26
+ ```
27
+
28
+ **With default file:**
29
+ ```javascript
30
+ _Fable.Orator.addStaticRoute('./public/', 'app.html');
31
+ ```
32
+
33
+ **With custom route:**
34
+ ```javascript
35
+ _Fable.Orator.addStaticRoute('./public/', 'index.html', '/static/*');
36
+ ```
37
+
38
+ **With route stripping:**
39
+ ```javascript
40
+ _Fable.Orator.addStaticRoute('./dist/', 'index.html', '/app/*', '/app/');
41
+ ```
42
+
43
+ **With serve-static options:**
44
+ ```javascript
45
+ _Fable.Orator.addStaticRoute('./public/', 'index.html', '/*', '/',
46
+ {
47
+ maxAge: '1d',
48
+ etag: true
49
+ });
50
+ ```
51
+
52
+ ## MIME Type Detection
53
+
54
+ Orator automatically sets the `Content-Type` response header based on the requested file's extension. It uses the `mime` library for detection and defaults to `application/octet-stream` for unknown file types.
55
+
56
+ The module handles both v1 and v2 of the `mime` library transparently, using `mime.lookup()` or `mime.getType()` depending on which is available.
57
+
58
+ ## serve-static Options
59
+
60
+ The `pParams` parameter is passed directly to [serve-static](https://github.com/expressjs/serve-static). Some useful options:
61
+
62
+ | Option | Type | Description |
63
+ |--------|------|-------------|
64
+ | `maxAge` | number/string | Set the Cache-Control max-age header (in ms or as a string like `'1d'`) |
65
+ | `etag` | boolean | Generate ETags for files |
66
+ | `dotfiles` | string | How to handle dotfiles: `'allow'`, `'deny'`, or `'ignore'` |
67
+ | `redirect` | boolean | Redirect to trailing `/` when pathname is a directory |
68
+ | `index` | string/boolean | Override the default file (set to `false` to disable) |
package/docs/cover.md ADDED
@@ -0,0 +1,11 @@
1
+ # Orator Static Server <small>1</small>
2
+
3
+ > Static file serving for Orator API servers
4
+
5
+ - Serve files from any directory on disk
6
+ - Automatic MIME type detection
7
+ - Subdomain-based folder routing
8
+ - Configurable default files and route stripping
9
+
10
+ [GitHub](https://github.com/stevenvelozo/orator-static-server)
11
+ [Get Started](#orator-static-server)
@@ -0,0 +1,84 @@
1
+ # Getting Started
2
+
3
+ ## Installation
4
+
5
+ Static file serving is built into the main `orator` module:
6
+
7
+ ```bash
8
+ npm install fable orator orator-serviceserver-restify
9
+ ```
10
+
11
+ ## Basic Static Server
12
+
13
+ The simplest static file server:
14
+
15
+ ```javascript
16
+ const libFable = require('fable');
17
+ const libOrator = require('orator');
18
+ const libOratorServiceServerRestify = require('orator-serviceserver-restify');
19
+
20
+ const _Fable = new libFable({
21
+ Product: 'DevServer',
22
+ ServicePort: 8080
23
+ });
24
+
25
+ _Fable.serviceManager.addServiceType('Orator', libOrator);
26
+ _Fable.serviceManager.addServiceType('OratorServiceServer', libOratorServiceServerRestify);
27
+ _Fable.serviceManager.instantiateServiceProvider('Orator');
28
+ _Fable.serviceManager.instantiateServiceProvider('OratorServiceServer');
29
+
30
+ // Serve files from ./public, defaulting to index.html
31
+ _Fable.Orator.addStaticRoute('./public/');
32
+
33
+ _Fable.Orator.startService(
34
+ () =>
35
+ {
36
+ _Fable.log.info('Static server is ready');
37
+ });
38
+ ```
39
+
40
+ ## Single Page Application
41
+
42
+ For SPAs where all routes should resolve to `index.html`:
43
+
44
+ ```javascript
45
+ _Fable.Orator.addStaticRoute('./dist/', 'index.html', '/*');
46
+ ```
47
+
48
+ ## API Server with Static Frontend
49
+
50
+ Register your API routes first, then add static file serving as a catch-all:
51
+
52
+ ```javascript
53
+ // API routes
54
+ _Fable.Orator.serviceServer.get('/api/users',
55
+ (pRequest, pResponse, fNext) =>
56
+ {
57
+ pResponse.send([{ id: 1, name: 'User One' }]);
58
+ return fNext();
59
+ });
60
+
61
+ _Fable.Orator.serviceServer.postWithBodyParser('/api/users',
62
+ (pRequest, pResponse, fNext) =>
63
+ {
64
+ pResponse.send({ created: true });
65
+ return fNext();
66
+ });
67
+
68
+ // Static files for everything else
69
+ _Fable.Orator.addStaticRoute('./public/', 'index.html', '/*');
70
+ ```
71
+
72
+ ## Serving Under a Subpath
73
+
74
+ If your static files should be served under a URL prefix:
75
+
76
+ ```javascript
77
+ // /app/styles.css serves ./dist/styles.css
78
+ _Fable.Orator.addStaticRoute('./dist/', 'index.html', '/app/*', '/app/');
79
+ ```
80
+
81
+ ## Next Steps
82
+
83
+ - [API Reference](api-reference.md) - Complete parameter documentation
84
+ - [Subdomain Routing](subdomain-routing.md) - Multi-tenant static hosting
@@ -0,0 +1,39 @@
1
+ <!doctype html>
2
+ <html lang="en">
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>
39
+ </html>
@@ -0,0 +1,63 @@
1
+ # Subdomain Folder Routing
2
+
3
+ Orator's static file serving includes a built-in feature for subdomain-based folder routing. This enables a simple multi-tenant static hosting setup without any additional configuration or infrastructure.
4
+
5
+ ## How It Works
6
+
7
+ When a request arrives, Orator inspects the `Host` header for subdomain prefixes. If the host has more than one segment (e.g., `clienta.example.com` vs just `localhost`), Orator takes the first segment and checks if a matching subfolder exists in the serve directory.
8
+
9
+ ```
10
+ Request: http://clienta.example.com/page.html
11
+ Host header: clienta.example.com
12
+
13
+ Split host: ["clienta", "example", "com"]
14
+ First segment: "clienta"
15
+
16
+ Check: does ./sites/clienta/ exist?
17
+ ├── Yes → Serve from ./sites/clienta/page.html
18
+ └── No → Serve from ./sites/page.html
19
+ ```
20
+
21
+ ## Setup
22
+
23
+ ```javascript
24
+ // Serve from ./sites, with subdomain-based subfolder routing
25
+ _Fable.Orator.addStaticRoute('./sites/');
26
+ ```
27
+
28
+ ## Directory Structure
29
+
30
+ ```
31
+ sites/
32
+ ├── index.html ← Served for requests without subdomain match
33
+ ├── styles.css
34
+ ├── clienta/
35
+ │ ├── index.html ← Served for clienta.example.com
36
+ │ └── styles.css
37
+ ├── clientb/
38
+ │ ├── index.html ← Served for clientb.example.com
39
+ │ └── styles.css
40
+ └── shared/
41
+ └── logo.png
42
+ ```
43
+
44
+ ## Example Requests
45
+
46
+ | Request URL | Served File |
47
+ |------------|-------------|
48
+ | `http://example.com/index.html` | `./sites/index.html` |
49
+ | `http://clienta.example.com/index.html` | `./sites/clienta/index.html` |
50
+ | `http://clientb.example.com/styles.css` | `./sites/clientb/styles.css` |
51
+ | `http://unknown.example.com/page.html` | `./sites/page.html` (no match, falls back) |
52
+
53
+ ## Limitations
54
+
55
+ - Subdomain routing is one level deep -- it only checks the first subdomain segment
56
+ - The subfolder must exist on disk for the routing to activate
57
+ - Requests to `localhost` or IP addresses won't trigger subdomain routing (only one host segment)
58
+
59
+ ## Use Cases
60
+
61
+ - **Multi-tenant SaaS frontends** - Each customer gets a branded subdomain serving their customized UI
62
+ - **Development environments** - Different feature branches served from subdomains
63
+ - **A/B testing** - Serve different static builds based on subdomain
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "orator-static-server",
3
- "version": "1.0.1",
4
- "description": "Orator static file server.",
3
+ "version": "2.0.0",
4
+ "description": "Static file serving for Orator API servers.",
5
5
  "main": "source/Orator-Static-Server.js",
6
6
  "scripts": {
7
7
  "test": "./node_modules/mocha/bin/_mocha --exit -u tdd -R spec",
@@ -38,14 +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
42
  "finalhandler": "^1.3.1",
42
- "orator-serviceserver-base": "^1.0.1",
43
+ "mime": "^3.0.0",
43
44
  "serve-static": "^1.16.2"
44
45
  },
45
46
  "devDependencies": {
46
- "fable": "^3.0.145",
47
- "orator": "^5.0.0",
48
- "orator-serviceserver-restify": "^2.0.3",
49
- "quackage": "^1.0.33"
47
+ "chai": "^4.3.7",
48
+ "fable": "^3.1.51",
49
+ "mocha": "^10.2.0",
50
+ "orator": "^5.0.1",
51
+ "orator-serviceserver-restify": "^2.0.5",
52
+ "quackage": "^1.0.45"
50
53
  }
51
54
  }