kempo-server 1.3.0 → 1.4.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.
- package/.github/copilot-instructions.md +96 -0
- package/README.md +212 -4
- package/docs/configuration.html +119 -0
- package/docs/examples.html +201 -0
- package/docs/getting-started.html +72 -0
- package/docs/index.html +53 -330
- package/docs/manifest.json +87 -0
- package/docs/media/hexagon.svg +22 -0
- package/docs/media/icon-maskable.png +0 -0
- package/docs/media/icon.svg +44 -0
- package/docs/media/icon128.png +0 -0
- package/docs/media/icon144.png +0 -0
- package/docs/media/icon152.png +0 -0
- package/docs/media/icon16-48.svg +21 -0
- package/docs/media/icon16.png +0 -0
- package/docs/media/icon192.png +0 -0
- package/docs/media/icon256.png +0 -0
- package/docs/media/icon32.png +0 -0
- package/docs/media/icon384.png +0 -0
- package/docs/media/icon48.png +0 -0
- package/docs/media/icon512.png +0 -0
- package/docs/media/icon64.png +0 -0
- package/docs/media/icon72.png +0 -0
- package/docs/media/icon96.png +0 -0
- package/docs/media/kempo-fist.svg +21 -0
- package/docs/middleware.html +147 -0
- package/docs/request-response.html +95 -0
- package/docs/routing.html +77 -0
- package/package.json +8 -3
- package/tests/builtinMiddleware-cors.node-test.js +17 -0
- package/tests/builtinMiddleware.node-test.js +74 -0
- package/tests/defaultConfig.node-test.js +13 -0
- package/tests/example-middleware.node-test.js +31 -0
- package/tests/findFile.node-test.js +46 -0
- package/tests/getFiles.node-test.js +25 -0
- package/tests/getFlags.node-test.js +30 -0
- package/tests/index.node-test.js +23 -0
- package/tests/middlewareRunner.node-test.js +18 -0
- package/tests/requestWrapper.node-test.js +51 -0
- package/tests/responseWrapper.node-test.js +74 -0
- package/tests/router-middleware.node-test.js +46 -0
- package/tests/router.node-test.js +88 -0
- package/tests/serveFile.node-test.js +52 -0
- package/tests/test-utils.js +106 -0
package/docs/index.html
CHANGED
|
@@ -4,355 +4,78 @@
|
|
|
4
4
|
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
|
|
5
5
|
<title>Kempo Server - Documentation</title>
|
|
6
6
|
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
|
7
|
-
<link rel="
|
|
7
|
+
<link rel="icon" type="image/png" sizes="48x48" href="media/icon48.png">
|
|
8
|
+
<link rel="manifest" href="manifest.json">
|
|
9
|
+
<link rel="stylesheet" href="essential.css" />
|
|
8
10
|
</head>
|
|
9
11
|
<body>
|
|
10
12
|
<main>
|
|
11
13
|
<h1 class="ta-center">Kempo Server</h1>
|
|
14
|
+
<div class="ta-center">
|
|
15
|
+
<p class="mb0">
|
|
16
|
+
<a href="https://github.com/dustinpoissant/kempo-server" class="btn primary mr" target="_blank">GitHub</a>
|
|
17
|
+
<a href="https://www.npmjs.com/package/kempo-server" class="btn" target="_blank">NPM</a>
|
|
18
|
+
</p>
|
|
19
|
+
</div>
|
|
12
20
|
<p>A lightweight, zero-dependency, file based routing server.</p>
|
|
13
21
|
|
|
14
|
-
<
|
|
15
|
-
<summary class="p">Table of Contents</summary>
|
|
16
|
-
<hr class="m0 mb" />
|
|
17
|
-
<ul class="mt ml pl">
|
|
18
|
-
<li><a href="#gettingStarted">Getting Started</a></li>
|
|
19
|
-
<li>
|
|
20
|
-
<a href="#routes">Routes</a>
|
|
21
|
-
<ul>
|
|
22
|
-
<li><a href="#htmlRoutes">HTML Routes</a></li>
|
|
23
|
-
<li><a href="#dynamicRoutes">Dynamic Routes</a></li>
|
|
24
|
-
<li><a href="#request">Request Object</a></li>
|
|
25
|
-
<li><a href="#response">Response Object</a></li>
|
|
26
|
-
</ul>
|
|
27
|
-
</li>
|
|
28
|
-
<li>
|
|
29
|
-
<a href="#config">Configuration</a>
|
|
30
|
-
<ul>
|
|
31
|
-
<li><a href="#allowedMimes">allowedMimes</a></li>
|
|
32
|
-
<li><a href="#disallowedRegex">disallowedRegex</a></li>
|
|
33
|
-
<li><a href="#routeFiles">routeFiles</a></li>
|
|
34
|
-
<li><a href="#noRescanPaths">noRescanPaths</a></li>
|
|
35
|
-
<li><a href="#customRoutes">customRoutes</a></li>
|
|
36
|
-
<li><a href="#maxRescanAttempts">maxRescanAttempts</a></li>
|
|
37
|
-
</ul>
|
|
38
|
-
</li>
|
|
39
|
-
<li><a href="#features">Features</a></li>
|
|
40
|
-
<li><a href="#examples">Examples</a></li>
|
|
41
|
-
<li><a href="#cli">Command Line Options</a></li>
|
|
42
|
-
<li><a href="#demos">Live Demos</a></li>
|
|
43
|
-
</ul>
|
|
44
|
-
</details>
|
|
45
|
-
|
|
46
|
-
<h3 id="gettingStarted">Getting Started</h3>
|
|
47
|
-
<p>1. Install the npm package.</p>
|
|
48
|
-
<pre><code>npm install kempo-server</code></pre>
|
|
49
|
-
<p>2. Add it to your <code>package.json</code> scripts, use the <code>--root</code> flag to tell it where the root of your site is.</p>
|
|
50
|
-
<pre><code class="hljs json">{<br /> ...<br /> <span class="hljs-attr">"scripts"</span>: {<br /> <span class="hljs-attr">"start"</span>: <span class="hljs-string">"kempo-server --root public"</span><br /> }<br /> ...<br />}</code></pre>
|
|
51
|
-
<p>3. Run it in your terminal.</p>
|
|
52
|
-
<pre><code>npm run start</code></pre>
|
|
53
|
-
|
|
54
|
-
<h3 id="routes">Routes</h3>
|
|
55
|
-
<p>A route is a request to a directory that will be handled by a file. To define routes, create the directory structure to the route and create a file with the name of the method that this file will handle. For example <code>GET.js</code> will handle the <code>GET</code> requests, <code>POST.js</code> will handle the <code>POST</code> requests and so on. Use <code>index.js</code> to handle all request types.</p>
|
|
56
|
-
<p>The Javascript file must have a <b>default</b> export that is the function that will handle the request. It will be passed a <code>request</code> object and a <code>response</code> object (See <a href="#request">Request Object</a> below).</p>
|
|
57
|
-
<p>For example this directory structure:</p>
|
|
58
|
-
<pre><code class="hljs markdown">my/<br />├─ route/<br />│ ├─ GET.js<br />│ ├─ POST.js<br />├─ other/<br />│ ├─ route/<br />│ │ ├─ GET.js<br /></code></pre>
|
|
59
|
-
<p>Would be used to handle <code>GET my/route/</code>, <code>POST my/route/</code> and <code>GET my/other/route/</code></p>
|
|
60
|
-
|
|
61
|
-
<h5 id="htmlRoutes">HTML Routes</h5>
|
|
62
|
-
<p>Just like JS files, HTML files can be used to define a route. Use <code>GET.html</code>, <code>POST.html</code>, ect... to define files that will be served when that route is requested.</p>
|
|
63
|
-
<pre><code class="hljs markdown">my/<br />├─ route/<br />│ ├─ GET.js<br />│ ├─ POST.js<br />├─ other/<br />│ ├─ route/<br />│ │ ├─ GET.js<br />│ ├─ POST.html<br />│ ├─ GET.html<br /></code></pre>
|
|
64
|
-
<h5><code>index</code> fallbacks</h5>
|
|
65
|
-
<p><code>index.js</code> or <code>index.html</code> will be used as a fallback for all routes if a <i>method</i> file is not defined. In the above examples we do not have any routes defined for <code>DELETE</code>, <code>PUT</code> <code>PATCH</code>, ect... so lets use an <code>index.js</code> and <code>index.html</code> to be a "catch-all" for all the methods we have not created handlers for.</p>
|
|
66
|
-
<pre><code class="hljs markdown">my/<br />├─ route/<br />│ ├─ GET.js<br />│ ├─ POST.js<br />│ ├─ index.js<br />├─ other/<br />│ ├─ route/<br />│ │ ├─ GET.js<br />│ │ ├─ index.js<br />│ ├─ POST.html<br />│ ├─ GET.html<br />│ ├─ index.html<br />├─ index.hml<br /></code></pre>
|
|
67
|
-
|
|
68
|
-
<h3 id="dynamicRoutes">Dynamic Routes</h3>
|
|
69
|
-
<p>A dynamic route is a route with a "param" in its path. To define the dynamic parts of the route just wrap the directory name in square brackets. For example if you wanted to get a users profile, or perform CRUD operations on a user you might create the following directory structure.</p>
|
|
70
|
-
<pre><code class="hljs markdown">api/<br />├─ user/<br />│ ├─ [id]/<br />│ │ ├─ [info]/<br />│ │ │ ├─ GET.js<br />│ │ │ ├─ DELETE.js<br />│ │ │ ├─ PUT.js<br />│ │ │ ├─ POST.js<br />│ │ ├─ GET.js<br /></code></pre>
|
|
71
|
-
<p>When a request is made to <code>/api/user/123/info</code>, the route file <code>api/user/[id]/[info]/GET.js</code> would be executed and receive an request object with <code>request.params</code> containing <code>{ id: "123", info: "info" }</code>.</p>
|
|
72
|
-
|
|
73
|
-
<h3 id="request">Request Object</h3>
|
|
74
|
-
<p>Kempo Server provides a request object that makes working with HTTP requests easier:</p>
|
|
75
|
-
|
|
76
|
-
<h4>Properties</h4>
|
|
77
|
-
<ul>
|
|
78
|
-
<li><code>request.params</code> - Route parameters from dynamic routes (e.g., <code>{ id: "123", info: "info" }</code>)</li>
|
|
79
|
-
<li><code>request.query</code> - Query string parameters as an object (e.g., <code>{ page: "1", limit: "10" }</code>)</li>
|
|
80
|
-
<li><code>request.path</code> - The pathname of the request URL</li>
|
|
81
|
-
<li><code>request.method</code> - HTTP method (GET, POST, etc.)</li>
|
|
82
|
-
<li><code>request.headers</code> - Request headers object</li>
|
|
83
|
-
<li><code>request.url</code> - Full request URL</li>
|
|
84
|
-
</ul>
|
|
85
|
-
|
|
86
|
-
<h4>Methods</h4>
|
|
87
|
-
<ul>
|
|
88
|
-
<li><code>await request.json()</code> - Parse request body as JSON</li>
|
|
89
|
-
<li><code>await request.text()</code> - Get request body as text</li>
|
|
90
|
-
<li><code>await request.body()</code> - Get raw request body as string</li>
|
|
91
|
-
<li><code>await request.buffer()</code> - Get request body as Buffer</li>
|
|
92
|
-
<li><code>request.get(headerName)</code> - Get specific header value</li>
|
|
93
|
-
<li><code>request.is(type)</code> - Check if content-type contains specified type</li>
|
|
94
|
-
</ul>
|
|
95
|
-
|
|
96
|
-
<h3 id="response">Response Object</h3>
|
|
97
|
-
<p>Kempo Server also provides a response object that makes sending responses easier:</p>
|
|
98
|
-
|
|
99
|
-
<h4>Methods</h4>
|
|
100
|
-
<ul>
|
|
101
|
-
<li><code>response.json(object)</code> - Send JSON response with automatic content-type</li>
|
|
102
|
-
<li><code>response.send(data)</code> - Send response (auto-detects content type)</liI >
|
|
103
|
-
<li><code>response.html(htmlString)</code> - Send HTML response</li>
|
|
104
|
-
<li><code>response.text(textString)</code> - Send plain text response</li>
|
|
105
|
-
<li><code>response.status(code)</code> - Set status code (chainable)</li>
|
|
106
|
-
<li><code>response.set(field, value)</code> - Set header (chainable)</li>
|
|
107
|
-
<li><code>response.type(contentType)</code> - Set content type (chainable)</li>
|
|
108
|
-
<li><code>response.redirect(url, statusCode)</code> - Redirect to URL</li>
|
|
109
|
-
<li><code>response.cookie(name, value, options)</code> - Set cookie</li>
|
|
110
|
-
<li><code>response.clearCookie(name, options)</code> - Clear cookie</li>
|
|
111
|
-
</ul>
|
|
112
|
-
|
|
113
|
-
<h4>Example Route File</h4>
|
|
114
|
-
<p>Here's an example of what a route file might look like:</p>
|
|
115
|
-
<pre><code class="hljs javascript"><span class="hljs-comment">// api/user/[id]/GET.js</span><br /><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">request, response</span>) </span>{<br /> <span class="hljs-keyword">const</span> { id } = request.params;<br /> <span class="hljs-keyword">const</span> { includeDetails } = request.query;<br /> <br /> <span class="hljs-comment">// Fetch user data from database</span><br /> <span class="hljs-keyword">const</span> userData = <span class="hljs-keyword">await</span> getUserById(id);<br /> <br /> <span class="hljs-keyword">if</span> (!userData) {<br /> <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">404</span>).json({ error: <span class="hljs-string">'User not found'</span> });<br /> }<br /> <br /> response.json(userData);<br />}</code></pre>
|
|
116
|
-
|
|
117
|
-
<h4>POST Request Example</h4>
|
|
118
|
-
<p>Here's an example of handling JSON data in a POST request:</p>
|
|
119
|
-
<pre><code class="hljs javascript"><span class="hljs-comment">// api/user/[id]/POST.js</span><br /><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">request, response</span>) </span>{<br /> <span class="hljs-keyword">const</span> { id } = request.params;<br /> <br /> <span class="hljs-keyword">try</span> {<br /> <span class="hljs-keyword">const</span> updateData = <span class="hljs-keyword">await</span> request.json();<br /> <br /> <span class="hljs-comment">// Update user in database</span><br /> <span class="hljs-keyword">const</span> updatedUser = <span class="hljs-keyword">await</span> updateUser(id, updateData);<br /> <br /> response.json(updatedUser);<br /> } <span class="hljs-keyword">catch</span> (error) {<br /> response.status(<span class="hljs-number">400</span>).json({ error: <span class="hljs-string">'Invalid JSON'</span> });<br /> }<br />}</code></pre>
|
|
120
|
-
|
|
121
|
-
<h4>Response Methods Examples</h4>
|
|
122
|
-
<p>The response object supports multiple ways to send responses:</p>
|
|
123
|
-
<pre><code class="hljs javascript"><span class="hljs-comment">// Different response types</span><br /><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">request, response</span>) </span>{<br /> <span class="hljs-comment">// JSON response</span><br /> response.json({ message: <span class="hljs-string">'Hello World'</span> });<br /> <br /> <span class="hljs-comment">// HTML response</span><br /> response.html(<span class="hljs-string">'<h1>Hello World</h1>'</span>);<br /> <br /> <span class="hljs-comment">// Text response</span><br /> response.text(<span class="hljs-string">'Hello World'</span>);<br /> <br /> <span class="hljs-comment">// Status code chaining</span><br /> response.status(<span class="hljs-number">201</span>).json({ created: <span class="hljs-literal">true</span> });<br /> <br /> <span class="hljs-comment">// Custom headers</span><br /> response.set(<span class="hljs-string">'X-Custom-Header'</span>, <span class="hljs-string">'value'</span>).json({ data: <span class="hljs-string">'test'</span> });<br /> <br /> <span class="hljs-comment">// Redirect</span><br /> response.redirect(<span class="hljs-string">'/login'</span>);<br /> <br /> <span class="hljs-comment">// Set cookies</span><br /> response.cookie(<span class="hljs-string">'session'</span>, <span class="hljs-string">'abc123'</span>, { httpOnly: <span class="hljs-literal">true</span> }).json({ success: <span class="hljs-literal">true</span> });<br />}</code></pre>
|
|
124
|
-
|
|
125
|
-
<h3 id="config">Configuration</h3>
|
|
126
|
-
<p>To configure the server create a <code>.config.json</code> within the root directory of your server (<code>public</code> in the start example <a href="#gettingStarted">above</a>).</p>
|
|
127
|
-
<p>This json file can have any of the following 6 properties, any property not defined will use the "Default Config".</p>
|
|
128
|
-
<ul>
|
|
129
|
-
<li><a href="#allowedMimes">allowedMimes</a></li>
|
|
130
|
-
<li><a href="#disallowedRegex">disallowedRegex</a></li>
|
|
131
|
-
<li><a href="#customRoutes">customRoutes</a></li>
|
|
132
|
-
<li><a href="#routeFiles">routeFiles</a></li>
|
|
133
|
-
<li><a href="#noRescanPaths">noRescanPaths</a></li>
|
|
134
|
-
<li><a href="#maxRescanAttempts">maxRescanAttempts</a></li>
|
|
135
|
-
</ul>
|
|
136
|
-
|
|
137
|
-
<h4 id="allowedMimes">allowedMimes</h4>
|
|
138
|
-
<p>An object mapping file extensions to their MIME types. Files with extensions not in this list will not be served.</p>
|
|
139
|
-
<pre><code class="hljs json">{<br /> <span class="hljs-attr">"allowedMimes"</span>: {<br /> <span class="hljs-attr">"html"</span>: <span class="hljs-string">"text/html"</span>,<br /> <span class="hljs-attr">"css"</span>: <span class="hljs-string">"text/css"</span>,<br /> <span class="hljs-attr">"js"</span>: <span class="hljs-string">"application/javascript"</span>,<br /> <span class="hljs-attr">"json"</span>: <span class="hljs-string">"application/json"</span>,<br /> <span class="hljs-attr">"png"</span>: <span class="hljs-string">"image/png"</span>,<br /> <span class="hljs-attr">"jpg"</span>: <span class="hljs-string">"image/jpeg"</span><br /> }<br />}</code></pre>
|
|
140
|
-
|
|
141
|
-
<h4 id="disallowedRegex">disallowedRegex</h4>
|
|
142
|
-
<p>An array of regular expressions that match paths that should never be served. This provides security by preventing access to sensitive files.</p>
|
|
143
|
-
<pre><code class="hljs json">{<br /> <span class="hljs-attr">"disallowedRegex"</span>: [<br /> <span class="hljs-string">"^/\\..*"</span>,<br /> <span class="hljs-string">"\\.env$"</span>,<br /> <span class="hljs-string">"\\.config$"</span>,<br /> <span class="hljs-string">"password"</span><br /> ]<br />}</code></pre>
|
|
144
|
-
|
|
145
|
-
<h4 id="routeFiles">routeFiles</h4>
|
|
146
|
-
<p>An array of filenames that should be treated as route handlers and executed as JavaScript modules.</p>
|
|
147
|
-
<pre><code class="hljs json">{<br /> <span class="hljs-attr">"routeFiles"</span>: [<br /> <span class="hljs-string">"GET.js"</span>,<br /> <span class="hljs-string">"POST.js"</span>,<br /> <span class="hljs-string">"PUT.js"</span>,<br /> <span class="hljs-string">"DELETE.js"</span>,<br /> <span class="hljs-string">"index.js"</span><br /> ]<br />}</code></pre>
|
|
148
|
-
|
|
149
|
-
<h4 id="noRescanPaths">noRescanPaths</h4>
|
|
150
|
-
<p>An array of regex patterns for paths that should not trigger a file system rescan. This improves performance for common static assets.</p>
|
|
151
|
-
<pre><code class="hljs json">{<br /> <span class="hljs-attr">"noRescanPaths"</span>: [<br /> <span class="hljs-string">"/favicon\\.ico$"</span>,<br /> <span class="hljs-string">"/robots\\.txt$"</span>,<br /> <span class="hljs-string">"\\.map$"</span><br /> ]<br />}</code></pre>
|
|
152
|
-
|
|
153
|
-
<h4 id="customRoutes">customRoutes</h4>
|
|
154
|
-
<p>An object mapping custom route paths to file paths. Useful for aliasing or serving files from outside the document root.</p>
|
|
155
|
-
|
|
156
|
-
<p><strong>Basic Routes:</strong></p>
|
|
157
|
-
<pre><code class="hljs json">{<br /> <span class="hljs-attr">"customRoutes"</span>: {<br /> <span class="hljs-attr">"/vendor/bootstrap.css"</span>: <span class="hljs-string">"./node_modules/bootstrap/dist/css/bootstrap.min.css"</span>,<br /> <span class="hljs-attr">"/api/status"</span>: <span class="hljs-string">"./status.js"</span><br /> }<br />}</code></pre>
|
|
158
|
-
|
|
159
|
-
<p><strong>Wildcard Routes:</strong></p>
|
|
160
|
-
<p>Wildcard routes allow you to map entire directory structures using the <code>*</code> wildcard:</p>
|
|
161
|
-
<pre><code class="hljs json">{<br /> <span class="hljs-attr">"customRoutes"</span>: {<br /> <span class="hljs-attr">"kempo/*"</span>: <span class="hljs-string">"./node_modules/kempo/dust/*"</span>,<br /> <span class="hljs-attr">"assets/*"</span>: <span class="hljs-string">"./static-files/*"</span>,<br /> <span class="hljs-attr">"docs/*"</span>: <span class="hljs-string">"./documentation/*"</span><br /> }<br />}</code></pre>
|
|
162
|
-
|
|
163
|
-
<p>With wildcard routes:</p>
|
|
164
|
-
<ul>
|
|
165
|
-
<li><code>kempo/styles.css</code> would serve <code>./node_modules/kempo/dust/styles.css</code></li>
|
|
166
|
-
<li><code>assets/logo.png</code> would serve <code>./static-files/logo.png</code></li>
|
|
167
|
-
<li><code>docs/readme.md</code> would serve <code>./documentation/readme.md</code></li>
|
|
168
|
-
</ul>
|
|
169
|
-
<p>The <code>*</code> wildcard matches any single path segment (anything between <code>/</code> characters). Multiple wildcards can be used in a single route pattern.</p>
|
|
170
|
-
|
|
171
|
-
<h4 id="maxRescanAttempts">maxRescanAttempts</h4>
|
|
172
|
-
<p>The maximum number of times to attempt rescanning the file system when a file is not found. Defaults to 3.</p>
|
|
173
|
-
<pre><code class="hljs json">{<br /> <span class="hljs-attr">"maxRescanAttempts"</span>: <span class="hljs-number">3</span><br />}</code></pre>
|
|
174
|
-
|
|
175
|
-
<h3 id="features">Features</h3>
|
|
176
|
-
<ul>
|
|
177
|
-
<li><strong>Zero Dependencies</strong> - No external dependencies required</li>
|
|
178
|
-
<li><strong>File-based Routing</strong> - Routes are defined by your directory structure</li>
|
|
179
|
-
<li><strong>Dynamic Routes</strong> - Support for parameterized routes with square bracket syntax</li>
|
|
180
|
-
<li><strong>Wildcard Routes</strong> - Map entire directory structures with wildcard patterns</li>
|
|
181
|
-
<li><strong>Multiple HTTP Methods</strong> - Support for GET, POST, PUT, DELETE, and more</li>
|
|
182
|
-
<li><strong>Static File Serving</strong> - Automatically serves static files with proper MIME types</li>
|
|
183
|
-
<li><strong>HTML Routes</strong> - Support for both JavaScript and HTML route handlers</li>
|
|
184
|
-
<li><strong>Configurable</strong> - Customize behavior with a simple JSON config file</li>
|
|
185
|
-
<li><strong>Security</strong> - Built-in protection against serving sensitive files</li>
|
|
186
|
-
<li><strong>Performance</strong> - Smart file system caching and rescan optimization</li>
|
|
187
|
-
</ul>
|
|
188
|
-
|
|
189
|
-
<h3 id="examples">Examples</h3>
|
|
190
|
-
|
|
191
|
-
<h4>Simple API Route</h4>
|
|
192
|
-
<pre><code class="hljs javascript"><span class="hljs-comment">// api/hello/GET.js</span><br /><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">request, response</span>) </span>{<br /> <span class="hljs-keyword">const</span> { name } = request.query;<br /> <span class="hljs-keyword">const</span> message = name ? <span class="hljs-string">`Hello ${name}!`</span> : <span class="hljs-string">'Hello World!'</span>;<br /> <br /> response.json({ message });<br />}</code></pre>
|
|
193
|
-
|
|
194
|
-
<h4>Dynamic User Profile Route</h4>
|
|
195
|
-
<pre><code class="hljs javascript"><span class="hljs-comment">// api/users/[id]/GET.js</span><br /><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">request, response</span>) </span>{<br /> <span class="hljs-keyword">const</span> { id } = request.params;<br /> <span class="hljs-keyword">const</span> { includeProfile } = request.query;<br /> <br /> <span class="hljs-comment">// Simulate database lookup</span><br /> <span class="hljs-keyword">const</span> user = {<br /> id: id,<br /> name: <span class="hljs-string">`User ${id}`</span>,<br /> email: <span class="hljs-string">`user${id}@example.com`</span><br /> };<br /> <br /> <span class="hljs-keyword">if</span> (includeProfile === <span class="hljs-string">'true'</span>) {<br /> user.profile = {<br /> bio: <span class="hljs-string">`Bio for user ${id}`</span>,<br /> joinDate: <span class="hljs-string">'2024-01-01'</span><br /> };<br /> }<br /> <br /> response.json(user);<br />}</code></pre>
|
|
196
|
-
|
|
197
|
-
<h4>Form Handling Route</h4>
|
|
198
|
-
<pre><code class="hljs javascript"><span class="hljs-comment">// contact/POST.js</span><br /><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">request, response</span>) </span>{<br /> <span class="hljs-keyword">try</span> {<br /> <span class="hljs-keyword">const</span> body = <span class="hljs-keyword">await</span> request.text();<br /> <span class="hljs-keyword">const</span> formData = <span class="hljs-keyword">new</span> URLSearchParams(body);<br /> <span class="hljs-keyword">const</span> name = formData.get(<span class="hljs-string">'name'</span>);<br /> <span class="hljs-keyword">const</span> email = formData.get(<span class="hljs-string">'email'</span>);<br /> <br /> <span class="hljs-comment">// Process form data...</span><br /> <br /> response.html(<span class="hljs-string">'<h1>Thank you for your message!</h1>'</span>);<br /> } <span class="hljs-keyword">catch</span> (error) {<br /> response.status(<span class="hljs-number">400</span>).html(<span class="hljs-string">'<h1>Error processing form</h1>'</span>);<br /> }<br />}</code></pre>
|
|
199
|
-
|
|
200
|
-
<h3 id="cli">Command Line Options</h3>
|
|
201
|
-
<p>Kempo Server supports several command line options to customize its behavior:</p>
|
|
202
|
-
<ul>
|
|
203
|
-
<li><code>--root <path></code> - Set the document root directory (required)</li>
|
|
204
|
-
<li><code>--port <number></code> - Set the port number (default: 3000)</li>
|
|
205
|
-
<li><code>--host <address></code> - Set the host address (default: localhost)</li>
|
|
206
|
-
<li><code>--verbose</code> - Enable verbose logging</li>
|
|
207
|
-
</ul>
|
|
208
|
-
|
|
209
|
-
<pre><code>kempo-server --root public --port 8080 --host 0.0.0.0 --verbose</code></pre>
|
|
210
|
-
|
|
211
|
-
<h3 id="demos">Live Demos</h3>
|
|
212
|
-
<p>Try out the example API endpoints below. These demonstrations show the actual routes working in this documentation site.</p>
|
|
213
|
-
|
|
214
|
-
<div class="mb">
|
|
215
|
-
<h4 class="mt0">Get User Profile</h4>
|
|
216
|
-
<p><code>GET /api/user/[id]</code></p>
|
|
22
|
+
<nav class="b r mb p">
|
|
217
23
|
<div class="row -mx">
|
|
218
24
|
<div class="col m-span-12 d-span-6 px">
|
|
219
|
-
<
|
|
220
|
-
<
|
|
221
|
-
<
|
|
222
|
-
<
|
|
223
|
-
|
|
25
|
+
<h4 class="mt0">Getting Started</h4>
|
|
26
|
+
<ul>
|
|
27
|
+
<li><a href="getting-started.html">Getting Started</a></li>
|
|
28
|
+
<li><a href="routing.html">Routes & Routing</a></li>
|
|
29
|
+
<li><a href="request-response.html">Request & Response</a></li>
|
|
30
|
+
</ul>
|
|
224
31
|
</div>
|
|
225
32
|
<div class="col m-span-12 d-span-6 px">
|
|
226
|
-
<
|
|
227
|
-
<
|
|
33
|
+
<h4 class="mt0">Advanced Features</h4>
|
|
34
|
+
<ul>
|
|
35
|
+
<li><a href="configuration.html">Configuration</a></li>
|
|
36
|
+
<li><a href="middleware.html">Middleware</a></li>
|
|
37
|
+
<li><a href="examples.html">Examples & Demos</a></li>
|
|
38
|
+
</ul>
|
|
228
39
|
</div>
|
|
229
40
|
</div>
|
|
230
|
-
</
|
|
41
|
+
</nav>
|
|
231
42
|
|
|
232
|
-
<div class="mb">
|
|
233
|
-
<
|
|
234
|
-
<p
|
|
235
|
-
<
|
|
236
|
-
|
|
237
|
-
<pre><code class="hljs javascript"><span class="hljs-comment">// api/user/[id]/[info]/GET.js</span><br /><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">request, response</span>) </span>{<br /> <span class="hljs-keyword">const</span> { id, info } = request.params;<br /> <br /> <span class="hljs-keyword">const</span> userInfo = {<br /> id: id,<br /> details: {<br /> bio: <span class="hljs-string">`This is ${id}'s bio`</span>,<br /> location: <span class="hljs-string">'Earth'</span>,<br /> website: <span class="hljs-string">`https://${id}.dev`</span>,<br /> followers: <span class="hljs-number">123</span>,<br /> following: <span class="hljs-number">456</span><br /> }<br /> };<br /> <br /> response.json(userInfo);<br />}</code></pre>
|
|
238
|
-
<div class="mb">
|
|
239
|
-
<input type="text" id="userInfoId" placeholder="Enter user ID" value="alice" class="mb mr">
|
|
240
|
-
<button onclick="fetchUserInfo()" class="primary">GET User Info</button>
|
|
241
|
-
</div>
|
|
242
|
-
</div>
|
|
243
|
-
<div class="col m-span-12 d-span-6 px">
|
|
244
|
-
<h5>Response:</h5>
|
|
245
|
-
<pre><output id="userInfoOutput" class="pb">Click "GET User Info" to see the response</output></pre>
|
|
246
|
-
</div>
|
|
247
|
-
</div>
|
|
43
|
+
<div class="b r mb p">
|
|
44
|
+
<h3 class="mt0">Quick Start</h3>
|
|
45
|
+
<p>Install and run Kempo Server in seconds:</p>
|
|
46
|
+
<pre><code>npm install kempo-server
|
|
47
|
+
npx kempo-server --root public</code></pre>
|
|
248
48
|
</div>
|
|
249
49
|
|
|
250
|
-
<div class="mb">
|
|
251
|
-
<
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
<
|
|
258
|
-
<
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
<button onclick="updateUserInfo()" class="primary">POST Update</button>
|
|
263
|
-
</div>
|
|
264
|
-
</div>
|
|
265
|
-
<div class="col m-span-12 d-span-6 px">
|
|
266
|
-
<h5>Response:</h5>
|
|
267
|
-
<pre><output id="postOutput" class="pb">Click "POST Update" to see the response</output></pre>
|
|
50
|
+
<div class="row -mx mb">
|
|
51
|
+
<div class="col m-span-12 d-span-6 px">
|
|
52
|
+
<div class="b r p">
|
|
53
|
+
<h4 class="mt0">Features</h4>
|
|
54
|
+
<ul>
|
|
55
|
+
<li><strong>Zero Dependencies</strong> - No external dependencies</li>
|
|
56
|
+
<li><strong>File-based Routing</strong> - Directory structure defines routes</li>
|
|
57
|
+
<li><strong>Dynamic Routes</strong> - Parameterized routes with [brackets]</li>
|
|
58
|
+
<li><strong>Wildcard Routes</strong> - Map directories with * patterns</li>
|
|
59
|
+
<li><strong>Middleware System</strong> - Authentication, CORS, logging, and more</li>
|
|
60
|
+
<li><strong>Request/Response Objects</strong> - Enhanced request handling</li>
|
|
61
|
+
</ul>
|
|
268
62
|
</div>
|
|
269
63
|
</div>
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
<
|
|
280
|
-
|
|
281
|
-
</div>
|
|
282
|
-
</div>
|
|
283
|
-
<div class="col m-span-12 d-span-6 px">
|
|
284
|
-
<h5>Response:</h5>
|
|
285
|
-
<pre><output id="deleteOutput" class="pb">Click "DELETE Info" to see the response</output></pre>
|
|
64
|
+
<div class="col m-span-12 d-span-6 px">
|
|
65
|
+
<div class="b r p">
|
|
66
|
+
<h4 class="mt0">Built-in Middleware</h4>
|
|
67
|
+
<ul>
|
|
68
|
+
<li><strong>CORS</strong> - Cross-origin resource sharing</li>
|
|
69
|
+
<li><strong>Compression</strong> - Automatic gzip compression</li>
|
|
70
|
+
<li><strong>Rate Limiting</strong> - Request throttling</li>
|
|
71
|
+
<li><strong>Security Headers</strong> - Security best practices</li>
|
|
72
|
+
<li><strong>Request Logging</strong> - Configurable logging</li>
|
|
73
|
+
<li><strong>Custom Middleware</strong> - Load your own middleware</li>
|
|
74
|
+
</ul>
|
|
286
75
|
</div>
|
|
287
76
|
</div>
|
|
288
77
|
</div>
|
|
289
|
-
|
|
290
|
-
<script>
|
|
291
|
-
async function fetchUser() {
|
|
292
|
-
const userId = document.getElementById('userId').value || 'john';
|
|
293
|
-
const output = document.getElementById('userOutput');
|
|
294
|
-
|
|
295
|
-
try {
|
|
296
|
-
output.textContent = 'Loading...';
|
|
297
|
-
const response = await fetch(`/api/user/${userId}`);
|
|
298
|
-
const data = await response.json();
|
|
299
|
-
output.textContent = JSON.stringify(data, null, 2);
|
|
300
|
-
} catch (error) {
|
|
301
|
-
output.textContent = `Error: ${error.message}`;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
async function fetchUserInfo() {
|
|
306
|
-
const userId = document.getElementById('userInfoId').value || 'alice';
|
|
307
|
-
const output = document.getElementById('userInfoOutput');
|
|
308
|
-
|
|
309
|
-
try {
|
|
310
|
-
output.textContent = 'Loading...';
|
|
311
|
-
const response = await fetch(`/api/user/${userId}/info`);
|
|
312
|
-
const data = await response.json();
|
|
313
|
-
output.textContent = JSON.stringify(data, null, 2);
|
|
314
|
-
} catch (error) {
|
|
315
|
-
output.textContent = `Error: ${error.message}`;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
async function updateUserInfo() {
|
|
320
|
-
const userId = document.getElementById('postUserId').value || 'bob';
|
|
321
|
-
const postData = document.getElementById('postData').value;
|
|
322
|
-
const output = document.getElementById('postOutput');
|
|
323
|
-
|
|
324
|
-
try {
|
|
325
|
-
output.textContent = 'Loading...';
|
|
326
|
-
const response = await fetch(`/api/user/${userId}/info`, {
|
|
327
|
-
method: 'POST',
|
|
328
|
-
headers: {
|
|
329
|
-
'Content-Type': 'application/json',
|
|
330
|
-
},
|
|
331
|
-
body: postData
|
|
332
|
-
});
|
|
333
|
-
const data = await response.json();
|
|
334
|
-
output.textContent = JSON.stringify(data, null, 2);
|
|
335
|
-
} catch (error) {
|
|
336
|
-
output.textContent = `Error: ${error.message}`;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
async function deleteUserInfo() {
|
|
341
|
-
const userId = document.getElementById('deleteUserId').value || 'charlie';
|
|
342
|
-
const output = document.getElementById('deleteOutput');
|
|
343
|
-
|
|
344
|
-
try {
|
|
345
|
-
output.textContent = 'Loading...';
|
|
346
|
-
const response = await fetch(`/api/user/${userId}/info`, {
|
|
347
|
-
method: 'DELETE'
|
|
348
|
-
});
|
|
349
|
-
const data = await response.json();
|
|
350
|
-
output.textContent = JSON.stringify(data, null, 2);
|
|
351
|
-
} catch (error) {
|
|
352
|
-
output.textContent = `Error: ${error.message}`;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
</script>
|
|
356
78
|
</main>
|
|
79
|
+
<div style="height:25vh"></div>
|
|
357
80
|
</body>
|
|
358
|
-
</html>
|
|
81
|
+
</html>
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Kempo Server",
|
|
3
|
+
"short_name": "Kempo Server",
|
|
4
|
+
"description": "A lightweight, zero-dependency, file based routing server",
|
|
5
|
+
"start_url": "/",
|
|
6
|
+
"display": "standalone",
|
|
7
|
+
"background_color": "#ffffff",
|
|
8
|
+
"theme_color": "#000000",
|
|
9
|
+
"orientation": "portrait-primary",
|
|
10
|
+
"scope": "/",
|
|
11
|
+
"lang": "en",
|
|
12
|
+
"categories": ["developer", "utilities"],
|
|
13
|
+
"icons": [
|
|
14
|
+
{
|
|
15
|
+
"src": "media/icon16.png",
|
|
16
|
+
"sizes": "16x16",
|
|
17
|
+
"type": "image/png"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"src": "media/icon32.png",
|
|
21
|
+
"sizes": "32x32",
|
|
22
|
+
"type": "image/png"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"src": "media/icon48.png",
|
|
26
|
+
"sizes": "48x48",
|
|
27
|
+
"type": "image/png"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"src": "media/icon64.png",
|
|
31
|
+
"sizes": "64x64",
|
|
32
|
+
"type": "image/png"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"src": "media/icon72.png",
|
|
36
|
+
"sizes": "72x72",
|
|
37
|
+
"type": "image/png"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"src": "media/icon96.png",
|
|
41
|
+
"sizes": "96x96",
|
|
42
|
+
"type": "image/png"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"src": "media/icon128.png",
|
|
46
|
+
"sizes": "128x128",
|
|
47
|
+
"type": "image/png"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"src": "media/icon144.png",
|
|
51
|
+
"sizes": "144x144",
|
|
52
|
+
"type": "image/png"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"src": "media/icon152.png",
|
|
56
|
+
"sizes": "152x152",
|
|
57
|
+
"type": "image/png"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"src": "media/icon192.png",
|
|
61
|
+
"sizes": "192x192",
|
|
62
|
+
"type": "image/png",
|
|
63
|
+
"purpose": "maskable"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"src": "media/icon256.png",
|
|
67
|
+
"sizes": "256x256",
|
|
68
|
+
"type": "image/png"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"src": "media/icon384.png",
|
|
72
|
+
"sizes": "384x384",
|
|
73
|
+
"type": "image/png"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"src": "media/icon-maskable.png",
|
|
77
|
+
"sizes": "512x512",
|
|
78
|
+
"type": "image/png",
|
|
79
|
+
"purpose": "maskable"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"src": "media/icon.svg",
|
|
83
|
+
"sizes": "any",
|
|
84
|
+
"type": "image/svg+xml"
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
+
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
3
|
+
|
|
4
|
+
<svg
|
|
5
|
+
version="1.1"
|
|
6
|
+
id="svg1"
|
|
7
|
+
width="572.89282"
|
|
8
|
+
height="520.2417"
|
|
9
|
+
viewBox="0 0 572.89282 520.2417"
|
|
10
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
11
|
+
xmlns:svg="http://www.w3.org/2000/svg">
|
|
12
|
+
<defs
|
|
13
|
+
id="defs1" />
|
|
14
|
+
<g
|
|
15
|
+
id="g1"
|
|
16
|
+
transform="translate(-55.316471,-79.136482)">
|
|
17
|
+
<path
|
|
18
|
+
style="fill:#673ab7;fill-opacity:1"
|
|
19
|
+
d="M 220.44305,596.99111 C 194.29421,590.50039 173.56773,571.24999 162.38846,547.08435 126.91657,486.65752 90.869779,426.46655 58.211559,364.46871 52.737569,338.98299 54.045079,310.89218 70.730909,289.61781 105.5259,229.55178 138.11337,168.06799 175.97366,109.8619 191.81565,87.209073 220.1809,78.117943 246.89684,80.020643 c 69.97113,-0.18609 140.03691,-2.21714 209.95538,0.5891 26.85701,3.01478 49.34166,21.684927 61.44676,45.308957 36.6854,61.47146 72.5551,123.49036 106.6198,186.45001 5.7217,24.40876 5.0131,51.88718 -10.4596,72.76015 -34.5562,60.94187 -68.0745,122.60428 -105.5068,181.82725 -19.06299,26.68069 -52.6428,34.03908 -83.55728,31.75257 -68.27925,0.42703 -136.76226,1.92797 -204.95205,-1.71757 z"
|
|
20
|
+
id="path3" />
|
|
21
|
+
</g>
|
|
22
|
+
</svg>
|
|
Binary file
|