tspace-spear 1.2.7 → 1.2.9-beta.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.
Files changed (99) hide show
  1. package/README.md +347 -155
  2. package/dist/cli/generators/app/index.d.ts +1 -0
  3. package/dist/cli/generators/app/index.js +124 -0
  4. package/dist/cli/generators/app/index.js.map +1 -0
  5. package/dist/cli/generators/app/template.d.ts +1 -0
  6. package/dist/cli/generators/app/template.js +42 -0
  7. package/dist/cli/generators/app/template.js.map +1 -0
  8. package/dist/cli/generators/client/template.d.ts +1 -0
  9. package/dist/cli/generators/client/template.js +30 -0
  10. package/dist/cli/generators/client/template.js.map +1 -0
  11. package/dist/cli/generators/controller/index.d.ts +1 -0
  12. package/dist/cli/generators/controller/index.js +78 -0
  13. package/dist/cli/generators/controller/index.js.map +1 -0
  14. package/dist/cli/generators/controller/template.d.ts +1 -0
  15. package/dist/cli/generators/controller/template.js +108 -0
  16. package/dist/cli/generators/controller/template.js.map +1 -0
  17. package/dist/cli/generators/dto/index.d.ts +1 -0
  18. package/dist/cli/generators/dto/index.js +57 -0
  19. package/dist/cli/generators/dto/index.js.map +1 -0
  20. package/dist/cli/generators/dto/template.d.ts +1 -0
  21. package/dist/cli/generators/dto/template.js +32 -0
  22. package/dist/cli/generators/dto/template.js.map +1 -0
  23. package/dist/cli/generators/middleware/index.d.ts +1 -0
  24. package/dist/cli/generators/middleware/index.js +38 -0
  25. package/dist/cli/generators/middleware/index.js.map +1 -0
  26. package/dist/cli/generators/middleware/template.d.ts +1 -0
  27. package/dist/cli/generators/middleware/template.js +16 -0
  28. package/dist/cli/generators/middleware/template.js.map +1 -0
  29. package/dist/cli/generators/module/index.d.ts +1 -0
  30. package/dist/cli/generators/module/index.js +173 -0
  31. package/dist/cli/generators/module/index.js.map +1 -0
  32. package/dist/cli/generators/service/index.d.ts +1 -0
  33. package/dist/cli/generators/service/index.js +53 -0
  34. package/dist/cli/generators/service/index.js.map +1 -0
  35. package/dist/cli/generators/service/template.d.ts +1 -0
  36. package/dist/cli/generators/service/template.js +74 -0
  37. package/dist/cli/generators/service/template.js.map +1 -0
  38. package/dist/cli/generators/shared/index.d.ts +3 -0
  39. package/dist/cli/generators/shared/index.js +22 -0
  40. package/dist/cli/generators/shared/index.js.map +1 -0
  41. package/dist/cli/index.js +55 -96
  42. package/dist/cli/index.js.map +1 -1
  43. package/dist/lib/core/client/index.d.ts +13 -43
  44. package/dist/lib/core/client/index.js +70 -33
  45. package/dist/lib/core/client/index.js.map +1 -1
  46. package/dist/lib/core/client/types.d.ts +43 -0
  47. package/dist/lib/core/client/types.js +3 -0
  48. package/dist/lib/core/client/types.js.map +1 -0
  49. package/dist/lib/core/compiler/generator.d.ts +4 -6
  50. package/dist/lib/core/compiler/generator.js +190 -39
  51. package/dist/lib/core/compiler/generator.js.map +1 -1
  52. package/dist/lib/core/compiler/index.d.ts +2 -2
  53. package/dist/lib/core/compiler/index.js +2 -2
  54. package/dist/lib/core/compiler/index.js.map +1 -1
  55. package/dist/lib/core/compiler/pre-routes.d.ts +12 -130
  56. package/dist/lib/core/compiler/pre-routes.js +13 -35
  57. package/dist/lib/core/compiler/pre-routes.js.map +1 -1
  58. package/dist/lib/core/compiler/types.d.ts +25 -0
  59. package/dist/lib/core/decorators/context.d.ts +78 -8
  60. package/dist/lib/core/decorators/context.js +84 -9
  61. package/dist/lib/core/decorators/context.js.map +1 -1
  62. package/dist/lib/core/decorators/controller.js +2 -1
  63. package/dist/lib/core/decorators/controller.js.map +1 -1
  64. package/dist/lib/core/decorators/index.d.ts +1 -0
  65. package/dist/lib/core/decorators/index.js +1 -0
  66. package/dist/lib/core/decorators/index.js.map +1 -1
  67. package/dist/lib/core/decorators/methods.js +4 -3
  68. package/dist/lib/core/decorators/methods.js.map +1 -1
  69. package/dist/lib/core/decorators/middleware.d.ts +40 -2
  70. package/dist/lib/core/decorators/middleware.js +54 -9
  71. package/dist/lib/core/decorators/middleware.js.map +1 -1
  72. package/dist/lib/core/decorators/service.d.ts +28 -0
  73. package/dist/lib/core/decorators/service.js +36 -0
  74. package/dist/lib/core/decorators/service.js.map +1 -0
  75. package/dist/lib/core/decorators/statusCode.js +3 -1
  76. package/dist/lib/core/decorators/statusCode.js.map +1 -1
  77. package/dist/lib/core/decorators/swagger.js +4 -3
  78. package/dist/lib/core/decorators/swagger.js.map +1 -1
  79. package/dist/lib/core/exception/index.d.ts +68 -0
  80. package/dist/lib/core/exception/index.js +123 -0
  81. package/dist/lib/core/exception/index.js.map +1 -0
  82. package/dist/lib/core/metadata/index.d.ts +6 -0
  83. package/dist/lib/core/metadata/index.js +13 -0
  84. package/dist/lib/core/metadata/index.js.map +1 -0
  85. package/dist/lib/core/package/index.d.ts +11 -0
  86. package/dist/lib/core/package/index.js +42 -0
  87. package/dist/lib/core/package/index.js.map +1 -0
  88. package/dist/lib/core/server/fast-router.d.ts +2 -2
  89. package/dist/lib/core/server/fast-router.js +17 -3
  90. package/dist/lib/core/server/fast-router.js.map +1 -1
  91. package/dist/lib/core/server/index.d.ts +32 -5
  92. package/dist/lib/core/server/index.js +188 -45
  93. package/dist/lib/core/server/index.js.map +1 -1
  94. package/dist/lib/core/server/parser-factory.js +59 -10
  95. package/dist/lib/core/server/parser-factory.js.map +1 -1
  96. package/dist/lib/core/server/response.js +21 -1
  97. package/dist/lib/core/server/response.js.map +1 -1
  98. package/dist/lib/core/types/index.d.ts +42 -29
  99. package/package.json +15 -6
package/README.md CHANGED
@@ -12,12 +12,20 @@ It is designed with a strong focus on developer experience and provides end-to-e
12
12
  ## Features
13
13
 
14
14
  - ⚡ High-performance core built on native Node.js HTTP
15
- - 🚀 Optional uWebSockets.js support via adapter for ultra-low latency and maximum throughput
16
- - 🧠 End-to-end (E2E) type safety across request → response lifecycle
17
- - 🧪 Built-in testing support for E2E validation
15
+ - 🚀 Optional [uWebSockets.js](#adapter) adapter support for ultra-low latency and maximum throughput
16
+ - 🧠 End-to-end [E2E](#e2e) type safety across the entire request → response lifecycle
17
+ - 🎮 Built-in support for [Controllers](#controller) and route-based architecture
18
+ - 🏷️ Powerful Decorator system for [routes](#router), [middleware](#middleware), validation, and metadata
19
+ - 💉 Built-in constructor-based dependency injection (DI) for [Services](#service)
20
+ - 📦 [DTO](#dto) (Data Transfer Object) support for structured and type-safe request handling
21
+ - 📂 Built-in [File Upload](#file-upload) support via `useFileUpload()` with zero configuration required
22
+ - 🔌 Native [WebSocket](#web-socket) support for real-time applications and event-driven systems
23
+ - ⚛️ [GraphQL](#graphql) support with flexible schema integration and HTTP adapters
24
+ - 🖥️ Built-in [Cluster mode](#cluster) support for multi-core scalability and higher throughput
25
+ - 🧪 Built-in testing utilities for [E2E](#e2e) validation
18
26
  - 🧩 Simple and intuitive developer experience
19
- - 🔌 Flexible architecture for plugins and extensions
20
- - 📘 Auto-generated Swagger documentation via `app.useSwagger()` (zero manual configuration required)
27
+ - 📘 Auto-generated [Swagger](#swagger) documentation via `app.useSwagger()` with zero manual configuration
28
+ - 🔥 Lightweight and optimized for high-performance APIs and microservices
21
29
 
22
30
  ---
23
31
 
@@ -36,7 +44,7 @@ See the [`docs`](https://thanathip41.github.io/tspace-spear) directory for full
36
44
 
37
45
  ## Basic Usage
38
46
  - [Getting Started](#getting-started)
39
- - [Cli](#cli)
47
+ - [Quick Started](#quick-started)
40
48
  - [Adapter](#adapter)
41
49
  - [Cluster](#cluster)
42
50
  - [Global Prefix](#global-prefix)
@@ -51,12 +59,13 @@ See the [`docs`](https://thanathip41.github.io/tspace-spear) directory for full
51
59
  - [Cookie](#cookie)
52
60
  - [Middleware](#middleware)
53
61
  - [Controller](#controller)
62
+ - [Service](#service)
54
63
  - [Dto](#dto)
55
64
  - [Router](#router)
56
65
  - [Swagger](#swagger)
57
66
  - [WebSocket](#websocket)
67
+ - [Graphql](#graphql)
58
68
  - [E2E](#e2e)
59
- - [Example CRUD](#example-crud)
60
69
 
61
70
  ## Getting Started
62
71
  ```js
@@ -72,29 +81,47 @@ new Spear()
72
81
  .listen(8000 , () => console.log(`Server is now listening http://localhost:8000`))
73
82
  ```
74
83
 
75
- ## Cli
84
+ ## Quick Started
85
+ Generate applications, modules, controllers, services, and middleware with the Spear CLI.
76
86
  ```sh
77
87
  # Install CLI globally
78
88
  npm install -g tspace-spear
79
89
 
80
90
  # Create a new application structure
81
- tspace-spear create app src
91
+ spear create new my-app
82
92
 
83
- # Create a new controller
84
- tspace-spear create controller src/controllers/dog
93
+ Successfully created project "my-app"
94
+
95
+ 📦 Project Structure
85
96
 
86
- # Generated structure
87
97
  src/
88
- ├── controllers/
89
- │ └── cat-controller.ts
90
- └── dog-controller.ts
98
+ ├── common/
99
+ │ └── middlewares/
100
+ └── log.middleware.ts
101
+
102
+ ├── modules/
103
+ │ └── cats/
104
+ │ ├── cat.controller.ts
105
+ │ ├── cat.service.ts
106
+ │ └── cat.dto.ts
107
+
108
+ ├── client.ts
91
109
  └── index.ts
92
110
 
93
- npm install ts-node --save-dev
111
+ 🚀 Next Steps
112
+
113
+ cd my-app
114
+
115
+ npm run dev
94
116
 
95
- ts-node src/index.ts
96
- ## Server is now listening http://localhost:8000
97
- ## Docs is now listening http://localhost:8000/api/docs
117
+ Server is running at:
118
+ http://localhost:8000
119
+
120
+ ✔ Swagger Docs:
121
+ http://localhost:8000/api/docs
122
+
123
+ ✔ Run E2E client:
124
+ ts-node src/client.ts
98
125
  ```
99
126
 
100
127
  ## Adapter
@@ -149,12 +176,31 @@ Global Prefix allows you to define a base path for all routes in your applicatio
149
176
  It helps keep your API structured and consistent (e.g. /api, /v1, /app).
150
177
  ```js
151
178
  const app = new Spear({
152
- globalPrefix : '/api' // prefix all routes
179
+ globalPrefix : '/api', // prefix all routes
153
180
  })
154
- .get('/' , () => 'Hello world!')
181
+ .get('/' , () => 'Hello world!') // http://localhost:8000/api
182
+ .get('/cats' , () => `Hello all cats`) // http://localhost:8000/api/cats
183
+ .get('/cats/:id' , ({ params }) => `Hello cat: ${params.id}`) // http://localhost:8000/api/cats/1
155
184
  .listen(8000 , () => console.log(`Server is now listening http://localhost:8000`))
156
185
 
157
186
  // http://localhost:8000/api => 'Hello world!'
187
+
188
+ // Or this
189
+
190
+ const app = new Spear()
191
+ .useGlobalPrefix('api', {
192
+ exclude : [
193
+ {
194
+ path : '/cats/*',
195
+ // methods : '*'
196
+ // methods : ['GET','POST']
197
+ }
198
+ ]
199
+ })
200
+ .get('/' , () => 'Hello world!') // http://localhost:8000/api
201
+ .get('/cats' , () => `Hello all cats`) // http://localhost:8000/cats
202
+ .get('/cats/:id' , ({ params }) => `Hello cat: ${params.id}`) // http://localhost:8000/cats/1
203
+ .listen(8000 , () => console.log(`Server is now listening http://localhost:8000`))
158
204
  ```
159
205
 
160
206
  ## Logger
@@ -574,14 +620,77 @@ import CatController from './cat-controller.ts'
574
620
  })()
575
621
  ```
576
622
 
623
+ ## Service
624
+ Registers one or more service classes for Dependency Injection.
625
+
626
+ All registered services will be available in the controller constructor
627
+ without manual instantiation.
628
+ ```js
629
+ // cat-service.ts
630
+ class CatService {
631
+ public index () {
632
+ return [
633
+ {
634
+ id: 1,
635
+ name: 'cat1'
636
+ },
637
+ {
638
+ id: 2,
639
+ name: 'cat2'
640
+ }
641
+ ]
642
+ }
643
+ }
644
+
645
+ // cat-controller.ts
646
+ import {
647
+ Controller,
648
+ Get
649
+ } from 'tspace-spear';
650
+ import CatService from './cat-service.ts'
651
+
652
+ @Service([CatService]) // don't forgot this to send CatService for Dependency Injection(DI)
653
+ @Controller('/cats')
654
+ class CatController {
655
+
656
+ constructor(
657
+ private catService: CatService
658
+ ) {}
659
+
660
+ @Get('/')
661
+ public index() {
662
+ return this.catService.index();
663
+ }
664
+ }
665
+
666
+ // app.ts
667
+ import { Spear } from "tspace-spear";
668
+
669
+ (async () => {
670
+
671
+ const app = new Spear({
672
+ controllers : {
673
+ folder : `${__dirname}/controllers`,
674
+ name : /controller\.(ts|js)$/i,
675
+ preRouteTypes : true
676
+ }
677
+ });
678
+
679
+ app.useSwagger();
680
+
681
+ app.listen(8000 , () => console.log(`Server is now listening http://localhost:8000`));
682
+ })()
683
+ ```
684
+
577
685
  ## Dto
578
686
  DTO (Data Transfer Object) is used to validate and transform incoming request data before it reaches your controller logic.
579
687
  ```js
580
688
  import {
581
689
  Controller ,
582
690
  Post,
583
- createDtoDecorator,
584
691
  Validate,
692
+ ValidateDto,
693
+ createDtoDecorator,
585
694
  type T
586
695
  } from 'tspace-spear';
587
696
 
@@ -593,8 +702,6 @@ import {
593
702
  validate
594
703
  } from "class-validator";
595
704
 
596
- import { ClassConstructor, plainToInstance } from 'class-transformer';
597
-
598
705
  const ValidateDtoCustomBody = (keys: string[]) => {
599
706
  return createDtoDecorator((ctx) => {
600
707
  const body = ctx.body ?? {};
@@ -620,13 +727,6 @@ const ValidateDtoCustomBody = (keys: string[]) => {
620
727
  });
621
728
  }
622
729
 
623
- const ValidateDtoZodBody = (schema: z.ZodTypeAny) => {
624
- return createDtoDecorator((ctx) => {
625
- const result = schema.parse(ctx.body);
626
- ctx.body = result as T.Body;
627
- });
628
- }
629
-
630
730
  const ValidateDtoPromiseBody = (keys: string[]) => {
631
731
  return createDtoDecorator(async (ctx) => {
632
732
  await new Promise(resolve => setTimeout(resolve,500));
@@ -646,39 +746,6 @@ const ValidateDtoPromiseBody = (keys: string[]) => {
646
746
  });
647
747
  }
648
748
 
649
- const ValidateDtoClsBody = <T extends object>(
650
- cls: ClassConstructor<T>
651
- ) => {
652
- return createDtoDecorator(async (ctx) => {
653
-
654
- const dto = plainToInstance(
655
- cls,
656
- ctx.body
657
- );
658
-
659
- const errors = await validate(dto);
660
-
661
- if (errors.length > 0) {
662
- throw {
663
- message: "Validation failed",
664
- issues: errors.flatMap((error) => {
665
- const constraints = error.constraints ?? {};
666
-
667
- const firstError = Object.values(constraints)[0] ?? "Validation error";
668
-
669
- return {
670
- path: error.property,
671
- message: firstError,
672
- };
673
- })
674
- };
675
- }
676
-
677
- ctx.body = dto;
678
- }
679
- );
680
- };
681
-
682
749
  const catSchema = z.object({
683
750
  name: z.string(),
684
751
  age: z.number(),
@@ -692,7 +759,6 @@ class CreateCatDto {
692
759
  age!: number;
693
760
  }
694
761
 
695
-
696
762
  // file cat-controller.ts
697
763
  @Controller('/cats')
698
764
  export class CatController {
@@ -701,47 +767,40 @@ export class CatController {
701
767
  // only required validation without type checking
702
768
  @Validate(["name", "age"], { required: { allowEmptyString: false, allowNull: false } })
703
769
  public async basic(ctx : T.Context<{ body : { name : any , age : any }}>) {
704
- const body = ctx.body;
705
770
  return {
706
- body
771
+ body : ctx.body
707
772
  }
708
773
  }
709
774
 
710
- @Post('/')
775
+ @Post('/custom')
711
776
  @ValidateDtoCustomBody(["name", "age"])
712
777
  public async custom(ctx : T.Context<{ body : { name : string , age : number }}>) {
713
- const body = ctx.body;
714
- return {
715
- body
716
- }
717
- }
718
-
719
- @Post('/zod')
720
- @ValidateDtoZodBody(catSchema)
721
- public async zod(ctx : T.Context<z.infer<typeof catSchema>>) {
722
- const body = ctx.body;
723
778
  return {
724
- body
779
+ body : ctx.body
725
780
  }
726
781
  }
727
782
 
728
783
  @Post('/promise')
729
784
  @ValidateDtoPromiseBody(['name'])
730
785
  public async promise(ctx : T.Context<{ body : { name : string }}>) {
731
- const body = ctx.body;
786
+ return {
787
+ body : ctx.body
788
+ }
789
+ }
732
790
 
791
+ @Post('/zod')
792
+ @ValidateDto(catSchema, { adaptor : "zod" })
793
+ public async zod(ctx : T.Context<{ body : z.infer<typeof catSchema>}>) {
733
794
  return {
734
- body
795
+ body : ctx.body
735
796
  }
736
797
  }
737
798
 
738
799
  @Post('/cls')
739
- @ValidateDtoClsBody(CreateCatDto)
800
+ @ValidateDto(CreateCatDto)
740
801
  public async cls(ctx : T.Context<{ body : CreateCatDto }>) {
741
- const body = ctx.body;
742
-
743
802
  return {
744
- body
803
+ body : ctx.body
745
804
  }
746
805
  }
747
806
  }
@@ -1112,6 +1171,163 @@ new Spear()
1112
1171
 
1113
1172
  ```
1114
1173
 
1174
+ ## Graphql
1175
+ GraphQL CRUD Example with graphql-yoga + tspace-spear
1176
+
1177
+ This example shows how to build a simple GraphQL CRUD API using graphql-yoga and tspace-spear.
1178
+
1179
+ It includes:
1180
+
1181
+ - GraphQL schema setup
1182
+ - Query and Mutation examples
1183
+ - Create / Read / Update / Delete operations
1184
+ - HTTP integration with graphql-yoga
1185
+
1186
+ The server uses an in-memory array as a fake database for simplicity.
1187
+
1188
+ Features
1189
+ - High performance HTTP server with tspace-spear
1190
+ - Native GraphQL schema definitions
1191
+ - Full CRUD operations
1192
+ - Simple and dependency-light setup
1193
+ - Works with standard GraphQL clients and tools
1194
+
1195
+ ```sh
1196
+ npm install graphql graphql-yoga
1197
+ ```
1198
+
1199
+ ```js
1200
+ import { type T, Spear } from "tspace-spear";
1201
+
1202
+ import {
1203
+ createYoga,
1204
+ createSchema,
1205
+ } from 'graphql-yoga';
1206
+
1207
+ type User = {
1208
+ id: number;
1209
+ name: string;
1210
+ email: string;
1211
+ };
1212
+
1213
+ const users: User[] = [
1214
+ {
1215
+ id: 1,
1216
+ name: 'John',
1217
+ email: 'john@gmail.com',
1218
+ },
1219
+ ];
1220
+
1221
+ const yoga = createYoga({
1222
+ graphqlEndpoint: '/graphql',
1223
+
1224
+ schema: createSchema({
1225
+ typeDefs: /* GraphQL */ `
1226
+ type User {
1227
+ id: Int!
1228
+ name: String!
1229
+ email: String!
1230
+ }
1231
+
1232
+ input CreateUserInput {
1233
+ name: String!
1234
+ email: String!
1235
+ }
1236
+
1237
+ input UpdateUserInput {
1238
+ id: Int!
1239
+ name: String
1240
+ email: String
1241
+ }
1242
+
1243
+ type Query {
1244
+ users: [User!]!
1245
+ user(id: Int!): User
1246
+ }
1247
+
1248
+ type Mutation {
1249
+ createUser(input: CreateUserInput!): User!
1250
+ updateUser(input: UpdateUserInput!): User!
1251
+ removeUser(id: Int!): User!
1252
+ }
1253
+ `,
1254
+
1255
+ resolvers: {
1256
+ Query: {
1257
+ users: () => users,
1258
+
1259
+ user: (_root, args) => {
1260
+ return users.find(
1261
+ (u) => u.id === args.id,
1262
+ );
1263
+ },
1264
+ },
1265
+
1266
+ Mutation: {
1267
+ createUser: (_root, args) => {
1268
+ const user = {
1269
+ id: Date.now(),
1270
+ name: args.input.name,
1271
+ email: args.input.email,
1272
+ };
1273
+
1274
+ users.push(user);
1275
+
1276
+ return user;
1277
+ },
1278
+
1279
+ updateUser: (_root, args) => {
1280
+ const user = users.find(
1281
+ (u) => u.id === args.input.id,
1282
+ );
1283
+
1284
+ if (!user) {
1285
+ throw new Error(
1286
+ 'User not found',
1287
+ );
1288
+ }
1289
+
1290
+ if (args.input.name !== undefined) {
1291
+ user.name = args.input.name;
1292
+ }
1293
+
1294
+ if (args.input.email !== undefined) {
1295
+ user.email = args.input.email;
1296
+ }
1297
+
1298
+ return user;
1299
+ },
1300
+
1301
+ removeUser: (_root, args) => {
1302
+ const index = users.findIndex(
1303
+ (u) => u.id === args.id,
1304
+ );
1305
+
1306
+ if (index === -1) {
1307
+ throw new Error(
1308
+ 'User not found',
1309
+ );
1310
+ }
1311
+
1312
+ const deleted = users[index];
1313
+
1314
+ users.splice(index, 1);
1315
+
1316
+ return deleted;
1317
+ },
1318
+ },
1319
+ },
1320
+ }),
1321
+ });
1322
+
1323
+ const app = new Spear()
1324
+ .get('/graphql',({ req , res }) => yoga(req , res))
1325
+ .post('/graphql',({ req , res }) => yoga(req , res))
1326
+ .listen(4000 , ({ port , server }) => {
1327
+ console.log(`server listening on : http://localhost:${port}/graphql`)
1328
+ })
1329
+ ```
1330
+
1115
1331
  ## E2E
1116
1332
  Provides end-to-end type safety and testing support across the full request lifecycle, from request input to
1117
1333
  response output. It allows you to:
@@ -1171,7 +1387,7 @@ class CatController {
1171
1387
  const cat = cats.find((d) => d.id === Number(params.id));
1172
1388
 
1173
1389
  if(cat == null) {
1174
- return res.notFound('not found cat')
1390
+ throw res.notFound('not found cat')
1175
1391
  }
1176
1392
 
1177
1393
  return {
@@ -1213,7 +1429,7 @@ class CatController {
1213
1429
  const index = cats.findIndex((d) => d.id === id);
1214
1430
 
1215
1431
  if (index === -1) {
1216
- return res.notFound('not found cat')
1432
+ throw res.notFound('not found cat')
1217
1433
  }
1218
1434
 
1219
1435
  cats[index] = {
@@ -1256,7 +1472,7 @@ import Spear from "tspace-spear";
1256
1472
  const app = new Spear({
1257
1473
  logger : true,
1258
1474
  controllers: {
1259
- folder : `${__dirname}/controllers`,
1475
+ folder : `${__dirname}/controllers/*`,
1260
1476
  name:/controller\.(ts|js)$/i,
1261
1477
  // don't forget to set this option for auto-generate route metadata for type-safe E2E usage,
1262
1478
  // and swagger documentation. By default if use .useSwagger() in app no need to set any description
@@ -1280,79 +1496,55 @@ const client: ApiClient<AppRouter> = new ApiClient(
1280
1496
  `http://localhost:8000/api`
1281
1497
  );
1282
1498
 
1283
- const test = await client.get("/catsq"); // Type error: Argument of type '"/catsq"' is not assignable to parameter of type '"/cats" | "/cats/:id" | ... 3 more
1499
+ await client.get("/catsq"); // Type error: Argument of type '"/catsq"' is not assignable to parameter of type '"/cats" | "/cats/:id" | ... 3 more
1284
1500
  const res = await client.get("/cats");
1285
- res.data.cats = 1 // Type error: Type 'number' is not assignable to type '{ id: number; name: string; age: number; }[]'
1286
- res.data.cats[0].name = 1 // Type error: Type 'number' is not assignable to type 'string'
1287
- res.data.cats[0].age = "1.6" // Type error: Type 'string' is not assignable to type 'number'
1288
-
1289
- console.log(res)
1290
- // res.ok -> boolean
1291
- // res.status -> number
1292
- // res.data -> { cats: [{ id: 1, name: 'cat1', age: 1.6 },{ id: 2, name: 'cat2', age: 1.8 }] }
1293
-
1294
- ```
1295
-
1296
- ## Example CRUD
1297
- ```js
1298
- import { Spear } from "tspace-spear";
1299
-
1300
- const spears = [
1301
- {
1302
- id : 1,
1303
- damage : 100
1304
- },
1305
- {
1306
- id : 2,
1307
- damage : 75
1308
- },
1309
- {
1310
- id : 3,
1311
- damage : 50
1312
- }
1313
- ]
1314
-
1315
- new Spear()
1316
- // enable body payload
1317
- .useBodyParser()
1318
- .get('/' , () => spears)
1319
- .get('/:id' , ({ params }) => spears.find(spear => spear.id === Number(params.id ?? 0)))
1320
- .post('/' , ({ body }) => {
1321
- // please validation the your body
1322
- const damage = Number(body.damage ?? (Math.random() * 100).toFixed(0))
1323
-
1324
- const id = spears.reduce((max, spear) => spear.id > max ? spear.id : max, 0) + 1
1325
-
1326
- spears.push({ id , damage })
1327
-
1328
- return spears.find(spear => spear.id === id)
1329
- })
1330
- .patch('/:id' , ({ params , body , res }) => {
1331
-
1332
- const damage = Number(body.damage ?? (Math.random() * 100).toFixed(0))
1333
-
1334
- const id = Number(params.id)
1335
-
1336
- const spear = spears.find(spear => spear.id === id)
1337
-
1338
- if (spear == null) return res.status(404).json({ message : 'Spear not found'})
1501
+ // res.ok -> true or false
1502
+ // res.status -> number
1503
+ // res.headers -> Hearders
1504
+ // res.data -> { cats: [{ id: 1, name: 'cat1', age: 1.6 },{ id: 2, name: 'cat2', age: 1.8 }] }
1505
+
1506
+ // Without checking `res.ok`, `res.data` is always typed as `any`.
1507
+ if(res.ok) {
1508
+ res.data.cats = 1 // Type error: Type 'number' is not assignable to type '{ id: number; name: string; age: number; }[]'
1509
+ res.data.cats[0].name = 1 ❌ // Type error: Type 'number' is not assignable to type 'string'
1510
+ res.data.cats[0].age = "1.6" ❌ // Type error: Type 'string' is not assignable to type 'number'
1511
+ }
1339
1512
 
1340
- spear.damage = damage;
1513
+ await client.get("/cats/:id") // Expected 2 arguments, but got 1.
1514
+ await client.get("/cats/:id", { params : { id : "1" }}) ❌
1515
+ // The expected type comes from property 'id' which is declared here on type '{ id: number; }'
1516
+ await client.get("/cats/:id", { params : { id : 1 }}) ✅
1341
1517
 
1342
- return spears.find(spear => spear.id === id)
1343
- })
1344
- .delete('/:id', ({ params , res }) => {
1518
+ await client.post("/cats") // Expected 2 arguments, but got 1.
1519
+ await client.post("/cats",{
1520
+ body : {} ❌ // Type '{}' is missing the following properties from type '{ name: string; age: number; }'
1521
+ });
1522
+ await client.post("/cats",{
1523
+ body : { name : "super cat" } ❌
1524
+ // Property 'age' is missing in type '{ name: string; }'
1525
+ // but required in type '{ name: string; age: number; }'.
1526
+ });
1527
+ await client.post("/cats",{
1528
+ body : { name : "super cat" , age : 5 } ✅
1529
+ });
1345
1530
 
1346
- const id = Number(params.id)
1531
+ await client.put("/cats")
1347
1532
 
1348
- const spear = spears.find(spear => spear.id === id)
1533
+ await client.put("/cats",{
1534
+ body : {} ✅
1535
+ });
1349
1536
 
1350
- if (spear == null) return res.status(404).json({ message : 'Spear not found'})
1537
+ await client.put("/cats",{
1538
+ body : { name : 1 } ❌ // Type 'number' is not assignable to type 'string'.
1539
+ });
1351
1540
 
1352
- spears.splice(spears.findIndex(spear => spear.id === Number(params.id ?? 0)), 1)
1541
+ await client.put("/cats",{
1542
+ body : { name : "super cat" } ✅
1543
+ });
1353
1544
 
1354
- return res.status(204).json()
1355
- })
1356
- .listen(8000 , () => console.log(`Server is now listening http://localhost:8000`))
1545
+ await client.put("/cats",{
1546
+ body : { name : "super cat" , age : 5 }
1547
+ });
1548
+
1549
+ ```
1357
1550
 
1358
- ```
@@ -0,0 +1 @@
1
+ export declare function createApp(inputPath?: string): Promise<void>;