kempo-server 2.2.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONFIG.md +295 -187
- package/README.md +5 -4
- package/SPA.md +14 -14
- package/dist/defaultConfig.js +1 -1
- package/dist/index.js +1 -1
- package/dist/render.js +2 -0
- package/dist/router.js +1 -1
- package/dist/serveFile.js +1 -1
- package/dist/templating/index.js +1 -0
- package/dist/templating/parse.js +1 -0
- package/docs/caching.html +103 -17
- package/docs/cli-utils.html +102 -16
- package/docs/configuration.html +104 -17
- package/docs/examples.html +104 -17
- package/docs/fs-utils.html +102 -16
- package/docs/getting-started.html +104 -17
- package/docs/index.html +176 -81
- package/docs/middleware.html +104 -17
- package/docs/request-response.html +104 -17
- package/docs/routing.html +104 -17
- package/docs/templating.html +292 -0
- package/docs-src/.config.js +11 -0
- package/docs-src/caching.page.html +220 -0
- package/docs-src/cli-utils.page.html +71 -0
- package/docs-src/configuration.page.html +310 -0
- package/docs-src/default.template.html +35 -0
- package/docs-src/examples.page.html +192 -0
- package/docs-src/fs-utils.page.html +102 -0
- package/docs-src/getting-started.page.html +63 -0
- package/docs-src/index.page.html +79 -0
- package/docs-src/middleware.page.html +133 -0
- package/docs-src/nav.fragment.html +73 -0
- package/docs-src/request-response.page.html +96 -0
- package/docs-src/routing.page.html +73 -0
- package/docs-src/templating.page.html +188 -0
- package/llms.txt +97 -31
- package/package.json +5 -2
- package/scripts/build.js +22 -1
- package/scripts/render.js +58 -0
- package/src/defaultConfig.js +14 -2
- package/src/index.js +1 -1
- package/src/router.js +69 -10
- package/src/serveFile.js +27 -0
- package/src/templating/index.js +132 -0
- package/src/templating/parse.js +285 -0
- package/tests/cacheConfig.node-test.js +2 -2
- package/tests/config-flag.node-test.js +61 -25
- package/tests/customRoute-outside-root.node-test.js +1 -1
- package/tests/router-wildcard.node-test.js +47 -2
- package/tests/templating-parse.node-test.js +243 -0
- package/tests/templating-render.node-test.js +188 -0
- package/tests/utils/test-scenario.js +4 -4
- package/docs/.config.json.example +0 -29
- package/docs/api/_admin/cache/DELETE.js +0 -28
- package/docs/api/_admin/cache/GET.js +0 -53
- package/docs/api/user/[id]/GET.js +0 -15
- package/docs/api/user/[id]/[info]/DELETE.js +0 -12
- package/docs/api/user/[id]/[info]/GET.js +0 -17
- package/docs/api/user/[id]/[info]/POST.js +0 -18
- package/docs/api/user/[id]/[info]/PUT.js +0 -19
- package/docs/init.js +0 -2
- package/docs/nav.inc.html +0 -70
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
<page pageName="Examples & Demos" title="Examples & Demos - Kempo Server">
|
|
2
|
+
<content>
|
|
3
|
+
<p>Explore practical examples and try interactive demos of Kempo Server features.</p>
|
|
4
|
+
|
|
5
|
+
<h2>Code Examples</h2>
|
|
6
|
+
|
|
7
|
+
<h3>Simple API Route</h3>
|
|
8
|
+
<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>
|
|
9
|
+
|
|
10
|
+
<h3>Dynamic User Profile Route</h3>
|
|
11
|
+
<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>
|
|
12
|
+
|
|
13
|
+
<h3>Form Handling Route</h3>
|
|
14
|
+
<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 /> <span class="hljs-keyword">const</span> message = formData.get(<span class="hljs-string">'message'</span>);<br /> <br /> <span class="hljs-comment">// Process form data...</span><br /> <span class="hljs-keyword">await</span> sendContactEmail({ name, email, message });<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>
|
|
15
|
+
|
|
16
|
+
<h3>File Upload Handling</h3>
|
|
17
|
+
<pre><code class="hljs javascript"><span class="hljs-comment">// api/upload/POST.js</span><br /><span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">'fs/promises'</span>;<br /><span class="hljs-keyword">import</span> path <span class="hljs-keyword">from</span> <span class="hljs-string">'path'</span>;<br /><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> buffer = <span class="hljs-keyword">await</span> request.buffer();<br /> <span class="hljs-keyword">const</span> contentType = request.get(<span class="hljs-string">'content-type'</span>);<br /> <br /> <span class="hljs-comment">// Generate filename</span><br /> <span class="hljs-keyword">const</span> extension = getExtensionFromMimeType(contentType);<br /> <span class="hljs-keyword">const</span> filename = <span class="hljs-string">`upload_${Date.now()}.${extension}`</span>;<br /> <span class="hljs-keyword">const</span> filepath = path.join(<span class="hljs-string">'./uploads'</span>, filename);<br /> <br /> <span class="hljs-comment">// Ensure uploads directory exists</span><br /> <span class="hljs-keyword">await</span> fs.mkdir(<span class="hljs-string">'./uploads'</span>, { recursive: <span class="hljs-literal">true</span> });<br /> <br /> <span class="hljs-comment">// Save file</span><br /> <span class="hljs-keyword">await</span> fs.writeFile(filepath, buffer);<br /> <br /> response.json({<br /> message: <span class="hljs-string">'File uploaded successfully'</span>,<br /> filename: filename,<br /> size: buffer.length,<br /> type: contentType<br /> });<br /> } <span class="hljs-keyword">catch</span> (error) {<br /> response.status(<span class="hljs-number">500</span>).json({<br /> error: <span class="hljs-string">'Upload failed'</span>,<br /> message: error.message<br /> });<br /> }<br />}<br /><br /><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getExtensionFromMimeType</span>(<span class="hljs-params">mimeType</span>) </span>{<br /> <span class="hljs-keyword">const</span> mimeMap = {<br /> <span class="hljs-string">'image/jpeg'</span>: <span class="hljs-string">'jpg'</span>,<br /> <span class="hljs-string">'image/png'</span>: <span class="hljs-string">'png'</span>,<br /> <span class="hljs-string">'image/gif'</span>: <span class="hljs-string">'gif'</span>,<br /> <span class="hljs-string">'text/plain'</span>: <span class="hljs-string">'txt'</span>,<br /> <span class="hljs-string">'application/pdf'</span>: <span class="hljs-string">'pdf'</span><br /> };<br /> <span class="hljs-keyword">return</span> mimeMap[mimeType] || <span class="hljs-string">'bin'</span>;<br />}</code></pre>
|
|
18
|
+
|
|
19
|
+
<h3>Authentication Route</h3>
|
|
20
|
+
<pre><code class="hljs javascript"><span class="hljs-comment">// api/auth/login/POST.js</span><br /><span class="hljs-keyword">import</span> crypto <span class="hljs-keyword">from</span> <span class="hljs-string">'crypto'</span>;<br /><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> { username, password } = <span class="hljs-keyword">await</span> request.json();<br /> <br /> <span class="hljs-comment">// Validate credentials</span><br /> <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> authenticateUser(username, password);<br /> <br /> <span class="hljs-keyword">if</span> (!user) {<br /> <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">401</span>).json({<br /> error: <span class="hljs-string">'Invalid credentials'</span><br /> });<br /> }<br /> <br /> <span class="hljs-comment">// Generate session token</span><br /> <span class="hljs-keyword">const</span> sessionToken = crypto.randomBytes(<span class="hljs-number">32</span>).toString(<span class="hljs-string">'hex'</span>);<br /> <span class="hljs-keyword">await</span> createSession(user.id, sessionToken);<br /> <br /> <span class="hljs-comment">// Set secure cookie</span><br /> response<br /> .cookie(<span class="hljs-string">'session'</span>, sessionToken, {<br /> httpOnly: <span class="hljs-literal">true</span>,<br /> secure: <span class="hljs-literal">true</span>,<br /> sameSite: <span class="hljs-string">'strict'</span>,<br /> maxAge: <span class="hljs-number">24</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span> * <span class="hljs-number">1000</span> <span class="hljs-comment">// 24 hours</span><br /> })<br /> .json({<br /> message: <span class="hljs-string">'Login successful'</span>,<br /> user: {<br /> id: user.id,<br /> username: user.username,<br /> email: user.email<br /> }<br /> });<br /> } <span class="hljs-keyword">catch</span> (error) {<br /> response.status(<span class="hljs-number">400</span>).json({<br /> error: <span class="hljs-string">'Invalid request'</span>,<br /> message: error.message<br /> });<br /> }<br />}</code></pre>
|
|
21
|
+
|
|
22
|
+
<h2>Interactive Demos</h2>
|
|
23
|
+
<p>Try out the example API endpoints below. These demonstrations show the actual routes working in this documentation site.</p>
|
|
24
|
+
|
|
25
|
+
<div class="mb">
|
|
26
|
+
<h3 class="mt0">Get User Profile</h3>
|
|
27
|
+
<p><code>GET /api/user/[id]</code></p>
|
|
28
|
+
<div class="row -mx">
|
|
29
|
+
<div class="col m-span-12 d-span-6 px">
|
|
30
|
+
<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 /> <br /> <span class="hljs-keyword">const</span> userData = {<br /> id: id,<br /> profile: {<br /> name: <span class="hljs-string">`${id.charAt(0).toUpperCase()}${id.slice(1)}`</span>,<br /> joinDate: <span class="hljs-string">'2024-01-15'</span>,<br /> posts: <span class="hljs-number">42</span><br /> }<br /> };<br /> <br /> response.json(userData);<br />}</code></pre>
|
|
31
|
+
<div class="mb">
|
|
32
|
+
<input type="text" id="userId" placeholder="Enter user ID (e.g., john)" value="john" class="mb mr">
|
|
33
|
+
<button onclick="fetchUser()" class="primary">GET User</button>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="col m-span-12 d-span-6 px">
|
|
37
|
+
<h4>Response:</h4>
|
|
38
|
+
<pre><output id="userOutput" class="pb">Click "GET User" to see the response</output></pre>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div class="mb">
|
|
44
|
+
<h3 class="mt0">Get User Info</h3>
|
|
45
|
+
<p><code>GET /api/user/[id]/[info]</code></p>
|
|
46
|
+
<div class="row -mx">
|
|
47
|
+
<div class="col m-span-12 d-span-6 px">
|
|
48
|
+
<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>
|
|
49
|
+
<div class="mb">
|
|
50
|
+
<input type="text" id="userInfoId" placeholder="Enter user ID" value="alice" class="mb mr">
|
|
51
|
+
<button onclick="fetchUserInfo()" class="primary">GET User Info</button>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="col m-span-12 d-span-6 px">
|
|
55
|
+
<h4>Response:</h4>
|
|
56
|
+
<pre><output id="userInfoOutput" class="pb">Click "GET User Info" to see the response</output></pre>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<div class="mb">
|
|
62
|
+
<h3 class="mt0">Update User Info</h3>
|
|
63
|
+
<p><code>POST /api/user/[id]/[info]</code></p>
|
|
64
|
+
<div class="row -mx">
|
|
65
|
+
<div class="col m-span-12 d-span-6 px">
|
|
66
|
+
<pre><code class="hljs javascript"><span class="hljs-comment">// api/user/[id]/[info]/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, info } = 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-keyword">const</span> updatedUser = {<br /> id: id,<br /> message: <span class="hljs-string">'User info updated successfully'</span>,<br /> updatedFields: updateData<br /> };<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>
|
|
67
|
+
<div class="mb">
|
|
68
|
+
<input type="text" id="postUserId" placeholder="Enter user ID" value="bob" class="mb">
|
|
69
|
+
<textarea id="postData" placeholder="Enter JSON data to update" class="mb">{
|
|
70
|
+
"bio": "Updated bio text",
|
|
71
|
+
"location": "New York"
|
|
72
|
+
}</textarea>
|
|
73
|
+
<button onclick="updateUserInfo()" class="primary">POST Update</button>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
<div class="col m-span-12 d-span-6 px">
|
|
77
|
+
<h4>Response:</h4>
|
|
78
|
+
<pre><output id="postOutput" class="pb">Click "POST Update" to see the response</output></pre>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<div class="mb">
|
|
84
|
+
<h3 class="mt0">Delete User Info</h3>
|
|
85
|
+
<p><code>DELETE /api/user/[id]/[info]</code></p>
|
|
86
|
+
<div class="row -mx">
|
|
87
|
+
<div class="col m-span-12 d-span-6 px">
|
|
88
|
+
<pre><code class="hljs javascript"><span class="hljs-comment">// api/user/[id]/[info]/DELETE.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> result = {<br /> id: id,<br /> message: <span class="hljs-string">'User info deleted successfully'</span>,<br /> deletedAt: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString()<br /> };<br /> <br /> response.json(result);<br />}</code></pre>
|
|
89
|
+
<div class="mb">
|
|
90
|
+
<input type="text" id="deleteUserId" placeholder="Enter user ID" value="charlie" class="mr">
|
|
91
|
+
<button onclick="deleteUserInfo()" class="primary">DELETE Info</button>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
<div class="col m-span-12 d-span-6 px">
|
|
95
|
+
<h4>Response:</h4>
|
|
96
|
+
<pre><output id="deleteOutput" class="pb">Click "DELETE Info" to see the response</output></pre>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<h2>Project Structure Examples</h2>
|
|
102
|
+
|
|
103
|
+
<h3>Basic Blog API</h3>
|
|
104
|
+
<pre><code class="hljs markdown">blog-api/<br />├─ public/ # Web root<br />│ ├─ index.html # Homepage<br />│ ├─ api/<br />│ │ ├─ posts/<br />│ │ │ ├─ GET.js # Get all posts<br />│ │ │ ├─ POST.js # Create new post<br />│ │ │ ├─ [id]/<br />│ │ │ │ ├─ GET.js # Get specific post<br />│ │ │ │ ├─ PUT.js # Update post<br />│ │ │ │ ├─ DELETE.js # Delete post<br />│ │ │ │ ├─ comments/<br />│ │ │ │ │ ├─ GET.js # Get post comments<br />│ │ │ │ │ ├─ POST.js # Add comment<br />│ │ ├─ users/<br />│ │ │ ├─ GET.js # Get all users<br />│ │ │ ├─ POST.js # Create user<br />│ │ │ ├─ [id]/<br />│ │ │ │ ├─ GET.js # Get user profile<br />│ │ │ │ ├─ PUT.js # Update user<br />│ │ │ │ ├─ DELETE.js # Delete user<br />│ │ ├─ auth/<br />│ │ │ ├─ login/<br />│ │ │ │ ├─ POST.js # User login<br />│ │ │ ├─ logout/<br />│ │ │ │ ├─ POST.js # User logout<br />│ │ │ ├─ register/<br />│ │ │ │ ├─ POST.js # User registration<br />├─ middleware/<br />│ ├─ auth.js # Authentication middleware<br />│ ├─ logging.js # Request logging<br />├─ .config.json # Server configuration<br />├─ package.json<br /></code></pre>
|
|
105
|
+
|
|
106
|
+
<h3>E-commerce API</h3>
|
|
107
|
+
<pre><code class="hljs markdown">ecommerce-api/<br />├─ public/<br />│ ├─ api/<br />│ │ ├─ products/<br />│ │ │ ├─ GET.js # Get all products<br />│ │ │ ├─ POST.js # Create product<br />│ │ │ ├─ [id]/<br />│ │ │ │ ├─ GET.js # Get product details<br />│ │ │ │ ├─ PUT.js # Update product<br />│ │ │ │ ├─ DELETE.js # Delete product<br />│ │ │ │ ├─ reviews/<br />│ │ │ │ │ ├─ GET.js # Get product reviews<br />│ │ │ │ │ ├─ POST.js # Add review<br />│ │ │ ├─ categories/<br />│ │ │ │ ├─ [category]/<br />│ │ │ │ │ ├─ GET.js # Get products by category<br />│ │ ├─ cart/<br />│ │ │ ├─ GET.js # Get cart contents<br />│ │ │ ├─ POST.js # Add item to cart<br />│ │ │ ├─ [id]/<br />│ │ │ │ ├─ PUT.js # Update cart item<br />│ │ │ │ ├─ DELETE.js # Remove cart item<br />│ │ ├─ orders/<br />│ │ │ ├─ GET.js # Get user orders<br />│ │ │ ├─ POST.js # Create order<br />│ │ │ ├─ [id]/<br />│ │ │ │ ├─ GET.js # Get order details<br />│ │ │ │ ├─ PUT.js # Update order status<br />│ │ ├─ users/<br />│ │ │ ├─ [id]/<br />│ │ │ │ ├─ profile/<br />│ │ │ │ │ ├─ GET.js # Get user profile<br />│ │ │ │ │ ├─ PUT.js # Update profile<br />│ │ │ │ ├─ addresses/<br />│ │ │ │ │ ├─ GET.js # Get addresses<br />│ │ │ │ │ ├─ POST.js # Add address<br />│ │ │ │ │ ├─ [addressId]/<br />│ │ │ │ │ │ ├─ PUT.js # Update address<br />│ │ │ │ │ │ ├─ DELETE.js # Delete address<br />├─ middleware/<br />│ ├─ auth.js # User authentication<br />│ ├─ admin.js # Admin-only routes<br />│ ├─ cors.js # CORS configuration<br />├─ .config.json<br /></code></pre>
|
|
108
|
+
|
|
109
|
+
<h3>SaaS Application API</h3>
|
|
110
|
+
<pre><code class="hljs markdown">saas-api/<br />├─ public/<br />│ ├─ api/<br />│ │ ├─ auth/<br />│ │ │ ├─ login/<br />│ │ │ ├─ register/<br />│ │ │ ├─ reset-password/<br />│ │ │ ├─ verify-email/<br />│ │ ├─ organizations/<br />│ │ │ ├─ [orgId]/<br />│ │ │ │ ├─ GET.js # Get organization<br />│ │ │ │ ├─ PUT.js # Update organization<br />│ │ │ │ ├─ members/<br />│ │ │ │ │ ├─ GET.js # Get members<br />│ │ │ │ │ ├─ POST.js # Invite member<br />│ │ │ │ │ ├─ [userId]/<br />│ │ │ │ │ │ ├─ PUT.js # Update member role<br />│ │ │ │ │ │ ├─ DELETE.js # Remove member<br />│ │ │ │ ├─ projects/<br />│ │ │ │ │ ├─ GET.js # Get projects<br />│ │ │ │ │ ├─ POST.js # Create project<br />│ │ │ │ │ ├─ [projectId]/<br />│ │ │ │ │ │ ├─ GET.js # Get project<br />│ │ │ │ │ │ ├─ PUT.js # Update project<br />│ │ │ │ │ │ ├─ DELETE.js # Delete project<br />│ │ │ │ │ │ ├─ tasks/<br />│ │ │ │ │ │ │ ├─ GET.js # Get tasks<br />│ │ │ │ │ │ │ ├─ POST.js # Create task<br />│ │ │ │ │ │ │ ├─ [taskId]/<br />│ │ │ │ │ │ │ │ ├─ GET.js # Get task<br />│ │ │ │ │ │ │ │ ├─ PUT.js # Update task<br />│ │ │ │ │ │ │ │ ├─ DELETE.js # Delete task<br />│ │ ├─ billing/<br />│ │ │ ├─ subscriptions/<br />│ │ │ ├─ invoices/<br />│ │ │ ├─ payment-methods/<br />│ │ ├─ analytics/<br />│ │ │ ├─ dashboard/<br />│ │ │ ├─ reports/<br />├─ middleware/<br />│ ├─ auth.js # Authentication<br />│ ├─ organization.js # Organization context<br />│ ├─ permissions.js # Permission checking<br />│ ├─ rate-limit.js # API rate limiting<br />│ ├─ analytics.js # Usage analytics<br />├─ .config.json<br /></code></pre>
|
|
111
|
+
|
|
112
|
+
<h2>Configuration Examples</h2>
|
|
113
|
+
|
|
114
|
+
<h3>Development Configuration</h3>
|
|
115
|
+
<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">"map"</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 /> <span class="hljs-attr">"middleware"</span>: {<br /> <span class="hljs-attr">"cors"</span>: {<br /> <span class="hljs-attr">"enabled"</span>: <span class="hljs-literal">true</span>,<br /> <span class="hljs-attr">"origin"</span>: <span class="hljs-string">"*"</span><br /> },<br /> <span class="hljs-attr">"compression"</span>: {<br /> <span class="hljs-attr">"enabled"</span>: <span class="hljs-literal">false</span><br /> },<br /> <span class="hljs-attr">"custom"</span>: [<br /> <span class="hljs-string">"./middleware/logging.js"</span><br /> ]<br /> }<br />}</code></pre>
|
|
116
|
+
|
|
117
|
+
<h3>Production Configuration</h3>
|
|
118
|
+
<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 /> <span class="hljs-attr">"svg"</span>: <span class="hljs-string">"image/svg+xml"</span>,<br /> <span class="hljs-attr">"woff"</span>: <span class="hljs-string">"font/woff"</span>,<br /> <span class="hljs-attr">"woff2"</span>: <span class="hljs-string">"font/woff2"</span><br /> },<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 /> <span class="hljs-string">"secret"</span>,<br /> <span class="hljs-string">"node_modules"</span>,<br /> <span class="hljs-string">"\\.git"</span>,<br /> <span class="hljs-string">"\\.map$"</span><br /> ],<br /> <span class="hljs-attr">"middleware"</span>: {<br /> <span class="hljs-attr">"cors"</span>: {<br /> <span class="hljs-attr">"enabled"</span>: <span class="hljs-literal">true</span>,<br /> <span class="hljs-attr">"origin"</span>: <span class="hljs-string">"https://yourdomain.com"</span>,<br /> <span class="hljs-attr">"credentials"</span>: <span class="hljs-literal">true</span><br /> },<br /> <span class="hljs-attr">"compression"</span>: {<br /> <span class="hljs-attr">"enabled"</span>: <span class="hljs-literal">true</span>,<br /> <span class="hljs-attr">"threshold"</span>: <span class="hljs-number">1024</span><br /> },<br /> <span class="hljs-attr">"security"</span>: {<br /> <span class="hljs-attr">"enabled"</span>: <span class="hljs-literal">true</span>,<br /> <span class="hljs-attr">"headers"</span>: {<br /> <span class="hljs-attr">"X-Content-Type-Options"</span>: <span class="hljs-string">"nosniff"</span>,<br /> <span class="hljs-attr">"X-Frame-Options"</span>: <span class="hljs-string">"DENY"</span>,<br /> <span class="hljs-attr">"X-XSS-Protection"</span>: <span class="hljs-string">"1; mode=block"</span>,<br /> <span class="hljs-attr">"Strict-Transport-Security"</span>: <span class="hljs-string">"max-age=31536000; includeSubDomains"</span><br /> }<br /> },<br /> <span class="hljs-attr">"rateLimit"</span>: {<br /> <span class="hljs-attr">"enabled"</span>: <span class="hljs-literal">true</span>,<br /> <span class="hljs-attr">"maxRequests"</span>: <span class="hljs-number">100</span>,<br /> <span class="hljs-attr">"windowMs"</span>: <span class="hljs-number">60000</span><br /> },<br /> <span class="hljs-attr">"custom"</span>: [<br /> <span class="hljs-string">"./middleware/auth.js"</span>,<br /> <span class="hljs-string">"./middleware/logging.js"</span>,<br /> <span class="hljs-string">"./middleware/analytics.js"</span><br /> ]<br /> }<br />}</code></pre>
|
|
119
|
+
|
|
120
|
+
<h3>Programmatic File Rescan</h3>
|
|
121
|
+
<p>When your code creates or removes files at runtime (e.g., a CMS generating static pages), you can trigger a file rescan without restarting the server. Import the <code>rescan</code> function from anywhere in the same Node process:</p>
|
|
122
|
+
<pre><code class="hljs javascript"><span class="hljs-comment">// api/pages/POST.js</span><br /><span class="hljs-keyword">import</span> { writeFile } <span class="hljs-keyword">from</span> <span class="hljs-string">'fs/promises'</span>;<br /><span class="hljs-keyword">import</span> rescan <span class="hljs-keyword">from</span> <span class="hljs-string">'kempo-server/rescan'</span>;<br /><br /><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> (req, res) => {<br /> <span class="hljs-keyword">const</span> { slug, html } = req.body;<br /> <span class="hljs-keyword">await</span> writeFile(<span class="hljs-string">`./pages/${slug}.html`</span>, html);<br /> <span class="hljs-keyword">const</span> fileCount = <span class="hljs-keyword">await</span> rescan();<br /> res.json({ published: <span class="hljs-literal">true</span>, fileCount });<br />};</code></pre>
|
|
123
|
+
<p>The <code>rescan()</code> function returns a promise that resolves with the number of files found. It works from route handlers, middleware, file watchers, scheduled tasks, or any other code running in the same Node process.</p>
|
|
124
|
+
|
|
125
|
+
<script>
|
|
126
|
+
async function fetchUser() {
|
|
127
|
+
const userId = document.getElementById('userId').value || 'john';
|
|
128
|
+
const output = document.getElementById('userOutput');
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
output.textContent = 'Loading...';
|
|
132
|
+
const response = await fetch(`/api/user/${userId}`);
|
|
133
|
+
const data = await response.json();
|
|
134
|
+
output.textContent = JSON.stringify(data, null, 2);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
output.textContent = `Error: ${error.message}`;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async function fetchUserInfo() {
|
|
141
|
+
const userId = document.getElementById('userInfoId').value || 'alice';
|
|
142
|
+
const output = document.getElementById('userInfoOutput');
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
output.textContent = 'Loading...';
|
|
146
|
+
const response = await fetch(`/api/user/${userId}/info`);
|
|
147
|
+
const data = await response.json();
|
|
148
|
+
output.textContent = JSON.stringify(data, null, 2);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
output.textContent = `Error: ${error.message}`;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async function updateUserInfo() {
|
|
155
|
+
const userId = document.getElementById('postUserId').value || 'bob';
|
|
156
|
+
const postData = document.getElementById('postData').value;
|
|
157
|
+
const output = document.getElementById('postOutput');
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
output.textContent = 'Loading...';
|
|
161
|
+
const response = await fetch(`/api/user/${userId}/info`, {
|
|
162
|
+
method: 'POST',
|
|
163
|
+
headers: {
|
|
164
|
+
'Content-Type': 'application/json',
|
|
165
|
+
},
|
|
166
|
+
body: postData
|
|
167
|
+
});
|
|
168
|
+
const data = await response.json();
|
|
169
|
+
output.textContent = JSON.stringify(data, null, 2);
|
|
170
|
+
} catch (error) {
|
|
171
|
+
output.textContent = `Error: ${error.message}`;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function deleteUserInfo() {
|
|
176
|
+
const userId = document.getElementById('deleteUserId').value || 'charlie';
|
|
177
|
+
const output = document.getElementById('deleteOutput');
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
output.textContent = 'Loading...';
|
|
181
|
+
const response = await fetch(`/api/user/${userId}/info`, {
|
|
182
|
+
method: 'DELETE'
|
|
183
|
+
});
|
|
184
|
+
const data = await response.json();
|
|
185
|
+
output.textContent = JSON.stringify(data, null, 2);
|
|
186
|
+
} catch (error) {
|
|
187
|
+
output.textContent = `Error: ${error.message}`;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
</script>
|
|
191
|
+
</content>
|
|
192
|
+
</page>
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<page pageName="File System Utilities" title="File System Utilities - Kempo Server">
|
|
2
|
+
<content>
|
|
3
|
+
<p>The file system utilities provide common file and directory operations with Promise-based APIs for Node.js applications.</p>
|
|
4
|
+
|
|
5
|
+
<h2>Installation</h2>
|
|
6
|
+
<p>Import the utilities from the kempo-server package:</p>
|
|
7
|
+
<pre><code class="hljs javascript">import { ensureDir, copyDir, emptyDir } from 'kempo-server/utils/fs-utils';</code></pre>
|
|
8
|
+
|
|
9
|
+
<h2>ensureDir(dirPath)</h2>
|
|
10
|
+
<p>Ensures that a directory exists, creating it and any necessary parent directories if they don't exist. Similar to <code>mkdir -p</code>.</p>
|
|
11
|
+
|
|
12
|
+
<h3>Parameters</h3>
|
|
13
|
+
<ul>
|
|
14
|
+
<li><code>dirPath</code> (string) - The directory path to ensure exists</li>
|
|
15
|
+
</ul>
|
|
16
|
+
|
|
17
|
+
<h3>Returns</h3>
|
|
18
|
+
<p>Promise that resolves when the directory is confirmed to exist.</p>
|
|
19
|
+
|
|
20
|
+
<h3>Example</h3>
|
|
21
|
+
<pre><code class="hljs javascript">import { ensureDir } from 'kempo-server/utils/fs-utils';
|
|
22
|
+
|
|
23
|
+
await ensureDir('./dist/assets');
|
|
24
|
+
await ensureDir('./logs/app');
|
|
25
|
+
// Creates ./dist/assets and ./logs/app directories if they don't exist</code></pre>
|
|
26
|
+
|
|
27
|
+
<h2>copyDir(srcPath, destPath)</h2>
|
|
28
|
+
<p>Recursively copies an entire directory structure from source to destination.</p>
|
|
29
|
+
|
|
30
|
+
<h3>Parameters</h3>
|
|
31
|
+
<ul>
|
|
32
|
+
<li><code>srcPath</code> (string) - The source directory to copy from</li>
|
|
33
|
+
<li><code>destPath</code> (string) - The destination directory to copy to</li>
|
|
34
|
+
</ul>
|
|
35
|
+
|
|
36
|
+
<h3>Returns</h3>
|
|
37
|
+
<p>Promise that resolves when the copy operation is complete.</p>
|
|
38
|
+
|
|
39
|
+
<h3>Example</h3>
|
|
40
|
+
<pre><code class="hljs javascript">import { copyDir } from 'kempo-server/utils/fs-utils';
|
|
41
|
+
|
|
42
|
+
await copyDir('./src/assets', './dist/assets');
|
|
43
|
+
await copyDir('./public', './dist');
|
|
44
|
+
// Copies all files and subdirectories from src to dest</code></pre>
|
|
45
|
+
|
|
46
|
+
<h2>emptyDir(dirPath)</h2>
|
|
47
|
+
<p>Removes all contents of a directory without deleting the directory itself.</p>
|
|
48
|
+
|
|
49
|
+
<h3>Parameters</h3>
|
|
50
|
+
<ul>
|
|
51
|
+
<li><code>dirPath</code> (string) - The directory path to empty</li>
|
|
52
|
+
</ul>
|
|
53
|
+
|
|
54
|
+
<h3>Returns</h3>
|
|
55
|
+
<p>Promise that resolves when the directory has been emptied.</p>
|
|
56
|
+
|
|
57
|
+
<h3>Example</h3>
|
|
58
|
+
<pre><code class="hljs javascript">import { emptyDir } from 'kempo-server/utils/fs-utils';
|
|
59
|
+
|
|
60
|
+
await emptyDir('./dist');
|
|
61
|
+
await emptyDir('./temp');
|
|
62
|
+
// Removes all files and subdirectories inside ./dist and ./temp</code></pre>
|
|
63
|
+
|
|
64
|
+
<h2>Common Use Cases</h2>
|
|
65
|
+
|
|
66
|
+
<h3>Build Script</h3>
|
|
67
|
+
<pre><code class="hljs javascript">import { ensureDir, copyDir, emptyDir } from 'kempo-server/utils/fs-utils';
|
|
68
|
+
|
|
69
|
+
async function buildProject() {
|
|
70
|
+
// Clean previous build
|
|
71
|
+
await emptyDir('./dist');
|
|
72
|
+
|
|
73
|
+
// Ensure build directories exist
|
|
74
|
+
await ensureDir('./dist/assets');
|
|
75
|
+
await ensureDir('./dist/components');
|
|
76
|
+
|
|
77
|
+
// Copy static assets
|
|
78
|
+
await copyDir('./src/assets', './dist/assets');
|
|
79
|
+
await copyDir('./src/public', './dist');
|
|
80
|
+
}</code></pre>
|
|
81
|
+
|
|
82
|
+
<h3>Backup Script</h3>
|
|
83
|
+
<pre><code class="hljs javascript">import { ensureDir, copyDir } from 'kempo-server/utils/fs-utils';
|
|
84
|
+
|
|
85
|
+
async function backupProject() {
|
|
86
|
+
const timestamp = new Date().toISOString().slice(0, 10);
|
|
87
|
+
const backupPath = `./backups/${timestamp}`;
|
|
88
|
+
|
|
89
|
+
await ensureDir(backupPath);
|
|
90
|
+
await copyDir('./src', `${backupPath}/src`);
|
|
91
|
+
await copyDir('./config', `${backupPath}/config`);
|
|
92
|
+
}</code></pre>
|
|
93
|
+
|
|
94
|
+
<h2>Notes</h2>
|
|
95
|
+
<ul>
|
|
96
|
+
<li>All functions use Node.js's Promise-based fs APIs</li>
|
|
97
|
+
<li>Operations are asynchronous and should be awaited</li>
|
|
98
|
+
<li>Functions handle errors appropriately (e.g., ensureDir ignores EEXIST)</li>
|
|
99
|
+
<li>copyDir preserves directory structure recursively</li>
|
|
100
|
+
</ul>
|
|
101
|
+
</content>
|
|
102
|
+
</page>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<page pageName="Getting Started" title="Getting Started - Kempo Server">
|
|
2
|
+
<content>
|
|
3
|
+
<p>Get up and running with Kempo Server in just a few steps.</p>
|
|
4
|
+
|
|
5
|
+
<h2>Installation</h2>
|
|
6
|
+
<p>1. Install the npm package.</p>
|
|
7
|
+
<pre><code>npm install kempo-server</code></pre>
|
|
8
|
+
|
|
9
|
+
<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>
|
|
10
|
+
<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>
|
|
11
|
+
|
|
12
|
+
<p>3. Run it in your terminal.</p>
|
|
13
|
+
<pre><code>npm run start</code></pre>
|
|
14
|
+
|
|
15
|
+
<h2>Basic Project Structure</h2>
|
|
16
|
+
<p>Once installed, create a basic project structure:</p>
|
|
17
|
+
<pre><code class="hljs markdown">my-project/<br />├─ public/ # Your web root<br />│ ├─ index.html # Homepage<br />│ ├─ styles.css # CSS files<br />│ ├─ api/ # API routes<br />│ │ ├─ hello/<br />│ │ │ ├─ GET.js # GET /api/hello/<br />│ │ ├─ users/<br />│ │ │ ├─ GET.js # GET /api/users/<br />│ │ │ ├─ POST.js # POST /api/users/<br />├─ package.json<br />├─ .config.json # Optional configuration<br /></code></pre>
|
|
18
|
+
|
|
19
|
+
<h2>Your First Route</h2>
|
|
20
|
+
<p>Create a simple API endpoint:</p>
|
|
21
|
+
|
|
22
|
+
<h3>1. Create the directory structure</h3>
|
|
23
|
+
<pre><code>mkdir -p public/api/hello</code></pre>
|
|
24
|
+
|
|
25
|
+
<h3>2. Create your first route file</h3>
|
|
26
|
+
<p>Create <code>public/api/hello/GET.js</code>:</p>
|
|
27
|
+
<pre><code class="hljs javascript"><span class="hljs-comment">// public/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, timestamp: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString() });<br />}</code></pre>
|
|
28
|
+
|
|
29
|
+
<h3>3. Test your route</h3>
|
|
30
|
+
<p>Start your server and visit:</p>
|
|
31
|
+
<ul>
|
|
32
|
+
<li><code>http://localhost:3000/api/hello/</code></li>
|
|
33
|
+
<li><code>http://localhost:3000/api/hello/?name=World</code></li>
|
|
34
|
+
</ul>
|
|
35
|
+
|
|
36
|
+
<h2>Command Line Options</h2>
|
|
37
|
+
<p>Kempo Server supports several command line options:</p>
|
|
38
|
+
<ul>
|
|
39
|
+
<li><code>--root <path></code> - Set the document root directory (required)</li>
|
|
40
|
+
<li><code>--port <number></code> - Set the port number (default: 3000)</li>
|
|
41
|
+
<li><code>--host <address></code> - Set the host address (default: localhost)</li>
|
|
42
|
+
<li><code>--config <path></code> - Set the configuration file path (default: .config.json)</li>
|
|
43
|
+
<li><code>--verbose</code> - Enable verbose logging</li>
|
|
44
|
+
</ul>
|
|
45
|
+
|
|
46
|
+
<p>Basic example:</p>
|
|
47
|
+
<pre><code>kempo-server --root public --port 8080 --host 0.0.0.0 --verbose</code></pre>
|
|
48
|
+
|
|
49
|
+
<h3>Configuration File Examples</h3>
|
|
50
|
+
<p>You can specify different configuration files for different environments:</p>
|
|
51
|
+
<pre><code class="hljs bash"># Development<br />kempo-server --root public --config dev.config.json<br /><br /># Staging<br />kempo-server --root public --config staging.config.json<br /><br /># Production with absolute path<br />kempo-server --root public --config /etc/kempo/production.config.json<br /><br /># Mix with other options<br />kempo-server --root dist --port 8080 --config production.config.json</code></pre>
|
|
52
|
+
|
|
53
|
+
<h2>What's Next?</h2>
|
|
54
|
+
<p>Now that you have Kempo Server running, explore these topics:</p>
|
|
55
|
+
<ul>
|
|
56
|
+
<li><a href="routing.html">Learn about Routes & Routing</a> - File-based routing, dynamic routes, and HTML routes</li>
|
|
57
|
+
<li><a href="request-response.html">Request & Response Objects</a> - Working with HTTP requests and responses</li>
|
|
58
|
+
<li><a href="configuration.html">Configuration</a> - Customize server behavior</li>
|
|
59
|
+
<li><a href="middleware.html">Middleware</a> - Add authentication, logging, CORS, and more</li>
|
|
60
|
+
<li><a href="examples.html">Examples & Demos</a> - See real-world examples in action</li>
|
|
61
|
+
</ul>
|
|
62
|
+
</content>
|
|
63
|
+
</page>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<page pageName="Kempo Server" title="Kempo Server">
|
|
2
|
+
<content>
|
|
3
|
+
<div class="ta-center">
|
|
4
|
+
<p class="mb0">
|
|
5
|
+
<a
|
|
6
|
+
href="https://github.com/dustinpoissant/kempo-server"
|
|
7
|
+
class="btn primary mr"
|
|
8
|
+
target="_blank"
|
|
9
|
+
>GitHub</a>
|
|
10
|
+
<a
|
|
11
|
+
href="https://www.npmjs.com/package/kempo-server"
|
|
12
|
+
class="btn"
|
|
13
|
+
target="_blank"
|
|
14
|
+
>NPM</a>
|
|
15
|
+
</p>
|
|
16
|
+
</div>
|
|
17
|
+
<p>A lightweight, zero-dependency, file based routing server.</p>
|
|
18
|
+
|
|
19
|
+
<nav class="b r mb p">
|
|
20
|
+
<div class="row -mx">
|
|
21
|
+
<div class="col m-span-12 d-span-6 px">
|
|
22
|
+
<h4 class="mt0">Getting Started</h4>
|
|
23
|
+
<ul>
|
|
24
|
+
<li><a href="getting-started.html">Getting Started</a></li>
|
|
25
|
+
<li><a href="routing.html">Routing</a></li>
|
|
26
|
+
<li><a href="request-response.html">Request & Response</a></li>
|
|
27
|
+
</ul>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="col m-span-12 d-span-6 px">
|
|
30
|
+
<h4 class="mt0">Advanced Features</h4>
|
|
31
|
+
<ul>
|
|
32
|
+
<li><a href="configuration.html">Configuration</a></li>
|
|
33
|
+
<li><a href="templating.html">Templating</a></li>
|
|
34
|
+
<li><a href="middleware.html">Middleware</a></li>
|
|
35
|
+
<li><a href="caching.html">Module Caching</a></li>
|
|
36
|
+
<li><a href="cli-utils.html">CLI Utilities</a></li>
|
|
37
|
+
<li><a href="fs-utils.html">File System Utilities</a></li>
|
|
38
|
+
<li><a href="examples.html">Examples & Demos</a></li>
|
|
39
|
+
</ul>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</nav>
|
|
43
|
+
|
|
44
|
+
<div class="b r mb p">
|
|
45
|
+
<h3 class="mt0">Quick Start</h3>
|
|
46
|
+
<p>Install and run Kempo Server in seconds:</p>
|
|
47
|
+
<pre><code>npm install kempo-server<br />npx kempo-server --root public</code></pre>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
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>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
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>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</content>
|
|
79
|
+
</page>
|