@tknf/matchbox 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/cgi.d.ts +10 -21
  2. package/dist/cgi.js +26 -97
  3. package/dist/htaccess/access-control.d.ts +9 -0
  4. package/dist/htaccess/access-control.js +91 -0
  5. package/dist/htaccess/error-document.d.ts +9 -0
  6. package/dist/htaccess/error-document.js +16 -0
  7. package/dist/htaccess/headers.d.ts +32 -0
  8. package/dist/htaccess/headers.js +98 -0
  9. package/dist/htaccess/index.d.ts +8 -0
  10. package/dist/htaccess/index.js +20 -0
  11. package/dist/htaccess/parser.d.ts +9 -0
  12. package/dist/htaccess/parser.js +365 -0
  13. package/dist/htaccess/rewrite.d.ts +13 -0
  14. package/dist/htaccess/rewrite.js +69 -0
  15. package/dist/htaccess/types.d.ts +156 -0
  16. package/dist/htaccess/types.js +0 -0
  17. package/dist/htaccess/utils.d.ts +21 -0
  18. package/dist/htaccess/utils.js +69 -0
  19. package/dist/html.d.ts +1 -0
  20. package/dist/index.d.ts +3 -0
  21. package/dist/index.js +5 -1
  22. package/dist/middleware/auth.d.ts +8 -0
  23. package/dist/middleware/auth.js +28 -0
  24. package/dist/middleware/htaccess.d.ts +13 -0
  25. package/dist/middleware/htaccess.js +42 -0
  26. package/dist/middleware/index.d.ts +10 -0
  27. package/dist/middleware/index.js +14 -0
  28. package/dist/middleware/protected-files.d.ts +8 -0
  29. package/dist/middleware/protected-files.js +14 -0
  30. package/dist/middleware/session.d.ts +16 -0
  31. package/dist/middleware/session.js +37 -0
  32. package/dist/middleware/trailing-slash.d.ts +8 -0
  33. package/dist/middleware/trailing-slash.js +12 -0
  34. package/dist/plugin.js +1 -1
  35. package/dist/with-defaults.d.ts +2 -1
  36. package/dist/with-defaults.js +17 -28
  37. package/package.json +1 -1
package/dist/cgi.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import * as hono_types from 'hono/types';
2
2
  import { Context, Hono } from 'hono';
3
3
  import { HtmlEscapedString } from 'hono/utils/html';
4
+ import { HtaccessConfig } from './htaccess/types.js';
4
5
 
5
- type ConfigObject = Record<string, any>;
6
+ type ConfigObject = Record<string, unknown>;
6
7
  /**
7
8
  * --- Session Cookie Configuration ---
8
9
  */
@@ -49,10 +50,10 @@ interface CgiContext<ConfigType = ConfigObject> {
49
50
  $_GET: Record<string, string>;
50
51
  $_POST: Record<string, string>;
51
52
  $_FILES: Record<string, File | File[]>;
52
- $_REQUEST: Record<string, any>;
53
- $_SESSION: Record<string, any>;
53
+ $_REQUEST: Record<string, unknown>;
54
+ $_SESSION: Record<string, unknown>;
54
55
  $_COOKIE: Record<string, string>;
55
- $_ENV: Record<string, string | undefined>;
56
+ $_ENV: Record<string, unknown>;
56
57
  $_SERVER: {
57
58
  REQUEST_METHOD: string;
58
59
  REQUEST_URI: string;
@@ -61,7 +62,7 @@ interface CgiContext<ConfigType = ConfigObject> {
61
62
  SCRIPT_NAME: string;
62
63
  PATH_INFO: string;
63
64
  QUERY_STRING: string;
64
- [key: string]: any;
65
+ [key: string]: unknown;
65
66
  };
66
67
  config: ConfigType;
67
68
  c: Context;
@@ -83,24 +84,12 @@ interface CgiContext<ConfigType = ConfigObject> {
83
84
  type Page = {
84
85
  urlPath: string;
85
86
  dirPath: string | null;
86
- component: (context: CgiContext) => any | Promise<any>;
87
+ component: (context: CgiContext) => unknown | Promise<unknown>;
87
88
  };
88
- type RedirectRule = {
89
- type: "redirect";
90
- code: string;
91
- source: string;
92
- target: string;
93
- };
94
- type RewriteRule = {
95
- type: "rewrite";
96
- pattern: string;
97
- target: string;
98
- flags: string;
99
- };
100
- type RewriteMap = Record<string, Array<RedirectRule | RewriteRule>>;
89
+
101
90
  /**
102
91
  * --- Matchbox Runtime Engine ---
103
92
  */
104
- declare const createCgiWithPages: (pages: Page[], siteConfig?: ConfigObject, authMap?: Record<string, string>, rewriteMap?: RewriteMap, options?: MatchboxOptions) => Hono<hono_types.BlankEnv, hono_types.BlankSchema, "/">;
93
+ declare const createCgiWithPages: (pages: Page[], siteConfig?: ConfigObject, authMap?: Record<string, string>, htaccessConfig?: HtaccessConfig, options?: MatchboxOptions) => Hono<hono_types.BlankEnv, hono_types.BlankSchema, "/">;
105
94
 
106
- export { type CgiContext, type ConfigObject, type MatchboxOptions, type ModuleInfo, type Page, type RewriteMap, type SessionCookieOptions, createCgiWithPages };
95
+ export { type CgiContext, type ConfigObject, HtaccessConfig, type MatchboxOptions, type ModuleInfo, type Page, type SessionCookieOptions, createCgiWithPages };
package/dist/cgi.js CHANGED
@@ -1,13 +1,20 @@
1
1
  import { Hono } from "hono";
2
- import { basicAuth } from "hono/basic-auth";
3
- import { getCookie, setCookie } from "hono/cookie";
2
+ import { getCookie } from "hono/cookie";
4
3
  import { generateCgiError, generateCgiInfo } from "./html.js";
4
+ import {
5
+ applyBasicAuth,
6
+ applyHtaccessMiddleware,
7
+ applyErrorDocumentMiddleware,
8
+ getSessionFromCookie,
9
+ saveSessionToCookie,
10
+ applyProtectedFilesMiddleware,
11
+ applyTrailingSlashMiddleware
12
+ } from "./middleware/index.js";
5
13
  const isRedirectObject = (obj) => {
6
- return obj && obj.__type === "redirect" && typeof obj.url === "string";
14
+ return typeof obj === "object" && obj !== null && "__type" in obj && obj.__type === "redirect" && "url" in obj && typeof obj.url === "string";
7
15
  };
8
- const createCgiWithPages = (pages, siteConfig = {}, authMap = {}, rewriteMap = {}, options = {}) => {
16
+ const createCgiWithPages = (pages, siteConfig = {}, authMap = {}, htaccessConfig = {}, options = {}) => {
9
17
  const app = new Hono();
10
- const SESS_KEY = options.sessionCookie?.name || "_SESSION_ID";
11
18
  if (options.middleware && options.middleware.length > 0) {
12
19
  for (const mw of options.middleware) {
13
20
  app.use("*", async (c, next) => {
@@ -18,66 +25,12 @@ const createCgiWithPages = (pages, siteConfig = {}, authMap = {}, rewriteMap = {
18
25
  });
19
26
  }
20
27
  }
21
- const protectedFiles = [".htaccess", ".htpasswd", ".htdigest", ".htgroup"];
22
- app.use("*", async (c, next) => {
23
- const path = c.req.path;
24
- const lastSegment = path.slice(path.lastIndexOf("/") + 1);
25
- if (protectedFiles.some((file) => lastSegment === file)) {
26
- return c.text("Forbidden", 403);
27
- }
28
- await next();
29
- });
28
+ applyProtectedFilesMiddleware(app);
30
29
  if (options.enforceTrailingSlash) {
31
- app.use("*", async (c, next) => {
32
- const path = c.req.path;
33
- if (!path.endsWith("/") && !path.includes(".")) {
34
- return c.redirect(`${path}/`, 301);
35
- }
36
- await next();
37
- });
30
+ applyTrailingSlashMiddleware(app);
38
31
  }
39
- Object.entries(rewriteMap).forEach(([dir, rules]) => {
40
- const basePath = dir === "/" ? "" : dir.replace(/\/$/, "");
41
- app.use(`${basePath}/*`, async (c, next) => {
42
- const relPath = c.req.path.replace(basePath, "") || "/";
43
- for (const rule of rules) {
44
- if (rule.type === "redirect") {
45
- if (relPath === rule.source) {
46
- return c.redirect(
47
- rule.target,
48
- Number.parseInt(rule.code, 10) || 302
49
- );
50
- }
51
- } else if (rule.type === "rewrite") {
52
- const regex = new RegExp(rule.pattern);
53
- if (regex.test(relPath)) {
54
- const target = rule.target.startsWith("/") ? rule.target : `${basePath}/${rule.target}`;
55
- if (rule.flags.includes("R")) {
56
- const code = rule.flags.match(/R=(\d+)/)?.[1] || "302";
57
- return c.redirect(target, Number.parseInt(code, 10));
58
- }
59
- }
60
- }
61
- }
62
- await next();
63
- });
64
- });
65
- Object.entries(authMap).forEach(([dir, content]) => {
66
- const credentials = content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => {
67
- const [username, password] = line.split(":");
68
- return { username, password };
69
- });
70
- if (credentials.length > 0) {
71
- const authPath = dir === "/" ? "*" : `${dir.replace(/\/$/, "")}/*`;
72
- app.use(authPath, async (c, next) => {
73
- const handler = basicAuth({
74
- verifyUser: (u, p) => credentials.some((cred) => cred.username === u && cred.password === p),
75
- realm: "Restricted Area"
76
- });
77
- return handler(c, next);
78
- });
79
- }
80
- });
32
+ applyHtaccessMiddleware(app, htaccessConfig);
33
+ applyBasicAuth(app, authMap);
81
34
  pages.forEach(({ urlPath, dirPath, component }) => {
82
35
  const routes = [urlPath, `${urlPath}/*`];
83
36
  if (dirPath) {
@@ -96,7 +49,7 @@ const createCgiWithPages = (pages, siteConfig = {}, authMap = {}, rewriteMap = {
96
49
  if (value instanceof File || Array.isArray(value) && value[0] instanceof File) {
97
50
  $_FILES[key] = value;
98
51
  } else {
99
- $_POST[key] = value;
52
+ $_POST[key] = String(value);
100
53
  }
101
54
  }
102
55
  const $_COOKIE = getCookie(c);
@@ -106,14 +59,10 @@ const createCgiWithPages = (pages, siteConfig = {}, authMap = {}, rewriteMap = {
106
59
  ...$_POST
107
60
  };
108
61
  const $_ENV = typeof process !== "undefined" && process.env ? process.env : c.env || {};
109
- let $_SESSION = {};
110
- const sRaw = getCookie(c, SESS_KEY);
111
- if (sRaw) {
112
- try {
113
- $_SESSION = JSON.parse(decodeURIComponent(sRaw));
114
- } catch {
115
- }
116
- }
62
+ let $_SESSION = getSessionFromCookie(
63
+ c,
64
+ options.sessionCookie?.name
65
+ );
117
66
  let responseStatus = 200;
118
67
  const responseHeaders = {
119
68
  "Content-Type": "text/html; charset=utf-8"
@@ -169,7 +118,7 @@ const createCgiWithPages = (pages, siteConfig = {}, authMap = {}, rewriteMap = {
169
118
  }
170
119
  },
171
120
  get_version: () => {
172
- return `MatchboxCGI/v${"0.2.5"}`;
121
+ return `MatchboxCGI/v${"0.3.0"}`;
173
122
  },
174
123
  /**
175
124
  * Returns information about all loaded CGI modules
@@ -184,48 +133,28 @@ const createCgiWithPages = (pages, siteConfig = {}, authMap = {}, rewriteMap = {
184
133
  };
185
134
  try {
186
135
  const result = await component(context);
187
- const sessionValue = encodeURIComponent(JSON.stringify($_SESSION));
188
- const sessionOptions = {
189
- path: options.sessionCookie?.path || "/",
190
- httpOnly: true,
191
- sameSite: options.sessionCookie?.sameSite || "Lax"
192
- };
193
- if (options.sessionCookie?.secure !== void 0) {
194
- sessionOptions.secure = options.sessionCookie.secure;
195
- }
196
- if (options.sessionCookie?.domain) {
197
- sessionOptions.domain = options.sessionCookie.domain;
198
- }
199
- if (options.sessionCookie?.maxAge) {
200
- sessionOptions.maxAge = options.sessionCookie.maxAge;
201
- }
136
+ saveSessionToCookie(c, $_SESSION, options.sessionCookie);
202
137
  if (isRedirectObject(result)) {
203
- setCookie(c, SESS_KEY, sessionValue, sessionOptions);
204
138
  return c.redirect(result.url, result.status);
205
139
  }
206
140
  if (result instanceof Response) {
207
- setCookie(c, SESS_KEY, sessionValue, sessionOptions);
208
141
  return result;
209
142
  }
210
- setCookie(c, SESS_KEY, sessionValue, sessionOptions);
211
143
  Object.entries(responseHeaders).forEach(([key, value]) => {
212
144
  c.header(key, value);
213
145
  });
214
146
  const contentType = responseHeaders["content-type"];
215
147
  if (contentType?.includes("application/json")) {
216
- return c.json(
217
- // biome-ignore lint/suspicious/noExplicitAny: to JSON response
218
- result ?? { success: true },
219
- responseStatus
220
- );
148
+ return c.json(result ?? { success: true }, responseStatus);
221
149
  }
222
- return c.html(result, responseStatus);
150
+ return c.html(String(result ?? ""), responseStatus);
223
151
  } catch (error) {
224
152
  return c.html(generateCgiError({ error, $_SERVER }), 500);
225
153
  }
226
154
  });
227
155
  });
228
156
  });
157
+ applyErrorDocumentMiddleware(app, htaccessConfig);
229
158
  return app;
230
159
  };
231
160
  export {
@@ -0,0 +1,9 @@
1
+ import { Context } from 'hono';
2
+ import { AccessControlConfig } from './types.js';
3
+
4
+ /**
5
+ * Create middleware for access control (Order/Allow/Deny)
6
+ */
7
+ declare function createAccessControlMiddleware(config: AccessControlConfig): (c: Context, next: () => Promise<void>) => Promise<Response | void>;
8
+
9
+ export { createAccessControlMiddleware };
@@ -0,0 +1,91 @@
1
+ function matchesIP(clientIP, ruleValue) {
2
+ const ips = Array.isArray(ruleValue) ? ruleValue : [ruleValue];
3
+ for (const ip of ips) {
4
+ if (clientIP === ip) return true;
5
+ if (ip.includes("/")) {
6
+ const [network, bits] = ip.split("/");
7
+ const mask = parseInt(bits, 10);
8
+ if (isSameNetwork(clientIP, network, mask)) return true;
9
+ }
10
+ }
11
+ return false;
12
+ }
13
+ function isSameNetwork(ip1, ip2, maskBits) {
14
+ const ip1Parts = ip1.split(".").map(Number);
15
+ const ip2Parts = ip2.split(".").map(Number);
16
+ let bits = maskBits;
17
+ for (let i = 0; i < 4; i++) {
18
+ if (bits <= 0) break;
19
+ const mask = bits >= 8 ? 255 : 256 - Math.pow(2, 8 - bits);
20
+ if ((ip1Parts[i] & mask) !== (ip2Parts[i] & mask)) {
21
+ return false;
22
+ }
23
+ bits -= 8;
24
+ }
25
+ return true;
26
+ }
27
+ function matchesHost(clientHost, ruleValue) {
28
+ const hosts = Array.isArray(ruleValue) ? ruleValue : [ruleValue];
29
+ for (const host of hosts) {
30
+ if (clientHost === host) return true;
31
+ if (host.startsWith("*.")) {
32
+ const domain = host.slice(2);
33
+ if (clientHost.endsWith(domain)) return true;
34
+ }
35
+ }
36
+ return false;
37
+ }
38
+ function matchesRule(rule, c) {
39
+ switch (rule.type) {
40
+ case "all":
41
+ return true;
42
+ case "ip": {
43
+ const clientIP = c.req.header("x-forwarded-for")?.split(",")[0].trim() || c.req.header("x-real-ip") || c.env?.REMOTE_ADDR || "127.0.0.1";
44
+ return rule.value ? matchesIP(clientIP, rule.value) : false;
45
+ }
46
+ case "host": {
47
+ const clientHost = c.req.header("host") || "";
48
+ return rule.value ? matchesHost(clientHost, rule.value) : false;
49
+ }
50
+ case "env": {
51
+ if (!rule.value) return false;
52
+ const envVar = typeof rule.value === "string" ? rule.value : rule.value[0];
53
+ return c.env?.[envVar] !== void 0;
54
+ }
55
+ default:
56
+ return false;
57
+ }
58
+ }
59
+ function evaluateAccessControl(config, c) {
60
+ const order = config.order || "allow,deny";
61
+ const allowMatches = config.allow.some((rule) => matchesRule(rule, c));
62
+ const denyMatches = config.deny.some((rule) => matchesRule(rule, c));
63
+ switch (order) {
64
+ case "allow,deny":
65
+ if (denyMatches) return false;
66
+ if (allowMatches) return true;
67
+ return false;
68
+ case "deny,allow":
69
+ if (allowMatches) return true;
70
+ if (denyMatches) return false;
71
+ return true;
72
+ case "mutual-failure":
73
+ if (denyMatches) return false;
74
+ if (allowMatches) return true;
75
+ return false;
76
+ default:
77
+ return false;
78
+ }
79
+ }
80
+ function createAccessControlMiddleware(config) {
81
+ return async (c, next) => {
82
+ const allowed = evaluateAccessControl(config, c);
83
+ if (!allowed) {
84
+ return c.text("Forbidden", 403);
85
+ }
86
+ await next();
87
+ };
88
+ }
89
+ export {
90
+ createAccessControlMiddleware
91
+ };
@@ -0,0 +1,9 @@
1
+ import { Context } from 'hono';
2
+ import { ErrorDocumentConfig } from './types.js';
3
+
4
+ /**
5
+ * Create middleware for error documents
6
+ */
7
+ declare function createErrorDocumentMiddleware(errorDocs: ErrorDocumentConfig[], _basePath: string): (c: Context, next: () => Promise<void>) => Promise<Response | void>;
8
+
9
+ export { createErrorDocumentMiddleware };
@@ -0,0 +1,16 @@
1
+ function createErrorDocumentMiddleware(errorDocs, _basePath) {
2
+ return async (c, next) => {
3
+ await next();
4
+ const status = c.res.status;
5
+ if (status < 400) return;
6
+ const errorDoc = errorDocs.find((doc) => doc.statusCode === status);
7
+ if (!errorDoc) return;
8
+ if (errorDoc.target.startsWith("http://") || errorDoc.target.startsWith("https://")) {
9
+ return c.redirect(errorDoc.target);
10
+ }
11
+ return c.text(`Error ${status}: See ${errorDoc.target}`, status);
12
+ };
13
+ }
14
+ export {
15
+ createErrorDocumentMiddleware
16
+ };
@@ -0,0 +1,32 @@
1
+ import { Context } from 'hono';
2
+ import { HeaderConfig } from './types.js';
3
+
4
+ /**
5
+ * Create middleware for header directives
6
+ */
7
+ declare function createHeaderMiddleware(headers: HeaderConfig[]): (c: Context, next: () => Promise<void>) => Promise<void>;
8
+ /**
9
+ * Predefined security header helpers
10
+ */
11
+ declare const securityHeaders: {
12
+ xFrameOptions: (value: "DENY" | "SAMEORIGIN" | string) => HeaderConfig;
13
+ xContentTypeOptions: () => HeaderConfig;
14
+ xssProtection: (enabled?: boolean) => HeaderConfig;
15
+ hsts: (maxAge?: number, includeSubdomains?: boolean) => HeaderConfig;
16
+ csp: (policy: string) => HeaderConfig;
17
+ referrerPolicy: (policy: string) => HeaderConfig;
18
+ permissionsPolicy: (policy: string) => HeaderConfig;
19
+ };
20
+ /**
21
+ * CORS (Cross-Origin Resource Sharing) header helpers
22
+ */
23
+ declare const corsHeaders: {
24
+ allowOrigin: (origin: string) => HeaderConfig;
25
+ allowMethods: (methods: string[]) => HeaderConfig;
26
+ allowHeaders: (headers: string[]) => HeaderConfig;
27
+ allowCredentials: (allow?: boolean) => HeaderConfig;
28
+ maxAge: (seconds: number) => HeaderConfig;
29
+ exposeHeaders: (headers: string[]) => HeaderConfig;
30
+ };
31
+
32
+ export { corsHeaders, createHeaderMiddleware, securityHeaders };
@@ -0,0 +1,98 @@
1
+ function createHeaderMiddleware(headers) {
2
+ return async (c, next) => {
3
+ await next();
4
+ for (const header of headers) {
5
+ switch (header.action) {
6
+ case "set":
7
+ if (header.value) {
8
+ c.header(header.name, header.value);
9
+ }
10
+ break;
11
+ case "append":
12
+ if (header.value) {
13
+ const existing = c.res.headers.get(header.name);
14
+ const newValue = existing ? `${existing}, ${header.value}` : header.value;
15
+ c.header(header.name, newValue);
16
+ }
17
+ break;
18
+ case "unset":
19
+ c.res.headers.delete(header.name);
20
+ break;
21
+ }
22
+ }
23
+ };
24
+ }
25
+ const securityHeaders = {
26
+ xFrameOptions: (value) => ({
27
+ action: "set",
28
+ name: "X-Frame-Options",
29
+ value
30
+ }),
31
+ xContentTypeOptions: () => ({
32
+ action: "set",
33
+ name: "X-Content-Type-Options",
34
+ value: "nosniff"
35
+ }),
36
+ xssProtection: (enabled = true) => ({
37
+ action: "set",
38
+ name: "X-XSS-Protection",
39
+ value: enabled ? "1; mode=block" : "0"
40
+ }),
41
+ hsts: (maxAge = 31536e3, includeSubdomains = true) => ({
42
+ action: "set",
43
+ name: "Strict-Transport-Security",
44
+ value: includeSubdomains ? `max-age=${maxAge}; includeSubDomains` : `max-age=${maxAge}`
45
+ }),
46
+ csp: (policy) => ({
47
+ action: "set",
48
+ name: "Content-Security-Policy",
49
+ value: policy
50
+ }),
51
+ referrerPolicy: (policy) => ({
52
+ action: "set",
53
+ name: "Referrer-Policy",
54
+ value: policy
55
+ }),
56
+ permissionsPolicy: (policy) => ({
57
+ action: "set",
58
+ name: "Permissions-Policy",
59
+ value: policy
60
+ })
61
+ };
62
+ const corsHeaders = {
63
+ allowOrigin: (origin) => ({
64
+ action: "set",
65
+ name: "Access-Control-Allow-Origin",
66
+ value: origin
67
+ }),
68
+ allowMethods: (methods) => ({
69
+ action: "set",
70
+ name: "Access-Control-Allow-Methods",
71
+ value: methods.join(", ")
72
+ }),
73
+ allowHeaders: (headers) => ({
74
+ action: "set",
75
+ name: "Access-Control-Allow-Headers",
76
+ value: headers.join(", ")
77
+ }),
78
+ allowCredentials: (allow = true) => ({
79
+ action: "set",
80
+ name: "Access-Control-Allow-Credentials",
81
+ value: allow ? "true" : "false"
82
+ }),
83
+ maxAge: (seconds) => ({
84
+ action: "set",
85
+ name: "Access-Control-Max-Age",
86
+ value: String(seconds)
87
+ }),
88
+ exposeHeaders: (headers) => ({
89
+ action: "set",
90
+ name: "Access-Control-Expose-Headers",
91
+ value: headers.join(", ")
92
+ })
93
+ };
94
+ export {
95
+ corsHeaders,
96
+ createHeaderMiddleware,
97
+ securityHeaders
98
+ };
@@ -0,0 +1,8 @@
1
+ export { AccessControlConfig, AccessRule, AuthConfig, ConditionFlags, DirectoryConfig, ErrorDocumentConfig, HeaderConfig, HonoContext, HtaccessConfig, RedirectConfig, RequireConfig, RewriteCondition, RewriteFlags, RewriteResult, RewriteRuleConfig, VariableContext } from './types.js';
2
+ export { parseHtaccess } from './parser.js';
3
+ export { createRewriteMiddleware, evaluateConditions } from './rewrite.js';
4
+ export { corsHeaders, createHeaderMiddleware, securityHeaders } from './headers.js';
5
+ export { createErrorDocumentMiddleware } from './error-document.js';
6
+ export { createAccessControlMiddleware } from './access-control.js';
7
+ export { applyRewriteFlags, buildVariableContext, expandVariables } from './utils.js';
8
+ import 'hono';
@@ -0,0 +1,20 @@
1
+ export * from "./types.js";
2
+ import { parseHtaccess } from "./parser.js";
3
+ import { createRewriteMiddleware, evaluateConditions } from "./rewrite.js";
4
+ import { createHeaderMiddleware, securityHeaders, corsHeaders } from "./headers.js";
5
+ import { createErrorDocumentMiddleware } from "./error-document.js";
6
+ import { createAccessControlMiddleware } from "./access-control.js";
7
+ import { buildVariableContext, expandVariables, applyRewriteFlags } from "./utils.js";
8
+ export {
9
+ applyRewriteFlags,
10
+ buildVariableContext,
11
+ corsHeaders,
12
+ createAccessControlMiddleware,
13
+ createErrorDocumentMiddleware,
14
+ createHeaderMiddleware,
15
+ createRewriteMiddleware,
16
+ evaluateConditions,
17
+ expandVariables,
18
+ parseHtaccess,
19
+ securityHeaders
20
+ };
@@ -0,0 +1,9 @@
1
+ import { DirectoryConfig } from './types.js';
2
+ import 'hono';
3
+
4
+ /**
5
+ * Main parser for .htaccess files
6
+ */
7
+ declare function parseHtaccess(content: string): DirectoryConfig;
8
+
9
+ export { parseHtaccess };