@hyperspan/framework 0.0.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/app.ts DELETED
@@ -1,186 +0,0 @@
1
- // @ts-ignore
2
- import Router from 'trek-router';
3
- // @ts-ignore
4
- import Middleware from 'trek-middleware';
5
- import deepmerge from '@fastify/deepmerge';
6
- import Headers from '@mjackson/headers';
7
-
8
- const mergeAll = deepmerge({ all: true });
9
-
10
- type THTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
11
-
12
- /**
13
- * Request context
14
- */
15
- export class HSRequestContext {
16
- public req: Request;
17
- public locals: Record<string, any>;
18
- public headers: Headers;
19
- public route: {
20
- params: Record<string, string>;
21
- query: URLSearchParams;
22
- };
23
-
24
- constructor(req: Request, params: Record<string, string> = {}) {
25
- this.req = req;
26
- this.locals = {};
27
- this.route = {
28
- params,
29
- query: new URL(req.url).searchParams,
30
- };
31
-
32
- // This could probably be re-visited...
33
- const allowHeaders = ['cookie'];
34
- const reqHeaders: Record<string, string> = {};
35
-
36
- for (let [name, value] of req.headers) {
37
- if (allowHeaders.includes(name)) {
38
- reqHeaders[name] = value;
39
- }
40
- }
41
-
42
- this.headers = new Headers(reqHeaders);
43
- }
44
-
45
- /**
46
- * Response helper
47
- * Merges a Response object while preserving all headers added in context/middleware
48
- */
49
- resMerge(res: Response) {
50
- const cHeaders: Record<string, string> = {};
51
- for (let [name, value] of this.headers) {
52
- cHeaders[name] = value;
53
- }
54
-
55
- const newRes = new Response(
56
- res.body,
57
- mergeAll(
58
- { headers: cHeaders },
59
- { headers: res.headers.toJSON() },
60
- { status: res.status, statusText: res.statusText }
61
- )
62
- );
63
-
64
- return newRes;
65
- }
66
-
67
- /**
68
- * HTML response helper
69
- * Preserves all headers added in context/middleware
70
- */
71
- html(content: string, options?: ResponseInit): Response {
72
- return new Response(content, mergeAll({ headers: { 'Content-Type': 'text/html' } }, options));
73
- }
74
-
75
- /**
76
- * JSON response helper
77
- * Preserves all headers added in context/middleware
78
- */
79
- json(content: any, options?: ResponseInit): Response {
80
- return new Response(
81
- JSON.stringify(content),
82
- mergeAll({ headers: { 'Content-Type': 'application/json' } }, options)
83
- );
84
- }
85
-
86
- notFound(msg: string = 'Not found!') {
87
- return this.html(msg, { status: 404 });
88
- }
89
- }
90
-
91
- type THSRouteHandler = (
92
- context: HSRequestContext
93
- ) => (Response | null | void) | Promise<Response | null | void>;
94
-
95
- /**
96
- * App
97
- */
98
- export class HSApp {
99
- private _router: typeof Router;
100
- private _mw: typeof Middleware;
101
- public _defaultRoute: THSRouteHandler;
102
-
103
- constructor() {
104
- this._router = new Router();
105
- this._mw = new Middleware();
106
- this._defaultRoute = (c: HSRequestContext) => {
107
- return c.notFound('Not found');
108
- };
109
- }
110
-
111
- // @TODO: Middleware !!!!
112
-
113
- public get(path: string, handler: THSRouteHandler) {
114
- return this._route('GET', path, handler);
115
- }
116
- public post(path: string, handler: THSRouteHandler) {
117
- return this._route('POST', path, handler);
118
- }
119
- public put(path: string, handler: THSRouteHandler) {
120
- return this._route('PUT', path, handler);
121
- }
122
- public delete(path: string, handler: THSRouteHandler) {
123
- return this._route('DELETE', path, handler);
124
- }
125
- public all(path: string, handler: THSRouteHandler) {
126
- return this.addRoute(['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], path, handler);
127
- }
128
- public addRoute(methods: THTTPMethod[], path: string, handler: THSRouteHandler) {
129
- methods.forEach((method) => {
130
- this._route(method, path, handler);
131
- });
132
- return this;
133
- }
134
- public defaultRoute(handler: THSRouteHandler) {
135
- this._defaultRoute = handler;
136
- }
137
- private _route(method: string | string[], path: string, handler: any) {
138
- this._router.add(method, path, handler);
139
- return this;
140
- }
141
-
142
- async run(req: Request): Promise<Response> {
143
- let response: Response;
144
- let url = new URL(req.url);
145
- let urlPath = normalizePath(url.pathname);
146
-
147
- // Redirect to normalized path (lowercase & without trailing slash)
148
- if (urlPath !== url.pathname) {
149
- url.pathname = urlPath;
150
- return Response.redirect(url);
151
- }
152
-
153
- let result = this._router.find(req.method.toUpperCase(), urlPath);
154
- let params: Record<string, any> = {};
155
-
156
- if (result && result[0]) {
157
- // Build params
158
- result[1].forEach((param: any) => (params[param.name] = param.value));
159
-
160
- // Run route with context
161
- const context = new HSRequestContext(req, params);
162
- response = result[0](context);
163
- }
164
-
165
- // @ts-ignore
166
- if (response) {
167
- return response;
168
- }
169
-
170
- const context = new HSRequestContext(req);
171
-
172
- // @ts-ignore
173
- return this._defaultRoute(context);
174
- }
175
- }
176
-
177
- /**
178
- * Normalize URL path
179
- * Removes trailing slash and lowercases path
180
- */
181
- export function normalizePath(urlPath: string): string {
182
- return (
183
- (urlPath.endsWith('/') ? urlPath.substring(0, urlPath.length - 1) : urlPath).toLowerCase() ||
184
- '/'
185
- );
186
- }