tspace-spear 1.0.0-rc

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,19 @@
1
+ Copyright (c) 2023 Thanathip Srisawatpattana
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,320 @@
1
+ # tspace-spear
2
+
3
+ [![NPM version](https://img.shields.io/npm/v/tspace-spear.svg)](https://www.npmjs.com)
4
+ [![NPM downloads](https://img.shields.io/npm/dm/tspace-spear.svg)](https://www.npmjs.com)
5
+
6
+ tspace-spear is an api framework for node.js fast and highly focused on providing the best developer experience.
7
+ the tspace-spear using native http server
8
+
9
+ ## Install
10
+
11
+ Install with [npm](https://www.npmjs.com/):
12
+
13
+ ```sh
14
+ npm install tspace-spear --save
15
+
16
+ ```
17
+ ## Basic Usage
18
+ - [StartServer](#start-server)
19
+ - [Middleware](#middleware)
20
+ - [Controller](#controller)
21
+ - [Router](#router)
22
+ - [Handlers](#handlers)
23
+
24
+ ## StartServer
25
+ ```js
26
+ import Spear from "tspace-spear";
27
+
28
+ new Spear()
29
+ .get('/' , () => 'Hello world!')
30
+ .get('/json' , () => {
31
+ return {
32
+ message : 'Hello world!'
33
+ }
34
+ })
35
+ .listen(3000 , ({ server, port }) => console.log(`server listening on : http://localhost:${port}`))
36
+
37
+ ```
38
+
39
+ ## Middleware
40
+ ```js
41
+ // file cat-middleware.ts
42
+ export default (ctx : TContext, next: TNextFunction) =>{
43
+ console.log('cat middleware globals');
44
+ return next();
45
+ }
46
+
47
+ import Spear { Router, TContext, TNextFunction } from "tspace-spear";
48
+ import CatMiddleware from './cat-middleware.ts'
49
+
50
+ (async () => {
51
+ const port = Number(process.env.PORT ?? 3000)
52
+ const app = new Spear({
53
+ middlewares: [ CatMiddleware ]
54
+ // if you want to import a middleware with a directory can you follow the example
55
+ // middlewares : {
56
+ // folder : `${__dirname}/middlewares`,
57
+ // name : /middleware\.(ts|js)$/i
58
+ // }
59
+ })
60
+
61
+ // or add a middleware
62
+ app.use((ctx : TContext , next : TNextFunction) => {
63
+ console.log('global middlewares')
64
+ return next()
65
+ })
66
+
67
+ app.get('/' , ({ res } : TContext) => {
68
+ return res.json({
69
+ message : 'hello world!'
70
+ });
71
+ })
72
+
73
+ app.listen(port , () => console.log(`Server is now listening port: ${port}`))
74
+
75
+ // localhost:3000
76
+
77
+ })()
78
+ ```
79
+
80
+ ## Controller
81
+ ```js
82
+ import {
83
+ Controller ,
84
+ Middleware ,
85
+ Get ,
86
+ Post,
87
+ Patch,
88
+ Put,
89
+ Delete,
90
+ WriteHeader,
91
+ Query,
92
+ Body,
93
+ Params,
94
+ Cookies,
95
+ Files,
96
+ StatusCode
97
+ } from 'tspace-spear';
98
+
99
+ import type {
100
+ TCookies, TParams,
101
+ TRequest, TResponse ,
102
+ TQuery, TFiles,
103
+ TContext, TNextFunction
104
+ } from 'tspace-spear';
105
+ import CatMiddleware from './cat-middleware.ts'
106
+
107
+ // file cat-controller.ts
108
+ @Controller('/cats')
109
+ class CatController {
110
+ @Get('/')
111
+ @Middleware(CatMiddleware)
112
+ @Query('test','id')
113
+ @Cookies('name')
114
+ public async index({ query , cookies , req } : {
115
+ query : TQuery<{ id : string }>
116
+ cookies : TCookies<{ name : string}>
117
+ req : TRequest
118
+ }) {
119
+
120
+ return {
121
+ query,
122
+ cookies
123
+ }
124
+ }
125
+
126
+ @Get('/:id')
127
+ @Middleware(CatMiddleware)
128
+ @Params('id')
129
+ public async show({ params} : TContext) {
130
+ return {
131
+ params
132
+ }
133
+ }
134
+
135
+ @Post('/')
136
+ @Middleware(CatMiddleware)
137
+ public async store({ body } : TContext) {
138
+ return {
139
+ body
140
+ }
141
+ }
142
+
143
+ @Put('/:id')
144
+ @Middleware(CatMiddleware)
145
+ public async update({ files } : TContext) {
146
+ return {
147
+ files
148
+ }
149
+ }
150
+
151
+ @Post('/upload')
152
+ @Middleware(CatMiddleware)
153
+ public async upload({ files } : TContext) {
154
+ return {
155
+ files
156
+ }
157
+ }
158
+
159
+ @Delete('/:id')
160
+ @Middleware(CatMiddleware)
161
+ public async destroy({ params } : TContext) {
162
+ return {
163
+ params
164
+ }
165
+ }
166
+ }
167
+
168
+ import Spear , { Router, TContext, TNextFunction } from "tspace-spear";
169
+ import CatController from './cat-controller.ts'
170
+
171
+ (async () => {
172
+
173
+ const app = new Spear({
174
+ controllers: [ CatController ]
175
+ // if you want to import a controller with a directory can you follow the example
176
+ // controllers : {
177
+ // folder : `${__dirname}/controllers`,
178
+ // name : /controller\.(ts|js)$/i
179
+ // }
180
+ })
181
+
182
+ app.get('/' , ( { res } : TContext) => {
183
+ return res.json({
184
+ message : 'hello world!'
185
+ });
186
+ })
187
+
188
+ let port = 3000
189
+
190
+ app.listen(port , () => console.log(`Server is now listening port: ${port}`))
191
+
192
+ // localhost:3000/cats
193
+ // localhost:3000/cats/41
194
+
195
+ })()
196
+ ```
197
+
198
+ ## Router
199
+
200
+ ```js
201
+ import Spear , { Router, TContext, TNextFunction } from "tspace-spear";
202
+
203
+ const app = new Spear()
204
+
205
+ const router = new Router()
206
+
207
+ router.groups('/my',(r) => {
208
+
209
+ r.get('/cats' , ({ req , res }) => {
210
+
211
+ return res.json({
212
+ message : 'Hello, World!'
213
+ })
214
+ })
215
+
216
+ return r
217
+ })
218
+
219
+ router.get('/cats' , ({ req , res }) => {
220
+ return res.json({
221
+ message : 'Hello, World!'
222
+ })
223
+ })
224
+
225
+ app.useRouter(router)
226
+
227
+ app.get('/' , ({ res } : TContext) => {
228
+ return res.json({
229
+ message : 'hello world!'
230
+ });
231
+ })
232
+
233
+ let port = 3000
234
+
235
+ app.listen(port , () => console.log(`Server is now listening port: ${port}`))
236
+
237
+ // localhost:3000/my/cats
238
+ // localhost:3000/cats
239
+
240
+ ```
241
+
242
+ ## Handlers
243
+ ```js
244
+
245
+ const app = new Spear({
246
+ logger : true, // logging
247
+ globalPrefix : '/api' // prefix all routes
248
+ })
249
+
250
+ app.enableCors({
251
+ origins: [
252
+ /^http:\/\/localhost:\d+$/
253
+ ],
254
+ credentials: true
255
+ })
256
+
257
+ app.useFileUpload({
258
+ limits : 1000 * 1000, // limits for file upload 1_000_000 bytes
259
+ useTempFiles : true, // whether to use temporary files
260
+ tempFileDir : 'tmp', // temporary directory
261
+ removeTempFile : {
262
+ remove : true, // remove temporary files
263
+ ms : 1000 * 60 // remove temporary after 60 seconds
264
+ }
265
+ })
266
+
267
+ app.useBodyParser()
268
+
269
+ app.useCookiesParser()
270
+
271
+ app.get('/' , ({ res } : TContext) => {
272
+ return res.json({
273
+ message : 'hello world!'
274
+ });
275
+ })
276
+
277
+ app.get('/errors', () => {
278
+ throw new Error('testing Error handler')
279
+ })
280
+
281
+ // every response should returns following this format response
282
+ app.formatResponse((results : unknown , statusCode : number) => {
283
+
284
+ if(typeof results === 'string') return results
285
+
286
+ /// ...
287
+
288
+ return {
289
+ success : statusCode < 400,
290
+ ...results,
291
+ code : statusCode
292
+ }
293
+ })
294
+
295
+ // every notfound page should returns following this format response
296
+ app.notFoundHandler(({ res } : TContext) => {
297
+ return res.notFound();
298
+ })
299
+
300
+ // every errors page should returns following this format response
301
+ app.errorHandler((err : Error , { res } : TContext) => {
302
+
303
+ return res
304
+ .status(500)
305
+ .json({
306
+ success : false,
307
+ message : err?.message,
308
+ code : 500
309
+ });
310
+ })
311
+
312
+ let port = 3000
313
+
314
+ app.listen(port , () => console.log(`Server is now listening port: ${port}`))
315
+
316
+ // localhost:3000/*********** // not found
317
+ // localhost:3000/errors // errors
318
+ // localhost:3000 // format response
319
+
320
+ ```
@@ -0,0 +1,5 @@
1
+ export declare const Body: (...bodyParms: string[]) => (target: any, key: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
2
+ export declare const Files: (...filesParms: string[]) => (target: any, key: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
3
+ export declare const Params: (...paramsData: string[]) => (target: any, key: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
4
+ export declare const Query: (...queryParms: string[]) => (target: any, key: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
5
+ export declare const Cookies: (...cookiesParms: string[]) => (target: any, key: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.Cookies = exports.Query = exports.Params = exports.Files = exports.Body = void 0;
13
+ const Body = (...bodyParms) => {
14
+ return function (target, key, descriptor) {
15
+ const originalMethod = descriptor.value;
16
+ descriptor.value = function (ctx, next) {
17
+ var _a;
18
+ return __awaiter(this, void 0, void 0, function* () {
19
+ const q = (_a = ctx === null || ctx === void 0 ? void 0 : ctx.body) !== null && _a !== void 0 ? _a : {};
20
+ const body = bodyParms.reduce((acc, key) => (q[key] != null ? Object.assign(Object.assign({}, acc), { [key]: q[key] }) : acc), {});
21
+ ctx.body = Object.keys(body).length ? body : null;
22
+ return yield originalMethod.call(this, ctx, next);
23
+ });
24
+ };
25
+ return descriptor;
26
+ };
27
+ };
28
+ exports.Body = Body;
29
+ const Files = (...filesParms) => {
30
+ return function (target, key, descriptor) {
31
+ const originalMethod = descriptor.value;
32
+ descriptor.value = function (ctx, next) {
33
+ var _a;
34
+ return __awaiter(this, void 0, void 0, function* () {
35
+ const q = (_a = ctx === null || ctx === void 0 ? void 0 : ctx.files) !== null && _a !== void 0 ? _a : {};
36
+ const files = filesParms.reduce((acc, key) => (q[key] != null ? Object.assign(Object.assign({}, acc), { [key]: q[key] }) : acc), {});
37
+ ctx.files = Object.keys(files).length ? files : null;
38
+ return yield originalMethod.call(this, ctx, next);
39
+ });
40
+ };
41
+ return descriptor;
42
+ };
43
+ };
44
+ exports.Files = Files;
45
+ const Params = (...paramsData) => {
46
+ return function (target, key, descriptor) {
47
+ const originalMethod = descriptor.value;
48
+ descriptor.value = function (ctx, next) {
49
+ var _a;
50
+ return __awaiter(this, void 0, void 0, function* () {
51
+ const q = (_a = ctx === null || ctx === void 0 ? void 0 : ctx.params) !== null && _a !== void 0 ? _a : {};
52
+ const params = paramsData.reduce((acc, key) => (q[key] != null ? Object.assign(Object.assign({}, acc), { [key]: q[key] }) : acc), {});
53
+ ctx.params = Object.keys(params).length ? params : null;
54
+ return yield originalMethod.call(this, ctx, next);
55
+ });
56
+ };
57
+ return descriptor;
58
+ };
59
+ };
60
+ exports.Params = Params;
61
+ const Query = (...queryParms) => {
62
+ return function (target, key, descriptor) {
63
+ const originalMethod = descriptor.value;
64
+ descriptor.value = function (ctx, next) {
65
+ var _a;
66
+ return __awaiter(this, void 0, void 0, function* () {
67
+ const q = (_a = ctx === null || ctx === void 0 ? void 0 : ctx.query) !== null && _a !== void 0 ? _a : {};
68
+ const query = queryParms.reduce((acc, key) => (q[key] != null ? Object.assign(Object.assign({}, acc), { [key]: q[key] }) : acc), {});
69
+ ctx.query = Object.keys(query).length ? query : null;
70
+ return yield originalMethod.call(this, ctx, next);
71
+ });
72
+ };
73
+ return descriptor;
74
+ };
75
+ };
76
+ exports.Query = Query;
77
+ const Cookies = (...cookiesParms) => {
78
+ return function (target, key, descriptor) {
79
+ const originalMethod = descriptor.value;
80
+ descriptor.value = function (ctx, next) {
81
+ var _a;
82
+ return __awaiter(this, void 0, void 0, function* () {
83
+ const q = (_a = ctx === null || ctx === void 0 ? void 0 : ctx.cookies) !== null && _a !== void 0 ? _a : {};
84
+ const cookies = cookiesParms.reduce((acc, key) => (q[key] != null ? Object.assign(Object.assign({}, acc), { [key]: q[key] }) : acc), {});
85
+ ctx.cookies = Object.keys(cookies).length ? cookies : null;
86
+ return yield originalMethod.call(this, ctx, next);
87
+ });
88
+ };
89
+ return descriptor;
90
+ };
91
+ };
92
+ exports.Cookies = Cookies;
@@ -0,0 +1 @@
1
+ export declare const Controller: (path: `/${string}`) => ClassDecorator;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Controller = void 0;
4
+ const Controller = (path) => {
5
+ return (target) => {
6
+ Reflect.defineMetadata("controllers", path, target);
7
+ };
8
+ };
9
+ exports.Controller = Controller;
@@ -0,0 +1,2 @@
1
+ import { OutgoingHttpHeaders } from 'http';
2
+ export declare const WriteHeader: (statusCode: number, contentType: OutgoingHttpHeaders) => (target: any, key: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.WriteHeader = void 0;
13
+ const WriteHeader = (statusCode, contentType) => {
14
+ return (target, key, descriptor) => {
15
+ const originalMethod = descriptor.value;
16
+ descriptor.value = function (ctx, next) {
17
+ return __awaiter(this, void 0, void 0, function* () {
18
+ ctx.res.writeHead(...[statusCode, contentType]);
19
+ return yield originalMethod.call(this, ctx, next);
20
+ });
21
+ };
22
+ return descriptor;
23
+ };
24
+ };
25
+ exports.WriteHeader = WriteHeader;
@@ -0,0 +1,8 @@
1
+ import 'reflect-metadata';
2
+ export * from './methods';
3
+ export * from './headers';
4
+ export * from './middleware';
5
+ export * from './controller';
6
+ export * from './headers';
7
+ export * from './statusCode';
8
+ export * from './context';
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ require("reflect-metadata");
18
+ __exportStar(require("./methods"), exports);
19
+ __exportStar(require("./headers"), exports);
20
+ __exportStar(require("./middleware"), exports);
21
+ __exportStar(require("./controller"), exports);
22
+ __exportStar(require("./headers"), exports);
23
+ __exportStar(require("./statusCode"), exports);
24
+ __exportStar(require("./context"), exports);
@@ -0,0 +1,5 @@
1
+ export declare const Get: (path: `/${string}`) => MethodDecorator;
2
+ export declare const Post: (path: `/${string}`) => MethodDecorator;
3
+ export declare const Put: (path: `/${string}`) => MethodDecorator;
4
+ export declare const Patch: (path: `/${string}`) => MethodDecorator;
5
+ export declare const Delete: (path: `/${string}`) => MethodDecorator;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Delete = exports.Patch = exports.Put = exports.Post = exports.Get = void 0;
4
+ const methodDecorator = (method) => {
5
+ return (path) => {
6
+ return (target, propertyKey) => {
7
+ const controller = target.constructor;
8
+ const routers = Reflect.hasMetadata("routers", controller)
9
+ ? Reflect.getMetadata("routers", controller)
10
+ : [];
11
+ routers.push({
12
+ method,
13
+ path,
14
+ handler: propertyKey,
15
+ });
16
+ Reflect.defineMetadata("routers", routers, controller);
17
+ };
18
+ };
19
+ };
20
+ exports.Get = methodDecorator('get');
21
+ exports.Post = methodDecorator('post');
22
+ exports.Put = methodDecorator('put');
23
+ exports.Patch = methodDecorator('patch');
24
+ exports.Delete = methodDecorator('delete');
@@ -0,0 +1,2 @@
1
+ import { TRequestFunction } from '../../types';
2
+ export declare const Middleware: (middleware: TRequestFunction) => (target: any, key: string, descriptor: PropertyDescriptor) => void;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Middleware = void 0;
4
+ const Middleware = (middleware) => {
5
+ return (target, key, descriptor) => {
6
+ const originalMethod = descriptor.value;
7
+ descriptor.value = function (ctx, next) {
8
+ try {
9
+ Reflect.defineMetadata("middlewares", descriptor, target);
10
+ return middleware(ctx, (err) => {
11
+ if (err != null) {
12
+ return next(err);
13
+ }
14
+ return originalMethod.call(this, ctx, next);
15
+ });
16
+ }
17
+ catch (error) {
18
+ return next(error);
19
+ }
20
+ };
21
+ };
22
+ };
23
+ exports.Middleware = Middleware;
@@ -0,0 +1 @@
1
+ export declare const StatusCode: (statusCode: number) => (target: any, key: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.StatusCode = void 0;
13
+ const StatusCode = (statusCode) => {
14
+ return (target, key, descriptor) => {
15
+ const originalMethod = descriptor.value;
16
+ statusCode = statusCode < 100 ? 100 : statusCode > 599 ? 599 : statusCode;
17
+ descriptor.value = function (ctx, next) {
18
+ return __awaiter(this, void 0, void 0, function* () {
19
+ ctx.res.writeHead(statusCode, { 'Content-Type': 'application/json' });
20
+ return yield originalMethod.call(this, ctx, next);
21
+ });
22
+ };
23
+ return descriptor;
24
+ };
25
+ };
26
+ exports.StatusCode = StatusCode;