{"_id":"@arxjs/nestjs","name":"@arxjs/nestjs","dist-tags":{"latest":"0.0.1"},"versions":{"0.0.1":{"name":"@arxjs/nestjs","version":"0.0.1","description":"NestJS module for @arxjs/core — guards, decorators and injectable service","keywords":["authorization","rbac","nestjs","guard","decorator","typescript"],"license":"MIT","repository":{"type":"git","url":"git+https://github.com/lcubas/arx.git","directory":"packages/nestjs"},"homepage":"https://github.com/lcubas/arx/tree/main/packages/nestjs#readme","bugs":{"url":"https://github.com/lcubas/arx/issues"},"type":"module","engines":{"node":">=18"},"exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"main":"./dist/index.cjs","module":"./dist/index.mjs","types":"./dist/index.d.cts","sideEffects":false,"publishConfig":{"access":"public"},"peerDependencies":{"@arxjs/core":"*","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/core":"^10.0.0 || ^11.0.0","reflect-metadata":">=0.1.12"},"devDependencies":{"@nestjs/common":"^10.0.0","@nestjs/core":"^10.0.0","reflect-metadata":"^0.2.0","rxjs":"^7.8.0","tsdown":"^0.21.0","typescript":"^5.7.0","@arxjs/core":"0.0.1"},"scripts":{"build":"tsdown src/index.ts --format esm,cjs --dts --sourcemap --no-splitting --clean --external @nestjs/common --external @nestjs/core --external reflect-metadata --external @arxjs/core","typecheck":"tsc --noEmit"},"_id":"@arxjs/nestjs@0.0.1","_integrity":"sha512-923FBrx/FL0nhtv1n/43S5kXUuu5CDyBeFrA5Uz9ihex8NDCSyiu7KMb8gWZhp7GhYywSe/IXPIx4+UHdxSI9Q==","_resolved":"/private/var/folders/s6/wkd256dd3gg23_7vr_h91ckr0000gn/T/84660b3fc3f05ad37ff91aebe057325d/arxjs-nestjs-0.0.1.tgz","_from":"file:arxjs-nestjs-0.0.1.tgz","_nodeVersion":"24.11.1","_npmVersion":"11.6.2","dist":{"integrity":"sha512-923FBrx/FL0nhtv1n/43S5kXUuu5CDyBeFrA5Uz9ihex8NDCSyiu7KMb8gWZhp7GhYywSe/IXPIx4+UHdxSI9Q==","shasum":"6aba19580e8575fb8c6d964668b147b8c4869f1a","tarball":"https://registry.npmjs.org/@arxjs/nestjs/-/nestjs-0.0.1.tgz","fileCount":10,"unpackedSize":67815,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDLGN19Y+S3//ThRgacbKxU34U6x6nc3jjUEE7BPAf1pAIgDgS78RrunmUy1QDmhMS0Z9VyuAPuYpEKz1lKBLfCVMs="}]},"_npmUser":{"name":"lcubas92","email":"langelcubas92@gmail.com"},"directories":{},"maintainers":[{"name":"lcubas92","email":"langelcubas92@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/nestjs_0.0.1_1777099342751_0.45519278991516043"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-25T06:42:22.650Z","0.0.1":"2026-04-25T06:42:22.898Z","modified":"2026-04-25T06:42:23.162Z"},"maintainers":[{"name":"lcubas92","email":"langelcubas92@gmail.com"}],"description":"NestJS module for @arxjs/core — guards, decorators and injectable service","homepage":"https://github.com/lcubas/arx/tree/main/packages/nestjs#readme","keywords":["authorization","rbac","nestjs","guard","decorator","typescript"],"repository":{"type":"git","url":"git+https://github.com/lcubas/arx.git","directory":"packages/nestjs"},"bugs":{"url":"https://github.com/lcubas/arx/issues"},"license":"MIT","readme":"# @arxjs/nestjs\n\nNestJS module for [`@arxjs/core`](https://github.com/lcubas/arx/tree/main/packages/core). Provides an injectable `ArxService`, a route guard, and declarative decorators for permission and role checks.\n\n## Installation\n\n```bash\npnpm add @arxjs/nestjs @arxjs/core\n# npm install @arxjs/nestjs @arxjs/core\n```\n\nInstall a storage adapter:\n\n```bash\npnpm add @arxjs/prisma    # Prisma\npnpm add @arxjs/drizzle   # Drizzle ORM\npnpm add @arxjs/typeorm   # TypeORM (also requires: typeorm reflect-metadata)\n```\n\n## Setup\n\nRegister `ArxModule` once in your root `AppModule`. It is global by default, so you only need to import it once.\n\n```ts\n// app.module.ts\nimport { Module } from '@nestjs/common'\nimport { ArxModule } from '@arxjs/nestjs'\nimport { PrismaAdapter } from '@arxjs/prisma'\nimport { PrismaService } from './prisma.service'\n\n@Module({\n  imports: [\n    ArxModule.forRoot({\n      adapter: new PrismaAdapter(prisma),\n      getUserId: (req) => req.user?.id,\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n### Async configuration\n\nUse `forRootAsync` when the adapter depends on other services (e.g. `PrismaService`, `DataSource`, `ConfigService`):\n\n```ts\nArxModule.forRootAsync({\n  inject: [PrismaService],\n  useFactory: (prisma: PrismaService) => ({\n    adapter: new PrismaAdapter(prisma),\n    getUserId: (req) => req.user?.id,\n  }),\n})\n```\n\n### Setup with TypeORM\n\nWhen using `@arxjs/typeorm`, the `DataSource` is managed by `@nestjs/typeorm` — inject it via `forRootAsync`:\n\n```bash\npnpm add @arxjs/typeorm @nestjs/typeorm typeorm reflect-metadata\n```\n\n```ts\n// app.module.ts\nimport 'reflect-metadata'\nimport { Module } from '@nestjs/common'\nimport { TypeOrmModule } from '@nestjs/typeorm'\nimport { APP_GUARD } from '@nestjs/core'\nimport { ArxModule, ArxGuard } from '@arxjs/nestjs'\nimport { TypeOrmAdapter, ARX_TYPEORM_ENTITIES } from '@arxjs/typeorm'\nimport { DataSource } from 'typeorm'\n\n@Module({\n  imports: [\n    // 1. Set up TypeORM with the arx entities\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      url: process.env.DATABASE_URL,\n      entities: [...ARX_TYPEORM_ENTITIES],\n      migrations: ['dist/migrations/*.js'],\n      migrationsRun: true, // run pending migrations automatically on startup\n    }),\n\n    // 2. Register ArxModule — inject DataSource managed by @nestjs/typeorm\n    ArxModule.forRootAsync({\n      inject: [DataSource],\n      useFactory: (dataSource: DataSource) => ({\n        adapter: new TypeOrmAdapter(dataSource),\n        getUserId: (req) => (req as { user?: { id?: string } }).user?.id,\n      }),\n    }),\n  ],\n  providers: [\n    // 3. (Optional) protect every route globally\n    { provide: APP_GUARD, useClass: ArxGuard },\n  ],\n})\nexport class AppModule {}\n```\n\nFrom here, everything works the same as with any other adapter — use `@RequirePermissions`, `@RequireRole`, and `ArxService` as shown below.\n\n### `getUserId`\n\nThe `getUserId` function receives the raw HTTP request object and must return the current user's ID as a string, or `undefined` if the user is not authenticated.\n\n```ts\n// Passport / JWT (request.user populated by a JwtAuthGuard)\ngetUserId: (req) => req.user?.id\n\n// Custom header\ngetUserId: (req) => req.headers['x-user-id'] as string | undefined\n```\n\nWhen `getUserId` returns `undefined` on a route protected by `@RequirePermissions` or `@RequireRole`, the guard throws `UnauthorizedException` (HTTP 401).\n\n## Protecting routes\n\nApply `@RequirePermissions()` or `@RequireRole()` to your controllers or handlers, then add `ArxGuard` to enforce them.\n\n```ts\n// posts.controller.ts\nimport { Controller, Delete, Get, Post, UseGuards } from '@nestjs/common'\nimport { ArxGuard, RequirePermissions, RequireRole } from '@arxjs/nestjs'\n\n@Controller('posts')\n@UseGuards(ArxGuard)\nexport class PostsController {\n\n  @Get()\n  @RequirePermissions('post:view')\n  findAll() { ... }\n\n  @Post()\n  @RequirePermissions('post:create')\n  create() { ... }\n\n  @Delete(':id')\n  @RequirePermissions('post:delete')\n  remove() { ... }\n\n  @Post('bulk-delete')\n  @RequireRole('admin', 'moderator')   // any one of these roles is sufficient\n  bulkDelete() { ... }\n}\n```\n\n### Decorator semantics\n\n| Decorator | Logic |\n|---|---|\n| `@RequirePermissions('a', 'b')` | User must hold **all** listed permissions (AND) |\n| `@RequireRole('admin', 'mod')` | User must hold **at least one** listed role (OR) |\n\nHandler-level decorators take precedence over controller-level ones when both are present.\n\n### Global guard\n\nTo protect every route in the application without adding `@UseGuards(ArxGuard)` to every controller:\n\n```ts\n// app.module.ts\nimport { APP_GUARD } from '@nestjs/core'\nimport { ArxGuard } from '@arxjs/nestjs'\n\n@Module({\n  providers: [\n    { provide: APP_GUARD, useClass: ArxGuard },\n  ],\n})\nexport class AppModule {}\n```\n\n> **Important:** routes without `@RequirePermissions` or `@RequireRole` are **allowed through** even with the global guard active. This means your public routes (e.g. login, health check) require no extra work — the guard only enforces routes that have one of the decorators. If you want a route to be explicitly public and self-documenting, you can omit the decorators — it will pass through automatically.\n\n## Programmatic checks\n\nInject `ArxService` for imperative permission checks inside services, guards, or resolvers:\n\n```ts\n// posts.service.ts\nimport { Injectable, ForbiddenException } from '@nestjs/common'\nimport { ArxService } from '@arxjs/nestjs'\n\n@Injectable()\nexport class PostsService {\n  constructor(private readonly arx: ArxService) {}\n\n  async publish(userId: string, postId: string) {\n    const canPublish = await this.arx.can(userId, 'post:publish')\n    if (!canPublish) throw new ForbiddenException()\n    // ...\n  }\n}\n```\n\n`ArxService` exposes the full `@arxjs/core` API — see [`@arxjs/core` docs](https://github.com/lcubas/arx/tree/main/packages/core#api) for the complete reference.\n\n## Peer dependencies\n\n| Package | Version |\n|---|---|\n| `@arxjs/core` | `*` |\n| `@nestjs/common` | `>=10.0.0` |\n| `@nestjs/core` | `>=10.0.0` |\n| `reflect-metadata` | `>=0.1.12` |\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-8678f7df70f25a3d3c7fa1a5be8bfd68"}