instaserve 1.1.1 → 1.1.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/README.md CHANGED
@@ -1,12 +1,25 @@
1
1
  <div align="center">
2
2
  <h1 style="color: #3b82f6; margin: 10px 0 5px;">Instaserve</h1>
3
3
  <p style="color: #6b7280; margin: 0;">Instant web stack for Node.js</p>
4
+
5
+ <p>
6
+ <img src="https://img.shields.io/npm/v/instaserve" alt="npm version" />
7
+ <img src="https://img.shields.io/bundlephobia/minzip/instaserve" alt="bundle size" />
8
+ </p>
4
9
  </div>
5
10
 
6
11
  ## Usage
7
12
 
8
13
  <div style="background: white; padding: 15px; border-radius: 6px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); margin: 15px 0;">
9
- <pre style="margin: 0;"><code>npx instaserve [options]</code></pre>
14
+ <pre style="margin: 0;"><code>npx instaserve [options]
15
+ npx instaserve generate-routes</code></pre>
16
+ </div>
17
+
18
+ ## Commands
19
+
20
+ <div style="display: flex; gap: 8px; margin: 8px 0;">
21
+ <code style="background: #f3f4f6; padding: 2px 4px; border-radius: 4px; color: #2563eb;">generate-routes</code>
22
+ <span>Create a sample routes.js file in the current directory</span>
10
23
  </div>
11
24
 
12
25
  ## Options
@@ -65,6 +78,24 @@ The certificate generation script:
65
78
 
66
79
  The routes file (`routes.js` by default) defines your API endpoints. Each route is a function that handles requests to a specific URL path.
67
80
 
81
+ ### Generating a Routes File
82
+
83
+ To create a sample `routes.js` file with example routes and middleware:
84
+
85
+ ```bash
86
+ npx instaserve generate-routes
87
+ ```
88
+
89
+ This creates a `routes.js` file in the current directory with example code. If the file already exists, the command will fail to prevent overwriting.
90
+
91
+ ### Routes File Validation
92
+
93
+ Instaserve validates routes files on startup:
94
+ - If `-api` is specified and the file doesn't exist, the server will fail to start
95
+ - The routes file must export a default object
96
+ - All route handlers must be functions
97
+ - Invalid routes files will cause the server to exit with an error message
98
+
68
99
  ### Basic Route Example
69
100
 
70
101
  ```javascript
package/instaserve CHANGED
@@ -2,10 +2,15 @@
2
2
 
3
3
  import chalk from 'chalk'
4
4
  import fs from 'node:fs'
5
+ import path from 'node:path'
6
+ import { pathToFileURL } from 'node:url'
5
7
 
6
8
  console.log(chalk.cyan('\nInstaserve - Instant Web Stack\n'))
7
9
  console.log(chalk.yellow('Usage:'))
8
- console.log(chalk.green(' npx instaserve [options]\n'))
10
+ console.log(chalk.green(' npx instaserve [options]'))
11
+ console.log(chalk.green(' npx instaserve generate-routes\n'))
12
+ console.log(chalk.yellow('Commands:'))
13
+ console.log(chalk.green(' generate-routes') + ' Create a sample routes.js file in the current directory\n')
9
14
  console.log(chalk.yellow('Options:'))
10
15
  console.log(chalk.green(' -port <number>') + ' Port to listen on (default: 3000)')
11
16
  console.log(chalk.green(' -ip <address>') + ' IP address to bind to (default: 127.0.0.1)')
@@ -18,9 +23,53 @@ if (process.argv.includes('-help')) {
18
23
  process.exit(0)
19
24
  }
20
25
 
26
+ const args = process.argv.slice(2)
27
+
28
+ // Handle generate-routes command
29
+ if (args[0] === 'generate-routes') {
30
+ const routesFile = './routes.js'
31
+ if (fs.existsSync(routesFile)) {
32
+ console.error(chalk.red(`Error: ${routesFile} already exists`))
33
+ process.exit(1)
34
+ }
35
+
36
+ const sampleRoutes = `export default {
37
+ // Middleware functions (prefixed with _) run on every request
38
+ // Return false to continue processing, or a value to use as response
39
+
40
+ // Example: Log all requests
41
+ _log: (req, res, data) => {
42
+ console.log(\`\${req.method} \${req.url}\`)
43
+ return false // Continue to next middleware or route
44
+ },
45
+
46
+ // Example: Basic authentication (commented out)
47
+ // _auth: (req, res, data) => {
48
+ // if (!data.token) {
49
+ // res.writeHead(401)
50
+ // return 'Unauthorized'
51
+ // }
52
+ // return false // Continue if authorized
53
+ // },
54
+
55
+ // Regular route handlers
56
+ hello: (req, res, data) => {
57
+ return { message: 'Hello World' }
58
+ },
59
+
60
+ api: (req, res, data) => {
61
+ return { message: 'API endpoint', data }
62
+ }
63
+ }
64
+ `
65
+
66
+ fs.writeFileSync(routesFile, sampleRoutes)
67
+ console.log(chalk.green(`✓ Created ${routesFile}`))
68
+ process.exit(0)
69
+ }
70
+
21
71
  import server from './module.mjs'
22
72
 
23
- const args = process.argv.slice(2)
24
73
  const params = {}
25
74
  for (let i = 0; i < args.length; i++) {
26
75
  const arg = args[i]
@@ -38,13 +87,39 @@ for (let i = 0; i < args.length; i++) {
38
87
 
39
88
  // Load routes file
40
89
  let routes = {}
41
- const routesFile = params.api || './routes.js'
90
+ const routesFileParam = params.api || './routes.js'
91
+ const routesFileSpecified = !!params.api
92
+
93
+ // Resolve to absolute path from current working directory
94
+ const routesFile = path.isAbsolute(routesFileParam)
95
+ ? routesFileParam
96
+ : path.resolve(process.cwd(), routesFileParam)
97
+
98
+ if (routesFileSpecified && !fs.existsSync(routesFile)) {
99
+ console.error(chalk.red(`Error: Routes file "${routesFileParam}" does not exist`))
100
+ process.exit(1)
101
+ }
102
+
42
103
  if (fs.existsSync(routesFile)) {
43
104
  try {
44
- const imported = await import(routesFile)
105
+ const routesFileURL = pathToFileURL(routesFile).href
106
+ const imported = await import(routesFileURL)
45
107
  routes = imported.default || imported
108
+
109
+ if (!routes || typeof routes !== 'object' || Array.isArray(routes)) {
110
+ console.error(chalk.red(`Error: Routes file "${routesFileParam}" must export a default object`))
111
+ process.exit(1)
112
+ }
113
+
114
+ for (const [key, handler] of Object.entries(routes)) {
115
+ if (typeof handler !== 'function') {
116
+ console.error(chalk.red(`Error: Route "${key}" in "${routesFileParam}" must be a function`))
117
+ process.exit(1)
118
+ }
119
+ }
46
120
  } catch (e) {
47
- console.log(chalk.yellow(`Warning: Could not load routes file ${routesFile}: ${e.message}`))
121
+ console.error(chalk.red(`Error: Could not load routes file "${routesFileParam}": ${e.message}`))
122
+ process.exit(1)
48
123
  }
49
124
  }
50
125
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instaserve",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "Instant web stack",
5
5
  "main": "module.mjs",
6
6
  "bin": "./instaserve",
@@ -9,6 +9,6 @@
9
9
  },
10
10
  "type": "module",
11
11
  "dependencies": {
12
- "chalk": "^5.4.1"
12
+ "chalk": "^5.6.2"
13
13
  }
14
14
  }
package/public/index.html DELETED
@@ -1,209 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>Instaserve</title>
5
- <style>
6
- :root {
7
- --primary: #3b82f6;
8
- --primary-dark: #2563eb;
9
- --text: #1f2937;
10
- --text-light: #6b7280;
11
- --bg: #f9fafb;
12
- }
13
- body {
14
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
15
- line-height: 1.5;
16
- max-width: 800px;
17
- margin: 0 auto;
18
- padding: 20px 15px;
19
- color: var(--text);
20
- background: var(--bg);
21
- }
22
- .header {
23
- text-align: center;
24
- margin-bottom: 20px;
25
- }
26
- .orb {
27
- width: 60px;
28
- height: 60px;
29
- background: radial-gradient(circle at 30% 30%, #60a5fa, var(--primary));
30
- border-radius: 50%;
31
- margin: 0 auto 10px;
32
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
33
- }
34
- h1 {
35
- color: var(--primary);
36
- font-size: 2rem;
37
- margin: 0;
38
- }
39
- .subtitle {
40
- color: var(--text-light);
41
- font-size: 1rem;
42
- margin: 5px 0;
43
- }
44
- h2 {
45
- color: var(--text);
46
- font-size: 1.3rem;
47
- margin: 20px 0 10px;
48
- padding-bottom: 5px;
49
- border-bottom: 2px solid var(--primary);
50
- }
51
- h3 {
52
- color: var(--text);
53
- font-size: 1.1rem;
54
- margin: 15px 0 8px;
55
- }
56
- code {
57
- background: #f3f4f6;
58
- padding: 2px 4px;
59
- border-radius: 4px;
60
- font-family: 'SF Mono', Menlo, monospace;
61
- color: var(--primary-dark);
62
- }
63
- pre {
64
- background: #f3f4f6;
65
- padding: 10px;
66
- border-radius: 6px;
67
- overflow-x: auto;
68
- border: 1px solid #e5e7eb;
69
- margin: 10px 0;
70
- font-size: 0.9rem;
71
- }
72
- .option {
73
- margin: 8px 0;
74
- padding-left: 0;
75
- position: relative;
76
- display: flex;
77
- gap: 8px;
78
- }
79
- .option:before {
80
- display: none;
81
- }
82
- .option code {
83
- flex-shrink: 0;
84
- }
85
- ul {
86
- padding-left: 15px;
87
- margin: 8px 0;
88
- }
89
- li {
90
- margin: 5px 0;
91
- }
92
- .usage {
93
- background: white;
94
- padding: 15px;
95
- border-radius: 6px;
96
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
97
- margin: 15px 0;
98
- }
99
- p {
100
- margin: 8px 0;
101
- }
102
- </style>
103
- </head>
104
- <body>
105
- <div class="header">
106
- <div class="orb"></div>
107
- <h1>Instaserve</h1>
108
- <p class="subtitle">Instant web stack for Node.js</p>
109
- </div>
110
-
111
- <div class="usage">
112
- <h2>Usage</h2>
113
- <pre><code>npx instaserve [options]</code></pre>
114
- </div>
115
-
116
- <h2>Options</h2>
117
- <div class="option"><code>-port &lt;number&gt;</code> - Port to listen on (default: 3000)</div>
118
- <div class="option"><code>-ip &lt;address&gt;</code> - IP address to bind to (default: 127.0.0.1)</div>
119
- <div class="option"><code>-public &lt;path&gt;</code> - Public directory path (default: ./public)</div>
120
- <div class="option"><code>-api &lt;file&gt;</code> - Path to routes file (default: ./routes.js)</div>
121
- <div class="option"><code>-secure</code> - Enable HTTPS (requires cert.pem and key.pem - run ./generate-certs.sh)</div>
122
- <div class="option"><code>-help</code> - Show help message</div>
123
-
124
- <h2>HTTPS Support</h2>
125
- <p>Instaserve supports HTTPS with self-signed certificates. To enable HTTPS:</p>
126
- <ol>
127
- <li><strong>Generate certificates:</strong> <code>./generate-certs.sh</code></li>
128
- <li><strong>Run with HTTPS:</strong> <code>npx instaserve -secure</code></li>
129
- </ol>
130
- <p>The certificate generation script creates trusted certificates that won't show browser warnings.</p>
131
-
132
- <h2>Routes</h2>
133
- <p>The routes file (<code>routes.js</code> by default) defines your API endpoints. Each route is a function that handles requests to a specific URL path.</p>
134
-
135
- <h3>Basic Route Example</h3>
136
- <pre><code>export default {
137
- // Handle GET /hello
138
- hello: (req, res, data) => {
139
- return { message: 'Hello World' }
140
- }
141
- }</code></pre>
142
-
143
- <h3>Special Routes (Middleware)</h3>
144
- <p>Routes starting with <code>_</code> are middleware functions that run on <strong>every request</strong> before the main route handler. They are useful for:</p>
145
- <ul>
146
- <li>Logging requests</li>
147
- <li>Authentication</li>
148
- <li>Request modification</li>
149
- <li>Response headers</li>
150
- </ul>
151
- <p>Middleware functions can:</p>
152
- <ul>
153
- <li>Return <code>false</code> to continue to the next middleware or main route</li>
154
- <li>Return a truthy value to stop processing and use that as the response</li>
155
- <li>Modify the request or response objects</li>
156
- </ul>
157
-
158
- <h4>Middleware Example</h4>
159
- <pre><code>export default {
160
- // Log every request
161
- _log: (req, res, data) => {
162
- console.log(`${req.method} ${req.url}`)
163
- return false // Continue processing
164
- },
165
-
166
- // Block unauthorized requests
167
- _auth: (req, res, data) => {
168
- if (!data.token) {
169
- res.writeHead(401)
170
- return 'Unauthorized'
171
- }
172
- return false // Continue if authorized
173
- }
174
- }</code></pre>
175
-
176
- <h3>Route Parameters</h3>
177
- <p>Each route function receives:</p>
178
- <ul>
179
- <li><code>req</code> - The HTTP request object</li>
180
- <li><code>res</code> - The HTTP response object</li>
181
- <li><code>data</code> - Combined data from:
182
- <ul>
183
- <li>POST body (if JSON)</li>
184
- <li>URL query parameters</li>
185
- <li>Form data</li>
186
- </ul>
187
- </li>
188
- </ul>
189
-
190
- <h3>Example Routes File</h3>
191
- <pre><code>export default {
192
- // Middleware example
193
- _debug: (req, res, data) => {
194
- console.log('Request:', req.url)
195
- return false // Continue to next route
196
- },
197
-
198
- // API endpoint
199
- api: (req, res, data) => {
200
- return { status: 'ok', data }
201
- },
202
-
203
- // Error handling
204
- testerror: () => {
205
- throw new Error('Test error')
206
- }
207
- }</code></pre>
208
- </body>
209
- </html>
File without changes