@tknf/matchbox 0.3.0 → 0.3.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/README.md +212 -46
- package/dist/cgi.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,29 +1,36 @@
|
|
|
1
1
|
# Matchbox
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A modern CGI-style web framework built on [Hono](https://hono.dev). Brings Apache-style conventions (`.htaccess`, `.htpasswd`) into the modern TypeScript/JSX ecosystem with file-based routing and familiar CGI variables.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- File-based routing
|
|
8
|
-
- CGI-style context
|
|
9
|
-
- `.htaccess` rewrites/redirects
|
|
10
|
-
-
|
|
11
|
-
-
|
|
7
|
+
- **File-based routing** - `.cgi.tsx`/`.cgi.jsx` files map directly to URL endpoints
|
|
8
|
+
- **CGI-style context** - Familiar `$_GET`, `$_POST`, `$_SESSION`, `$_SERVER`, `$_COOKIE`, etc.
|
|
9
|
+
- **Apache compatibility** - `.htaccess` for rewrites/redirects/headers, `.htpasswd` for Basic Auth
|
|
10
|
+
- **Modern tooling** - Full TypeScript support, Vite integration, JSX rendering
|
|
11
|
+
- **Flexible configuration** - Session management, custom middleware, security headers
|
|
12
|
+
- **Production ready** - Comprehensive test coverage, security best practices
|
|
12
13
|
|
|
13
|
-
##
|
|
14
|
+
## Installation
|
|
14
15
|
|
|
15
16
|
```bash
|
|
16
|
-
|
|
17
|
+
npm add @tknf/matchbox hono
|
|
18
|
+
# or
|
|
19
|
+
pnpm add @tknf/matchbox hono
|
|
20
|
+
# or
|
|
21
|
+
yarn add @tknf/matchbox hono
|
|
17
22
|
```
|
|
18
23
|
|
|
19
24
|
## Quick Start
|
|
20
25
|
|
|
21
|
-
|
|
26
|
+
### 1. Configure Vite
|
|
22
27
|
|
|
23
|
-
|
|
28
|
+
Create `vite.config.ts`:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
24
31
|
import devServer from "@hono/vite-dev-server";
|
|
25
32
|
import { defineConfig } from "vite";
|
|
26
|
-
import { MatchboxPlugin } from "matchbox/plugin";
|
|
33
|
+
import { MatchboxPlugin } from "@tknf/matchbox/plugin";
|
|
27
34
|
|
|
28
35
|
export default defineConfig({
|
|
29
36
|
plugins: [
|
|
@@ -36,98 +43,257 @@ export default defineConfig({
|
|
|
36
43
|
});
|
|
37
44
|
```
|
|
38
45
|
|
|
39
|
-
|
|
46
|
+
### 2. Create Server Entry
|
|
47
|
+
|
|
48
|
+
Create `server.ts`:
|
|
40
49
|
|
|
41
|
-
```
|
|
42
|
-
import { createCgi } from "matchbox";
|
|
50
|
+
```typescript
|
|
51
|
+
import { createCgi } from "@tknf/matchbox";
|
|
43
52
|
|
|
44
53
|
export default createCgi();
|
|
45
54
|
```
|
|
46
55
|
|
|
47
|
-
|
|
56
|
+
### 3. Create Your First Page
|
|
57
|
+
|
|
58
|
+
Create `public/index.cgi.tsx`:
|
|
48
59
|
|
|
49
60
|
```tsx
|
|
50
|
-
import type { CgiContext } from "matchbox";
|
|
61
|
+
import type { CgiContext } from "@tknf/matchbox";
|
|
51
62
|
|
|
52
|
-
export default function ({ $_SERVER }: CgiContext) {
|
|
63
|
+
export default function ({ $_SERVER, $_GET }: CgiContext) {
|
|
53
64
|
return (
|
|
54
65
|
<html>
|
|
55
66
|
<head>
|
|
56
67
|
<title>Matchbox</title>
|
|
57
68
|
</head>
|
|
58
69
|
<body>
|
|
59
|
-
<h1>Hello Matchbox
|
|
60
|
-
<p>Method: {$_SERVER.REQUEST_METHOD}</p>
|
|
70
|
+
<h1>Hello from Matchbox!</h1>
|
|
71
|
+
<p>Request Method: {$_SERVER.REQUEST_METHOD}</p>
|
|
72
|
+
<p>Query Params: {JSON.stringify($_GET)}</p>
|
|
61
73
|
</body>
|
|
62
74
|
</html>
|
|
63
75
|
);
|
|
64
76
|
}
|
|
65
77
|
```
|
|
66
78
|
|
|
67
|
-
Start
|
|
79
|
+
### 4. Start Development Server
|
|
68
80
|
|
|
69
81
|
```bash
|
|
70
|
-
|
|
82
|
+
npm run dev
|
|
71
83
|
```
|
|
72
84
|
|
|
85
|
+
Visit `http://localhost:5173` to see your page.
|
|
86
|
+
|
|
73
87
|
## CGI Context
|
|
74
88
|
|
|
75
|
-
|
|
89
|
+
Every page function receives a `CgiContext` object with:
|
|
90
|
+
|
|
91
|
+
### Request Data
|
|
92
|
+
|
|
93
|
+
- `$_GET` - Query parameters
|
|
94
|
+
- `$_POST` - Form data (POST/PUT)
|
|
95
|
+
- `$_FILES` - Uploaded files
|
|
96
|
+
- `$_REQUEST` - Combined `$_GET` + `$_POST` + `$_COOKIE`
|
|
97
|
+
- `$_COOKIE` - Cookie values
|
|
98
|
+
- `$_SERVER` - Server and request information
|
|
99
|
+
- `$_ENV` - Environment variables
|
|
100
|
+
- `$_SESSION` - Session data
|
|
101
|
+
|
|
102
|
+
### Helper Functions
|
|
76
103
|
|
|
77
|
-
-
|
|
78
|
-
-
|
|
79
|
-
- `
|
|
80
|
-
- `cgiinfo()`
|
|
104
|
+
- `header(name, value)` - Set response header
|
|
105
|
+
- `status(code)` - Set HTTP status code
|
|
106
|
+
- `redirect(url, status?)` - Redirect to another URL
|
|
107
|
+
- `cgiinfo()` - HTML debug info block
|
|
108
|
+
- `get_modules()` - List all available CGI modules
|
|
109
|
+
- `get_version()` - Get Matchbox version string
|
|
110
|
+
- `log(message)` - Custom logging
|
|
111
|
+
- `request_headers()` - Get all request headers
|
|
112
|
+
- `response_headers()` - Get current response headers
|
|
113
|
+
|
|
114
|
+
### Example Usage
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
export default function (ctx: CgiContext) {
|
|
118
|
+
const { $_GET, $_POST, $_SESSION, header, status, redirect } = ctx;
|
|
119
|
+
|
|
120
|
+
// Handle form submission
|
|
121
|
+
if ($_POST.username) {
|
|
122
|
+
$_SESSION.user = $_POST.username;
|
|
123
|
+
return redirect("/dashboard");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Set custom headers
|
|
127
|
+
header("X-Custom-Header", "value");
|
|
128
|
+
status(200);
|
|
129
|
+
|
|
130
|
+
return <div>Welcome</div>;
|
|
131
|
+
}
|
|
132
|
+
```
|
|
81
133
|
|
|
82
134
|
## Configuration
|
|
83
135
|
|
|
84
|
-
###
|
|
136
|
+
### Plugin Options
|
|
85
137
|
|
|
86
|
-
```
|
|
138
|
+
```typescript
|
|
87
139
|
MatchboxPlugin({
|
|
88
|
-
publicDir: "public",
|
|
89
|
-
config: {
|
|
140
|
+
publicDir: "public", // Directory for .cgi files (default: "public")
|
|
141
|
+
config: { // Custom config object injected into pages
|
|
142
|
+
siteName: "My Site",
|
|
143
|
+
apiUrl: "https://api.example.com"
|
|
144
|
+
}
|
|
90
145
|
});
|
|
91
146
|
```
|
|
92
147
|
|
|
93
|
-
|
|
94
|
-
- `config`: Configuration object injected into pages
|
|
148
|
+
Access config in your pages via `context.config`.
|
|
95
149
|
|
|
96
|
-
###
|
|
150
|
+
### Runtime Options
|
|
97
151
|
|
|
98
|
-
```
|
|
152
|
+
```typescript
|
|
99
153
|
createCgi({
|
|
154
|
+
// Session cookie configuration
|
|
100
155
|
sessionCookie: {
|
|
101
|
-
name: "_SESSION_ID",
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
156
|
+
name: "_SESSION_ID", // Cookie name (default: "_SESSION_ID")
|
|
157
|
+
path: "/", // Cookie path (default: "/")
|
|
158
|
+
domain: "example.com", // Cookie domain
|
|
159
|
+
secure: true, // HTTPS only (default: false)
|
|
160
|
+
sameSite: "Strict", // CSRF protection: "Strict" | "Lax" | "None"
|
|
161
|
+
maxAge: 3600, // Session timeout in seconds
|
|
105
162
|
},
|
|
163
|
+
|
|
164
|
+
// URL trailing slash enforcement
|
|
106
165
|
enforceTrailingSlash: true,
|
|
166
|
+
|
|
167
|
+
// Custom middleware (runs before page handlers)
|
|
107
168
|
middleware: [
|
|
108
169
|
async (c, next) => {
|
|
109
170
|
c.header("X-App", "matchbox");
|
|
110
171
|
await next();
|
|
111
172
|
},
|
|
112
173
|
],
|
|
174
|
+
|
|
175
|
+
// Custom logger
|
|
113
176
|
logger: (message, level) => {
|
|
114
177
|
console.log(`[${level ?? "info"}] ${message}`);
|
|
115
178
|
},
|
|
116
179
|
});
|
|
117
180
|
```
|
|
118
181
|
|
|
119
|
-
##
|
|
182
|
+
## Apache-Style Features
|
|
183
|
+
|
|
184
|
+
### Basic Authentication (.htpasswd)
|
|
185
|
+
|
|
186
|
+
Place a `.htpasswd` file in any directory under `public/` to protect it:
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
# Generate with: htpasswd -c .htpasswd username
|
|
190
|
+
admin:$apr1$abc123$...
|
|
191
|
+
user:$apr1$xyz789$...
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
All files in that directory and subdirectories will require authentication.
|
|
195
|
+
|
|
196
|
+
### URL Rewriting and Redirects (.htaccess)
|
|
197
|
+
|
|
198
|
+
Create `.htaccess` files to configure rewrites, redirects, headers, and error pages:
|
|
199
|
+
|
|
200
|
+
```apache
|
|
201
|
+
# Permanent redirect
|
|
202
|
+
Redirect 301 /old-page /new-page
|
|
120
203
|
|
|
121
|
-
|
|
204
|
+
# Conditional rewrite
|
|
205
|
+
RewriteCond %{HTTP_HOST} ^www\.example\.com$
|
|
206
|
+
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]
|
|
122
207
|
|
|
123
|
-
|
|
124
|
-
|
|
208
|
+
# Pattern-based rewrite
|
|
209
|
+
RewriteRule ^blog/(.+)$ /posts.cgi?slug=$1 [QSA,L]
|
|
125
210
|
|
|
126
|
-
|
|
211
|
+
# Forbidden
|
|
212
|
+
RewriteRule ^private$ - [F]
|
|
127
213
|
|
|
128
|
-
|
|
129
|
-
-
|
|
214
|
+
# Security headers
|
|
215
|
+
Header set X-Frame-Options "SAMEORIGIN"
|
|
216
|
+
Header set X-Content-Type-Options "nosniff"
|
|
217
|
+
Header set Strict-Transport-Security "max-age=31536000"
|
|
218
|
+
|
|
219
|
+
# Custom error pages
|
|
220
|
+
ErrorDocument 404 /errors/404.html
|
|
221
|
+
ErrorDocument 500 /errors/500.html
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
#### Supported RewriteRule Flags
|
|
225
|
+
|
|
226
|
+
- `[L]` - Last rule, stop processing
|
|
227
|
+
- `[R]` / `[R=301]` / `[R=302]` - Redirect with status code
|
|
228
|
+
- `[F]` - Forbidden (403)
|
|
229
|
+
- `[G]` - Gone (410)
|
|
230
|
+
- `[NC]` - No Case (case-insensitive)
|
|
231
|
+
- `[QSA]` - Query String Append
|
|
232
|
+
- `[QSD]` - Query String Discard
|
|
233
|
+
- `[NE]` - No Escape
|
|
234
|
+
|
|
235
|
+
#### Supported RewriteCond Variables
|
|
236
|
+
|
|
237
|
+
- `%{HTTP_HOST}` - Request host
|
|
238
|
+
- `%{HTTP_USER_AGENT}` - User agent
|
|
239
|
+
- `%{HTTP_REFERER}` - Referer header
|
|
240
|
+
- `%{REQUEST_URI}` - Request URI
|
|
241
|
+
- `%{REQUEST_METHOD}` - HTTP method
|
|
242
|
+
- `%{QUERY_STRING}` - Query string
|
|
243
|
+
- `%{REMOTE_ADDR}` - Client IP
|
|
244
|
+
- And more... (see [documentation](./docs/htaccess.md))
|
|
245
|
+
|
|
246
|
+
## Examples
|
|
247
|
+
|
|
248
|
+
Check out the [`examples/`](./examples) directory for complete working examples:
|
|
249
|
+
|
|
250
|
+
- **basic** - Minimal setup with a simple page
|
|
251
|
+
- **htaccess-auth** - Authentication and URL rewriting
|
|
252
|
+
- **custom-middleware** - Custom middleware and logging
|
|
253
|
+
|
|
254
|
+
## Documentation
|
|
255
|
+
|
|
256
|
+
- [Apache .htaccess Features](./docs/htaccess.md) - Complete `.htaccess` feature reference
|
|
257
|
+
- [Security Guide](./docs/security.md) - Security best practices
|
|
258
|
+
- [API Reference](./docs/api.md) - Complete API documentation
|
|
259
|
+
- [Roadmap](./docs/roadmap.md) - Planned features and improvements
|
|
260
|
+
|
|
261
|
+
## Migration from v0.2.x
|
|
262
|
+
|
|
263
|
+
Version 0.3.0 introduced enhanced `.htaccess` parsing. If you're upgrading:
|
|
264
|
+
|
|
265
|
+
- ✅ Existing `.htaccess` files work without changes
|
|
266
|
+
- ✅ Both `[R=301]` and `R=301` flag syntaxes are supported
|
|
267
|
+
- ⚠️ Malformed directives now throw errors (previously silently ignored)
|
|
268
|
+
|
|
269
|
+
See the [migration guide](./docs/htaccess.md#migration-from-v02x-to-v03) for details.
|
|
270
|
+
|
|
271
|
+
## Development
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
# Install dependencies
|
|
275
|
+
pnpm install
|
|
276
|
+
|
|
277
|
+
# Run tests
|
|
278
|
+
pnpm test
|
|
279
|
+
|
|
280
|
+
# Build
|
|
281
|
+
pnpm run build
|
|
282
|
+
|
|
283
|
+
# Type check
|
|
284
|
+
pnpm run typecheck
|
|
285
|
+
```
|
|
130
286
|
|
|
131
287
|
## License
|
|
132
288
|
|
|
133
|
-
MIT License
|
|
289
|
+
MIT License - see [LICENSE](./LICENSE) for details.
|
|
290
|
+
|
|
291
|
+
## Contributing
|
|
292
|
+
|
|
293
|
+
Contributions are welcome! Please read the [contributing guidelines](./CONTRIBUTING.md) before submitting PRs.
|
|
294
|
+
|
|
295
|
+
## Links
|
|
296
|
+
|
|
297
|
+
- [GitHub Repository](https://github.com/tknf-labs/matchbox)
|
|
298
|
+
- [NPM Package](https://www.npmjs.com/package/@tknf/matchbox)
|
|
299
|
+
- [Hono Framework](https://hono.dev)
|
package/dist/cgi.js
CHANGED
|
@@ -118,7 +118,7 @@ const createCgiWithPages = (pages, siteConfig = {}, authMap = {}, htaccessConfig
|
|
|
118
118
|
}
|
|
119
119
|
},
|
|
120
120
|
get_version: () => {
|
|
121
|
-
return `MatchboxCGI/v${"0.3.
|
|
121
|
+
return `MatchboxCGI/v${"0.3.1"}`;
|
|
122
122
|
},
|
|
123
123
|
/**
|
|
124
124
|
* Returns information about all loaded CGI modules
|