yinzerflow 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Redact Digital
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,340 @@
1
+ # YinzerJS Documentation
2
+
3
+ ## Overview
4
+
5
+ YinzJS is a lightweight HTTP server framework built for Node.js, designed with TypeScript in mind. It leverages TypeScript's powerful type system to provide enhanced type safety and autocompletion, making it easier for developers to build robust web applications. With YinzJS, you can enjoy a flexible routing system, middleware support, and a straightforward interface to handle incoming requests and responses—all while benefiting from TypeScript's clear typing and error-checking capabilities. This combination allows for a smoother development experience, reducing runtime errors and improving code maintainability.
6
+
7
+ ```typescript
8
+ import { YinzJS } from '@yinzjs/yinzjs';
9
+
10
+ export const app = new YinzJS({
11
+ port: 5000,
12
+ });
13
+
14
+ app.post('/example-route', (ctx) => {
15
+ const { body } = ctx.request;
16
+ return { message: 'Hello, world!' };
17
+ });
18
+
19
+ app.listen();
20
+ ```
21
+
22
+ Sure! Here’s an expanded version of the installation section for YinzJS, providing more context and options for users:
23
+
24
+ ---
25
+
26
+ ## Installation
27
+
28
+ To get started with YinzJS, simply install it using your preferred package manager. YinzJS is available via npm, as well as other popular package managers such as Bun, Yarn, and pnpm. Follow the instructions below based on the package manager you are using:
29
+
30
+ ### Using npm
31
+
32
+ If you are using npm, run the following command in your terminal:
33
+
34
+ ```bash
35
+ npm install @yinzjs/yinzjs
36
+ ```
37
+
38
+ This command will download and install YinzJS along with its dependencies into your project's `node_modules` folder.
39
+
40
+ ### Using Bun
41
+
42
+ For those who prefer Bun, you can add YinzJS to your project with the following command:
43
+
44
+ ```bash
45
+ bun add @yinzjs/yinzjs
46
+ ```
47
+
48
+ Bun is known for its speed and efficiency, making it a great choice for modern JavaScript development.
49
+
50
+ ### Using Yarn
51
+
52
+ If you're a Yarn user, you can easily install YinzJS by running:
53
+
54
+ ```bash
55
+ yarn add @yinzjs/yinzjs
56
+ ```
57
+
58
+ Yarn provides a fast and reliable way to manage your project's dependencies.
59
+
60
+ ### Using pnpm
61
+
62
+ For developers who utilize pnpm, you can install YinzJS with:
63
+
64
+ ```bash
65
+ pnpm add @yinzjs/yinzjs
66
+ ```
67
+
68
+ pnpm is an efficient package manager that saves disk space and speeds up installation times.
69
+
70
+ ## Getting Started
71
+
72
+ ### Importing YinzJS
73
+
74
+ ```typescript
75
+ import { YinzJS } from '@yinzjs/yinzjs';
76
+ ```
77
+
78
+ ### Creating an Application Instance
79
+
80
+ You can create an instance of YinzJS by specifying the desired port:
81
+
82
+ ```typescript
83
+ const app = new YinzJS({ port: 5000 });
84
+ ```
85
+
86
+ ### Defining Routes
87
+
88
+ You can define routes using the `route` method. Each route can have a path, a handler, and optional before and after handlers.
89
+
90
+ ```typescript
91
+ app.get(
92
+ '/example',
93
+ ({ request, response }) => {
94
+ return { message: 'Hello, world!' };
95
+ },
96
+ {
97
+ beforeHandler: ({ request, response }) => {
98
+ // Logic before the main handler
99
+ },
100
+ afterHandler: ({ request, response }) => {
101
+ // Logic after the main handler
102
+ },
103
+ },
104
+ );
105
+ ```
106
+
107
+ **Before handler uses:**
108
+ The before handler is a good place to perform operations such as authentication, validation, or any pre-processing logic before the main handler is executed.
109
+
110
+ **After handler uses:**
111
+ The after handler can be used for post-processing tasks like logging, modifying the response, or cleaning up resources after the main handler has completed.
112
+
113
+ ### Additional Route Methods and Parameters
114
+
115
+ YinzJS supports various HTTP methods such as `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, and `OPTIONS`. You can use these methods to define routes for specific HTTP requests.
116
+
117
+ ```typescript
118
+ app.get('/example-route', ({ request, response }) => {
119
+ // Route handler logic
120
+ });
121
+ app.patch('/example-route', ({ request, response }) => {
122
+ // Route handler logic
123
+ });
124
+ app.post('/example-route', ({ request, response }) => {
125
+ // Route handler logic
126
+ });
127
+ app.delete('/example-route', ({ request, response }) => {
128
+ // Route handler logic
129
+ });
130
+ ```
131
+
132
+ You can also specify route parameters using the `:param` syntax:
133
+
134
+ ```typescript
135
+ app.get('/users/:id', ({ request }) => {
136
+ const { params } = request;
137
+ const { id } = params;
138
+ // Route handler logic
139
+ });
140
+ ```
141
+
142
+ You can also access query parameters from the request:
143
+
144
+ ```typescript
145
+ app.get('/search?location=pittsburgh', ({ request, response }) => {
146
+ const { query } = request;
147
+ const { location } = query;
148
+ // Route handler logic
149
+ });
150
+ ```
151
+
152
+ ### Route Groups
153
+
154
+ You can group routes using the `group` method. This is useful for applying middleware to multiple routes at once or for organizing related routes.
155
+
156
+ ```typescript
157
+ app.group('/api', () => {
158
+ app.get('/users', ({ request, response }) => {
159
+ // Route handler logic
160
+ });
161
+ app.post('/users', ({ request, response }) => {
162
+ // Route handler logic
163
+ });
164
+ });
165
+ ```
166
+
167
+ If needed, you can also apply before handlers to the entire group. This logic will run after the global middleware but before the individual route before handlers
168
+
169
+ ```typescript
170
+ app.group(
171
+ '/api',
172
+ {
173
+ beforeHandler: ({ request, response }) => {
174
+ // Logic before the group
175
+ },
176
+ },
177
+ () => {
178
+ app.get('/users', ({ request, response }) => {
179
+ // Route handler logic
180
+ });
181
+ },
182
+ );
183
+ ```
184
+
185
+ ### Response Handling
186
+
187
+ The route handlers, before handlers, and middleware functions can return a response in the form of an object or a string. The headers and status code can be set using the `response` object as well. The return headers and status code will be assumed if they are not specified.
188
+
189
+ ```typescript
190
+ app.get('/example-route', () => {
191
+ return {
192
+ success: true,
193
+ message: 'Hello, world!',
194
+ };
195
+ });
196
+ ```
197
+
198
+ In this example, the response status is set to `200`, and the response body is an object meaning the response headers will be set to `application/json` by default.
199
+
200
+ ```typescript
201
+ app.post('/example-route', ({ response }) => {
202
+ response.setStatus(201);
203
+ return 'Hello, world!';
204
+ });
205
+ ```
206
+
207
+ There for more strict control over the response, you can use the `TResponseBody` type parameter to specify the response body type:
208
+
209
+ ```typescript
210
+ app.get('/example-route', (): TResponseBody<{ success: boolean; message: string }> => {
211
+ return {
212
+ success: true,
213
+ message: 'Hello, world!',
214
+ };
215
+ });
216
+ ```
217
+
218
+ In this example, the response status is set to `201`, and the response body is a string. The response headers are set to `text/plain` by default in this case.
219
+
220
+ ### Changing or Adding Headers
221
+
222
+ You can also add or remove headers using the `response` object:
223
+
224
+ ```typescript
225
+ app.get('/example-route', ({ response }) => {
226
+ response.addHeaders(['Content-Type: application/json']);
227
+ response.removeHeaders(['X-Auth-Token']);
228
+ return { success: true, message: 'Hello, world!' };
229
+ });
230
+ ```
231
+
232
+ ### Route Validation (Coming Soon)
233
+
234
+ You can validate routes using the `validate` method. This method takes a schema object and validates the request body, query parameters, or route parameters against it.
235
+
236
+ ```typescript
237
+ app.post(
238
+ '/example-route',
239
+ ({ request }) => {
240
+ const { body } = request;
241
+ const { name, age } = body;
242
+ // Route handler logic
243
+ },
244
+ {
245
+ validate: {
246
+ body: {
247
+ email: { type: 'email', required: true },
248
+ name: { type: 'string', required: true },
249
+ dateOfBirth: { type: 'date' },
250
+ age: { type: 'number', min: 18 },
251
+ },
252
+ },
253
+ },
254
+ );
255
+ ```
256
+
257
+ ### Middleware
258
+
259
+ YinzJS supports middleware that can be applied globally or to specific routes. Middleware can manipulate the request and also return a response. This is useful for tasks such as authentication and throttling.
260
+
261
+ #### Global Middleware
262
+
263
+ To apply middleware before all routes:
264
+
265
+ ```typescript
266
+ app.beforeAll(({ request, response }) => {
267
+ // middleware logic
268
+ });
269
+ ```
270
+
271
+ To apply middleware to specific routes:
272
+
273
+ ```typescript
274
+ app.beforeAll(
275
+ ({ request, response }) => {
276
+ // middleware logic
277
+ },
278
+ {
279
+ paths: ['/user/:id'],
280
+ excluded: [],
281
+ },
282
+ );
283
+ ```
284
+
285
+ To apply middleware to all routes except specific ones:
286
+
287
+ ```typescript
288
+ app.beforeAll(
289
+ ({ request, response }) => {
290
+ // middleware logic
291
+ },
292
+ {
293
+ paths: 'allButExcluded',
294
+ excluded: ['/login', '/register'],
295
+ },
296
+ );
297
+ ```
298
+
299
+ #### Include Middleware
300
+
301
+ To apply middleware to specific routes:
302
+
303
+ ```typescript
304
+ app.use({ paths: ['/route1', '/route2'] }, (ctx) => {
305
+ // Middleware logic
306
+ });
307
+ ```
308
+
309
+ ### Starting the Server
310
+
311
+ To start the server, call the `listen` method:
312
+
313
+ ```typescript
314
+ app.listen();
315
+ ```
316
+
317
+ ## Request Handling Flow
318
+
319
+ The request handling process follows this sequence:
320
+
321
+ 1. Incoming request
322
+ 2. Route validation
323
+ 3. Global middleware
324
+ 4. Before group middleware
325
+ 5. Before route middleware
326
+ 6. Route handler
327
+ 7. After route middleware
328
+ 8. Response sent
329
+
330
+ ## Examples
331
+
332
+ Refer to the examples folder in the YinzJS repository for more detailed usage examples.
333
+
334
+ ## Conclusion
335
+
336
+ YinzJS provides a straightforward way to build HTTP servers in Node.js, with support for routing and middleware. For more advanced features, consider extending the framework or integrating with other libraries.
337
+
338
+ ---
339
+
340
+ Feel free to modify or expand upon this documentation as needed! If you have specific sections or features you'd like to elaborate on, let me know!
package/index.d.ts ADDED
@@ -0,0 +1,244 @@
1
+ export declare const HttpMethod: {
2
+ readonly DELETE: "DELETE";
3
+ readonly GET: "GET";
4
+ readonly POST: "POST";
5
+ readonly PUT: "PUT";
6
+ readonly PATCH: "PATCH";
7
+ readonly HEAD: "HEAD";
8
+ readonly OPTIONS: "OPTIONS";
9
+ };
10
+ export type THttpMethod = Enum<typeof HttpMethod>;
11
+ export interface IRequest {
12
+ protocol: string;
13
+ method: THttpMethod;
14
+ path: string;
15
+ headers: Array<Record<string, string>>;
16
+ body?: string;
17
+ }
18
+ export declare class HttpRequest {
19
+ readonly protocol: IRequest["protocol"];
20
+ readonly method: IRequest["method"];
21
+ readonly path: IRequest["path"];
22
+ readonly headers: IRequest["headers"];
23
+ readonly body: IRequest["body"];
24
+ constructor(request: string);
25
+ private _parseRequest;
26
+ private _divideStringOn;
27
+ }
28
+ declare const HttpStatus: {
29
+ readonly OK: "OK";
30
+ readonly CREATED: "Created";
31
+ readonly NO_CONTENT: "No Content";
32
+ readonly BAD_REQUEST: "Bad Request";
33
+ readonly UNAUTHORIZED: "Unauthorized";
34
+ readonly FORBIDDEN: "Forbidden";
35
+ readonly NOT_FOUND: "Not Found";
36
+ readonly METHOD_NOT_ALLOWED: "Method Not Allowed";
37
+ readonly TOO_MANY_REQUESTS: "Too Many Requests";
38
+ readonly INTERNAL_SERVER_ERROR: "Internal Server Error";
39
+ };
40
+ export type THttpStatus = Enum<typeof HttpStatus>;
41
+ export declare const HttpStatusCode: {
42
+ readonly OK: 200;
43
+ readonly CREATED: 201;
44
+ readonly NO_CONTENT: 204;
45
+ readonly BAD_REQUEST: 400;
46
+ readonly UNAUTHORIZED: 401;
47
+ readonly FORBIDDEN: 403;
48
+ readonly NOT_FOUND: 404;
49
+ readonly METHOD_NOT_ALLOWED: 405;
50
+ readonly TOO_MANY_REQUESTS: 429;
51
+ readonly INTERNAL_SERVER_ERROR: 500;
52
+ };
53
+ export type THttpStatusCode = Enum<typeof HttpStatusCode>;
54
+ export interface IHeaders {
55
+ Authorization?: string;
56
+ Proxy_Authorization?: string;
57
+ "WWW-Authenticate"?: string;
58
+ Age?: string;
59
+ "Cache-Control"?: string;
60
+ "Clear-Site-Data"?: string;
61
+ Expires?: string;
62
+ "No-Vary-Search"?: string;
63
+ "Last-Modified"?: string;
64
+ ETag?: string;
65
+ "If-Match"?: string;
66
+ "If-None-Match"?: string;
67
+ "If-Modified-Since"?: string;
68
+ "If-Unmodified-Since"?: string;
69
+ Vary?: string;
70
+ Connection?: string;
71
+ "Keep-Alive"?: string;
72
+ Accept?: string;
73
+ "Accept-Encoding"?: string;
74
+ "Accept-Language"?: string;
75
+ Expect?: string;
76
+ "Max-Forwards"?: string;
77
+ Cookie?: string;
78
+ "Set-Cookie"?: string;
79
+ "Access-Control-Allow-Credentials"?: string;
80
+ "Access-Control-Allow-Methods"?: string;
81
+ "Access-Control-Allow-Headers"?: string;
82
+ "Access-Control-Allow-Origin"?: string;
83
+ "Access-Control-Expose-Headers"?: string;
84
+ "Access-Control-Max-Age"?: string;
85
+ "Access-Control-Request-Headers"?: string;
86
+ "Access-Control-Request-Method"?: string;
87
+ Origin?: string;
88
+ "Timing-Allow-Origin"?: string;
89
+ "Content-Disposition"?: string;
90
+ "Content-Length"?: string;
91
+ "Content-Type"?: string | "application/json" | "text/html" | "text/plain";
92
+ "Content-Encoding"?: string;
93
+ "Content-Language"?: string;
94
+ "Content-Location"?: string;
95
+ Forwarded?: string;
96
+ Via?: string;
97
+ Location?: string;
98
+ Refresh?: string;
99
+ From?: string;
100
+ Host?: string;
101
+ Referer?: string;
102
+ "Referrer-Policy"?: string;
103
+ "User-Agent"?: string;
104
+ Allow?: string;
105
+ Server?: string;
106
+ Range?: string;
107
+ "Accept-Ranges"?: string;
108
+ "Content-Range"?: string;
109
+ "If-Range"?: string;
110
+ "Cross-Origin-Embedder-Policy"?: string;
111
+ "Cross-Origin-Opener-Policy"?: string;
112
+ "Cross-Origin-Resource-Policy"?: string;
113
+ "Content-Security-Policy"?: string;
114
+ "Content-Security-Policy-Report-Only"?: string;
115
+ "Permissions-Policy"?: string;
116
+ "Strict-Transport-Security"?: string;
117
+ "Upgrade-Insecure-Requests"?: string;
118
+ "X-Content-Type-Options"?: string;
119
+ "X-Frames-Options"?: string;
120
+ "X-Permitted-Cross-Domain-Policies"?: string;
121
+ "X-Powered-By"?: string;
122
+ "X-XSS-Protection"?: string;
123
+ "Report-To"?: string;
124
+ TE?: string;
125
+ Trailer?: string;
126
+ "Transfer-Encoding"?: string;
127
+ "Alt-Svc"?: string;
128
+ "Alt-Used"?: string;
129
+ Date?: string;
130
+ Link?: string;
131
+ "Retry-After"?: string;
132
+ "Server-Timing"?: string;
133
+ "Service-Worker-Allowed"?: string;
134
+ SourceMap?: string;
135
+ Upgrade?: string;
136
+ Priority?: string;
137
+ "Sec-GPC"?: string;
138
+ }
139
+ export type TResponseBody<T> = T;
140
+ export interface IResponse {
141
+ status: THttpStatus;
142
+ statusCode: THttpStatusCode;
143
+ protocol: string;
144
+ method: THttpMethod;
145
+ path: string;
146
+ headers: IHeaders;
147
+ body: TResponseBody<unknown>;
148
+ }
149
+ export declare class HttpResponse {
150
+ protected readonly protocol: IResponse["protocol"];
151
+ protected readonly method: IResponse["method"];
152
+ protected readonly path: IResponse["path"];
153
+ protected status: IResponse["status"];
154
+ protected statusCode: IResponse["statusCode"];
155
+ protected headers: IResponse["headers"];
156
+ protected body: IResponse["body"];
157
+ constructor(request: HttpRequest);
158
+ addHeaders(headers: Array<IResponse["headers"]>): void;
159
+ removeHeaders(headers: Array<keyof IHeaders>): void;
160
+ setStatus(status: THttpStatusCode): void;
161
+ setBody(body: TResponseBody<unknown>): void;
162
+ formatHttpResponse(): string;
163
+ }
164
+ export declare class Context {
165
+ request: HttpRequest;
166
+ response: HttpResponse;
167
+ constructor(request: HttpRequest, response: HttpResponse);
168
+ }
169
+ export type Enum<T> = T[keyof T];
170
+ export type TResponseFunction = (ctx: Context) => TResponseBody<unknown>;
171
+ export type TUndefinableResponseFunction = TResponseFunction | undefined;
172
+ export interface IRoute {
173
+ path: string;
174
+ method: THttpMethod;
175
+ handler: TResponseFunction;
176
+ beforeHandler?: TResponseFunction | TUndefinableResponseFunction | undefined;
177
+ afterHandler?: TUndefinableResponseFunction | undefined;
178
+ beforeGroup?: TResponseFunction | TUndefinableResponseFunction | undefined;
179
+ }
180
+ export interface IMiddleware {
181
+ fn: TResponseFunction | ((ctx: Context) => void);
182
+ }
183
+ export interface IExcludeMiddleware extends IMiddleware {
184
+ paths: "allButExcluded";
185
+ excluded: Array<string>;
186
+ }
187
+ export interface IIncludeMiddleware extends IMiddleware {
188
+ paths: Array<string>;
189
+ excluded: [
190
+ ];
191
+ }
192
+ export type TMiddleware = IExcludeMiddleware | IIncludeMiddleware;
193
+ export export declare class YinzJS {
194
+ private readonly backlog;
195
+ private readonly ip;
196
+ private readonly port;
197
+ private readonly _routes;
198
+ private readonly middleware;
199
+ constructor(options?: {
200
+ port: number;
201
+ });
202
+ protected _handleMiddleware(route: IRoute, ctx: Context): TResponseBody<unknown> | void;
203
+ protected _handleRoute(route: IRoute, ctx: Context): TResponseBody<unknown>;
204
+ protected _handleRequest(request: HttpRequest): HttpResponse;
205
+ protected _route(path: IRoute["path"], handler: IRoute["handler"], options?: {
206
+ method: IRoute["method"];
207
+ beforeHandler?: IRoute["beforeHandler"];
208
+ afterHandler?: IRoute["afterHandler"];
209
+ }): IRoute;
210
+ get(path: IRoute["path"], handler: IRoute["handler"], options?: {
211
+ beforeHandler?: IRoute["beforeHandler"];
212
+ afterHandler?: IRoute["afterHandler"];
213
+ }): IRoute;
214
+ post(path: IRoute["path"], handler: IRoute["handler"], options?: {
215
+ beforeHandler?: IRoute["beforeHandler"];
216
+ afterHandler?: IRoute["afterHandler"];
217
+ }): IRoute;
218
+ put(path: IRoute["path"], handler: IRoute["handler"], options?: {
219
+ beforeHandler?: IRoute["beforeHandler"];
220
+ afterHandler?: IRoute["afterHandler"];
221
+ }): IRoute;
222
+ delete(path: IRoute["path"], handler: IRoute["handler"], options?: {
223
+ beforeHandler?: IRoute["beforeHandler"];
224
+ afterHandler?: IRoute["afterHandler"];
225
+ }): IRoute;
226
+ patch(path: IRoute["path"], handler: IRoute["handler"], options?: {
227
+ beforeHandler?: IRoute["beforeHandler"];
228
+ afterHandler?: IRoute["afterHandler"];
229
+ }): IRoute;
230
+ group(prefix: IRoute["path"], routes: Array<IRoute>, options?: {
231
+ beforeGroup: IRoute["beforeGroup"];
232
+ }): void;
233
+ routes(routes: Array<IRoute>): void;
234
+ beforeAll(fn: TMiddleware["fn"], options?: {
235
+ paths: IExcludeMiddleware["paths"];
236
+ excluded: IExcludeMiddleware["excluded"];
237
+ } | {
238
+ paths: IIncludeMiddleware["paths"];
239
+ excluded: IIncludeMiddleware["excluded"];
240
+ }): void;
241
+ listen(): void;
242
+ }
243
+
244
+ export {};