@float.js/core 2.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/dist/ai/index.d.ts +103 -0
- package/dist/ai/index.js +293 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/analytics/index.d.ts +193 -0
- package/dist/analytics/index.js +499 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/api/index.d.ts +172 -0
- package/dist/api/index.js +643 -0
- package/dist/api/index.js.map +1 -0
- package/dist/cli/index.js +2367 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/devtools/index.d.ts +82 -0
- package/dist/devtools/index.js +839 -0
- package/dist/devtools/index.js.map +1 -0
- package/dist/image/index.d.ts +114 -0
- package/dist/image/index.js +242 -0
- package/dist/image/index.js.map +1 -0
- package/dist/index.d.ts +400 -0
- package/dist/index.js +6511 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/index.d.ts +179 -0
- package/dist/middleware/index.js +362 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/realtime/index.d.ts +198 -0
- package/dist/realtime/index.js +555 -0
- package/dist/realtime/index.js.map +1 -0
- package/dist/router/index.d.ts +43 -0
- package/dist/router/index.js +143 -0
- package/dist/router/index.js.map +1 -0
- package/dist/server/index.d.ts +51 -0
- package/dist/server/index.js +2163 -0
- package/dist/server/index.js.map +1 -0
- package/dist/ssg/index.d.ts +178 -0
- package/dist/ssg/index.js +399 -0
- package/dist/ssg/index.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from 'http';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Float.js Edge Middleware
|
|
5
|
+
* Run code at the edge before requests hit your application
|
|
6
|
+
*
|
|
7
|
+
* Inspired by Vercel Edge but works everywhere!
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
interface MiddlewareRequest {
|
|
11
|
+
/** HTTP method */
|
|
12
|
+
method: string;
|
|
13
|
+
/** Request URL */
|
|
14
|
+
url: string;
|
|
15
|
+
/** Parsed URL */
|
|
16
|
+
nextUrl: NextURL;
|
|
17
|
+
/** Request headers */
|
|
18
|
+
headers: Headers;
|
|
19
|
+
/** Cookies from request */
|
|
20
|
+
cookies: RequestCookies;
|
|
21
|
+
/** Geolocation data (if available) */
|
|
22
|
+
geo?: GeoData;
|
|
23
|
+
/** IP address */
|
|
24
|
+
ip?: string;
|
|
25
|
+
/** Original request */
|
|
26
|
+
request: Request;
|
|
27
|
+
}
|
|
28
|
+
interface NextURL {
|
|
29
|
+
/** Full URL */
|
|
30
|
+
href: string;
|
|
31
|
+
/** Origin */
|
|
32
|
+
origin: string;
|
|
33
|
+
/** Protocol */
|
|
34
|
+
protocol: string;
|
|
35
|
+
/** Hostname */
|
|
36
|
+
hostname: string;
|
|
37
|
+
/** Port */
|
|
38
|
+
port: string;
|
|
39
|
+
/** Pathname */
|
|
40
|
+
pathname: string;
|
|
41
|
+
/** Search params */
|
|
42
|
+
searchParams: URLSearchParams;
|
|
43
|
+
/** Search string */
|
|
44
|
+
search: string;
|
|
45
|
+
/** Hash */
|
|
46
|
+
hash: string;
|
|
47
|
+
/** Base path */
|
|
48
|
+
basePath: string;
|
|
49
|
+
/** Locale */
|
|
50
|
+
locale?: string;
|
|
51
|
+
/** Clone the URL */
|
|
52
|
+
clone(): NextURL;
|
|
53
|
+
}
|
|
54
|
+
interface RequestCookies {
|
|
55
|
+
get(name: string): {
|
|
56
|
+
name: string;
|
|
57
|
+
value: string;
|
|
58
|
+
} | undefined;
|
|
59
|
+
getAll(): Array<{
|
|
60
|
+
name: string;
|
|
61
|
+
value: string;
|
|
62
|
+
}>;
|
|
63
|
+
has(name: string): boolean;
|
|
64
|
+
set(name: string, value: string, options?: CookieOptions): void;
|
|
65
|
+
delete(name: string): void;
|
|
66
|
+
}
|
|
67
|
+
interface CookieOptions {
|
|
68
|
+
domain?: string;
|
|
69
|
+
path?: string;
|
|
70
|
+
maxAge?: number;
|
|
71
|
+
expires?: Date;
|
|
72
|
+
httpOnly?: boolean;
|
|
73
|
+
secure?: boolean;
|
|
74
|
+
sameSite?: 'strict' | 'lax' | 'none';
|
|
75
|
+
}
|
|
76
|
+
interface GeoData {
|
|
77
|
+
city?: string;
|
|
78
|
+
country?: string;
|
|
79
|
+
countryCode?: string;
|
|
80
|
+
region?: string;
|
|
81
|
+
latitude?: number;
|
|
82
|
+
longitude?: number;
|
|
83
|
+
}
|
|
84
|
+
type MiddlewareHandler = (request: MiddlewareRequest) => Promise<MiddlewareResponse | void> | MiddlewareResponse | void;
|
|
85
|
+
type MiddlewareResponse = Response | NextResponse;
|
|
86
|
+
interface MiddlewareConfig {
|
|
87
|
+
matcher?: string | string[];
|
|
88
|
+
}
|
|
89
|
+
declare class NextResponse extends Response {
|
|
90
|
+
private _cookies;
|
|
91
|
+
private _headers;
|
|
92
|
+
constructor(body?: BodyInit | null, init?: ResponseInit);
|
|
93
|
+
get cookies(): {
|
|
94
|
+
set(name: string, value: string, options?: CookieOptions): void;
|
|
95
|
+
delete(name: string): void;
|
|
96
|
+
get(name: string): {
|
|
97
|
+
name: string;
|
|
98
|
+
value: string;
|
|
99
|
+
} | undefined;
|
|
100
|
+
getAll(): {
|
|
101
|
+
name: string;
|
|
102
|
+
value: string;
|
|
103
|
+
}[];
|
|
104
|
+
};
|
|
105
|
+
private _serializeCookie;
|
|
106
|
+
/**
|
|
107
|
+
* Continue to the next middleware/handler
|
|
108
|
+
*/
|
|
109
|
+
static next(init?: {
|
|
110
|
+
request?: {
|
|
111
|
+
headers?: Headers;
|
|
112
|
+
};
|
|
113
|
+
}): NextResponse;
|
|
114
|
+
/**
|
|
115
|
+
* Redirect to a URL
|
|
116
|
+
*/
|
|
117
|
+
static redirect(url: string | URL, status?: 301 | 302 | 303 | 307 | 308): NextResponse;
|
|
118
|
+
/**
|
|
119
|
+
* Rewrite to a different URL (internal redirect)
|
|
120
|
+
*/
|
|
121
|
+
static rewrite(url: string | URL): NextResponse;
|
|
122
|
+
/**
|
|
123
|
+
* Return a JSON response
|
|
124
|
+
*/
|
|
125
|
+
static json(data: unknown, init?: ResponseInit): NextResponse;
|
|
126
|
+
}
|
|
127
|
+
interface MiddlewareDefinition {
|
|
128
|
+
handler: MiddlewareHandler;
|
|
129
|
+
config?: MiddlewareConfig;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Register a middleware
|
|
133
|
+
*/
|
|
134
|
+
declare function registerMiddleware(handler: MiddlewareHandler, config?: MiddlewareConfig): void;
|
|
135
|
+
/**
|
|
136
|
+
* Clear all middleware
|
|
137
|
+
*/
|
|
138
|
+
declare function clearMiddleware(): void;
|
|
139
|
+
/**
|
|
140
|
+
* Create middleware handler for server integration
|
|
141
|
+
*/
|
|
142
|
+
declare function createMiddlewareHandler(middlewares?: MiddlewareDefinition[]): (req: IncomingMessage, res: ServerResponse, next: () => void) => Promise<void>;
|
|
143
|
+
declare const middleware: {
|
|
144
|
+
register: typeof registerMiddleware;
|
|
145
|
+
clear: typeof clearMiddleware;
|
|
146
|
+
handler: typeof createMiddlewareHandler;
|
|
147
|
+
NextResponse: typeof NextResponse;
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Shorthand for common middleware patterns
|
|
151
|
+
*/
|
|
152
|
+
declare const middlewareHelpers: {
|
|
153
|
+
/**
|
|
154
|
+
* Basic auth middleware
|
|
155
|
+
*/
|
|
156
|
+
basicAuth(username: string, password: string): MiddlewareHandler;
|
|
157
|
+
/**
|
|
158
|
+
* CORS middleware
|
|
159
|
+
*/
|
|
160
|
+
cors(options?: {
|
|
161
|
+
origin?: string | string[];
|
|
162
|
+
methods?: string[];
|
|
163
|
+
headers?: string[];
|
|
164
|
+
credentials?: boolean;
|
|
165
|
+
}): MiddlewareHandler;
|
|
166
|
+
/**
|
|
167
|
+
* Rate limiting middleware
|
|
168
|
+
*/
|
|
169
|
+
rateLimit(options: {
|
|
170
|
+
limit: number;
|
|
171
|
+
window: number;
|
|
172
|
+
}): MiddlewareHandler;
|
|
173
|
+
/**
|
|
174
|
+
* Redirect trailing slashes
|
|
175
|
+
*/
|
|
176
|
+
trailingSlash(add?: boolean): MiddlewareHandler;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
export { type CookieOptions, type GeoData, type MiddlewareConfig, type MiddlewareDefinition, type MiddlewareHandler, type MiddlewareRequest, type MiddlewareResponse, NextResponse, type NextURL, type RequestCookies, clearMiddleware, createMiddlewareHandler, middleware, middlewareHelpers, registerMiddleware };
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
// src/middleware/index.ts
|
|
2
|
+
var NextResponse = class _NextResponse extends Response {
|
|
3
|
+
_cookies = /* @__PURE__ */ new Map();
|
|
4
|
+
_headers;
|
|
5
|
+
constructor(body, init) {
|
|
6
|
+
super(body, init);
|
|
7
|
+
this._headers = new Headers(init?.headers);
|
|
8
|
+
}
|
|
9
|
+
get cookies() {
|
|
10
|
+
const self = this;
|
|
11
|
+
return {
|
|
12
|
+
set(name, value, options) {
|
|
13
|
+
self._cookies.set(name, { value, options });
|
|
14
|
+
self._headers.append("Set-Cookie", self._serializeCookie(name, value, options));
|
|
15
|
+
},
|
|
16
|
+
delete(name) {
|
|
17
|
+
self._cookies.delete(name);
|
|
18
|
+
self._headers.append("Set-Cookie", `${name}=; Max-Age=0; Path=/`);
|
|
19
|
+
},
|
|
20
|
+
get(name) {
|
|
21
|
+
const cookie = self._cookies.get(name);
|
|
22
|
+
return cookie ? { name, value: cookie.value } : void 0;
|
|
23
|
+
},
|
|
24
|
+
getAll() {
|
|
25
|
+
return Array.from(self._cookies.entries()).map(([name, { value }]) => ({ name, value }));
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
_serializeCookie(name, value, options) {
|
|
30
|
+
let cookie = `${name}=${encodeURIComponent(value)}`;
|
|
31
|
+
if (options?.domain) cookie += `; Domain=${options.domain}`;
|
|
32
|
+
if (options?.path) cookie += `; Path=${options.path}`;
|
|
33
|
+
if (options?.maxAge) cookie += `; Max-Age=${options.maxAge}`;
|
|
34
|
+
if (options?.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
|
|
35
|
+
if (options?.httpOnly) cookie += "; HttpOnly";
|
|
36
|
+
if (options?.secure) cookie += "; Secure";
|
|
37
|
+
if (options?.sameSite) cookie += `; SameSite=${options.sameSite}`;
|
|
38
|
+
return cookie;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Continue to the next middleware/handler
|
|
42
|
+
*/
|
|
43
|
+
static next(init) {
|
|
44
|
+
const response = new _NextResponse(null, { status: 200 });
|
|
45
|
+
if (init?.request?.headers) {
|
|
46
|
+
init.request.headers.forEach((value, key) => {
|
|
47
|
+
response._headers.set(`x-middleware-request-${key}`, value);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
response._headers.set("x-middleware-next", "1");
|
|
51
|
+
return response;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Redirect to a URL
|
|
55
|
+
*/
|
|
56
|
+
static redirect(url, status = 307) {
|
|
57
|
+
const urlString = typeof url === "string" ? url : url.toString();
|
|
58
|
+
return new _NextResponse(null, {
|
|
59
|
+
status,
|
|
60
|
+
headers: { Location: urlString }
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Rewrite to a different URL (internal redirect)
|
|
65
|
+
*/
|
|
66
|
+
static rewrite(url) {
|
|
67
|
+
const urlString = typeof url === "string" ? url : url.toString();
|
|
68
|
+
const response = new _NextResponse(null, { status: 200 });
|
|
69
|
+
response._headers.set("x-middleware-rewrite", urlString);
|
|
70
|
+
return response;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Return a JSON response
|
|
74
|
+
*/
|
|
75
|
+
static json(data, init) {
|
|
76
|
+
const body = JSON.stringify(data);
|
|
77
|
+
return new _NextResponse(body, {
|
|
78
|
+
...init,
|
|
79
|
+
headers: {
|
|
80
|
+
"Content-Type": "application/json",
|
|
81
|
+
...init?.headers
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
function matcherToRegex(pattern) {
|
|
87
|
+
if (pattern === "*") return /.*/;
|
|
88
|
+
if (pattern === "/") return /^\/$/;
|
|
89
|
+
let regex = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, "(?<$1>[^/]+)").replace(/\\\*/g, ".*").replace(/\\\(([^)]+)\\\)/g, "($1)?");
|
|
90
|
+
return new RegExp(`^${regex}$`);
|
|
91
|
+
}
|
|
92
|
+
function matchesPath(path, matcher) {
|
|
93
|
+
if (!matcher) return true;
|
|
94
|
+
const patterns = Array.isArray(matcher) ? matcher : [matcher];
|
|
95
|
+
return patterns.some((pattern) => matcherToRegex(pattern).test(path));
|
|
96
|
+
}
|
|
97
|
+
function parseCookies(cookieHeader) {
|
|
98
|
+
const cookies = /* @__PURE__ */ new Map();
|
|
99
|
+
if (!cookieHeader) return cookies;
|
|
100
|
+
cookieHeader.split(";").forEach((cookie) => {
|
|
101
|
+
const [name, ...valueParts] = cookie.trim().split("=");
|
|
102
|
+
if (name) {
|
|
103
|
+
cookies.set(name, valueParts.join("="));
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
return cookies;
|
|
107
|
+
}
|
|
108
|
+
function createRequestCookies(cookieHeader) {
|
|
109
|
+
const cookies = parseCookies(cookieHeader);
|
|
110
|
+
const toSet = /* @__PURE__ */ new Map();
|
|
111
|
+
const toDelete = /* @__PURE__ */ new Set();
|
|
112
|
+
return {
|
|
113
|
+
get(name) {
|
|
114
|
+
if (toDelete.has(name)) return void 0;
|
|
115
|
+
const value = toSet.get(name)?.value ?? cookies.get(name);
|
|
116
|
+
return value ? { name, value } : void 0;
|
|
117
|
+
},
|
|
118
|
+
getAll() {
|
|
119
|
+
const result = [];
|
|
120
|
+
cookies.forEach((value, name) => {
|
|
121
|
+
if (!toDelete.has(name) && !toSet.has(name)) {
|
|
122
|
+
result.push({ name, value });
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
toSet.forEach(({ value }, name) => {
|
|
126
|
+
result.push({ name, value });
|
|
127
|
+
});
|
|
128
|
+
return result;
|
|
129
|
+
},
|
|
130
|
+
has(name) {
|
|
131
|
+
if (toDelete.has(name)) return false;
|
|
132
|
+
return toSet.has(name) || cookies.has(name);
|
|
133
|
+
},
|
|
134
|
+
set(name, value, options) {
|
|
135
|
+
toDelete.delete(name);
|
|
136
|
+
toSet.set(name, { value, options });
|
|
137
|
+
},
|
|
138
|
+
delete(name) {
|
|
139
|
+
toSet.delete(name);
|
|
140
|
+
toDelete.add(name);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function createNextUrl(url, basePath = "") {
|
|
145
|
+
return {
|
|
146
|
+
href: url.href,
|
|
147
|
+
origin: url.origin,
|
|
148
|
+
protocol: url.protocol,
|
|
149
|
+
hostname: url.hostname,
|
|
150
|
+
port: url.port,
|
|
151
|
+
pathname: url.pathname,
|
|
152
|
+
searchParams: url.searchParams,
|
|
153
|
+
search: url.search,
|
|
154
|
+
hash: url.hash,
|
|
155
|
+
basePath,
|
|
156
|
+
locale: void 0,
|
|
157
|
+
clone() {
|
|
158
|
+
return createNextUrl(new URL(url.href), basePath);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
var middlewareStack = [];
|
|
163
|
+
function registerMiddleware(handler, config) {
|
|
164
|
+
middlewareStack.push({ handler, config });
|
|
165
|
+
}
|
|
166
|
+
function clearMiddleware() {
|
|
167
|
+
middlewareStack.length = 0;
|
|
168
|
+
}
|
|
169
|
+
function createMiddlewareHandler(middlewares) {
|
|
170
|
+
const stack = middlewares || middlewareStack;
|
|
171
|
+
return async (req, res, next) => {
|
|
172
|
+
const protocol = req.socket.encrypted ? "https" : "http";
|
|
173
|
+
const host = req.headers.host || "localhost";
|
|
174
|
+
const urlString = req.url || "/";
|
|
175
|
+
const url = new URL(urlString, `${protocol}://${host}`);
|
|
176
|
+
const headers = new Headers();
|
|
177
|
+
Object.entries(req.headers).forEach(([key, value]) => {
|
|
178
|
+
if (value) {
|
|
179
|
+
headers.set(key, Array.isArray(value) ? value.join(", ") : value);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
const request = new Request(url.href, {
|
|
183
|
+
method: req.method,
|
|
184
|
+
headers
|
|
185
|
+
});
|
|
186
|
+
const middlewareReq = {
|
|
187
|
+
method: req.method || "GET",
|
|
188
|
+
url: urlString,
|
|
189
|
+
nextUrl: createNextUrl(url),
|
|
190
|
+
headers,
|
|
191
|
+
cookies: createRequestCookies(req.headers.cookie || ""),
|
|
192
|
+
ip: (req.socket.remoteAddress || "").replace("::ffff:", ""),
|
|
193
|
+
request
|
|
194
|
+
};
|
|
195
|
+
for (const { handler, config } of stack) {
|
|
196
|
+
if (!matchesPath(url.pathname, config?.matcher)) {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
const result = await handler(middlewareReq);
|
|
201
|
+
if (!result) {
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
const middlewareHeaders = result.headers;
|
|
205
|
+
if (middlewareHeaders.get("x-middleware-next")) {
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
const rewriteUrl = middlewareHeaders.get("x-middleware-rewrite");
|
|
209
|
+
if (rewriteUrl) {
|
|
210
|
+
req.url = rewriteUrl;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (result.status >= 300 && result.status < 400) {
|
|
214
|
+
const location = middlewareHeaders.get("Location");
|
|
215
|
+
if (location) {
|
|
216
|
+
res.setHeader("Location", location);
|
|
217
|
+
res.statusCode = result.status;
|
|
218
|
+
res.end();
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (result.body || result.status !== 200) {
|
|
223
|
+
res.statusCode = result.status;
|
|
224
|
+
result.headers.forEach((value, key) => {
|
|
225
|
+
if (!key.startsWith("x-middleware-")) {
|
|
226
|
+
res.setHeader(key, value);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
if (result.body) {
|
|
230
|
+
const body = await result.text();
|
|
231
|
+
res.end(body);
|
|
232
|
+
} else {
|
|
233
|
+
res.end();
|
|
234
|
+
}
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
} catch (error) {
|
|
238
|
+
console.error("Middleware error:", error);
|
|
239
|
+
res.statusCode = 500;
|
|
240
|
+
res.end("Internal Server Error");
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
next();
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
var middleware = {
|
|
248
|
+
register: registerMiddleware,
|
|
249
|
+
clear: clearMiddleware,
|
|
250
|
+
handler: createMiddlewareHandler,
|
|
251
|
+
NextResponse
|
|
252
|
+
};
|
|
253
|
+
var middlewareHelpers = {
|
|
254
|
+
/**
|
|
255
|
+
* Basic auth middleware
|
|
256
|
+
*/
|
|
257
|
+
basicAuth(username, password) {
|
|
258
|
+
return (req) => {
|
|
259
|
+
const authHeader = req.headers.get("authorization");
|
|
260
|
+
if (!authHeader || !authHeader.startsWith("Basic ")) {
|
|
261
|
+
return new NextResponse("Unauthorized", {
|
|
262
|
+
status: 401,
|
|
263
|
+
headers: { "WWW-Authenticate": 'Basic realm="Secure Area"' }
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
const credentials = atob(authHeader.slice(6));
|
|
267
|
+
const [user, pass] = credentials.split(":");
|
|
268
|
+
if (user !== username || pass !== password) {
|
|
269
|
+
return new NextResponse("Invalid credentials", { status: 401 });
|
|
270
|
+
}
|
|
271
|
+
return NextResponse.next();
|
|
272
|
+
};
|
|
273
|
+
},
|
|
274
|
+
/**
|
|
275
|
+
* CORS middleware
|
|
276
|
+
*/
|
|
277
|
+
cors(options = {}) {
|
|
278
|
+
const {
|
|
279
|
+
origin = "*",
|
|
280
|
+
methods = ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
|
281
|
+
headers = ["Content-Type", "Authorization"],
|
|
282
|
+
credentials = false
|
|
283
|
+
} = options;
|
|
284
|
+
return (req) => {
|
|
285
|
+
const response = NextResponse.next();
|
|
286
|
+
const requestOrigin = req.headers.get("origin");
|
|
287
|
+
const allowedOrigin = Array.isArray(origin) ? origin.includes(requestOrigin || "") ? requestOrigin : origin[0] : origin;
|
|
288
|
+
response.headers.set("Access-Control-Allow-Origin", allowedOrigin || "*");
|
|
289
|
+
response.headers.set("Access-Control-Allow-Methods", methods.join(", "));
|
|
290
|
+
response.headers.set("Access-Control-Allow-Headers", headers.join(", "));
|
|
291
|
+
if (credentials) {
|
|
292
|
+
response.headers.set("Access-Control-Allow-Credentials", "true");
|
|
293
|
+
}
|
|
294
|
+
if (req.method === "OPTIONS") {
|
|
295
|
+
return new NextResponse(null, {
|
|
296
|
+
status: 204,
|
|
297
|
+
headers: response.headers
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
return response;
|
|
301
|
+
};
|
|
302
|
+
},
|
|
303
|
+
/**
|
|
304
|
+
* Rate limiting middleware
|
|
305
|
+
*/
|
|
306
|
+
rateLimit(options) {
|
|
307
|
+
const { limit, window } = options;
|
|
308
|
+
const requests = /* @__PURE__ */ new Map();
|
|
309
|
+
return (req) => {
|
|
310
|
+
const ip = req.ip || "unknown";
|
|
311
|
+
const now = Date.now();
|
|
312
|
+
let record = requests.get(ip);
|
|
313
|
+
if (!record || record.resetAt < now) {
|
|
314
|
+
record = { count: 0, resetAt: now + window * 1e3 };
|
|
315
|
+
requests.set(ip, record);
|
|
316
|
+
}
|
|
317
|
+
record.count++;
|
|
318
|
+
if (record.count > limit) {
|
|
319
|
+
return NextResponse.json(
|
|
320
|
+
{ error: "Too many requests" },
|
|
321
|
+
{
|
|
322
|
+
status: 429,
|
|
323
|
+
headers: {
|
|
324
|
+
"Retry-After": String(Math.ceil((record.resetAt - now) / 1e3))
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
const response = NextResponse.next();
|
|
330
|
+
response.headers.set("X-RateLimit-Limit", String(limit));
|
|
331
|
+
response.headers.set("X-RateLimit-Remaining", String(limit - record.count));
|
|
332
|
+
response.headers.set("X-RateLimit-Reset", String(Math.ceil(record.resetAt / 1e3)));
|
|
333
|
+
return response;
|
|
334
|
+
};
|
|
335
|
+
},
|
|
336
|
+
/**
|
|
337
|
+
* Redirect trailing slashes
|
|
338
|
+
*/
|
|
339
|
+
trailingSlash(add = false) {
|
|
340
|
+
return (req) => {
|
|
341
|
+
const path = req.nextUrl.pathname;
|
|
342
|
+
if (path === "/") return NextResponse.next();
|
|
343
|
+
const hasSlash = path.endsWith("/");
|
|
344
|
+
if (add && !hasSlash) {
|
|
345
|
+
return NextResponse.redirect(new URL(path + "/", req.request.url));
|
|
346
|
+
}
|
|
347
|
+
if (!add && hasSlash) {
|
|
348
|
+
return NextResponse.redirect(new URL(path.slice(0, -1), req.request.url));
|
|
349
|
+
}
|
|
350
|
+
return NextResponse.next();
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
export {
|
|
355
|
+
NextResponse,
|
|
356
|
+
clearMiddleware,
|
|
357
|
+
createMiddlewareHandler,
|
|
358
|
+
middleware,
|
|
359
|
+
middlewareHelpers,
|
|
360
|
+
registerMiddleware
|
|
361
|
+
};
|
|
362
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/middleware/index.ts"],"sourcesContent":["/**\n * Float.js Edge Middleware\n * Run code at the edge before requests hit your application\n * \n * Inspired by Vercel Edge but works everywhere!\n */\n\nimport type { IncomingMessage, ServerResponse } from 'http';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\nexport interface MiddlewareRequest {\n /** HTTP method */\n method: string;\n /** Request URL */\n url: string;\n /** Parsed URL */\n nextUrl: NextURL;\n /** Request headers */\n headers: Headers;\n /** Cookies from request */\n cookies: RequestCookies;\n /** Geolocation data (if available) */\n geo?: GeoData;\n /** IP address */\n ip?: string;\n /** Original request */\n request: Request;\n}\n\nexport interface NextURL {\n /** Full URL */\n href: string;\n /** Origin */\n origin: string;\n /** Protocol */\n protocol: string;\n /** Hostname */\n hostname: string;\n /** Port */\n port: string;\n /** Pathname */\n pathname: string;\n /** Search params */\n searchParams: URLSearchParams;\n /** Search string */\n search: string;\n /** Hash */\n hash: string;\n /** Base path */\n basePath: string;\n /** Locale */\n locale?: string;\n /** Clone the URL */\n clone(): NextURL;\n}\n\nexport interface RequestCookies {\n get(name: string): { name: string; value: string } | undefined;\n getAll(): Array<{ name: string; value: string }>;\n has(name: string): boolean;\n set(name: string, value: string, options?: CookieOptions): void;\n delete(name: string): void;\n}\n\nexport interface CookieOptions {\n domain?: string;\n path?: string;\n maxAge?: number;\n expires?: Date;\n httpOnly?: boolean;\n secure?: boolean;\n sameSite?: 'strict' | 'lax' | 'none';\n}\n\nexport interface GeoData {\n city?: string;\n country?: string;\n countryCode?: string;\n region?: string;\n latitude?: number;\n longitude?: number;\n}\n\nexport type MiddlewareHandler = (\n request: MiddlewareRequest\n) => Promise<MiddlewareResponse | void> | MiddlewareResponse | void;\n\nexport type MiddlewareResponse = Response | NextResponse;\n\nexport interface MiddlewareConfig {\n matcher?: string | string[];\n}\n\n// ============================================================================\n// NEXT RESPONSE\n// ============================================================================\n\nexport class NextResponse extends Response {\n private _cookies: Map<string, { value: string; options?: CookieOptions }> = new Map();\n private _headers: Headers;\n\n constructor(body?: BodyInit | null, init?: ResponseInit) {\n super(body, init);\n this._headers = new Headers(init?.headers);\n }\n\n get cookies() {\n const self = this;\n return {\n set(name: string, value: string, options?: CookieOptions) {\n self._cookies.set(name, { value, options });\n self._headers.append('Set-Cookie', self._serializeCookie(name, value, options));\n },\n delete(name: string) {\n self._cookies.delete(name);\n self._headers.append('Set-Cookie', `${name}=; Max-Age=0; Path=/`);\n },\n get(name: string) {\n const cookie = self._cookies.get(name);\n return cookie ? { name, value: cookie.value } : undefined;\n },\n getAll() {\n return Array.from(self._cookies.entries()).map(([name, { value }]) => ({ name, value }));\n },\n };\n }\n\n private _serializeCookie(name: string, value: string, options?: CookieOptions): string {\n let cookie = `${name}=${encodeURIComponent(value)}`;\n \n if (options?.domain) cookie += `; Domain=${options.domain}`;\n if (options?.path) cookie += `; Path=${options.path}`;\n if (options?.maxAge) cookie += `; Max-Age=${options.maxAge}`;\n if (options?.expires) cookie += `; Expires=${options.expires.toUTCString()}`;\n if (options?.httpOnly) cookie += '; HttpOnly';\n if (options?.secure) cookie += '; Secure';\n if (options?.sameSite) cookie += `; SameSite=${options.sameSite}`;\n \n return cookie;\n }\n\n /**\n * Continue to the next middleware/handler\n */\n static next(init?: { request?: { headers?: Headers } }): NextResponse {\n const response = new NextResponse(null, { status: 200 });\n \n if (init?.request?.headers) {\n init.request.headers.forEach((value, key) => {\n response._headers.set(`x-middleware-request-${key}`, value);\n });\n }\n \n // Mark as \"continue\"\n response._headers.set('x-middleware-next', '1');\n \n return response;\n }\n\n /**\n * Redirect to a URL\n */\n static redirect(url: string | URL, status: 301 | 302 | 303 | 307 | 308 = 307): NextResponse {\n const urlString = typeof url === 'string' ? url : url.toString();\n return new NextResponse(null, {\n status,\n headers: { Location: urlString },\n });\n }\n\n /**\n * Rewrite to a different URL (internal redirect)\n */\n static rewrite(url: string | URL): NextResponse {\n const urlString = typeof url === 'string' ? url : url.toString();\n const response = new NextResponse(null, { status: 200 });\n response._headers.set('x-middleware-rewrite', urlString);\n return response;\n }\n\n /**\n * Return a JSON response\n */\n static json(data: unknown, init?: ResponseInit): NextResponse {\n const body = JSON.stringify(data);\n return new NextResponse(body, {\n ...init,\n headers: {\n 'Content-Type': 'application/json',\n ...init?.headers,\n },\n });\n }\n}\n\n// ============================================================================\n// MATCHER UTILITIES\n// ============================================================================\n\n/**\n * Convert matcher pattern to regex\n */\nfunction matcherToRegex(pattern: string): RegExp {\n // Handle special patterns\n if (pattern === '*') return /.*/;\n if (pattern === '/') return /^\\/$/;\n \n // Convert Next.js-style patterns to regex\n let regex = pattern\n // Escape special regex chars (except our patterns)\n .replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&')\n // Convert :param to named capture groups\n .replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, '(?<$1>[^/]+)')\n // Convert * to match any characters\n .replace(/\\\\\\*/g, '.*')\n // Handle (group) for optional segments\n .replace(/\\\\\\(([^)]+)\\\\\\)/g, '($1)?');\n \n return new RegExp(`^${regex}$`);\n}\n\n/**\n * Check if path matches any of the patterns\n */\nfunction matchesPath(path: string, matcher?: string | string[]): boolean {\n if (!matcher) return true;\n \n const patterns = Array.isArray(matcher) ? matcher : [matcher];\n return patterns.some(pattern => matcherToRegex(pattern).test(path));\n}\n\n// ============================================================================\n// REQUEST PARSING\n// ============================================================================\n\nfunction parseCookies(cookieHeader: string): Map<string, string> {\n const cookies = new Map<string, string>();\n if (!cookieHeader) return cookies;\n \n cookieHeader.split(';').forEach(cookie => {\n const [name, ...valueParts] = cookie.trim().split('=');\n if (name) {\n cookies.set(name, valueParts.join('='));\n }\n });\n \n return cookies;\n}\n\nfunction createRequestCookies(cookieHeader: string): RequestCookies {\n const cookies = parseCookies(cookieHeader);\n const toSet: Map<string, { value: string; options?: CookieOptions }> = new Map();\n const toDelete: Set<string> = new Set();\n \n return {\n get(name: string) {\n if (toDelete.has(name)) return undefined;\n const value = toSet.get(name)?.value ?? cookies.get(name);\n return value ? { name, value } : undefined;\n },\n getAll() {\n const result: Array<{ name: string; value: string }> = [];\n \n cookies.forEach((value, name) => {\n if (!toDelete.has(name) && !toSet.has(name)) {\n result.push({ name, value });\n }\n });\n \n toSet.forEach(({ value }, name) => {\n result.push({ name, value });\n });\n \n return result;\n },\n has(name: string) {\n if (toDelete.has(name)) return false;\n return toSet.has(name) || cookies.has(name);\n },\n set(name: string, value: string, options?: CookieOptions) {\n toDelete.delete(name);\n toSet.set(name, { value, options });\n },\n delete(name: string) {\n toSet.delete(name);\n toDelete.add(name);\n },\n };\n}\n\nfunction createNextUrl(url: URL, basePath: string = ''): NextURL {\n return {\n href: url.href,\n origin: url.origin,\n protocol: url.protocol,\n hostname: url.hostname,\n port: url.port,\n pathname: url.pathname,\n searchParams: url.searchParams,\n search: url.search,\n hash: url.hash,\n basePath,\n locale: undefined,\n clone() {\n return createNextUrl(new URL(url.href), basePath);\n },\n };\n}\n\n// ============================================================================\n// MIDDLEWARE RUNNER\n// ============================================================================\n\nexport interface MiddlewareDefinition {\n handler: MiddlewareHandler;\n config?: MiddlewareConfig;\n}\n\nconst middlewareStack: MiddlewareDefinition[] = [];\n\n/**\n * Register a middleware\n */\nexport function registerMiddleware(\n handler: MiddlewareHandler,\n config?: MiddlewareConfig\n): void {\n middlewareStack.push({ handler, config });\n}\n\n/**\n * Clear all middleware\n */\nexport function clearMiddleware(): void {\n middlewareStack.length = 0;\n}\n\n/**\n * Create middleware handler for server integration\n */\nexport function createMiddlewareHandler(\n middlewares?: MiddlewareDefinition[]\n) {\n const stack = middlewares || middlewareStack;\n \n return async (\n req: IncomingMessage,\n res: ServerResponse,\n next: () => void\n ): Promise<void> => {\n const protocol = (req.socket as any).encrypted ? 'https' : 'http';\n const host = req.headers.host || 'localhost';\n const urlString = req.url || '/';\n const url = new URL(urlString, `${protocol}://${host}`);\n \n // Create middleware request\n const headers = new Headers();\n Object.entries(req.headers).forEach(([key, value]) => {\n if (value) {\n headers.set(key, Array.isArray(value) ? value.join(', ') : value);\n }\n });\n \n const request = new Request(url.href, {\n method: req.method,\n headers,\n });\n \n const middlewareReq: MiddlewareRequest = {\n method: req.method || 'GET',\n url: urlString,\n nextUrl: createNextUrl(url),\n headers,\n cookies: createRequestCookies(req.headers.cookie || ''),\n ip: (req.socket.remoteAddress || '').replace('::ffff:', ''),\n request,\n };\n \n // Run middleware stack\n for (const { handler, config } of stack) {\n // Check if path matches\n if (!matchesPath(url.pathname, config?.matcher)) {\n continue;\n }\n \n try {\n const result = await handler(middlewareReq);\n \n if (!result) {\n continue; // No response, continue to next middleware\n }\n \n // Check for special headers\n const middlewareHeaders = result.headers;\n \n // Handle \"next\" (continue)\n if (middlewareHeaders.get('x-middleware-next')) {\n continue;\n }\n \n // Handle rewrite\n const rewriteUrl = middlewareHeaders.get('x-middleware-rewrite');\n if (rewriteUrl) {\n // Update request URL for downstream handlers\n (req as any).url = rewriteUrl;\n continue;\n }\n \n // Handle redirect\n if (result.status >= 300 && result.status < 400) {\n const location = middlewareHeaders.get('Location');\n if (location) {\n res.setHeader('Location', location);\n res.statusCode = result.status;\n res.end();\n return;\n }\n }\n \n // Handle response\n if (result.body || result.status !== 200) {\n res.statusCode = result.status;\n \n result.headers.forEach((value, key) => {\n if (!key.startsWith('x-middleware-')) {\n res.setHeader(key, value);\n }\n });\n \n if (result.body) {\n const body = await result.text();\n res.end(body);\n } else {\n res.end();\n }\n return;\n }\n } catch (error) {\n console.error('Middleware error:', error);\n res.statusCode = 500;\n res.end('Internal Server Error');\n return;\n }\n }\n \n // No middleware blocked, continue\n next();\n };\n}\n\n// ============================================================================\n// EXPORTS\n// ============================================================================\n\nexport const middleware = {\n register: registerMiddleware,\n clear: clearMiddleware,\n handler: createMiddlewareHandler,\n NextResponse,\n};\n\n/**\n * Shorthand for common middleware patterns\n */\nexport const middlewareHelpers = {\n /**\n * Basic auth middleware\n */\n basicAuth(username: string, password: string): MiddlewareHandler {\n return (req) => {\n const authHeader = req.headers.get('authorization');\n \n if (!authHeader || !authHeader.startsWith('Basic ')) {\n return new NextResponse('Unauthorized', {\n status: 401,\n headers: { 'WWW-Authenticate': 'Basic realm=\"Secure Area\"' },\n });\n }\n \n const credentials = atob(authHeader.slice(6));\n const [user, pass] = credentials.split(':');\n \n if (user !== username || pass !== password) {\n return new NextResponse('Invalid credentials', { status: 401 });\n }\n \n return NextResponse.next();\n };\n },\n \n /**\n * CORS middleware\n */\n cors(options: {\n origin?: string | string[];\n methods?: string[];\n headers?: string[];\n credentials?: boolean;\n } = {}): MiddlewareHandler {\n const {\n origin = '*',\n methods = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],\n headers = ['Content-Type', 'Authorization'],\n credentials = false,\n } = options;\n \n return (req) => {\n const response = NextResponse.next();\n \n const requestOrigin = req.headers.get('origin');\n const allowedOrigin = Array.isArray(origin)\n ? (origin.includes(requestOrigin || '') ? requestOrigin : origin[0])\n : origin;\n \n response.headers.set('Access-Control-Allow-Origin', allowedOrigin || '*');\n response.headers.set('Access-Control-Allow-Methods', methods.join(', '));\n response.headers.set('Access-Control-Allow-Headers', headers.join(', '));\n \n if (credentials) {\n response.headers.set('Access-Control-Allow-Credentials', 'true');\n }\n \n // Handle preflight\n if (req.method === 'OPTIONS') {\n return new NextResponse(null, {\n status: 204,\n headers: response.headers,\n });\n }\n \n return response;\n };\n },\n \n /**\n * Rate limiting middleware\n */\n rateLimit(options: {\n limit: number;\n window: number; // seconds\n }): MiddlewareHandler {\n const { limit, window } = options;\n const requests = new Map<string, { count: number; resetAt: number }>();\n \n return (req) => {\n const ip = req.ip || 'unknown';\n const now = Date.now();\n \n let record = requests.get(ip);\n \n if (!record || record.resetAt < now) {\n record = { count: 0, resetAt: now + window * 1000 };\n requests.set(ip, record);\n }\n \n record.count++;\n \n if (record.count > limit) {\n return NextResponse.json(\n { error: 'Too many requests' },\n { \n status: 429,\n headers: {\n 'Retry-After': String(Math.ceil((record.resetAt - now) / 1000)),\n },\n }\n );\n }\n \n const response = NextResponse.next();\n response.headers.set('X-RateLimit-Limit', String(limit));\n response.headers.set('X-RateLimit-Remaining', String(limit - record.count));\n response.headers.set('X-RateLimit-Reset', String(Math.ceil(record.resetAt / 1000)));\n \n return response;\n };\n },\n \n /**\n * Redirect trailing slashes\n */\n trailingSlash(add: boolean = false): MiddlewareHandler {\n return (req) => {\n const path = req.nextUrl.pathname;\n \n if (path === '/') return NextResponse.next();\n \n const hasSlash = path.endsWith('/');\n \n if (add && !hasSlash) {\n return NextResponse.redirect(new URL(path + '/', req.request.url));\n }\n \n if (!add && hasSlash) {\n return NextResponse.redirect(new URL(path.slice(0, -1), req.request.url));\n }\n \n return NextResponse.next();\n };\n },\n};\n"],"mappings":"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","names":[]}
|