lynnix 0.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/README.md +542 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/lynnix.d.ts +46 -0
- package/dist/lynnix.d.ts.map +1 -0
- package/dist/lynnix.js +199 -0
- package/dist/lynnix.js.map +1 -0
- package/dist/utils/augmentRequest.d.ts +12 -0
- package/dist/utils/augmentRequest.d.ts.map +1 -0
- package/dist/utils/augmentRequest.js +66 -0
- package/dist/utils/augmentRequest.js.map +1 -0
- package/dist/utils/augmentResponse.d.ts +17 -0
- package/dist/utils/augmentResponse.d.ts.map +1 -0
- package/dist/utils/augmentResponse.js +56 -0
- package/dist/utils/augmentResponse.js.map +1 -0
- package/dist/utils/buildRoutesMap.d.ts +19 -0
- package/dist/utils/buildRoutesMap.d.ts.map +1 -0
- package/dist/utils/buildRoutesMap.js +48 -0
- package/dist/utils/buildRoutesMap.js.map +1 -0
- package/dist/utils/error.d.ts +18 -0
- package/dist/utils/error.d.ts.map +1 -0
- package/dist/utils/error.js +20 -0
- package/dist/utils/error.js.map +1 -0
- package/dist/utils/findClosestBoundary.d.ts +14 -0
- package/dist/utils/findClosestBoundary.d.ts.map +1 -0
- package/dist/utils/findClosestBoundary.js +29 -0
- package/dist/utils/findClosestBoundary.js.map +1 -0
- package/dist/utils/getMiddlewareChain.d.ts +19 -0
- package/dist/utils/getMiddlewareChain.d.ts.map +1 -0
- package/dist/utils/getMiddlewareChain.js +31 -0
- package/dist/utils/getMiddlewareChain.js.map +1 -0
- package/dist/utils/handleHttpError.d.ts +24 -0
- package/dist/utils/handleHttpError.d.ts.map +1 -0
- package/dist/utils/handleHttpError.js +23 -0
- package/dist/utils/handleHttpError.js.map +1 -0
- package/dist/utils/handleNotFound.d.ts +33 -0
- package/dist/utils/handleNotFound.d.ts.map +1 -0
- package/dist/utils/handleNotFound.js +71 -0
- package/dist/utils/handleNotFound.js.map +1 -0
- package/dist/utils/lruCache.d.ts +17 -0
- package/dist/utils/lruCache.d.ts.map +1 -0
- package/dist/utils/lruCache.js +36 -0
- package/dist/utils/lruCache.js.map +1 -0
- package/dist/utils/lynnixRequest.d.ts +22 -0
- package/dist/utils/lynnixRequest.d.ts.map +1 -0
- package/dist/utils/lynnixRequest.js +21 -0
- package/dist/utils/lynnixRequest.js.map +1 -0
- package/dist/utils/lynnixResponse.d.ts +53 -0
- package/dist/utils/lynnixResponse.d.ts.map +1 -0
- package/dist/utils/lynnixResponse.js +142 -0
- package/dist/utils/lynnixResponse.js.map +1 -0
- package/dist/utils/matchRoute.d.ts +20 -0
- package/dist/utils/matchRoute.d.ts.map +1 -0
- package/dist/utils/matchRoute.js +55 -0
- package/dist/utils/matchRoute.js.map +1 -0
- package/dist/utils/parseReqBody.d.ts +28 -0
- package/dist/utils/parseReqBody.d.ts.map +1 -0
- package/dist/utils/parseReqBody.js +415 -0
- package/dist/utils/parseReqBody.js.map +1 -0
- package/dist/utils/runMiddlewares.d.ts +5 -0
- package/dist/utils/runMiddlewares.d.ts.map +1 -0
- package/dist/utils/runMiddlewares.js +18 -0
- package/dist/utils/runMiddlewares.js.map +1 -0
- package/dist/utils/sortRoutes.d.ts +16 -0
- package/dist/utils/sortRoutes.d.ts.map +1 -0
- package/dist/utils/sortRoutes.js +44 -0
- package/dist/utils/sortRoutes.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lynnix
|
|
3
|
+
* File-based hypermedia routing middleware for Node.js, Mutor.js, and HTMX.
|
|
4
|
+
*
|
|
5
|
+
* @author Onah Victor <victoronah.dev@gmail.com>
|
|
6
|
+
* @repository https://github.com/allAboutJS/Lynnix
|
|
7
|
+
* @license MIT
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Parse an incoming request body into a Lynnix-friendly shape.
|
|
11
|
+
*
|
|
12
|
+
* Supported content types:
|
|
13
|
+
* - `application/json`
|
|
14
|
+
* - `application/x-www-form-urlencoded`
|
|
15
|
+
* - `multipart/form-data`
|
|
16
|
+
*
|
|
17
|
+
* Parsed text values are assigned to `req.body` and uploaded files are assigned
|
|
18
|
+
* to `req.files`, similar to middleware such as multer/formidable.
|
|
19
|
+
*
|
|
20
|
+
* Design goals:
|
|
21
|
+
* - stream-based parsing for forms/uploads
|
|
22
|
+
* - bounded in-memory buffering for cross-environment compatibility
|
|
23
|
+
* - no temporary filesystem dependency, so it works in serverless runtimes too
|
|
24
|
+
* - dynamic imports for optional peer dependencies like `@fastify/busboy` and `qs`
|
|
25
|
+
*/
|
|
26
|
+
const DEFAULT_BODY_LIMIT = 1024 * 1024;
|
|
27
|
+
const DEFAULT_FILE_SIZE_LIMIT = 10 * 1024 * 1024;
|
|
28
|
+
const DEFAULT_FILE_COUNT_LIMIT = 10;
|
|
29
|
+
const DEFAULT_FIELD_COUNT_LIMIT = 100;
|
|
30
|
+
const DEFAULT_PART_COUNT_LIMIT = 110;
|
|
31
|
+
let bodyParserJsonPromise = null;
|
|
32
|
+
let busboyConstructorPromise = null;
|
|
33
|
+
let qsModulePromise = null;
|
|
34
|
+
export default async function parseReqBody(req, res, options = {}) {
|
|
35
|
+
const rawReq = req.raw;
|
|
36
|
+
if (!rawReq.method || ["GET", "HEAD"].includes(rawReq.method.toUpperCase())) {
|
|
37
|
+
const result = { body: {}, files: {} };
|
|
38
|
+
req.body = result.body;
|
|
39
|
+
req.files = result.files;
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
const contentType = getHeaderValue(rawReq.headers["content-type"]).toLowerCase();
|
|
43
|
+
if (!contentType) {
|
|
44
|
+
const result = { body: {}, files: {} };
|
|
45
|
+
req.body = result.body;
|
|
46
|
+
req.files = result.files;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (contentType.includes("application/json")) {
|
|
50
|
+
const result = await parseJsonRequestBody(req, res, options);
|
|
51
|
+
if (result) {
|
|
52
|
+
req.body = result.body;
|
|
53
|
+
req.files = result.files;
|
|
54
|
+
}
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
58
|
+
const result = await parseUrlEncodedBody(req, options);
|
|
59
|
+
if (result) {
|
|
60
|
+
req.body = result.body;
|
|
61
|
+
req.files = result.files;
|
|
62
|
+
}
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (contentType.includes("multipart/form-data")) {
|
|
66
|
+
const result = await parseMultipartBody(req, options);
|
|
67
|
+
if (result) {
|
|
68
|
+
req.body = result.body;
|
|
69
|
+
req.files = result.files;
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const result = { body: {}, files: {} };
|
|
74
|
+
req.body = result.body;
|
|
75
|
+
req.files = result.files;
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
async function parseJsonRequestBody(req, res, options) {
|
|
79
|
+
const createJsonParser = await loadJsonBodyParser();
|
|
80
|
+
// Return early if the JSON parser is not available
|
|
81
|
+
if (!createJsonParser) {
|
|
82
|
+
console.error(`[Lynnix] Parsing JSON requests requires the optional peer dependency "body-parser"`);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const jsonParser = createJsonParser({
|
|
86
|
+
limit: options.jsonLimit ?? options.bodyLimit ?? DEFAULT_BODY_LIMIT,
|
|
87
|
+
});
|
|
88
|
+
const rawReq = req.raw;
|
|
89
|
+
await new Promise((resolve, reject) => {
|
|
90
|
+
jsonParser(rawReq, res.raw, (error) => {
|
|
91
|
+
if (error) {
|
|
92
|
+
reject(normalizeError(error, "Failed to parse JSON request body"));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
resolve();
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
return {
|
|
99
|
+
body: (rawReq.body ?? {}),
|
|
100
|
+
files: {},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
async function parseUrlEncodedBody(req, options) {
|
|
104
|
+
const Busboy = await loadBusboy();
|
|
105
|
+
const entries = [];
|
|
106
|
+
const rawReq = req.raw;
|
|
107
|
+
// Allow URL-encoded body parsing only if Busboy is available
|
|
108
|
+
if (!Busboy) {
|
|
109
|
+
console.error(`[Lynnix] Parsing URL-encoded requests requires the optional peer dependency "@fastify/busboy"`);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
return new Promise((resolve, reject) => {
|
|
113
|
+
const busboy = new Busboy({
|
|
114
|
+
headers: rawReq.headers,
|
|
115
|
+
limits: {
|
|
116
|
+
fieldNameSize: options.fieldNameSize,
|
|
117
|
+
fieldSize: options.fieldSize ?? options.bodyLimit ?? DEFAULT_BODY_LIMIT,
|
|
118
|
+
fields: options.fields ?? DEFAULT_FIELD_COUNT_LIMIT,
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
let settled = false;
|
|
122
|
+
const fail = (error) => {
|
|
123
|
+
if (settled) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
settled = true;
|
|
127
|
+
reject(error);
|
|
128
|
+
};
|
|
129
|
+
busboy.on("field", (fieldName, value, fieldNameTruncated, valueTruncated) => {
|
|
130
|
+
if (fieldNameTruncated) {
|
|
131
|
+
fail(new Error(`Urlencoded field name exceeded the allowed size: ${fieldName}`));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (valueTruncated) {
|
|
135
|
+
fail(new Error(`Urlencoded field value exceeded the allowed size: ${fieldName}`));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
entries.push([fieldName, value]);
|
|
139
|
+
});
|
|
140
|
+
busboy.on("fieldsLimit", () => {
|
|
141
|
+
fail(new Error("Urlencoded request exceeded the configured field limit"));
|
|
142
|
+
});
|
|
143
|
+
busboy.on("partsLimit", () => {
|
|
144
|
+
fail(new Error("Urlencoded request exceeded the configured parts limit"));
|
|
145
|
+
});
|
|
146
|
+
busboy.on("error", (error) => {
|
|
147
|
+
fail(normalizeError(error, "Failed to parse urlencoded request body"));
|
|
148
|
+
});
|
|
149
|
+
busboy.on("finish", async () => {
|
|
150
|
+
if (settled) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
const body = await parseUrlEncodedEntries(entries, options);
|
|
155
|
+
settled = true;
|
|
156
|
+
resolve({ body, files: {} });
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
fail(normalizeError(error, "Failed to parse urlencoded request body"));
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
rawReq.pipe(busboy);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
async function parseMultipartBody(req, options) {
|
|
166
|
+
const Busboy = await loadBusboy();
|
|
167
|
+
if (!Busboy) {
|
|
168
|
+
console.error(`[Lynnix] Parsing multipart requests requires the optional peer dependency "@fastify/busboy"`);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const body = {};
|
|
172
|
+
const files = {};
|
|
173
|
+
const filePromises = [];
|
|
174
|
+
const allowedMimeTypes = options.allowedMimeTypes ?? null;
|
|
175
|
+
const allowMultipleFilesPerField = options.allowMultipleFilesPerField ?? false;
|
|
176
|
+
const rawReq = req.raw;
|
|
177
|
+
return new Promise((resolve, reject) => {
|
|
178
|
+
const busboy = new Busboy({
|
|
179
|
+
headers: rawReq.headers,
|
|
180
|
+
preservePath: options.preservePath ?? false,
|
|
181
|
+
limits: {
|
|
182
|
+
fieldNameSize: options.fieldNameSize,
|
|
183
|
+
fieldSize: options.fieldSize ?? DEFAULT_BODY_LIMIT,
|
|
184
|
+
fields: options.fields ?? DEFAULT_FIELD_COUNT_LIMIT,
|
|
185
|
+
fileSize: options.fileSize ?? DEFAULT_FILE_SIZE_LIMIT,
|
|
186
|
+
files: options.files ?? DEFAULT_FILE_COUNT_LIMIT,
|
|
187
|
+
parts: options.parts ?? DEFAULT_PART_COUNT_LIMIT,
|
|
188
|
+
headerPairs: options.headerPairs,
|
|
189
|
+
headerSize: options.headerSize,
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
let settled = false;
|
|
193
|
+
const fail = (error) => {
|
|
194
|
+
if (settled) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
settled = true;
|
|
198
|
+
reject(error);
|
|
199
|
+
};
|
|
200
|
+
busboy.on("field", (fieldName, value, fieldNameTruncated, valueTruncated) => {
|
|
201
|
+
if (fieldNameTruncated) {
|
|
202
|
+
fail(new Error(`Multipart field name exceeded the allowed size: ${fieldName}`));
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (valueTruncated) {
|
|
206
|
+
fail(new Error(`Multipart field value exceeded the allowed size: ${fieldName}`));
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
appendValue(body, fieldName, value);
|
|
210
|
+
});
|
|
211
|
+
busboy.on("file", (fieldName, stream, filename, encoding, mimeType) => {
|
|
212
|
+
// Busboy can surface unnamed file parts. If there is no filename, we
|
|
213
|
+
// treat the part as discardable and drain the stream so parsing can finish.
|
|
214
|
+
if (!filename) {
|
|
215
|
+
stream.resume();
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
// Reject unsupported uploads as early as possible, but always resume the
|
|
219
|
+
// stream first so Busboy can continue consuming the rest of the request.
|
|
220
|
+
if (allowedMimeTypes && !matchesMimeType(mimeType, allowedMimeTypes)) {
|
|
221
|
+
stream.resume();
|
|
222
|
+
fail(new Error(`File field ${fieldName} uses unsupported mime type ${mimeType}`));
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
// Enforce the single-file-per-field contract before buffering anything.
|
|
226
|
+
if (!allowMultipleFilesPerField && files[fieldName]) {
|
|
227
|
+
stream.resume();
|
|
228
|
+
fail(new Error(`Multiple files are not allowed for the field ${fieldName}`));
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
// File contents are buffered in memory with size limits instead of being
|
|
232
|
+
// written to disk. This keeps the parser portable across Node servers and
|
|
233
|
+
// serverless environments where temp storage may be unavailable.
|
|
234
|
+
const filePromise = consumeFileStream(stream, fieldName, filename, encoding, mimeType).then((file) => {
|
|
235
|
+
appendFile(files, fieldName, file, allowMultipleFilesPerField);
|
|
236
|
+
});
|
|
237
|
+
filePromises.push(filePromise.catch((error) => fail(normalizeError(error, "Failed to read uploaded file"))));
|
|
238
|
+
});
|
|
239
|
+
busboy.on("filesLimit", () => {
|
|
240
|
+
fail(new Error("Multipart request exceeded the configured file limit"));
|
|
241
|
+
});
|
|
242
|
+
busboy.on("fieldsLimit", () => {
|
|
243
|
+
fail(new Error("Multipart request exceeded the configured field limit"));
|
|
244
|
+
});
|
|
245
|
+
busboy.on("partsLimit", () => {
|
|
246
|
+
fail(new Error("Multipart request exceeded the configured parts limit"));
|
|
247
|
+
});
|
|
248
|
+
busboy.on("error", (error) => {
|
|
249
|
+
fail(normalizeError(error, "Failed to parse multipart request body"));
|
|
250
|
+
});
|
|
251
|
+
busboy.on("finish", () => {
|
|
252
|
+
Promise.all(filePromises)
|
|
253
|
+
.then(() => {
|
|
254
|
+
if (settled) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
settled = true;
|
|
258
|
+
resolve({ body, files });
|
|
259
|
+
})
|
|
260
|
+
.catch((error) => {
|
|
261
|
+
fail(normalizeError(error, "Failed to finalize multipart request body"));
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
rawReq.pipe(busboy);
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Consume one uploaded file stream into a bounded in-memory buffer.
|
|
269
|
+
*
|
|
270
|
+
* The stream is fully drained so Busboy can complete parsing, but uploads that
|
|
271
|
+
* hit configured limits are rejected instead of being silently truncated.
|
|
272
|
+
*/
|
|
273
|
+
async function consumeFileStream(stream, fieldName, filename, encoding, mimeType) {
|
|
274
|
+
const chunks = [];
|
|
275
|
+
let size = 0;
|
|
276
|
+
let limitReached = false;
|
|
277
|
+
return new Promise((resolve, reject) => {
|
|
278
|
+
// Busboy emits `limit` when the configured file size is exceeded. We keep
|
|
279
|
+
// draining until `end`, then reject with a deterministic error.
|
|
280
|
+
stream.on("limit", () => {
|
|
281
|
+
limitReached = true;
|
|
282
|
+
});
|
|
283
|
+
stream.on("data", (chunk) => {
|
|
284
|
+
const buffer = toBuffer(chunk);
|
|
285
|
+
size += buffer.length;
|
|
286
|
+
chunks.push(buffer);
|
|
287
|
+
});
|
|
288
|
+
stream.on("error", (error) => {
|
|
289
|
+
reject(normalizeError(error, `Failed to process uploaded file ${filename}`));
|
|
290
|
+
});
|
|
291
|
+
stream.on("end", () => {
|
|
292
|
+
// Reject oversized files instead of returning partial buffers. That keeps
|
|
293
|
+
// downstream handlers from accidentally treating truncated uploads as valid.
|
|
294
|
+
if (limitReached || stream.truncated) {
|
|
295
|
+
reject(new Error(`Uploaded file for field ${fieldName} exceeded the configured file size limit`));
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
resolve({
|
|
299
|
+
fieldName,
|
|
300
|
+
filename,
|
|
301
|
+
encoding,
|
|
302
|
+
mimeType,
|
|
303
|
+
size,
|
|
304
|
+
buffer: Buffer.concat(chunks),
|
|
305
|
+
truncated: false,
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
async function parseUrlEncodedEntries(entries, options) {
|
|
311
|
+
if (!entries.length) {
|
|
312
|
+
return {};
|
|
313
|
+
}
|
|
314
|
+
const queryString = entries
|
|
315
|
+
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
|
|
316
|
+
.join("&");
|
|
317
|
+
const qsModule = await loadQsModule();
|
|
318
|
+
if (qsModule) {
|
|
319
|
+
return qsModule.parse(queryString, options.qsOptions);
|
|
320
|
+
}
|
|
321
|
+
const fallback = {};
|
|
322
|
+
for (let i = 0; i < entries.length; i++) {
|
|
323
|
+
const [key, value] = entries[i];
|
|
324
|
+
appendValue(fallback, key, value);
|
|
325
|
+
}
|
|
326
|
+
return fallback;
|
|
327
|
+
}
|
|
328
|
+
async function loadJsonBodyParser() {
|
|
329
|
+
if (!bodyParserJsonPromise) {
|
|
330
|
+
bodyParserJsonPromise = import("body-parser")
|
|
331
|
+
.then((mod) => mod.default.json.bind(mod.default))
|
|
332
|
+
.catch(() => {
|
|
333
|
+
console.log(`[Lynnix] Parsing JSON requests requires the optional peer dependency "body-parser"`);
|
|
334
|
+
return null;
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
return bodyParserJsonPromise;
|
|
338
|
+
}
|
|
339
|
+
async function loadBusboy() {
|
|
340
|
+
if (!busboyConstructorPromise) {
|
|
341
|
+
busboyConstructorPromise = import("@fastify/busboy")
|
|
342
|
+
.then((mod) => mod.default)
|
|
343
|
+
.catch(() => {
|
|
344
|
+
console.log(`[Lynnix] Parsing form requests requires the optional peer dependency "@fastify/busboy"`);
|
|
345
|
+
return null;
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
return busboyConstructorPromise;
|
|
349
|
+
}
|
|
350
|
+
async function loadQsModule() {
|
|
351
|
+
if (!qsModulePromise) {
|
|
352
|
+
qsModulePromise = import("qs")
|
|
353
|
+
.then((mod) => ({ parse: mod.default.parse.bind(mod.default) }))
|
|
354
|
+
.catch(() => {
|
|
355
|
+
console.log(`[Lynnix] Parsing search queries requires the optional peer dependency "qs"`);
|
|
356
|
+
return null;
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
return qsModulePromise;
|
|
360
|
+
}
|
|
361
|
+
function appendValue(target, key, value) {
|
|
362
|
+
const existing = target[key];
|
|
363
|
+
if (typeof existing === "undefined") {
|
|
364
|
+
target[key] = value;
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
if (Array.isArray(existing)) {
|
|
368
|
+
existing.push(value);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
target[key] = [existing, value];
|
|
372
|
+
}
|
|
373
|
+
function appendFile(target, key, file, allowMultipleFilesPerField) {
|
|
374
|
+
const existing = target[key];
|
|
375
|
+
if (typeof existing === "undefined") {
|
|
376
|
+
target[key] = allowMultipleFilesPerField ? [file] : file;
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
if (Array.isArray(existing)) {
|
|
380
|
+
existing.push(file);
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
target[key] = [existing, file];
|
|
384
|
+
}
|
|
385
|
+
function matchesMimeType(mimeType, allowedMimeTypes) {
|
|
386
|
+
for (let i = 0; i < allowedMimeTypes.length; i++) {
|
|
387
|
+
const allowed = allowedMimeTypes[i];
|
|
388
|
+
if (allowed === mimeType) {
|
|
389
|
+
return true;
|
|
390
|
+
}
|
|
391
|
+
if (allowed.endsWith("/*")) {
|
|
392
|
+
const prefix = allowed.slice(0, allowed.indexOf("/"));
|
|
393
|
+
if (mimeType.startsWith(`${prefix}/`)) {
|
|
394
|
+
return true;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
function getHeaderValue(value) {
|
|
401
|
+
if (Array.isArray(value)) {
|
|
402
|
+
return value[0] ?? "";
|
|
403
|
+
}
|
|
404
|
+
return value ?? "";
|
|
405
|
+
}
|
|
406
|
+
function normalizeError(error, fallbackMessage) {
|
|
407
|
+
if (error instanceof Error) {
|
|
408
|
+
return error;
|
|
409
|
+
}
|
|
410
|
+
return new Error(fallbackMessage);
|
|
411
|
+
}
|
|
412
|
+
function toBuffer(chunk) {
|
|
413
|
+
return Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
414
|
+
}
|
|
415
|
+
//# sourceMappingURL=parseReqBody.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseReqBody.js","sourceRoot":"","sources":["../../src/utils/parseReqBody.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { RoutesMap } from "../types.js";
|
|
2
|
+
import type LynnixRequest from "./lynnixRequest.js";
|
|
3
|
+
import type LynnixResponse from "./lynnixResponse.js";
|
|
4
|
+
export default function runMiddlewares(req: LynnixRequest, res: LynnixResponse, route: string, routesMap: RoutesMap): Promise<void>;
|
|
5
|
+
//# sourceMappingURL=runMiddlewares.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runMiddlewares.d.ts","sourceRoot":"","sources":["../../src/utils/runMiddlewares.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AAEtD,wBAA8B,cAAc,CAC3C,GAAG,EAAE,aAAa,EAClB,GAAG,EAAE,cAAc,EACnB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,SAAS,iBAqBpB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { pathToFileURL } from "node:url";
|
|
2
|
+
import getMiddlewareChain from "./getMiddlewareChain.js";
|
|
3
|
+
export default async function runMiddlewares(req, res, route, routesMap) {
|
|
4
|
+
const middlewareChain = getMiddlewareChain(route, routesMap);
|
|
5
|
+
for (let i = 0; i < middlewareChain.length; i++) {
|
|
6
|
+
const middlewarePath = middlewareChain[i];
|
|
7
|
+
const mod = await import(pathToFileURL(middlewarePath).href);
|
|
8
|
+
if (typeof mod?.default !== "function") {
|
|
9
|
+
console.warn(`[Lynnix] Middleware at ${middlewarePath} is not a function`);
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
await mod.default(req, res);
|
|
13
|
+
if (res.raw.writableEnded) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=runMiddlewares.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runMiddlewares.js","sourceRoot":"","sources":["../../src/utils/runMiddlewares.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,kBAAkB,MAAM,yBAAyB,CAAC;AAIzD,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,cAAc,CAC3C,GAAkB,EAClB,GAAmB,EACnB,KAAa,EACb,SAAoB;IAEpB,MAAM,eAAe,GAAG,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAE7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACjD,MAAM,cAAc,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC;QAE7D,IAAI,OAAO,GAAG,EAAE,OAAO,KAAK,UAAU,EAAE,CAAC;YACxC,OAAO,CAAC,IAAI,CACX,0BAA0B,cAAc,oBAAoB,CAC5D,CAAC;YACF,SAAS;QACV,CAAC;QAED,MAAM,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAE5B,IAAI,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;YAC3B,OAAO;QACR,CAAC;IACF,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lynnix
|
|
3
|
+
* File-based hypermedia routing middleware for Node.js, Mutor.js, and HTMX.
|
|
4
|
+
*
|
|
5
|
+
* @author Onah Victor <victoronah.dev@gmail.com>
|
|
6
|
+
* @repository https://github.com/allAboutJS/Lynnix
|
|
7
|
+
* @license MIT
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Sorts an array of routes, placing static routes before dynamic routes.
|
|
11
|
+
*
|
|
12
|
+
* @param routes An array of routes to sort.
|
|
13
|
+
* @returns The sorted array of routes.
|
|
14
|
+
*/
|
|
15
|
+
export declare function sortRoutes(routes: string[]): string[];
|
|
16
|
+
//# sourceMappingURL=sortRoutes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sortRoutes.d.ts","sourceRoot":"","sources":["../../src/utils/sortRoutes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,YAqC1C"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lynnix
|
|
3
|
+
* File-based hypermedia routing middleware for Node.js, Mutor.js, and HTMX.
|
|
4
|
+
*
|
|
5
|
+
* @author Onah Victor <victoronah.dev@gmail.com>
|
|
6
|
+
* @repository https://github.com/allAboutJS/Lynnix
|
|
7
|
+
* @license MIT
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Sorts an array of routes, placing static routes before dynamic routes.
|
|
11
|
+
*
|
|
12
|
+
* @param routes An array of routes to sort.
|
|
13
|
+
* @returns The sorted array of routes.
|
|
14
|
+
*/
|
|
15
|
+
export function sortRoutes(routes) {
|
|
16
|
+
const isCatchAll = (route) => /\[\[.*\]\]/.test(route);
|
|
17
|
+
const isDynamic = (route) => /\[.*\]/.test(route);
|
|
18
|
+
const depth = (route) => route.split("/").filter(Boolean).length;
|
|
19
|
+
const staticCount = (route) => route.split("/").filter((seg) => seg && !/^\[/.test(seg)).length;
|
|
20
|
+
return routes.sort((a, b) => {
|
|
21
|
+
const aCatchAll = isCatchAll(a);
|
|
22
|
+
const bCatchAll = isCatchAll(b);
|
|
23
|
+
if (aCatchAll !== bCatchAll) {
|
|
24
|
+
return aCatchAll ? 1 : -1;
|
|
25
|
+
}
|
|
26
|
+
const aDynamic = isDynamic(a);
|
|
27
|
+
const bDynamic = isDynamic(b);
|
|
28
|
+
if (aDynamic !== bDynamic) {
|
|
29
|
+
return aDynamic ? 1 : -1;
|
|
30
|
+
}
|
|
31
|
+
// Within catch-all tier: deeper prefix is more specific, wins
|
|
32
|
+
if (aCatchAll) {
|
|
33
|
+
return depth(b) - depth(a);
|
|
34
|
+
}
|
|
35
|
+
// Within static/dynamic tier: more static segments = more specific, wins
|
|
36
|
+
const staticDiff = staticCount(b) - staticCount(a);
|
|
37
|
+
if (staticDiff !== 0) {
|
|
38
|
+
return staticDiff;
|
|
39
|
+
}
|
|
40
|
+
// Same static segment count: shallower wins
|
|
41
|
+
return depth(a) - depth(b);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=sortRoutes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sortRoutes.js","sourceRoot":"","sources":["../../src/utils/sortRoutes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,MAAgB;IAC1C,MAAM,UAAU,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;IACzE,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,EAAE,CACrC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;IAElE,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC3B,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAEhC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC7B,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3B,CAAC;QAED,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAE9B,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC3B,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC;QAED,8DAA8D;QAC9D,IAAI,SAAS,EAAE,CAAC;YACf,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;QAED,yEAAyE;QACzE,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAEnD,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,UAAU,CAAC;QACnB,CAAC;QAED,4CAA4C;QAC5C,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lynnix",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "File-based hypermedia routing middleware for Node.js and HTMX",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"types": "./dist/types.d.ts"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"prepublishOnly": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"repository": "https://github.com/allaboutjs/lynnix",
|
|
23
|
+
"author": "Onah Victor",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"private": false,
|
|
26
|
+
"type": "module",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"mutorjs": "^3.0.2"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"@fastify/busboy": "^3.2.0",
|
|
32
|
+
"body-parser": "^2.3.0",
|
|
33
|
+
"cookie": "^1.1.1",
|
|
34
|
+
"qs": "^6.15.2"
|
|
35
|
+
},
|
|
36
|
+
"peerDependenciesMeta": {
|
|
37
|
+
"@fastify/busboy": {
|
|
38
|
+
"optional": true
|
|
39
|
+
},
|
|
40
|
+
"body-parser": {
|
|
41
|
+
"optional": true
|
|
42
|
+
},
|
|
43
|
+
"cookie": {
|
|
44
|
+
"optional": true
|
|
45
|
+
},
|
|
46
|
+
"qs": {
|
|
47
|
+
"optional": true
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/body-parser": "^1.19.6",
|
|
52
|
+
"@types/node": "^25.9.3",
|
|
53
|
+
"@types/qs": "^6.15.1",
|
|
54
|
+
"tsx": "^4.22.4"
|
|
55
|
+
},
|
|
56
|
+
"allowScripts": {
|
|
57
|
+
"esbuild@0.28.1": true
|
|
58
|
+
},
|
|
59
|
+
"keywords": [
|
|
60
|
+
"htmx",
|
|
61
|
+
"hypermedia",
|
|
62
|
+
"routing",
|
|
63
|
+
"ssr",
|
|
64
|
+
"file-based",
|
|
65
|
+
"mutor",
|
|
66
|
+
"node"
|
|
67
|
+
]
|
|
68
|
+
}
|