@tinyhttp/app 2.1.4 → 2.2.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/app.d.ts CHANGED
@@ -3,29 +3,10 @@ import { Server } from 'node:http';
3
3
  import type { Request } from './request.js';
4
4
  import type { Response } from './response.js';
5
5
  import type { ErrorHandler } from './onError.js';
6
- import { Middleware, Handler, NextFunction, Router, UseMethodParams } from '@tinyhttp/router';
7
- /**
8
- * tinyhttp App has a few settings for toggling features
9
- */
10
- export type AppSettings = Partial<{
11
- networkExtensions: boolean;
12
- subdomainOffset: number;
13
- bindAppToReqRes: boolean;
14
- xPoweredBy: string | boolean;
15
- enableReqRoute: boolean;
16
- views: string;
17
- }>;
18
- /**
19
- * Function that processes the template
20
- */
21
- export type TemplateFunc<O> = (path: string, locals: Record<string, any>, opts: TemplateEngineOptions<O>, cb: (err: Error | null, html: unknown) => void) => void;
22
- export type TemplateEngineOptions<O> = Partial<{
23
- cache: boolean;
24
- ext: string;
25
- renderOptions: Partial<O>;
26
- viewsFolder: string;
27
- _locals: Record<string, any>;
28
- }>;
6
+ import type { Middleware, Handler, NextFunction, UseMethodParams } from '@tinyhttp/router';
7
+ import { Router } from '@tinyhttp/router';
8
+ import { AppConstructor, AppRenderOptions, AppSettings, TemplateEngine } from './types.js';
9
+ import { TemplateEngineOptions } from './index.js';
29
10
  /**
30
11
  * `App` class - the starting point of tinyhttp app.
31
12
  *
@@ -48,33 +29,40 @@ export type TemplateEngineOptions<O> = Partial<{
48
29
  * const app = App<any, CoolReq, Response>()
49
30
  * ```
50
31
  */
51
- export declare class App<RenderOptions = any, Req extends Request = Request, Res extends Response<RenderOptions> = Response<RenderOptions>> extends Router<App, Req, Res> {
32
+ export declare class App<Req extends Request = Request, Res extends Response = Response> extends Router<App, Req, Res> {
52
33
  #private;
53
34
  middleware: Middleware<Req, Res>[];
54
35
  locals: Record<string, unknown>;
55
36
  noMatchHandler: Handler;
56
37
  onError: ErrorHandler;
57
38
  settings: AppSettings;
58
- engines: Record<string, TemplateFunc<RenderOptions>>;
39
+ engines: Record<string, TemplateEngine>;
59
40
  applyExtensions: (req: Request, res: Response, next: NextFunction) => void;
60
41
  attach: (req: Req, res: Res) => void;
61
- constructor(options?: Partial<{
62
- noMatchHandler: Handler<Req, Res>;
63
- onError: ErrorHandler;
64
- settings: AppSettings;
65
- applyExtensions: (req: Request, res: Response, next: NextFunction) => void;
66
- }>);
42
+ cache: Record<string, unknown>;
43
+ constructor(options?: AppConstructor<Req, Res>);
67
44
  /**
68
45
  * Set app setting
69
46
  * @param setting setting name
70
47
  * @param value setting value
71
48
  */
72
- set<T = unknown>(setting: string, value: T): this;
49
+ set<K extends keyof AppSettings>(setting: K, value: AppSettings[K]): this;
73
50
  /**
74
51
  * Enable app setting
75
52
  * @param setting Setting name
76
53
  */
77
- enable(setting: string): this;
54
+ enable<K extends keyof AppSettings>(setting: K): this;
55
+ /**
56
+ * Check if setting is enabled
57
+ * @param setting Setting name
58
+ * @returns
59
+ */
60
+ enabled<K extends keyof AppSettings>(setting: K): boolean;
61
+ /**
62
+ * Disable app setting
63
+ * @param setting Setting name
64
+ */
65
+ disable<K extends keyof AppSettings>(setting: K): this;
78
66
  /**
79
67
  * Return the app's absolute pathname
80
68
  * based on the parent(s) that have
@@ -88,10 +76,9 @@ export declare class App<RenderOptions = any, Req extends Request = Request, Res
88
76
  */
89
77
  path(): string;
90
78
  /**
91
- * Disable app setting
92
- * @param setting
79
+ * Register a template engine with extension
93
80
  */
94
- disable(setting: string): this;
81
+ engine<RenderOptions extends TemplateEngineOptions = TemplateEngineOptions>(ext: string, fn: TemplateEngine<RenderOptions>): this;
95
82
  /**
96
83
  * Render a template
97
84
  * @param file What to render
@@ -99,19 +86,15 @@ export declare class App<RenderOptions = any, Req extends Request = Request, Res
99
86
  * @param options Template engine options
100
87
  * @param cb Callback that consumes error and html
101
88
  */
102
- render(file: string, data: Record<string, unknown>, cb: (err: unknown, html: unknown) => void, options?: TemplateEngineOptions<RenderOptions>): this;
89
+ render<RenderOptions extends TemplateEngineOptions = TemplateEngineOptions>(name: string, data: Record<string, unknown>, options: AppRenderOptions<RenderOptions>, cb: (err: unknown, html?: unknown) => void): void;
103
90
  use(...args: UseMethodParams<Req, Res, App>): this;
104
- /**
105
- * Register a template engine with extension
106
- */
107
- engine(ext: string, fn: TemplateFunc<RenderOptions>): this;
108
91
  route(path: string): App;
109
92
  /**
110
93
  * Extends Req / Res objects, pushes 404 and 500 handlers, dispatches middleware
111
94
  * @param req Req object
112
95
  * @param res Res object
113
96
  */
114
- handler(req: Req, res: Res, next?: NextFunction): void;
97
+ handler<RenderOptions extends TemplateEngineOptions = TemplateEngineOptions>(req: Req, res: Res, next?: NextFunction): void;
115
98
  /**
116
99
  * Creates HTTP server and dispatches middleware
117
100
  * @param port server listening port
package/dist/extend.d.ts CHANGED
@@ -2,7 +2,8 @@ import { Request } from './request.js';
2
2
  import type { NextFunction } from '@tinyhttp/router';
3
3
  import type { Response } from './response.js';
4
4
  import { App } from './app.js';
5
+ import { TemplateEngineOptions } from './types.js';
5
6
  /**
6
7
  * Extends Request and Response objects with custom properties and methods
7
8
  */
8
- export declare const extendMiddleware: <EngineOptions>(app: App) => (req: Request, res: Response<EngineOptions, any>, next: NextFunction) => void;
9
+ export declare const extendMiddleware: <EngineOptions extends TemplateEngineOptions = TemplateEngineOptions>(app: App) => (req: Request, res: Response<EngineOptions>, next: NextFunction) => void;
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  export { App } from './app.js';
2
- export type { AppSettings, TemplateEngineOptions, TemplateFunc } from './app.js';
3
2
  export * from './request.js';
4
- import type { Request } from './request.js';
5
3
  export * from './response.js';
6
- import type { Response } from './response.js';
7
4
  export { extendMiddleware } from './extend.js';
8
- export { onErrorHandler } from './onError.js';
9
- export type { ErrorHandler } from './onError.js';
5
+ export { onErrorHandler, type ErrorHandler } from './onError.js';
6
+ export { View } from './view.js';
7
+ export type { AppSettings, TemplateEngineOptions, TemplateEngine, AppConstructor } from './types.js';
8
+ import type { Request } from './request.js';
9
+ import type { Response } from './response.js';
10
10
  import type { NextFunction, Handler as RHandler, AsyncHandler as RAsyncHandler, SyncHandler as RSyncHandler, Middleware } from '@tinyhttp/router';
11
11
  export type Handler = RHandler<Request, Response>;
12
12
  export type AsyncHandler = RAsyncHandler<Request, Response>;
package/dist/index.js CHANGED
@@ -1,19 +1,4 @@
1
- var __accessCheck = (obj, member, msg) => {
2
- if (!member.has(obj))
3
- throw TypeError("Cannot " + msg);
4
- };
5
- var __privateAdd = (obj, member, value) => {
6
- if (member.has(obj))
7
- throw TypeError("Cannot add the same private member more than once");
8
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
9
- };
10
- var __privateMethod = (obj, member, method) => {
11
- __accessCheck(obj, member, "access private method");
12
- return method;
13
- };
14
- var _find, find_fn;
15
1
  import { STATUS_CODES, createServer } from "node:http";
16
- import path from "node:path";
17
2
  import { proxyaddr, all, compile } from "@tinyhttp/proxy-addr";
18
3
  import { isIP } from "node:net";
19
4
  import { getRequestHeader, getQueryParams, getRangeFromHeader, getAccepts, getAcceptsCharsets, getAcceptsEncodings, getAcceptsLanguages, checkIfXMLHttpRequest, getFreshOrStale, getPathname, getURLParams } from "@tinyhttp/req";
@@ -21,13 +6,14 @@ import { getURLParams as getURLParams2 } from "@tinyhttp/req";
21
6
  import { Router, pushMiddleware } from "@tinyhttp/router";
22
7
  import { getResponseHeader, setHeader, send, json, status, sendStatus, sendFile, setContentType, setLocationHeader, setLinksHeader, setVaryHeader, setCookie, clearCookie, formatResponse, redirect, attachment, download, append } from "@tinyhttp/res";
23
8
  import { parse } from "regexparam";
9
+ import { extname, resolve, dirname, basename, join } from "node:path";
10
+ import { statSync } from "node:fs";
24
11
  const trustRemoteAddress = ({ socket }) => {
25
12
  const val = socket.remoteAddress;
26
13
  if (typeof val === "string")
27
14
  return compile(val.split(",").map((x) => x.trim()));
28
15
  return compile(val || []);
29
16
  };
30
- const getRouteFromApp = ({ middleware }, h) => middleware.find(({ handler }) => typeof handler === "function" && handler.name === h.name);
31
17
  const getProtocol = (req) => {
32
18
  const proto = `http${req.secure ? "s" : ""}`;
33
19
  if (!trustRemoteAddress(req))
@@ -68,16 +54,11 @@ const onErrorHandler = function(err, _req, res) {
68
54
  res.writeHead(500).end(err.message);
69
55
  };
70
56
  const renderTemplate = (_req, res, app) => (file, data, options) => {
71
- app.render(
72
- file,
73
- data ? { ...data, ...res.locals } : res.locals,
74
- (err, html) => {
75
- if (err)
76
- throw err;
77
- res.send(html);
78
- },
79
- options
80
- );
57
+ app.render(file, data ? { ...res.locals, ...data } : res.locals, options, (err, html) => {
58
+ if (err)
59
+ throw err;
60
+ res.send(html);
61
+ });
81
62
  return res;
82
63
  };
83
64
  const extendMiddleware = (app) => (req, res, next) => {
@@ -126,6 +107,60 @@ const extendMiddleware = (app) => (req, res, next) => {
126
107
  req.stale = !req.fresh;
127
108
  next();
128
109
  };
110
+ function tryStat(path) {
111
+ try {
112
+ return statSync(path);
113
+ } catch (e) {
114
+ return void 0;
115
+ }
116
+ }
117
+ class View {
118
+ constructor(name, opts = {}) {
119
+ this.ext = extname(name);
120
+ this.name = name;
121
+ this.root = opts.root;
122
+ this.defaultEngine = opts.defaultEngine;
123
+ if (!this.ext && !this.defaultEngine)
124
+ throw new Error("No default engine was specified and no extension was provided.");
125
+ let fileName = name;
126
+ if (!this.ext) {
127
+ this.ext = this.defaultEngine[0] !== "." ? "." + this.defaultEngine : this.defaultEngine;
128
+ fileName += this.ext;
129
+ }
130
+ if (!opts.engines[this.ext])
131
+ throw new Error(`No engine was found for ${this.ext}`);
132
+ this.engine = opts.engines[this.ext];
133
+ this.path = this.#lookup(fileName);
134
+ }
135
+ #lookup(name) {
136
+ let path;
137
+ const roots = [].concat(this.root);
138
+ for (let i = 0; i < roots.length && !path; i++) {
139
+ const root = roots[i];
140
+ const loc = resolve(root, name);
141
+ const dir = dirname(loc);
142
+ const file = basename(loc);
143
+ path = this.#resolve(dir, file);
144
+ }
145
+ return path;
146
+ }
147
+ #resolve(dir, file) {
148
+ const ext = this.ext;
149
+ let path = join(dir, file);
150
+ let stat = tryStat(path);
151
+ if (stat && stat.isFile()) {
152
+ return path;
153
+ }
154
+ path = join(dir, basename(file, ext), "index" + ext);
155
+ stat = tryStat(path);
156
+ if (stat && stat.isFile()) {
157
+ return path;
158
+ }
159
+ }
160
+ render(options, data, cb) {
161
+ this.engine(this.path, data, options, cb);
162
+ }
163
+ }
129
164
  const lead = (x) => x.charCodeAt(0) === 47 ? x : "/" + x;
130
165
  const mount = (fn) => fn instanceof App ? fn.attach : fn;
131
166
  const applyHandler = (h) => async (req, res, next) => {
@@ -138,18 +173,24 @@ const applyHandler = (h) => async (req, res, next) => {
138
173
  next(e);
139
174
  }
140
175
  };
141
- const _App = class _App extends Router {
176
+ class App extends Router {
142
177
  constructor(options = {}) {
143
178
  super();
144
- __privateAdd(this, _find);
145
179
  this.middleware = [];
146
180
  this.locals = {};
147
181
  this.engines = {};
148
182
  this.onError = (options == null ? void 0 : options.onError) || onErrorHandler;
149
183
  this.noMatchHandler = (options == null ? void 0 : options.noMatchHandler) || this.onError.bind(this, { code: 404 });
150
- this.settings = options.settings || { xPoweredBy: true, views: `${process.cwd()}/views` };
184
+ this.settings = {
185
+ view: View,
186
+ xPoweredBy: true,
187
+ views: `${process.cwd()}/views`,
188
+ "view cache": process.env.NODE_ENV === "production",
189
+ ...options.settings
190
+ };
151
191
  this.applyExtensions = options == null ? void 0 : options.applyExtensions;
152
192
  this.attach = (req, res) => setImmediate(this.handler.bind(this, req, res, void 0), req, res);
193
+ this.cache = {};
153
194
  }
154
195
  /**
155
196
  * Set app setting
@@ -168,6 +209,22 @@ const _App = class _App extends Router {
168
209
  this.settings[setting] = true;
169
210
  return this;
170
211
  }
212
+ /**
213
+ * Check if setting is enabled
214
+ * @param setting Setting name
215
+ * @returns
216
+ */
217
+ enabled(setting) {
218
+ return Boolean(this.settings[setting]);
219
+ }
220
+ /**
221
+ * Disable app setting
222
+ * @param setting Setting name
223
+ */
224
+ disable(setting) {
225
+ this.settings[setting] = false;
226
+ return this;
227
+ }
171
228
  /**
172
229
  * Return the app's absolute pathname
173
230
  * based on the parent(s) that have
@@ -183,11 +240,10 @@ const _App = class _App extends Router {
183
240
  return this.parent ? this.parent.path() + this.mountpath : "";
184
241
  }
185
242
  /**
186
- * Disable app setting
187
- * @param setting
243
+ * Register a template engine with extension
188
244
  */
189
- disable(setting) {
190
- this.settings[setting] = false;
245
+ engine(ext, fn) {
246
+ this.engines[ext[0] === "." ? ext : `.${ext}`] = fn;
191
247
  return this;
192
248
  }
193
249
  /**
@@ -197,25 +253,45 @@ const _App = class _App extends Router {
197
253
  * @param options Template engine options
198
254
  * @param cb Callback that consumes error and html
199
255
  */
200
- render(file, data = {}, cb, options = {}) {
201
- options.viewsFolder = options.viewsFolder || this.settings.views || `${process.cwd()}/views`;
202
- options.ext = options.ext || file.slice(file.lastIndexOf(".") + 1) || "ejs";
203
- options._locals = options._locals || {};
204
- options.cache = options.cache || process.env.NODE_ENV === "production";
205
- let locals = { ...data, ...this.locals };
206
- if (options._locals)
207
- locals = { ...locals, ...options._locals };
208
- if (!file.endsWith(`.${options.ext}`))
209
- file = `${file}.${options.ext}`;
210
- const dest = options.viewsFolder ? path.join(options.viewsFolder, file) : file;
211
- this.engines[options.ext](dest, locals, options.renderOptions, cb);
212
- return this;
256
+ render(name, data = {}, options = {}, cb) {
257
+ let view;
258
+ const { _locals, ...opts } = options;
259
+ let locals = this.locals;
260
+ if (_locals)
261
+ locals = { ...locals, ..._locals };
262
+ locals = { ...locals, ...data };
263
+ if (opts.cache == null)
264
+ opts.cache = this.enabled("view cache");
265
+ if (opts.cache) {
266
+ view = this.cache[name];
267
+ }
268
+ if (!view) {
269
+ const View2 = this.settings["view"];
270
+ view = new View2(name, {
271
+ defaultEngine: this.settings["view engine"],
272
+ root: this.settings.views,
273
+ engines: this.engines
274
+ });
275
+ if (!view.path) {
276
+ const dirs = Array.isArray(view.root) && view.root.length > 1 ? 'directories "' + view.root.slice(0, -1).join('", "') + '" or "' + view.root[view.root.length - 1] + '"' : 'directory "' + view.root + '"';
277
+ const err = new Error('Failed to lookup view "' + name + '" in views ' + dirs);
278
+ return cb(err);
279
+ }
280
+ if (opts.cache) {
281
+ this.cache[name] = view;
282
+ }
283
+ }
284
+ try {
285
+ view.render(opts, locals, cb);
286
+ } catch (err) {
287
+ cb(err);
288
+ }
213
289
  }
214
290
  use(...args) {
215
291
  const base = args[0];
216
292
  const fns = args.slice(1).flat();
217
293
  let pathArray = [];
218
- if (typeof base === "function" || base instanceof _App) {
294
+ if (typeof base === "function" || base instanceof App) {
219
295
  fns.unshift(base);
220
296
  } else {
221
297
  let basePaths = [];
@@ -232,26 +308,26 @@ const _App = class _App extends Router {
232
308
  });
233
309
  fns.unshift(...basePaths);
234
310
  }
235
- pathArray = pathArray.length ? pathArray : ["/"];
311
+ pathArray = pathArray.length ? pathArray.map((path) => lead(path)) : ["/"];
236
312
  const mountpath = pathArray.join(", ");
237
313
  let regex;
238
314
  for (const fn of fns) {
239
- if (fn instanceof _App) {
240
- pathArray.forEach((path2) => {
241
- regex = parse(path2, true);
315
+ if (fn instanceof App) {
316
+ pathArray.forEach((path) => {
317
+ regex = parse(path, true);
242
318
  fn.mountpath = mountpath;
243
- this.apps[path2] = fn;
319
+ this.apps[path] = fn;
244
320
  fn.parent = this;
245
321
  });
246
322
  }
247
323
  }
248
- pathArray.forEach((path2) => {
324
+ pathArray.forEach((path) => {
249
325
  var _a;
250
326
  const handlerPaths = [];
251
327
  const handlerFunctions = [];
252
- const handlerPathBase = path2 === "/" ? "" : lead(path2);
328
+ const handlerPathBase = path === "/" ? "" : lead(path);
253
329
  for (const fn of fns) {
254
- if (fn instanceof _App && ((_a = fn.middleware) == null ? void 0 : _a.length)) {
330
+ if (fn instanceof App && ((_a = fn.middleware) == null ? void 0 : _a.length)) {
255
331
  for (const mw of fn.middleware) {
256
332
  handlerPaths.push(handlerPathBase + lead(mw.path));
257
333
  handlerFunctions.push(fn);
@@ -262,7 +338,7 @@ const _App = class _App extends Router {
262
338
  }
263
339
  }
264
340
  pushMiddleware(this.middleware)({
265
- path: path2,
341
+ path,
266
342
  regex,
267
343
  type: "mw",
268
344
  handler: mount(handlerFunctions[0]),
@@ -272,18 +348,19 @@ const _App = class _App extends Router {
272
348
  });
273
349
  return this;
274
350
  }
275
- /**
276
- * Register a template engine with extension
277
- */
278
- engine(ext, fn) {
279
- this.engines[ext] = fn;
280
- return this;
281
- }
282
- route(path2) {
283
- const app = new _App();
284
- this.use(path2, app);
351
+ route(path) {
352
+ const app = new App({ settings: this.settings });
353
+ this.use(path, app);
285
354
  return app;
286
355
  }
356
+ #find(url) {
357
+ return this.middleware.filter((m) => {
358
+ m.regex = m.regex || parse(m.path, m.type === "mw");
359
+ let fullPathRegex;
360
+ m.fullPath && typeof m.fullPath === "string" ? fullPathRegex = parse(m.fullPath, m.type === "mw") : fullPathRegex = null;
361
+ return m.regex.pattern.test(url) && (m.type === "mw" && fullPathRegex ? fullPathRegex.pattern.test(url) : true);
362
+ });
363
+ }
287
364
  /**
288
365
  * Extends Req / Res objects, pushes 404 and 500 handlers, dispatches middleware
289
366
  * @param req Req object
@@ -296,7 +373,7 @@ const _App = class _App extends Router {
296
373
  const exts = this.applyExtensions || extendMiddleware(this);
297
374
  req.originalUrl = req.url || req.originalUrl;
298
375
  const pathname = getPathname(req.originalUrl);
299
- const matched = __privateMethod(this, _find, find_fn).call(this, pathname);
376
+ const matched = this.#find(pathname);
300
377
  const mw = [
301
378
  {
302
379
  handler: exts,
@@ -325,7 +402,7 @@ const _App = class _App extends Router {
325
402
  });
326
403
  const handle = (mw2) => async (req2, res2, next2) => {
327
404
  var _a;
328
- const { path: path2, handler, regex } = mw2;
405
+ const { path, handler, regex } = mw2;
329
406
  let params;
330
407
  try {
331
408
  params = regex ? getURLParams(regex, pathname) : {};
@@ -336,18 +413,24 @@ const _App = class _App extends Router {
336
413
  else
337
414
  throw e;
338
415
  }
416
+ let prefix = path;
417
+ if (regex) {
418
+ for (const key of regex.keys) {
419
+ if (key === "wild") {
420
+ prefix = prefix.replace("*", params.wild);
421
+ } else {
422
+ prefix = prefix.replace(`:${key}`, params[key]);
423
+ }
424
+ }
425
+ }
339
426
  req2.params = { ...req2.params, ...params };
340
- if (path2.includes(":")) {
341
- const first = Object.values(params)[0];
342
- const url = req2.url.slice(req2.url.indexOf(first) + (first == null ? void 0 : first.length));
343
- req2.url = lead(url);
344
- } else {
345
- req2.url = lead(req2.url.substring(path2.length));
427
+ if (mw2.type === "mw") {
428
+ req2.url = lead(req2.originalUrl.substring(prefix.length));
346
429
  }
347
430
  if (!req2.path)
348
431
  req2.path = getPathname(req2.url);
349
432
  if ((_a = this.settings) == null ? void 0 : _a.enableReqRoute)
350
- req2.route = getRouteFromApp(this, handler);
433
+ req2.route = mw2;
351
434
  await applyHandler(handler)(req2, res2, next2);
352
435
  };
353
436
  let idx = 0;
@@ -364,25 +447,15 @@ const _App = class _App extends Router {
364
447
  listen(port, cb, host) {
365
448
  return createServer().on("request", this.attach).listen(port, host, cb);
366
449
  }
367
- };
368
- _find = new WeakSet();
369
- find_fn = function(url) {
370
- return this.middleware.filter((m) => {
371
- m.regex = m.regex || parse(m.path, m.type === "mw");
372
- let fullPathRegex;
373
- m.fullPath && typeof m.fullPath === "string" ? fullPathRegex = parse(m.fullPath, m.type === "mw") : fullPathRegex = null;
374
- return m.regex.pattern.test(url) && (m.type === "mw" && fullPathRegex ? fullPathRegex.pattern.test(url) : true);
375
- });
376
- };
377
- let App = _App;
450
+ }
378
451
  export {
379
452
  App,
453
+ View,
380
454
  extendMiddleware,
381
455
  getHostname,
382
456
  getIP,
383
457
  getIPs,
384
458
  getProtocol,
385
- getRouteFromApp,
386
459
  getSubdomains,
387
460
  getURLParams2 as getURLParams,
388
461
  onErrorHandler,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/request.ts","../src/onError.ts","../src/response.ts","../src/extend.ts","../src/app.ts"],"sourcesContent":["import { IncomingMessage } from 'node:http'\nimport type { ParsedUrlQuery } from 'node:querystring'\n\nimport { Options, Ranges } from 'header-range-parser'\nimport { proxyaddr as proxyAddr, all, compile } from '@tinyhttp/proxy-addr'\n\nimport { App } from './app.js'\nimport type { Middleware, Handler } from '@tinyhttp/router'\nimport type { Response } from './response.js'\n\nimport type { URLParams } from '@tinyhttp/req'\nimport { isIP } from 'node:net'\nimport type { Socket } from 'node:net'\nimport type { TLSSocket } from 'node:tls'\n\nexport { getURLParams } from '@tinyhttp/req'\n\nconst trustRemoteAddress = ({ socket }: Pick<Request, 'headers' | 'socket'>) => {\n const val = socket.remoteAddress\n\n if (typeof val === 'string') return compile(val.split(',').map((x) => x.trim()))\n\n return compile(val || [])\n}\n\nexport const getRouteFromApp = ({ middleware }: App, h: Handler<Request, Response>): Middleware<Request, Response> =>\n middleware.find(({ handler }) => typeof handler === 'function' && handler.name === h.name)\n\nexport const getProtocol = (req: Request): Protocol => {\n const proto = `http${req.secure ? 's' : ''}`\n\n if (!trustRemoteAddress(req)) return proto\n\n const header = (req.headers['X-Forwarded-Proto'] as string) || proto\n\n const index = header.indexOf(',')\n\n return index !== -1 ? header.substring(0, index).trim() : header.trim()\n}\n\nexport const getHostname = (req: Request): string | undefined => {\n let host: string = req.get('X-Forwarded-Host') as string\n\n if (!host || !trustRemoteAddress(req)) host = req.get('Host') as string\n\n if (!host) return\n\n // IPv6 literal support\n const index = host.indexOf(':', host[0] === '[' ? host.indexOf(']') + 1 : 0)\n\n return index !== -1 ? host.substring(0, index) : host\n}\n\nexport const getIP = (req: Pick<Request, 'headers' | 'connection' | 'socket'>): string | undefined =>\n proxyAddr(req, trustRemoteAddress(req)).replace(/^.*:/, '') // striping the redundant prefix addeded by OS to IPv4 address\n\nexport const getIPs = (req: Pick<Request, 'headers' | 'connection' | 'socket'>): string[] | undefined =>\n all(req, trustRemoteAddress(req))\n\nexport const getSubdomains = (req: Request, subdomainOffset = 2): string[] => {\n const hostname = getHostname(req)\n\n if (!hostname) return []\n\n const subdomains = isIP(hostname) ? [hostname] : hostname.split('.').reverse()\n\n return subdomains.slice(subdomainOffset)\n}\n\nexport type Connection = IncomingMessage['socket'] & {\n encrypted: boolean\n}\n\nexport type Protocol = 'node:http' | 'https' | string\n\nexport type { URLParams }\n\ntype AcceptsReturns = string | boolean | string[]\n\nexport interface Request extends IncomingMessage {\n originalUrl: string\n path: string\n url: string\n query: ParsedUrlQuery\n params: URLParams\n connection: Connection\n socket: TLSSocket | Socket\n route?: Middleware\n protocol: Protocol\n secure: boolean\n xhr: boolean\n hostname?: string\n ip?: string\n ips?: string[]\n subdomains?: string[]\n get: (header: string) => string | string[] | undefined\n range: (size: number, options?: Options) => -1 | -2 | -3 | Ranges | undefined\n accepts: (...types: string[]) => AcceptsReturns\n acceptsEncodings: (...encodings: string[]) => AcceptsReturns\n acceptsCharsets: (...charsets: string[]) => AcceptsReturns\n acceptsLanguages: (...languages: string[]) => AcceptsReturns\n is: (...types: string[]) => boolean\n cookies?: any\n signedCookies?: any\n secret?: string | string[]\n fresh?: boolean\n stale?: boolean\n body?: any\n app?: App\n}\n","import type { NextFunction } from '@tinyhttp/router'\nimport { STATUS_CODES } from 'node:http'\nimport type { Request } from './request.js'\nimport type { Response } from './response.js'\nimport type { App } from './app.js'\n\nexport type ErrorHandler = (this: App, err: any, req: Request, res: Response, next?: NextFunction) => void\n\nexport const onErrorHandler: ErrorHandler = function (this: App, err: any, _req: Request, res: Response) {\n if (this.onError === onErrorHandler && this.parent) return this.parent.onError(err, _req, res)\n\n if (err instanceof Error) console.error(err)\n\n const code = err.code in STATUS_CODES ? err.code : err.status\n\n if (typeof err === 'string' || Buffer.isBuffer(err)) res.writeHead(500).end(err)\n else if (code in STATUS_CODES) res.writeHead(code).end(STATUS_CODES[code])\n else res.writeHead(500).end(err.message)\n}\n","import { ServerResponse } from 'node:http'\nimport type { SerializeOptions } from '@tinyhttp/cookie'\nimport { Request } from './request.js'\nimport { App, TemplateEngineOptions } from './app.js'\nimport type { ReadStreamOptions, FormatProps, DownloadOptions } from '@tinyhttp/res'\n\nexport const renderTemplate =\n <O>(_req: Request, res: Response, app: App) =>\n (file: string, data?: Record<string, any>, options?: TemplateEngineOptions<O>): Response => {\n app.render(\n file,\n data ? { ...data, ...res.locals } : res.locals,\n (err: unknown, html: unknown) => {\n if (err) throw err\n res.send(html)\n },\n options\n )\n return res\n }\n\nexport interface Response<O = any, B = any> extends ServerResponse {\n header(field: string | Record<string, unknown>, val?: string | any[]): Response<O, B>\n set(field: string | Record<string, unknown>, val?: string | any[]): Response<O, B>\n get(field: string): string | number | string[]\n send(body: B): Response<O, B>\n sendFile(path: string, options?: ReadStreamOptions, cb?: (err?: any) => void): Response<O, B>\n json(body: B): Response<O, B>\n status(status: number): Response<O, B>\n sendStatus(statusCode: number): Response<O, B>\n cookie(\n name: string,\n value: string | Record<string, unknown>,\n options?: SerializeOptions & Partial<{ signed: boolean }>\n ): Response<O, B>\n clearCookie(name: string, options?: SerializeOptions): Response<O, B>\n location(url: string): Response<O, B>\n links(links: { [key: string]: string }): Response<O, B>\n render(file: string, data?: Record<string, any>, options?: TemplateEngineOptions<O>): Response<O, B>\n vary(field: string): Response<O, B>\n format(obj: FormatProps): Response<O, B>\n redirect(url: string, status?: number): Response<O, B>\n type(type: string): Response<O, B>\n download(path: string, filename: string, options?: DownloadOptions, cb?: (err?: any) => void): Response<O, B>\n attachment(filename?: string): Response<O, B>\n app?: App\n locals?: Record<string, any>\n /**\n * Send JSON response with JSONP callback support.\n *\n * To enable this method, install the `@tinyhttp/jsonp` package and attach the method to `res.jsonp` property.\n *\n * @param obj Response object\n */\n jsonp(obj: any): Response<O, B>\n\n append(field: string, value: any): Response<O, B>\n}\n","import { getSubdomains, Request } from './request.js'\nimport type { NextFunction } from '@tinyhttp/router'\nimport type { Response } from './response.js'\nimport {\n getFreshOrStale,\n getRangeFromHeader,\n getRequestHeader,\n checkIfXMLHttpRequest,\n getQueryParams,\n getAccepts,\n getAcceptsCharsets,\n getAcceptsEncodings,\n getAcceptsLanguages\n} from '@tinyhttp/req'\nimport { getProtocol, getHostname, getIP, getIPs } from './request.js'\nimport {\n send,\n json,\n status,\n setCookie,\n clearCookie,\n setHeader,\n getResponseHeader,\n setLocationHeader,\n setLinksHeader,\n sendStatus,\n setVaryHeader,\n sendFile,\n formatResponse,\n redirect,\n setContentType,\n attachment,\n download,\n append\n} from '@tinyhttp/res'\nimport { renderTemplate } from './response.js'\nimport { App } from './app.js'\n\n/**\n * Extends Request and Response objects with custom properties and methods\n */\nexport const extendMiddleware =\n <EngineOptions>(app: App) =>\n (req: Request, res: Response<EngineOptions>, next: NextFunction): void => {\n const { settings } = app\n\n res.get = getResponseHeader(res)\n req.get = getRequestHeader(req)\n\n if (settings?.bindAppToReqRes) {\n req.app = app\n res.app = app\n }\n\n if (settings?.networkExtensions) {\n req.protocol = getProtocol(req)\n req.secure = req.protocol === 'https'\n req.hostname = getHostname(req)\n req.subdomains = getSubdomains(req, settings.subdomainOffset)\n req.ip = getIP(req)\n req.ips = getIPs(req)\n }\n\n req.query = getQueryParams(req.url)\n\n req.range = getRangeFromHeader(req)\n req.accepts = getAccepts(req)\n req.acceptsCharsets = getAcceptsCharsets(req)\n req.acceptsEncodings = getAcceptsEncodings(req)\n req.acceptsLanguages = getAcceptsLanguages(req)\n\n req.xhr = checkIfXMLHttpRequest(req)\n\n res.header = res.set = setHeader<Response>(res)\n res.send = send<Request, Response>(req, res)\n res.json = json<Response>(res)\n res.status = status<Response>(res)\n res.sendStatus = sendStatus<Request, Response>(req, res)\n res.sendFile = sendFile<Request, Response>(req, res)\n res.type = setContentType<Response>(res)\n res.location = setLocationHeader<Request, Response>(req, res)\n res.links = setLinksHeader<Response>(res)\n res.vary = setVaryHeader<Response>(res)\n res.cookie = setCookie<Request, Response>(req, res)\n res.clearCookie = clearCookie<Request, Response>(req, res)\n res.render = renderTemplate<EngineOptions>(req, res, app)\n res.format = formatResponse(req, res, next)\n res.redirect = redirect(req, res, next)\n res.attachment = attachment<Response>(res)\n res.download = download<Request, Response>(req, res)\n res.append = append<Response>(res)\n res.locals = res.locals || Object.create(null)\n\n Object.defineProperty(req, 'fresh', { get: getFreshOrStale.bind(null, req, res), configurable: true })\n req.stale = !req.fresh\n\n next()\n }\n","import { createServer, Server } from 'node:http'\nimport path from 'node:path'\nimport { getRouteFromApp, getURLParams } from './request.js'\nimport type { Request, URLParams } from './request.js'\nimport type { Response } from './response.js'\nimport type { ErrorHandler } from './onError.js'\nimport { onErrorHandler } from './onError.js'\nimport { Middleware, Handler, NextFunction, Router, UseMethodParams, pushMiddleware } from '@tinyhttp/router'\nimport { extendMiddleware } from './extend.js'\nimport { parse as rg } from 'regexparam'\nimport { getPathname } from '@tinyhttp/req'\n\n/**\n * Add leading slash if not present (e.g. path -> /path, /path -> /path)\n * @param x\n */\nconst lead = (x: string) => (x.charCodeAt(0) === 47 ? x : '/' + x)\n\nconst mount = (fn: App | Handler) => (fn instanceof App ? fn.attach : fn)\n\nconst applyHandler =\n <Req, Res>(h: Handler<Req, Res>) =>\n async (req: Req, res: Res, next?: NextFunction) => {\n try {\n if (h[Symbol.toStringTag] === 'AsyncFunction') {\n await h(req, res, next)\n } else h(req, res, next)\n } catch (e) {\n next(e)\n }\n }\n/**\n * tinyhttp App has a few settings for toggling features\n */\nexport type AppSettings = Partial<{\n networkExtensions: boolean\n subdomainOffset: number\n bindAppToReqRes: boolean\n xPoweredBy: string | boolean\n enableReqRoute: boolean\n views: string\n}>\n\n/**\n * Function that processes the template\n */\nexport type TemplateFunc<O> = (\n path: string,\n locals: Record<string, any>,\n opts: TemplateEngineOptions<O>,\n cb: (err: Error | null, html: unknown) => void\n) => void\n\nexport type TemplateEngineOptions<O> = Partial<{\n cache: boolean\n ext: string\n renderOptions: Partial<O>\n viewsFolder: string\n _locals: Record<string, any>\n}>\n\n/**\n * `App` class - the starting point of tinyhttp app.\n *\n * With the `App` you can:\n * * use routing methods and `.use(...)`\n * * set no match (404) and error (500) handlers\n * * configure template engines\n * * store data in locals\n * * listen the http server on a specified port\n *\n * In case you use TypeScript, you can pass custom types to this class because it is also a generic class.\n *\n * Example:\n *\n * ```ts\n * interface CoolReq extends Request {\n * genericsAreDope: boolean\n * }\n *\n * const app = App<any, CoolReq, Response>()\n * ```\n */\nexport class App<\n RenderOptions = any,\n Req extends Request = Request,\n Res extends Response<RenderOptions> = Response<RenderOptions>\n> extends Router<App, Req, Res> {\n middleware: Middleware<Req, Res>[] = []\n locals: Record<string, unknown> = {}\n noMatchHandler: Handler\n onError: ErrorHandler\n settings: AppSettings\n engines: Record<string, TemplateFunc<RenderOptions>> = {}\n applyExtensions: (req: Request, res: Response, next: NextFunction) => void\n attach: (req: Req, res: Res) => void\n\n constructor(\n options: Partial<{\n noMatchHandler: Handler<Req, Res>\n onError: ErrorHandler\n settings: AppSettings\n applyExtensions: (req: Request, res: Response, next: NextFunction) => void\n }> = {}\n ) {\n super()\n this.onError = options?.onError || onErrorHandler\n this.noMatchHandler = options?.noMatchHandler || this.onError.bind(this, { code: 404 })\n this.settings = options.settings || { xPoweredBy: true, views: `${process.cwd()}/views` }\n this.applyExtensions = options?.applyExtensions\n this.attach = (req, res) => setImmediate(this.handler.bind(this, req, res, undefined), req, res)\n }\n /**\n * Set app setting\n * @param setting setting name\n * @param value setting value\n */\n set<T = unknown>(setting: string, value: T): this {\n this.settings[setting] = value\n\n return this\n }\n\n /**\n * Enable app setting\n * @param setting Setting name\n */\n enable(setting: string): this {\n this.settings[setting] = true\n\n return this\n }\n\n /**\n * Return the app's absolute pathname\n * based on the parent(s) that have\n * mounted it.\n *\n * For example if the application was\n * mounted as `\"/admin\"`, which itself\n * was mounted as `\"/blog\"` then the\n * return value would be `\"/blog/admin\"`.\n *\n */\n path(): string {\n return this.parent ? this.parent.path() + this.mountpath : ''\n }\n\n /**\n * Disable app setting\n * @param setting\n */\n disable(setting: string): this {\n this.settings[setting] = false\n\n return this\n }\n\n /**\n * Render a template\n * @param file What to render\n * @param data data that is passed to a template\n * @param options Template engine options\n * @param cb Callback that consumes error and html\n */\n render(\n file: string,\n data: Record<string, unknown> = {},\n cb: (err: unknown, html: unknown) => void,\n options: TemplateEngineOptions<RenderOptions> = {}\n ): this {\n options.viewsFolder = options.viewsFolder || this.settings.views || `${process.cwd()}/views`\n options.ext = options.ext || file.slice(file.lastIndexOf('.') + 1) || 'ejs'\n\n options._locals = options._locals || {}\n\n options.cache = options.cache || process.env.NODE_ENV === 'production'\n\n let locals = { ...data, ...this.locals }\n\n if (options._locals) locals = { ...locals, ...options._locals }\n\n if (!file.endsWith(`.${options.ext}`)) file = `${file}.${options.ext}`\n\n const dest = options.viewsFolder ? path.join(options.viewsFolder, file) : file\n\n this.engines[options.ext](dest, locals, options.renderOptions, cb)\n\n return this\n }\n use(...args: UseMethodParams<Req, Res, App>): this {\n const base = args[0]\n\n const fns = args.slice(1).flat()\n\n let pathArray = []\n if (typeof base === 'function' || base instanceof App) {\n fns.unshift(base)\n } else {\n // if base is not an array of paths, then convert it to an array.\n let basePaths = []\n if (Array.isArray(base)) basePaths = [...base]\n else if (typeof base === 'string') basePaths = [base]\n\n basePaths = basePaths.filter((element) => {\n if (typeof element === 'string') {\n pathArray.push(element)\n return false\n }\n return true\n })\n fns.unshift(...basePaths)\n }\n pathArray = pathArray.length ? pathArray : ['/']\n\n const mountpath = pathArray.join(', ')\n let regex: { keys: string[]; pattern: RegExp }\n\n for (const fn of fns) {\n if (fn instanceof App) {\n pathArray.forEach((path) => {\n regex = rg(path, true)\n fn.mountpath = mountpath\n this.apps[path] = fn\n fn.parent = this\n })\n }\n }\n pathArray.forEach((path) => {\n const handlerPaths = []\n const handlerFunctions = []\n const handlerPathBase = path === '/' ? '' : lead(path)\n for (const fn of fns) {\n if (fn instanceof App && fn.middleware?.length) {\n for (const mw of fn.middleware) {\n handlerPaths.push(handlerPathBase + lead(mw.path))\n handlerFunctions.push(fn)\n }\n } else {\n handlerPaths.push('')\n handlerFunctions.push(fn)\n }\n }\n pushMiddleware(this.middleware)({\n path,\n regex,\n type: 'mw',\n handler: mount(handlerFunctions[0] as Handler),\n handlers: handlerFunctions.slice(1).map(mount),\n fullPaths: handlerPaths\n })\n })\n return this\n }\n /**\n * Register a template engine with extension\n */\n engine(ext: string, fn: TemplateFunc<RenderOptions>): this {\n this.engines[ext] = fn\n\n return this\n }\n\n route(path: string): App {\n const app = new App()\n\n this.use(path, app)\n\n return app\n }\n\n #find(url: string): Middleware<Req, Res>[] {\n return this.middleware.filter((m) => {\n m.regex = m.regex || rg(m.path, m.type === 'mw')\n\n let fullPathRegex: { keys: string[]; pattern: RegExp }\n\n m.fullPath && typeof m.fullPath === 'string'\n ? (fullPathRegex = rg(m.fullPath, m.type === 'mw'))\n : (fullPathRegex = null)\n\n return m.regex.pattern.test(url) && (m.type === 'mw' && fullPathRegex ? fullPathRegex.pattern.test(url) : true)\n })\n }\n\n /**\n * Extends Req / Res objects, pushes 404 and 500 handlers, dispatches middleware\n * @param req Req object\n * @param res Res object\n */\n handler(req: Req, res: Res, next?: NextFunction): void {\n /* Set X-Powered-By header */\n const { xPoweredBy } = this.settings\n if (xPoweredBy) res.setHeader('X-Powered-By', typeof xPoweredBy === 'string' ? xPoweredBy : 'tinyhttp')\n\n const exts = this.applyExtensions || extendMiddleware<RenderOptions>(this)\n\n req.originalUrl = req.url || req.originalUrl\n\n const pathname = getPathname(req.originalUrl)\n\n const matched = this.#find(pathname)\n\n const mw: Middleware[] = [\n {\n handler: exts,\n type: 'mw',\n path: '/'\n },\n ...matched.filter((x) => req.method === 'HEAD' || (x.method ? x.method === req.method : true))\n ]\n\n if (matched[0] != null) {\n mw.push({\n type: 'mw',\n handler: (req, res, next) => {\n if (req.method === 'HEAD') {\n res.statusCode = 204\n return res.end('')\n }\n next()\n },\n path: '/'\n })\n }\n\n mw.push({\n handler: this.noMatchHandler,\n type: 'mw',\n path: '/'\n })\n\n const handle = (mw: Middleware) => async (req: Req, res: Res, next?: NextFunction) => {\n const { path, handler, regex } = mw\n\n let params: URLParams\n\n try {\n params = regex ? getURLParams(regex, pathname) : {}\n } catch (e) {\n console.error(e)\n if (e instanceof URIError) return res.sendStatus(400) // Handle malformed URI\n else throw e\n }\n\n req.params = { ...req.params, ...params }\n\n if (path.includes(':')) {\n const first = Object.values(params)[0]\n const url = req.url.slice(req.url.indexOf(first) + first?.length)\n req.url = lead(url)\n } else {\n req.url = lead(req.url.substring(path.length))\n }\n\n if (!req.path) req.path = getPathname(req.url)\n\n if (this.settings?.enableReqRoute) req.route = getRouteFromApp(this, handler)\n\n await applyHandler<Req, Res>(handler as unknown as Handler<Req, Res>)(req, res, next)\n }\n\n let idx = 0\n\n const loop = () => res.writableEnded || (idx < mw.length && handle(mw[idx++])(req, res, next))\n\n next = next || ((err) => (err ? this.onError(err, req, res) : loop()))\n\n loop()\n }\n\n /**\n * Creates HTTP server and dispatches middleware\n * @param port server listening port\n * @param Server callback after server starts listening\n * @param host server listening host\n */\n listen(port?: number, cb?: () => void, host?: string): Server {\n return createServer().on('request', this.attach).listen(port, host, cb)\n }\n}\n"],"names":["proxyAddr","path","rg","req","res","next","mw"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/request.ts","../src/onError.ts","../src/response.ts","../src/extend.ts","../src/view.ts","../src/app.ts"],"sourcesContent":["import { IncomingMessage } from 'node:http'\nimport type { ParsedUrlQuery } from 'node:querystring'\n\nimport { Options, Ranges } from 'header-range-parser'\nimport { proxyaddr as proxyAddr, all, compile } from '@tinyhttp/proxy-addr'\n\nimport { App } from './app.js'\nimport type { Middleware } from '@tinyhttp/router'\n\nimport type { URLParams } from '@tinyhttp/req'\nimport { isIP } from 'node:net'\nimport type { Socket } from 'node:net'\nimport type { TLSSocket } from 'node:tls'\n\nexport { getURLParams } from '@tinyhttp/req'\n\nconst trustRemoteAddress = ({ socket }: Pick<Request, 'headers' | 'socket'>) => {\n const val = socket.remoteAddress\n if (typeof val === 'string') return compile(val.split(',').map((x) => x.trim()))\n return compile(val || [])\n}\n\nexport const getProtocol = (req: Request): Protocol => {\n const proto = `http${req.secure ? 's' : ''}`\n\n if (!trustRemoteAddress(req)) return proto\n\n const header = (req.headers['X-Forwarded-Proto'] as string) || proto\n\n const index = header.indexOf(',')\n\n return index !== -1 ? header.substring(0, index).trim() : header.trim()\n}\n\nexport const getHostname = (req: Request): string | undefined => {\n let host: string = req.get('X-Forwarded-Host') as string\n\n if (!host || !trustRemoteAddress(req)) host = req.get('Host') as string\n\n if (!host) return\n\n // IPv6 literal support\n const index = host.indexOf(':', host[0] === '[' ? host.indexOf(']') + 1 : 0)\n\n return index !== -1 ? host.substring(0, index) : host\n}\n\nexport const getIP = (req: Pick<Request, 'headers' | 'connection' | 'socket'>): string | undefined =>\n proxyAddr(req, trustRemoteAddress(req)).replace(/^.*:/, '') // striping the redundant prefix addeded by OS to IPv4 address\n\nexport const getIPs = (req: Pick<Request, 'headers' | 'connection' | 'socket'>): string[] | undefined =>\n all(req, trustRemoteAddress(req))\n\nexport const getSubdomains = (req: Request, subdomainOffset = 2): string[] => {\n const hostname = getHostname(req)\n\n if (!hostname) return []\n\n const subdomains = isIP(hostname) ? [hostname] : hostname.split('.').reverse()\n\n return subdomains.slice(subdomainOffset)\n}\n\nexport type Connection = IncomingMessage['socket'] & {\n encrypted: boolean\n}\n\nexport type Protocol = 'http' | 'https' | string\n\nexport type { URLParams }\n\ntype AcceptsReturns = string | boolean | string[]\n\nexport interface Request extends IncomingMessage {\n originalUrl: string\n path: string\n url: string\n query: ParsedUrlQuery\n params: URLParams\n connection: Connection\n socket: TLSSocket | Socket\n route?: Middleware\n protocol: Protocol\n secure: boolean\n xhr: boolean\n hostname?: string\n ip?: string\n ips?: string[]\n subdomains?: string[]\n get: (header: string) => string | string[] | undefined\n range: (size: number, options?: Options) => -1 | -2 | -3 | Ranges | undefined\n accepts: (...types: string[]) => AcceptsReturns\n acceptsEncodings: (...encodings: string[]) => AcceptsReturns\n acceptsCharsets: (...charsets: string[]) => AcceptsReturns\n acceptsLanguages: (...languages: string[]) => AcceptsReturns\n is: (...types: string[]) => boolean\n cookies?: any\n signedCookies?: any\n secret?: string | string[]\n fresh?: boolean\n stale?: boolean\n body?: any\n app?: App\n}\n","import type { NextFunction } from '@tinyhttp/router'\nimport { STATUS_CODES } from 'node:http'\nimport type { Request } from './request.js'\nimport type { Response } from './response.js'\nimport type { App } from './app.js'\n\nexport type ErrorHandler = (this: App, err: any, req: Request, res: Response, next?: NextFunction) => void\n\nexport const onErrorHandler: ErrorHandler = function (this: App, err: any, _req: Request, res: Response) {\n if (this.onError === onErrorHandler && this.parent) return this.parent.onError(err, _req, res)\n\n if (err instanceof Error) console.error(err)\n\n const code = err.code in STATUS_CODES ? err.code : err.status\n\n if (typeof err === 'string' || Buffer.isBuffer(err)) res.writeHead(500).end(err)\n else if (code in STATUS_CODES) res.writeHead(code).end(STATUS_CODES[code])\n else res.writeHead(500).end(err.message)\n}\n","import { ServerResponse } from 'node:http'\nimport type { SerializeOptions } from '@tinyhttp/cookie'\nimport { Request } from './request.js'\nimport { App } from './app.js'\nimport type { ReadStreamOptions, FormatProps, DownloadOptions } from '@tinyhttp/res'\nimport type { AppRenderOptions, TemplateEngineOptions } from './types.js'\n\nexport const renderTemplate =\n <O extends TemplateEngineOptions = TemplateEngineOptions>(_req: Request, res: Response, app: App) =>\n (file: string, data?: Record<string, unknown>, options?: AppRenderOptions<O>): Response => {\n app.render(file, data ? { ...res.locals, ...data } : res.locals, options, (err: unknown, html: unknown) => {\n if (err) throw err\n res.send(html)\n })\n return res\n }\n\nexport interface Response<B = unknown> extends ServerResponse {\n header(field: string | Record<string, unknown>, val?: string | any[]): Response<B>\n set(field: string | Record<string, unknown>, val?: string | any[]): Response<B>\n get(field: string): string | number | string[]\n send(body: B): Response<B>\n sendFile(path: string, options?: ReadStreamOptions, cb?: (err?: unknown) => void): Response<B>\n json(body: B): Response<B>\n status(status: number): Response<B>\n sendStatus(statusCode: number): Response<B>\n cookie(\n name: string,\n value: string | Record<string, unknown>,\n options?: SerializeOptions & Partial<{ signed: boolean }>\n ): Response<B>\n clearCookie(name: string, options?: SerializeOptions): Response<B>\n location(url: string): Response<B>\n links(links: { [key: string]: string }): Response<B>\n render<O extends TemplateEngineOptions = TemplateEngineOptions>(\n file: string,\n data?: Record<string, any>,\n options?: AppRenderOptions<O>\n ): Response<B>\n vary(field: string): Response<B>\n format(obj: FormatProps): Response<B>\n redirect(url: string, status?: number): Response<B>\n type(type: string): Response<B>\n download(path: string, filename: string, options?: DownloadOptions, cb?: (err?: unknown) => void): Response<B>\n attachment(filename?: string): Response<B>\n app?: App\n locals: Record<string, any>\n /**\n * Send JSON response with JSONP callback support.\n *\n * To enable this method, install the `@tinyhttp/jsonp` package and attach the method to `res.jsonp` property.\n *\n * @param obj Response object\n */\n jsonp(obj: any): Response<B>\n\n append(field: string, value: any): Response<B>\n}\n","import { getSubdomains, Request } from './request.js'\nimport type { NextFunction } from '@tinyhttp/router'\nimport type { Response } from './response.js'\nimport {\n getFreshOrStale,\n getRangeFromHeader,\n getRequestHeader,\n checkIfXMLHttpRequest,\n getQueryParams,\n getAccepts,\n getAcceptsCharsets,\n getAcceptsEncodings,\n getAcceptsLanguages\n} from '@tinyhttp/req'\nimport { getProtocol, getHostname, getIP, getIPs } from './request.js'\nimport {\n send,\n json,\n status,\n setCookie,\n clearCookie,\n setHeader,\n getResponseHeader,\n setLocationHeader,\n setLinksHeader,\n sendStatus,\n setVaryHeader,\n sendFile,\n formatResponse,\n redirect,\n setContentType,\n attachment,\n download,\n append\n} from '@tinyhttp/res'\nimport { renderTemplate } from './response.js'\nimport { App } from './app.js'\nimport { TemplateEngineOptions } from './types.js'\n\n/**\n * Extends Request and Response objects with custom properties and methods\n */\nexport const extendMiddleware =\n <EngineOptions extends TemplateEngineOptions = TemplateEngineOptions>(app: App) =>\n (req: Request, res: Response<EngineOptions>, next: NextFunction): void => {\n const { settings } = app\n\n res.get = getResponseHeader(res)\n req.get = getRequestHeader(req)\n\n if (settings?.bindAppToReqRes) {\n req.app = app\n res.app = app\n }\n\n if (settings?.networkExtensions) {\n req.protocol = getProtocol(req)\n req.secure = req.protocol === 'https'\n req.hostname = getHostname(req)\n req.subdomains = getSubdomains(req, settings.subdomainOffset)\n req.ip = getIP(req)\n req.ips = getIPs(req)\n }\n\n req.query = getQueryParams(req.url)\n\n req.range = getRangeFromHeader(req)\n req.accepts = getAccepts(req)\n req.acceptsCharsets = getAcceptsCharsets(req)\n req.acceptsEncodings = getAcceptsEncodings(req)\n req.acceptsLanguages = getAcceptsLanguages(req)\n\n req.xhr = checkIfXMLHttpRequest(req)\n\n res.header = res.set = setHeader<Response>(res)\n res.send = send<Request, Response>(req, res)\n res.json = json<Response>(res)\n res.status = status<Response>(res)\n res.sendStatus = sendStatus<Request, Response>(req, res)\n res.sendFile = sendFile<Request, Response>(req, res)\n res.type = setContentType<Response>(res)\n res.location = setLocationHeader<Request, Response>(req, res)\n res.links = setLinksHeader<Response>(res)\n res.vary = setVaryHeader<Response>(res)\n res.cookie = setCookie<Request, Response>(req, res)\n res.clearCookie = clearCookie<Request, Response>(req, res)\n res.render = renderTemplate(req, res, app)\n res.format = formatResponse(req, res, next)\n res.redirect = redirect(req, res, next)\n res.attachment = attachment<Response>(res)\n res.download = download<Request, Response>(req, res)\n res.append = append<Response>(res)\n res.locals = res.locals || Object.create(null)\n\n Object.defineProperty(req, 'fresh', { get: getFreshOrStale.bind(null, req, res), configurable: true })\n req.stale = !req.fresh\n\n next()\n }\n","/*!\n * Ported from https://github.com/expressjs/express/blob/master/lib/view.js\n * express\n * Copyright(c) 2009-2013 TJ Holowaychuk\n * Copyright(c) 2013 Roman Shtylman\n * Copyright(c) 2014-2015 Douglas Christopher Wilson\n * MIT Licensed\n */\n\nimport { extname, resolve, dirname, basename, join } from 'node:path'\nimport { TemplateEngineOptions, TemplateEngine } from './types.js'\nimport { statSync } from 'node:fs'\n\nfunction tryStat(path: string) {\n try {\n return statSync(path)\n } catch (e) {\n return undefined\n }\n}\n\n/**\n * Initialize a new `View` with the given `name`.\n *\n * Options:\n *\n * - `defaultEngine` the default template engine name\n * - `engines` template engine require() cache\n * - `root` root path for view lookup\n *\n * @param name\n * @param options\n * @public\n */\n\nexport class View<RenderOptions extends TemplateEngineOptions = TemplateEngineOptions> {\n ext: string\n defaultEngine: string\n name: string\n engine: TemplateEngine<RenderOptions>\n path: string\n root: string | string[]\n constructor(\n name: string,\n opts: Partial<{\n defaultEngine: string\n root: string | string[]\n engines: Record<string, TemplateEngine<RenderOptions>>\n }> = {}\n ) {\n this.ext = extname(name)\n this.name = name\n this.root = opts.root\n this.defaultEngine = opts.defaultEngine\n\n if (!this.ext && !this.defaultEngine)\n throw new Error('No default engine was specified and no extension was provided.')\n\n let fileName = name\n\n if (!this.ext) {\n // get extension from default engine name\n this.ext = this.defaultEngine[0] !== '.' ? '.' + this.defaultEngine : this.defaultEngine\n\n fileName += this.ext\n }\n\n if (!opts.engines[this.ext]) throw new Error(`No engine was found for ${this.ext}`)\n\n this.engine = opts.engines[this.ext]\n this.path = this.#lookup(fileName)\n }\n #lookup(name: string) {\n let path: string\n const roots = [].concat(this.root)\n\n for (let i = 0; i < roots.length && !path; i++) {\n const root = roots[i]\n // resolve the path\n const loc = resolve(root, name)\n const dir = dirname(loc)\n const file = basename(loc)\n\n // resolve the file\n path = this.#resolve(dir, file)\n }\n\n return path\n }\n #resolve(dir: string, file: string) {\n const ext = this.ext\n\n // <path>.<ext>\n let path = join(dir, file)\n let stat = tryStat(path)\n\n if (stat && stat.isFile()) {\n return path\n }\n\n // <path>/index.<ext>\n path = join(dir, basename(file, ext), 'index' + ext)\n stat = tryStat(path)\n\n if (stat && stat.isFile()) {\n return path\n }\n }\n render(options: RenderOptions, data: Record<string, unknown>, cb: (err: Error | null, html: unknown) => void) {\n this.engine(this.path, data, options, cb)\n }\n}\n","import { createServer, Server } from 'node:http'\nimport { getURLParams } from './request.js'\nimport type { Request, URLParams } from './request.js'\nimport type { Response } from './response.js'\nimport type { ErrorHandler } from './onError.js'\nimport { onErrorHandler } from './onError.js'\nimport type { Middleware, Handler, NextFunction, UseMethodParams } from '@tinyhttp/router'\nimport { Router, pushMiddleware } from '@tinyhttp/router'\nimport { extendMiddleware } from './extend.js'\nimport { parse as rg } from 'regexparam'\nimport { getPathname } from '@tinyhttp/req'\nimport { AppConstructor, AppRenderOptions, AppSettings, TemplateEngine } from './types.js'\nimport { TemplateEngineOptions } from './index.js'\nimport { View } from './view.js'\n\n/**\n * Add leading slash if not present (e.g. path -> /path, /path -> /path)\n * @param x\n */\nconst lead = (x: string) => (x.charCodeAt(0) === 47 ? x : '/' + x)\n\nconst mount = (fn: App | Handler) => (fn instanceof App ? fn.attach : fn)\n\nconst applyHandler =\n <Req, Res>(h: Handler<Req, Res>) =>\n async (req: Req, res: Res, next?: NextFunction) => {\n try {\n if (h[Symbol.toStringTag] === 'AsyncFunction') {\n await h(req, res, next)\n } else h(req, res, next)\n } catch (e) {\n next(e)\n }\n }\n\n/**\n * `App` class - the starting point of tinyhttp app.\n *\n * With the `App` you can:\n * * use routing methods and `.use(...)`\n * * set no match (404) and error (500) handlers\n * * configure template engines\n * * store data in locals\n * * listen the http server on a specified port\n *\n * In case you use TypeScript, you can pass custom types to this class because it is also a generic class.\n *\n * Example:\n *\n * ```ts\n * interface CoolReq extends Request {\n * genericsAreDope: boolean\n * }\n *\n * const app = App<any, CoolReq, Response>()\n * ```\n */\nexport class App<Req extends Request = Request, Res extends Response = Response> extends Router<App, Req, Res> {\n middleware: Middleware<Req, Res>[] = []\n locals: Record<string, unknown> = {}\n noMatchHandler: Handler\n onError: ErrorHandler\n settings: AppSettings\n engines: Record<string, TemplateEngine> = {}\n applyExtensions: (req: Request, res: Response, next: NextFunction) => void\n attach: (req: Req, res: Res) => void\n cache: Record<string, unknown>\n\n constructor(options: AppConstructor<Req, Res> = {}) {\n super()\n this.onError = options?.onError || onErrorHandler\n this.noMatchHandler = options?.noMatchHandler || this.onError.bind(this, { code: 404 })\n this.settings = {\n view: View,\n xPoweredBy: true,\n views: `${process.cwd()}/views`,\n 'view cache': process.env.NODE_ENV === 'production',\n ...options.settings\n }\n this.applyExtensions = options?.applyExtensions\n this.attach = (req, res) => setImmediate(this.handler.bind(this, req, res, undefined), req, res)\n this.cache = {}\n }\n\n /**\n * Set app setting\n * @param setting setting name\n * @param value setting value\n */\n set<K extends keyof AppSettings>(setting: K, value: AppSettings[K]): this {\n this.settings[setting] = value\n\n return this\n }\n\n /**\n * Enable app setting\n * @param setting Setting name\n */\n enable<K extends keyof AppSettings>(setting: K): this {\n this.settings[setting] = true as AppSettings[K]\n\n return this\n }\n\n /**\n * Check if setting is enabled\n * @param setting Setting name\n * @returns\n */\n enabled<K extends keyof AppSettings>(setting: K): boolean {\n return Boolean(this.settings[setting])\n }\n\n /**\n * Disable app setting\n * @param setting Setting name\n */\n disable<K extends keyof AppSettings>(setting: K): this {\n this.settings[setting] = false as AppSettings[K]\n\n return this\n }\n\n /**\n * Return the app's absolute pathname\n * based on the parent(s) that have\n * mounted it.\n *\n * For example if the application was\n * mounted as `\"/admin\"`, which itself\n * was mounted as `\"/blog\"` then the\n * return value would be `\"/blog/admin\"`.\n *\n */\n path(): string {\n return this.parent ? this.parent.path() + this.mountpath : ''\n }\n\n /**\n * Register a template engine with extension\n */\n engine<RenderOptions extends TemplateEngineOptions = TemplateEngineOptions>(\n ext: string,\n fn: TemplateEngine<RenderOptions>\n ): this {\n this.engines[ext[0] === '.' ? ext : `.${ext}`] = fn\n\n return this\n }\n\n /**\n * Render a template\n * @param file What to render\n * @param data data that is passed to a template\n * @param options Template engine options\n * @param cb Callback that consumes error and html\n */\n render<RenderOptions extends TemplateEngineOptions = TemplateEngineOptions>(\n name: string,\n data: Record<string, unknown> = {},\n options: AppRenderOptions<RenderOptions> = {} as AppRenderOptions<RenderOptions>,\n cb: (err: unknown, html?: unknown) => void\n ): void {\n let view: View | undefined\n\n const { _locals, ...opts } = options\n\n let locals = this.locals\n\n if (_locals) locals = { ...locals, ..._locals }\n\n locals = { ...locals, ...data }\n\n if (opts.cache == null) (opts.cache as boolean) = this.enabled('view cache')\n\n if (opts.cache) {\n view = this.cache[name] as View\n }\n\n if (!view) {\n const View = this.settings['view']\n view = new View(name, {\n defaultEngine: this.settings['view engine'],\n root: this.settings.views,\n engines: this.engines\n })\n\n if (!view.path) {\n const dirs =\n Array.isArray(view.root) && view.root.length > 1\n ? 'directories \"' + view.root.slice(0, -1).join('\", \"') + '\" or \"' + view.root[view.root.length - 1] + '\"'\n : 'directory \"' + view.root + '\"'\n const err = new Error('Failed to lookup view \"' + name + '\" in views ' + dirs)\n\n return cb(err)\n }\n\n if (opts.cache) {\n this.cache[name] = view\n }\n }\n\n try {\n view.render(opts, locals, cb)\n } catch (err) {\n cb(err)\n }\n }\n use(...args: UseMethodParams<Req, Res, App>): this {\n const base = args[0]\n\n const fns = args.slice(1).flat()\n\n let pathArray = []\n if (typeof base === 'function' || base instanceof App) {\n fns.unshift(base)\n } else {\n // if base is not an array of paths, then convert it to an array.\n let basePaths = []\n if (Array.isArray(base)) basePaths = [...base]\n else if (typeof base === 'string') basePaths = [base]\n\n basePaths = basePaths.filter((element) => {\n if (typeof element === 'string') {\n pathArray.push(element)\n return false\n }\n return true\n })\n fns.unshift(...basePaths)\n }\n pathArray = pathArray.length ? pathArray.map((path) => lead(path)) : ['/']\n\n const mountpath = pathArray.join(', ')\n let regex: { keys: string[]; pattern: RegExp }\n\n for (const fn of fns) {\n if (fn instanceof App) {\n pathArray.forEach((path) => {\n regex = rg(path, true)\n fn.mountpath = mountpath\n this.apps[path] = fn\n fn.parent = this\n })\n }\n }\n pathArray.forEach((path) => {\n const handlerPaths = []\n const handlerFunctions = []\n const handlerPathBase = path === '/' ? '' : lead(path)\n for (const fn of fns) {\n if (fn instanceof App && fn.middleware?.length) {\n for (const mw of fn.middleware) {\n handlerPaths.push(handlerPathBase + lead(mw.path))\n handlerFunctions.push(fn)\n }\n } else {\n handlerPaths.push('')\n handlerFunctions.push(fn)\n }\n }\n pushMiddleware(this.middleware)({\n path,\n regex,\n type: 'mw',\n handler: mount(handlerFunctions[0] as Handler),\n handlers: handlerFunctions.slice(1).map(mount),\n fullPaths: handlerPaths\n })\n })\n return this\n }\n\n route(path: string): App {\n const app = new App({ settings: this.settings })\n\n this.use(path, app)\n\n return app\n }\n\n #find(url: string): Middleware<Req, Res>[] {\n return this.middleware.filter((m) => {\n m.regex = m.regex || rg(m.path, m.type === 'mw')\n\n let fullPathRegex: { keys: string[]; pattern: RegExp }\n\n m.fullPath && typeof m.fullPath === 'string'\n ? (fullPathRegex = rg(m.fullPath, m.type === 'mw'))\n : (fullPathRegex = null)\n\n return m.regex.pattern.test(url) && (m.type === 'mw' && fullPathRegex ? fullPathRegex.pattern.test(url) : true)\n })\n }\n\n /**\n * Extends Req / Res objects, pushes 404 and 500 handlers, dispatches middleware\n * @param req Req object\n * @param res Res object\n */\n handler<RenderOptions extends TemplateEngineOptions = TemplateEngineOptions>(\n req: Req,\n res: Res,\n next?: NextFunction\n ): void {\n /* Set X-Powered-By header */\n const { xPoweredBy } = this.settings\n if (xPoweredBy) res.setHeader('X-Powered-By', typeof xPoweredBy === 'string' ? xPoweredBy : 'tinyhttp')\n\n const exts = this.applyExtensions || extendMiddleware<RenderOptions>(this)\n\n req.originalUrl = req.url || req.originalUrl\n\n const pathname = getPathname(req.originalUrl)\n\n const matched = this.#find(pathname)\n\n const mw: Middleware[] = [\n {\n handler: exts,\n type: 'mw',\n path: '/'\n },\n ...matched.filter((x) => req.method === 'HEAD' || (x.method ? x.method === req.method : true))\n ]\n\n if (matched[0] != null) {\n mw.push({\n type: 'mw',\n handler: (req, res, next) => {\n if (req.method === 'HEAD') {\n res.statusCode = 204\n return res.end('')\n }\n next()\n },\n path: '/'\n })\n }\n\n mw.push({\n handler: this.noMatchHandler,\n type: 'mw',\n path: '/'\n })\n\n const handle = (mw: Middleware) => async (req: Req, res: Res, next?: NextFunction) => {\n const { path, handler, regex } = mw\n\n let params: URLParams\n\n try {\n params = regex ? getURLParams(regex, pathname) : {}\n } catch (e) {\n console.error(e)\n if (e instanceof URIError) return res.sendStatus(400) // Handle malformed URI\n else throw e\n }\n\n // Warning: users should not use :wild as a pattern\n let prefix = path\n if (regex) {\n for (const key of regex.keys) {\n if (key === 'wild') {\n prefix = prefix.replace('*', params.wild)\n } else {\n prefix = prefix.replace(`:${key}`, params[key])\n }\n }\n }\n\n req.params = { ...req.params, ...params }\n\n if (mw.type === 'mw') {\n req.url = lead(req.originalUrl.substring(prefix.length))\n }\n\n if (!req.path) req.path = getPathname(req.url)\n\n if (this.settings?.enableReqRoute) req.route = mw\n\n await applyHandler<Req, Res>(handler as unknown as Handler<Req, Res>)(req, res, next)\n }\n\n let idx = 0\n\n const loop = () => res.writableEnded || (idx < mw.length && handle(mw[idx++])(req, res, next))\n\n next = next || ((err) => (err ? this.onError(err, req, res) : loop()))\n\n loop()\n }\n\n /**\n * Creates HTTP server and dispatches middleware\n * @param port server listening port\n * @param Server callback after server starts listening\n * @param host server listening host\n */\n listen(port?: number, cb?: () => void, host?: string): Server {\n return createServer().on('request', this.attach).listen(port, host, cb)\n }\n}\n"],"names":["proxyAddr","View","rg","req","res","next","mw"],"mappings":"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"}
package/dist/request.d.ts CHANGED
@@ -6,13 +6,11 @@ import { IncomingMessage } from 'node:http';
6
6
  import type { ParsedUrlQuery } from 'node:querystring';
7
7
  import { Options, Ranges } from 'header-range-parser';
8
8
  import { App } from './app.js';
9
- import type { Middleware, Handler } from '@tinyhttp/router';
10
- import type { Response } from './response.js';
9
+ import type { Middleware } from '@tinyhttp/router';
11
10
  import type { URLParams } from '@tinyhttp/req';
12
11
  import type { Socket } from 'node:net';
13
12
  import type { TLSSocket } from 'node:tls';
14
13
  export { getURLParams } from '@tinyhttp/req';
15
- export declare const getRouteFromApp: ({ middleware }: App, h: Handler<Request, Response>) => Middleware<Request, Response>;
16
14
  export declare const getProtocol: (req: Request) => Protocol;
17
15
  export declare const getHostname: (req: Request) => string | undefined;
18
16
  export declare const getIP: (req: Pick<Request, 'headers' | 'connection' | 'socket'>) => string | undefined;
@@ -21,7 +19,7 @@ export declare const getSubdomains: (req: Request, subdomainOffset?: number) =>
21
19
  export type Connection = IncomingMessage['socket'] & {
22
20
  encrypted: boolean;
23
21
  };
24
- export type Protocol = 'node:http' | 'https' | string;
22
+ export type Protocol = 'http' | 'https' | string;
25
23
  export type { URLParams };
26
24
  type AcceptsReturns = string | boolean | string[];
27
25
  export interface Request extends IncomingMessage {
@@ -2,41 +2,36 @@
2
2
  import { ServerResponse } from 'node:http';
3
3
  import type { SerializeOptions } from '@tinyhttp/cookie';
4
4
  import { Request } from './request.js';
5
- import { App, TemplateEngineOptions } from './app.js';
5
+ import { App } from './app.js';
6
6
  import type { ReadStreamOptions, FormatProps, DownloadOptions } from '@tinyhttp/res';
7
- export declare const renderTemplate: <O>(_req: Request, res: Response, app: App) => (file: string, data?: Record<string, any>, options?: Partial<{
8
- cache: boolean;
9
- ext: string;
10
- renderOptions: Partial<O>;
11
- viewsFolder: string;
12
- _locals: Record<string, any>;
13
- }>) => Response;
14
- export interface Response<O = any, B = any> extends ServerResponse {
15
- header(field: string | Record<string, unknown>, val?: string | any[]): Response<O, B>;
16
- set(field: string | Record<string, unknown>, val?: string | any[]): Response<O, B>;
7
+ import type { AppRenderOptions, TemplateEngineOptions } from './types.js';
8
+ export declare const renderTemplate: <O extends TemplateEngineOptions = TemplateEngineOptions>(_req: Request, res: Response, app: App) => (file: string, data?: Record<string, unknown>, options?: AppRenderOptions<O>) => Response;
9
+ export interface Response<B = unknown> extends ServerResponse {
10
+ header(field: string | Record<string, unknown>, val?: string | any[]): Response<B>;
11
+ set(field: string | Record<string, unknown>, val?: string | any[]): Response<B>;
17
12
  get(field: string): string | number | string[];
18
- send(body: B): Response<O, B>;
19
- sendFile(path: string, options?: ReadStreamOptions, cb?: (err?: any) => void): Response<O, B>;
20
- json(body: B): Response<O, B>;
21
- status(status: number): Response<O, B>;
22
- sendStatus(statusCode: number): Response<O, B>;
13
+ send(body: B): Response<B>;
14
+ sendFile(path: string, options?: ReadStreamOptions, cb?: (err?: unknown) => void): Response<B>;
15
+ json(body: B): Response<B>;
16
+ status(status: number): Response<B>;
17
+ sendStatus(statusCode: number): Response<B>;
23
18
  cookie(name: string, value: string | Record<string, unknown>, options?: SerializeOptions & Partial<{
24
19
  signed: boolean;
25
- }>): Response<O, B>;
26
- clearCookie(name: string, options?: SerializeOptions): Response<O, B>;
27
- location(url: string): Response<O, B>;
20
+ }>): Response<B>;
21
+ clearCookie(name: string, options?: SerializeOptions): Response<B>;
22
+ location(url: string): Response<B>;
28
23
  links(links: {
29
24
  [key: string]: string;
30
- }): Response<O, B>;
31
- render(file: string, data?: Record<string, any>, options?: TemplateEngineOptions<O>): Response<O, B>;
32
- vary(field: string): Response<O, B>;
33
- format(obj: FormatProps): Response<O, B>;
34
- redirect(url: string, status?: number): Response<O, B>;
35
- type(type: string): Response<O, B>;
36
- download(path: string, filename: string, options?: DownloadOptions, cb?: (err?: any) => void): Response<O, B>;
37
- attachment(filename?: string): Response<O, B>;
25
+ }): Response<B>;
26
+ render<O extends TemplateEngineOptions = TemplateEngineOptions>(file: string, data?: Record<string, any>, options?: AppRenderOptions<O>): Response<B>;
27
+ vary(field: string): Response<B>;
28
+ format(obj: FormatProps): Response<B>;
29
+ redirect(url: string, status?: number): Response<B>;
30
+ type(type: string): Response<B>;
31
+ download(path: string, filename: string, options?: DownloadOptions, cb?: (err?: unknown) => void): Response<B>;
32
+ attachment(filename?: string): Response<B>;
38
33
  app?: App;
39
- locals?: Record<string, any>;
34
+ locals: Record<string, any>;
40
35
  /**
41
36
  * Send JSON response with JSONP callback support.
42
37
  *
@@ -44,6 +39,6 @@ export interface Response<O = any, B = any> extends ServerResponse {
44
39
  *
45
40
  * @param obj Response object
46
41
  */
47
- jsonp(obj: any): Response<O, B>;
48
- append(field: string, value: any): Response<O, B>;
42
+ jsonp(obj: any): Response<B>;
43
+ append(field: string, value: any): Response<B>;
49
44
  }
@@ -0,0 +1,39 @@
1
+ import type { Handler, NextFunction } from '@tinyhttp/router';
2
+ import type { ErrorHandler } from './onError.js';
3
+ import type { Request } from './request.js';
4
+ import type { Response } from './response.js';
5
+ import type { View } from './view.js';
6
+ /**
7
+ * tinyhttp App has a few settings for toggling features
8
+ */
9
+ export type AppSettings = Partial<{
10
+ networkExtensions: boolean;
11
+ subdomainOffset: number;
12
+ bindAppToReqRes: boolean;
13
+ xPoweredBy: string | boolean;
14
+ enableReqRoute: boolean;
15
+ views: string | string[];
16
+ view: typeof View;
17
+ 'view cache': boolean;
18
+ 'view engine': string;
19
+ }>;
20
+ export type TemplateEngineOptions = {
21
+ [key: string]: unknown;
22
+ };
23
+ /**
24
+ * Function that processes the template
25
+ */
26
+ export type TemplateEngine<O extends TemplateEngineOptions = TemplateEngineOptions> = (path: string, locals: Record<string, unknown>, opts: AppRenderOptions<O>, cb: (err: Error | null, html: unknown) => void) => void;
27
+ export type AppRenderOptions<O extends TemplateEngineOptions = TemplateEngineOptions> = O & Partial<{
28
+ cache: boolean;
29
+ ext: string;
30
+ viewsFolder: string;
31
+ _locals: Record<string, unknown>;
32
+ }>;
33
+ export type AppConstructor<Req extends Request = Request, Res extends Response = Response> = Partial<{
34
+ noMatchHandler: Handler<Req, Res>;
35
+ onError: ErrorHandler;
36
+ settings: AppSettings;
37
+ applyExtensions: (req: Request, res: Response, next: NextFunction) => void;
38
+ }>;
39
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAErC;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC;IAChC,iBAAiB,EAAE,OAAO,CAAA;IAC1B,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,OAAO,CAAA;IACxB,UAAU,EAAE,MAAM,GAAG,OAAO,CAAA;IAC5B,cAAc,EAAE,OAAO,CAAA;IACvB,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACxB,IAAI,EAAE,OAAO,IAAI,CAAA;IACjB,YAAY,EAAE,OAAO,CAAA;IACrB,aAAa,EAAE,MAAM,CAAA;CACtB,CAAC,CAAA;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,qBAAqB,GAAG,qBAAqB,IAAI,CACpF,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,EACzB,EAAE,EAAE,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,KAC3C,IAAI,CAAA;AAET,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,qBAAqB,GAAG,qBAAqB,IAAI,CAAC,GACvF,OAAO,CAAC;IACN,KAAK,EAAE,OAAO,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACjC,CAAC,CAAA;AAEJ,MAAM,MAAM,cAAc,CAAC,GAAG,SAAS,OAAO,GAAG,OAAO,EAAE,GAAG,SAAS,QAAQ,GAAG,QAAQ,IAAI,OAAO,CAAC;IACnG,cAAc,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IACjC,OAAO,EAAE,YAAY,CAAA;IACrB,QAAQ,EAAE,WAAW,CAAA;IACrB,eAAe,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAA;CAC3E,CAAC,CAAA"}
package/dist/view.d.ts ADDED
@@ -0,0 +1,37 @@
1
+ /*!
2
+ * Ported from https://github.com/expressjs/express/blob/master/lib/view.js
3
+ * express
4
+ * Copyright(c) 2009-2013 TJ Holowaychuk
5
+ * Copyright(c) 2013 Roman Shtylman
6
+ * Copyright(c) 2014-2015 Douglas Christopher Wilson
7
+ * MIT Licensed
8
+ */
9
+ import { TemplateEngineOptions, TemplateEngine } from './types.js';
10
+ /**
11
+ * Initialize a new `View` with the given `name`.
12
+ *
13
+ * Options:
14
+ *
15
+ * - `defaultEngine` the default template engine name
16
+ * - `engines` template engine require() cache
17
+ * - `root` root path for view lookup
18
+ *
19
+ * @param name
20
+ * @param options
21
+ * @public
22
+ */
23
+ export declare class View<RenderOptions extends TemplateEngineOptions = TemplateEngineOptions> {
24
+ #private;
25
+ ext: string;
26
+ defaultEngine: string;
27
+ name: string;
28
+ engine: TemplateEngine<RenderOptions>;
29
+ path: string;
30
+ root: string | string[];
31
+ constructor(name: string, opts?: Partial<{
32
+ defaultEngine: string;
33
+ root: string | string[];
34
+ engines: Record<string, TemplateEngine<RenderOptions>>;
35
+ }>);
36
+ render(options: RenderOptions, data: Record<string, unknown>, cb: (err: Error | null, html: unknown) => void): void;
37
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinyhttp/app",
3
- "version": "2.1.4",
3
+ "version": "2.2.1",
4
4
  "description": "0-legacy, tiny & fast web framework as a replacement of Express",
5
5
  "type": "module",
6
6
  "homepage": "https://tinyhttp.v1rtl.site",
@@ -36,9 +36,9 @@
36
36
  "regexparam": "^2.0.1",
37
37
  "@tinyhttp/cookie": "2.1.0",
38
38
  "@tinyhttp/proxy-addr": "2.1.2",
39
- "@tinyhttp/res": "2.1.0",
40
- "@tinyhttp/req": "2.1.0",
41
- "@tinyhttp/router": "2.2.1"
39
+ "@tinyhttp/req": "2.2.0",
40
+ "@tinyhttp/router": "2.2.1",
41
+ "@tinyhttp/res": "2.2.0"
42
42
  },
43
43
  "scripts": {
44
44
  "dev": "vite",