@alevnyacow/nzmt 0.12.1 → 0.13.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.
Files changed (3) hide show
  1. package/README.md +46 -29
  2. package/bin/cli.js +6 -4
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -9,59 +9,76 @@
9
9
  NZMT is a toolkit for building structured Next.js full-stack applications.
10
10
 
11
11
  It combines dependency injection, Zod validation and a DDD-inspired architecture,
12
- while removing most of the boilerplate through code generation.
12
+ while removing most of the boilerplate through code generation out of the box.
13
13
 
14
- - 🧩 Generate entities, stores, services and controllers boilerplate **with simple CLI commands**.
15
- - 🔐 **Runtime safety** across server layers with Zod out of the box.
16
- - **Dependency Injection** powered by Inversify with no setup required.
14
+ Batteries included!
15
+
16
+ ## Why NZMT?
17
+
18
+ - You want to focus on domain logic without full DDD complexity
19
+ - You’re tired of rewriting CRUD, data layer logic, DTOs, and validation
20
+ - You want to follow best practices without overengineering or repetitive boilerplate
21
+ - You want your application to be runtime-safe
22
+ - You want to move fast without losing predictability
23
+ - You want a backend that can evolve into a full-stack solution
24
+
25
+ You focus on business logic; NZMT handles the infrastructure.
17
26
 
18
27
  # Quick start with Prisma
19
28
 
20
- Suppose you have NextJS application with generated Prisma client.
29
+ Assuming you have a Next.js project with a generated Prisma client and a `User` Prisma model:
21
30
 
22
31
  1. Install required peer dependencies and the toolkit itself.
23
32
  ```bash
24
33
  npm install inversify zod reflect-metadata @alevnyacow/nzmt
25
34
  ```
35
+
26
36
  2. Enable `Experimental decorators` and `Emit Decorator Metadata` options in your `tsconfig.json`.
37
+ ```json
38
+ // tsconfig.json
39
+ {
40
+ "compilerOptions": {
41
+ "experimentalDecorators": true,
42
+ "emitDecoratorMetadata": true
43
+ }
44
+ }
45
+ ```
27
46
 
28
47
  3. Initialize NZMT. This will set up all required infrastructure and configuration for you:
29
48
  ```bash
30
49
  npx nzmt init prismaClientPath:@/app/generated/prisma/client
31
50
  ```
32
51
 
33
- 4. Scaffold your first entity. Example for a `Product` with `title` and `price`:
52
+ 4. Now you can scaffold everything you need for `User` entity CRUD API in one CLI command:
34
53
  ```bash
35
- # Field syntax: f:<name>-<zod-rules>
36
- npx nzmt entity product f:title-string,price-int.positive
54
+ npx nzmt crud-api user
37
55
  ```
38
- This will generate the entity, its Zod schema and related types.
39
56
 
40
- 5. Scaffold server boilerplate
41
- ```bash
42
- # product store (with Prisma implementation, RAM implementation and DI)
43
- npx nzmt store product
44
- # product service proxying all product store methods (with DI)
45
- npx nzmt service product p:ProductStore
46
- # shop controller with injected product service and logger (with DI)
47
- npx nzmt controller shop i:Logger,ProductService
48
- ```
49
- Now you have scaffolded structure for `ProductStore`, `ProductService` and `ShopController` and all of them are registered in the DI container. You can now implement your logic inside these modules and expose it via controllers.
57
+ This will generate:
50
58
 
51
- You can use `fromDI` method anywhere you need an instance of a controller or a service:
59
+ - `User` entity
60
+ - `UserStore` contract, `UserRAMStore` and `UserPrismaStore` implementation
61
+ - `UserService` proxying all `UserStore` methods
62
+ - `UserController` proxying all `UserService` methods.
52
63
 
53
- ```ts
54
- // app/api/shop/route.ts
64
+ All code is editable - you stay in full control.
55
65
 
56
- import type { ShopController } from "@/server/controllers/shop"
57
- import { fromDI } from "@/server/di"
66
+ 5. **Describe entity properties and validation rules using Zod** for the `User` entity in the scaffolded file `/shared/entities/user/user.entity.ts`.
67
+
68
+ 6. **Implement Prisma mappers** in `/server/stores/user/user.store.prisma.ts`.
69
+ All methods and contracts are already scaffolded; you only need to describe the mappers themselves.
58
70
 
59
- // The key is fully typed, so you get autocomplete
60
- // across all registered DI modules.
61
- const controller = fromDI<ShopController>('ShopController')
71
+ 7. Use generated controller in `app/api/user/route.ts` file via DI.
72
+
73
+ ```ts
74
+ import type { UserController } from "@/server/controllers/user"
75
+ import { fromDI } from "@/server/di"
62
76
 
63
- // Suppose you have implemented the list_GET method in the controller.
64
- export const GET = controller.list_GET
77
+ // Get a fully typed controller instance from the DI container.
78
+ // Key is fully typed too, of course.
79
+ const controller = fromDI<UserController>('UserController')
80
+ // Use controller method as a route method.
81
+ export const GET = controller.GET
65
82
  ```
66
83
 
67
84
  # Design principles
package/bin/cli.js CHANGED
@@ -884,8 +884,9 @@ function generateController(upperCase, lowerCase, crudService) {
884
884
  // Metadata
885
885
 
886
886
  fs.writeFileSync(path.resolve(folder, `${entityName}.controller.metadata.ts`), [
887
- `import { Controller } from '@alevnyacow/nzmt'`,
888
- crudService ? `import { ${crudServiceLowercase}Metadata } from '@${config.paths.services}/${toKebabFromPascal(crudService).slice(0, -'-service'.length)}'` : undefined
887
+ crudService ? `import z from 'zod'` : undefined,
888
+ `import { Controller, ValueObjects } from '@alevnyacow/nzmt'`,
889
+ crudService ? `import { ${crudServiceLowercase}Metadata } from '@${config.paths.services}/${toKebabFromPascal(crudService).slice(0, -'-service'.length)}'` : undefined,
889
890
  ``,
890
891
  `export const ${lowerCase}ControllerMetadata = {`,
891
892
  `\tname: '${upperCase}Controller',`,
@@ -895,7 +896,7 @@ function generateController(upperCase, lowerCase, crudService) {
895
896
  `\t\t\tquery: z.union([`,
896
897
  `\t\t\t\tValueObjects.Pagination.schema.extend(${crudServiceLowercase}Metadata.schemas.getList.payload.shape.filter.shape),`,
897
898
  `\t\t\t\t${crudServiceLowercase}Metadata.schemas.getList.payload.shape.filter`,
898
- `\t\t\t])`,
899
+ `\t\t\t]),`,
899
900
  `\t\t\tresponse: ${crudServiceLowercase}Metadata.schemas.getList.response`,
900
901
  `\t\t},`,
901
902
  `\t\tdetails_GET: {`,
@@ -945,7 +946,8 @@ function generateController(upperCase, lowerCase, crudService) {
945
946
  `\t\t\treturn await this.${crudServiceLowercase}.getList({ filter, pagination: { pageSize, zeroBasedIndex } })`,
946
947
  `\t\t}`,
947
948
  `\t\treturn await this.${crudServiceLowercase}.getList({ filter: x })`,
948
- `\t}`,
949
+ `\t})`,
950
+ ``,
949
951
  `\tdetails_GET = this.endpoints('details_GET', this.${crudServiceLowercase}.getDetails)`,
950
952
  `\tPOST = this.endpoints('POST', this.${crudServiceLowercase}.create)`,
951
953
  `\tPATCH = this.endpoints('PATCH', this.${crudServiceLowercase}.update)`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alevnyacow/nzmt",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "description": "Next Zod Modules Toolkit",
5
5
  "repository": {
6
6
  "type": "git",