{"_id":"@arkveil/nest","_rev":"4-5333f938d3c11d6cc7c33142551ca2ff","name":"@arkveil/nest","dist-tags":{"latest":"0.3.0"},"versions":{"0.1.0":{"name":"@arkveil/nest","version":"0.1.0","keywords":["arkveil","abac","nestjs","permissions","authorization","access-control","rbac","security"],"author":{"name":"Dan Zabrotski"},"license":"MIT","_id":"@arkveil/nest@0.1.0","maintainers":[{"name":"dantechceo","email":"dan@speekl.com"}],"homepage":"https://www.arkveil.com","bugs":{"url":"https://github.com/arkveil-abac/arkveil-js/issues"},"dist":{"shasum":"b4151e1279171f5b9553d200a61615b98276db79","tarball":"https://registry.npmjs.org/@arkveil/nest/-/nest-0.1.0.tgz","fileCount":7,"integrity":"sha512-4+b60WpG/PqFOctJTxhNXf56C0gxTS/9qKaA0imImRQ03AvdI/O2aPBWxkAI4HPATPZfMi0LTlj5FUcVV/8G3Q==","signatures":[{"sig":"MEYCIQD3b6+FX4bcI8Dgdp1UmxDMrKKGJPJJ0EOVjbiTxQyqTgIhAIVfmYwph9MusNIqV85bX5+JL3zLRJhLHUz5tr4MGAvv","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":36827},"main":"./dist/index.cjs","type":"module","_from":"file:arkveil-nest-0.1.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"scripts":{"build":"tsup"},"_npmUser":{"name":"dantechceo","email":"dan@speekl.com"},"_resolved":"/private/var/folders/yk/kczcj9k16_g579hlgpqzz6dh0000gn/T/c39accc69db84e85f9c9b5dd07ee85c5/arkveil-nest-0.1.0.tgz","_integrity":"sha512-4+b60WpG/PqFOctJTxhNXf56C0gxTS/9qKaA0imImRQ03AvdI/O2aPBWxkAI4HPATPZfMi0LTlj5FUcVV/8G3Q==","repository":{"url":"git+https://github.com/arkveil-abac/arkveil-js.git","type":"git","directory":"packages/nest"},"_npmVersion":"10.9.2","description":"NestJS SDK for Arkveil — declarative ABAC permission checks via decorators and guards.","directories":{},"_nodeVersion":"22.13.1","dependencies":{"arkveil":"0.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","typescript":"^5.9.3","@types/node":"^22","@nestjs/core":"^11.1.8","@nestjs/common":"^11.1.8","@nestjs/graphql":"^13.2.0","reflect-metadata":"^0.2.2"},"peerDependencies":{"@nestjs/core":"^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0","@nestjs/common":"^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0","@nestjs/graphql":"^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0","reflect-metadata":"^0.1.0 || ^0.2.0"},"peerDependenciesMeta":{"@nestjs/graphql":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nest_0.1.0_1782789970809_0.9244108578629162","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@arkveil/nest","version":"0.2.0","keywords":["arkveil","abac","nestjs","permissions","authorization","access-control","rbac","security"],"author":{"name":"Dan Zabrotski"},"license":"MIT","_id":"@arkveil/nest@0.2.0","maintainers":[{"name":"dantechceo","email":"dan@speekl.com"}],"homepage":"https://www.arkveil.com","bugs":{"url":"https://github.com/arkveil-abac/arkveil-js/issues"},"dist":{"shasum":"622af2abad41949e086cb2dc5c086c7228bba679","tarball":"https://registry.npmjs.org/@arkveil/nest/-/nest-0.2.0.tgz","fileCount":7,"integrity":"sha512-ak307BrIVun2EUskGkVFiOq8KTTUpvyYAwWcyE5dF4p2WpNns59sIA+uz0RVwVrawCS4xy1gIHS+De9DDoMamg==","signatures":[{"sig":"MEYCIQCyy/apxksgHEnct1VWbhvA5Zfu9Tm1qhjkfLzvx+DPYAIhAPIR7FM8bHPuFYhBzJgiXduHEsH2TB/QkzoFYfGiccc+","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":38904},"main":"./dist/index.cjs","type":"module","_from":"file:arkveil-nest-0.2.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"scripts":{"build":"tsup"},"_npmUser":{"name":"dantechceo","email":"dan@speekl.com"},"_resolved":"/private/var/folders/yk/kczcj9k16_g579hlgpqzz6dh0000gn/T/9d94f9fd18dc1020319daf341ea4b424/arkveil-nest-0.2.0.tgz","_integrity":"sha512-ak307BrIVun2EUskGkVFiOq8KTTUpvyYAwWcyE5dF4p2WpNns59sIA+uz0RVwVrawCS4xy1gIHS+De9DDoMamg==","repository":{"url":"git+https://github.com/arkveil-abac/arkveil-js.git","type":"git","directory":"packages/nest"},"_npmVersion":"10.9.2","description":"NestJS SDK for Arkveil — declarative ABAC permission checks via decorators and guards.","directories":{},"_nodeVersion":"22.13.1","dependencies":{"arkveil":"0.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","typescript":"^5.9.3","@types/node":"^22","@nestjs/core":"^11.1.8","@nestjs/common":"^11.1.8","@nestjs/graphql":"^13.2.0","reflect-metadata":"^0.2.2"},"peerDependencies":{"@nestjs/core":"^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0","@nestjs/common":"^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0","@nestjs/graphql":"^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0","reflect-metadata":"^0.1.0 || ^0.2.0"},"peerDependenciesMeta":{"@nestjs/graphql":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nest_0.2.0_1784569741073_0.7725529184129287","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@arkveil/nest","version":"0.2.1","keywords":["arkveil","abac","nestjs","permissions","authorization","access-control","rbac","security"],"author":{"name":"Dan Zabrotski"},"license":"MIT","_id":"@arkveil/nest@0.2.1","maintainers":[{"name":"dantechceo","email":"dan@speekl.com"}],"homepage":"https://www.arkveil.com","bugs":{"url":"https://github.com/arkveil-abac/arkveil-js/issues"},"dist":{"shasum":"abaade65255b39d6648eeac2768345ccbb51e42c","tarball":"https://registry.npmjs.org/@arkveil/nest/-/nest-0.2.1.tgz","fileCount":7,"integrity":"sha512-9AgajIiqfqdA4FuuA84vafUWGI6WNiEj0x8edFBcGq7gN0jhIWOUb7yo4v0FNgH9qJoOUCbCamXYNghun/YFIQ==","signatures":[{"sig":"MEYCIQCIU1mVJbhmbEk+coXXFnLLJ/Dl+RJk+m9z8rfbs1mv7gIhAMfSQza8zVQaIPLPzvI5/Giy6re2MafGdFEdaLpoHSlM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":31905},"main":"./dist/index.cjs","type":"module","_from":"file:arkveil-nest-0.2.1.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"scripts":{"test":"pnpm run build && vitest run","build":"tsup"},"_npmUser":{"name":"dantechceo","email":"dan@speekl.com"},"_resolved":"/private/var/folders/yk/kczcj9k16_g579hlgpqzz6dh0000gn/T/fd3ee249a0e9e8b951ec5d77a79eb32f/arkveil-nest-0.2.1.tgz","_integrity":"sha512-9AgajIiqfqdA4FuuA84vafUWGI6WNiEj0x8edFBcGq7gN0jhIWOUb7yo4v0FNgH9qJoOUCbCamXYNghun/YFIQ==","repository":{"url":"git+https://github.com/arkveil-abac/arkveil-js.git","type":"git","directory":"packages/nest"},"_npmVersion":"10.9.2","description":"NestJS SDK for Arkveil — declarative ABAC permission checks via decorators and guards.","directories":{},"_nodeVersion":"22.13.1","dependencies":{"arkveil":"0.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vitest":"^2.1.0","typescript":"^5.9.3","@types/node":"^22","@nestjs/core":"^11.1.8","@nestjs/common":"^11.1.8","@nestjs/graphql":"^13.2.0","@nestjs/testing":"^11.1.8","reflect-metadata":"^0.2.2"},"peerDependencies":{"@nestjs/core":"^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0","@nestjs/common":"^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0","@nestjs/graphql":"^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0","reflect-metadata":"^0.1.0 || ^0.2.0"},"peerDependenciesMeta":{"@nestjs/graphql":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nest_0.2.1_1786841603090_0.27490594929404666","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@arkveil/nest","version":"0.3.0","description":"NestJS SDK for Arkveil — declarative ABAC permission checks via decorators and guards.","keywords":["arkveil","abac","nestjs","permissions","authorization","access-control","rbac","security"],"homepage":"https://www.arkveil.com","bugs":{"url":"https://github.com/arkveil-abac/arkveil-js/issues"},"repository":{"type":"git","url":"git+https://github.com/arkveil-abac/arkveil-js.git","directory":"packages/nest"},"license":"MIT","author":{"name":"Dan Zabrotski"},"type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"publishConfig":{"access":"public"},"engines":{"node":">=18"},"dependencies":{"arkveil":"0.3.0"},"peerDependencies":{"@nestjs/common":"^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0","@nestjs/core":"^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0","@nestjs/graphql":"^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0","reflect-metadata":"^0.1.0 || ^0.2.0"},"peerDependenciesMeta":{"@nestjs/graphql":{"optional":true}},"devDependencies":{"@nestjs/common":"^11.1.8","@nestjs/core":"^11.1.8","@nestjs/graphql":"^13.2.0","@nestjs/testing":"^11.1.8","@types/node":"^22","reflect-metadata":"^0.2.2","tsup":"^8.5.1","typescript":"^5.9.3","vitest":"^2.1.0"},"scripts":{"build":"tsup","test":"pnpm run build && vitest run"},"_id":"@arkveil/nest@0.3.0","_integrity":"sha512-3czMaa+Aculjdue+vcKwrMohOrEzU3Faw8AJp1rrpyuYrza5SFdZ/vkBDv3URiUKGe34qPsiheGtAYg0/xznAg==","_resolved":"/private/var/folders/yk/kczcj9k16_g579hlgpqzz6dh0000gn/T/2fa777a5c93b0328c760557987222937/arkveil-nest-0.3.0.tgz","_from":"file:arkveil-nest-0.3.0.tgz","_nodeVersion":"22.13.1","_npmVersion":"10.9.2","dist":{"integrity":"sha512-3czMaa+Aculjdue+vcKwrMohOrEzU3Faw8AJp1rrpyuYrza5SFdZ/vkBDv3URiUKGe34qPsiheGtAYg0/xznAg==","shasum":"fd3239f98e31f38dcc17a9f429041f202bf891b4","tarball":"https://registry.npmjs.org/@arkveil/nest/-/nest-0.3.0.tgz","fileCount":7,"unpackedSize":32987,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIE+a4aBMUvmt4GA7hT7jgJkXI31lhpXUDt2X7SqzeyE+AiBU2gqU94tXqAUBHJEM8ttnWIN5WDP3GxIFQNXMlMhnfg=="}]},"_npmUser":{"name":"dantechceo","email":"dan@speekl.com"},"directories":{},"maintainers":[{"name":"dantechceo","email":"dan@speekl.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/nest_0.3.0_1788626231943_0.038677887424800605"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-30T03:26:10.677Z","modified":"2026-09-05T16:37:12.320Z","0.1.0":"2026-06-30T03:26:10.938Z","0.2.0":"2026-07-20T17:49:01.246Z","0.2.1":"2026-08-16T00:53:23.245Z","0.3.0":"2026-09-05T16:37:12.142Z"},"bugs":{"url":"https://github.com/arkveil-abac/arkveil-js/issues"},"author":{"name":"Dan Zabrotski"},"license":"MIT","homepage":"https://www.arkveil.com","keywords":["arkveil","abac","nestjs","permissions","authorization","access-control","rbac","security"],"repository":{"type":"git","url":"git+https://github.com/arkveil-abac/arkveil-js.git","directory":"packages/nest"},"description":"NestJS SDK for Arkveil — declarative ABAC permission checks via decorators and guards.","maintainers":[{"name":"dantechceo","email":"dan@speekl.com"}],"readme":"# @arkveil/nest\n\n## Installation\n\n```bash\nnpm install @arkveil/nest\n# or\nyarn add @arkveil/nest\n# or\npnpm add @arkveil/nest\n```\n\n## Features\n\n- 🔒 **Declarative Permission Checks** - Use decorators to protect your endpoints\n- 🌐 **Global Module** - Configure once, use everywhere\n- 🔄 **Async Configuration** - Support for async configuration with dependency injection\n- 📡 **Multi-Protocol Support** - Works with HTTP, GraphQL, and WebSocket contexts\n- 🎯 **Type-Safe** - Full TypeScript support with type definitions\n\n## Quick Start\n\n### 1. Configure the Module\n\n#### Option A: Synchronous Configuration\n\n```typescript\nimport { Module } from \"@nestjs/common\";\nimport { ArkveilModule } from \"@arkveil/nest\";\n\n@Module({\n  imports: [\n    ArkveilModule.forRoot({\n      serviceUrl: \"https://api.arkveil.com\",\n      apiKey: \"your-api-key\",\n      getUserAttributes: (req) => ({\n        id: req.user?.id,\n        email: req.user?.email,\n        role: req.user?.role,\n      }),\n      getContextAttributes: (req) => ({\n        ip: req.ip,\n        userAgent: req.headers[\"user-agent\"],\n      }),\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n#### Option B: Async Configuration\n\n```typescript\nimport { Module } from \"@nestjs/common\";\nimport { ConfigModule, ConfigService } from \"@nestjs/config\";\nimport { ArkveilModule } from \"@arkveil/nest\";\n\n@Module({\n  imports: [\n    ConfigModule.forRoot(),\n    ArkveilModule.forRootAsync({\n      imports: [ConfigModule],\n      useFactory: (configService: ConfigService) => ({\n        serviceUrl: configService.get(\"ARKVEIL_SERVICE_URL\"),\n        apiKey: configService.get(\"ARKVEIL_API_KEY\"),\n        getUserAttributes: (req) => ({\n          id: req.user?.id,\n          email: req.user?.email,\n          role: req.user?.role,\n        }),\n      }),\n      inject: [ConfigService],\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n### 2. Protect Your Endpoints\n\nUse the `@PermissionPoint` decorator to protect your endpoints:\n\n```typescript\nimport { Controller, Get, Post, Delete } from \"@nestjs/common\";\nimport { PermissionPoint } from \"@arkveil/nest\";\n\n@Controller(\"articles\")\nexport class ArticlesController {\n  @Get()\n  @PermissionPoint(\"content-service.article-read\")\n  getAllArticles() {\n    return \"List of articles\";\n  }\n\n  @Post()\n  @PermissionPoint(\"content-service.article-create\")\n  createArticle() {\n    return \"Article created\";\n  }\n\n  @Delete(\":id\")\n  @PermissionPoint(\"content-service.article-delete\")\n  deleteArticle() {\n    return \"Article deleted\";\n  }\n\n  @Get(\"/admin\")\n  @PermissionPoint(\"content-service.admin-access\")\n  adminAction() {\n    return \"Admin content\";\n  }\n}\n```\n\n## Typed Codes & Attributes\n\nGet autocomplete and compile-time checking for the `code` passed to\n`@PermissionPoint` (and for `user`/`context` attributes). Generate the file with\nthe Arkveil CLI (`arkveil generate typescript -o src/arkveil.generated.ts`) and\nregister it once via declaration merging:\n\n```typescript\n// arkveil.generated.ts — generated by `arkveil generate typescript`\nexport type ArkveilCodes =\n  \"content-service.article-read\" | \"content-service.article-delete\";\n\ndeclare module \"arkveil\" {\n  interface ArkveilCodeRegistry {\n    codes: ArkveilCodes;\n  }\n  // ...also augments ArkveilUserRegistry / ArkveilContextRegistry\n}\n```\n\nThat's all — `@PermissionPoint` is now typed everywhere:\n\n```typescript\n@PermissionPoint(\"content-service.article-delete\") // ✅ autocompletes\n@PermissionPoint(\"nope\") // ❌ compile error\n```\n\nIf you'd rather not augment globally, build a typed decorator from an explicit\nunion instead:\n\n```typescript\nimport { createPermissionPoint } from \"@arkveil/nest\";\nimport type { ArkveilCodes } from \"./arkveil.generated\";\n\n// Re-export this and use it in place of the built-in PermissionPoint.\nexport const PermissionPoint = createPermissionPoint<ArkveilCodes>();\n```\n\n## Configuration Options\n\n### ArkveilModuleOptions\n\n| Option                 | Type       | Required | Description                                  |\n| ---------------------- | ---------- | -------- | -------------------------------------------- |\n| `serviceUrl`           | `string`   | Yes      | The URL of your Arkveil service              |\n| `apiKey`               | `string`   | Yes      | Your Arkveil API key                         |\n| `version`              | `string`   | No       | API version (default: \"v1\")                  |\n| `timeout`              | `number`   | No       | Request timeout in milliseconds              |\n| `retryAttempts`        | `number`   | No       | Number of retry attempts for failed requests |\n| `logger`               | `Logger`   | No       | Custom logger instance                       |\n| `getUserAttributes`    | `Function` | No       | Extract user attributes from request         |\n| `getContextAttributes` | `Function` | No       | Extract context attributes from request      |\n| `onDenied`             | `Function` | No       | Custom handler for denied access             |\n\n## Advanced Usage\n\n### Custom User Attribute Extraction\n\n```typescript\nArkveilModule.forRoot({\n  serviceUrl: \"https://api.arkveil.com\",\n  apiKey: \"your-api-key\",\n  getUserAttributes: (req) => ({\n    // Custom logic to extract user attributes\n    id: req.headers[\"x-user-id\"] || req.user?.id,\n    role: req.user?.role,\n  }),\n});\n```\n\n### Adding Context Attributes\n\n```typescript\nArkveilModule.forRoot({\n  serviceUrl: \"https://api.arkveil.com\",\n  apiKey: \"your-api-key\",\n  getContextAttributes: (req) => ({\n    ip: req.ip,\n    userAgent: req.headers[\"user-agent\"],\n    timestamp: new Date().toISOString(),\n    organizationId: req.user?.organizationId,\n  }),\n});\n```\n\n### Custom Denied Handler\n\n```typescript\nArkveilModule.forRoot({\n  serviceUrl: \"https://api.arkveil.com\",\n  apiKey: \"your-api-key\",\n  onDenied: (req, res) => {\n    // Custom logic when access is denied\n    res.status(403).json({\n      error: \"Access Denied\",\n      message: \"You do not have the required permissions\",\n      requestId: req.id,\n    });\n  },\n});\n```\n\n### GraphQL Support\n\nThe `@PermissionPoint` decorator works seamlessly with GraphQL resolvers:\n\n```typescript\nimport { Resolver, Query, Mutation } from \"@nestjs/graphql\";\nimport { PermissionPoint } from \"@arkveil/nest\";\n\n@Resolver()\nexport class ArticleResolver {\n  @Query(() => [Article])\n  @PermissionPoint(\"content-service.article-read\")\n  articles() {\n    return this.articleService.findAll();\n  }\n\n  @Mutation(() => Article)\n  @PermissionPoint(\"content-service.article-create\")\n  createArticle(@Args(\"input\") input: CreateArticleInput) {\n    return this.articleService.create(input);\n  }\n}\n```\n\n### Using the Guard Directly\n\nIf you need more control, you can use the guard directly:\n\n```typescript\nimport { Controller, Get, UseGuards } from \"@nestjs/common\";\nimport { PermissionPointGuard } from \"@arkveil/nest\";\n\n@Controller(\"articles\")\n@UseGuards(PermissionPointGuard)\nexport class ArticlesController {\n  @Get()\n  getAllArticles() {\n    return \"List of articles\";\n  }\n}\n```\n\n## Error Handling\n\nThe SDK throws standard NestJS exceptions:\n\n- `ForbiddenException` - When the permission point is missing, the check is denied, or the check fails (fail-closed)\n\nYou can handle these using NestJS exception filters:\n\n```typescript\nimport {\n  ExceptionFilter,\n  Catch,\n  ArgumentsHost,\n  ForbiddenException,\n} from \"@nestjs/common\";\n\n@Catch(ForbiddenException)\nexport class ForbiddenExceptionFilter implements ExceptionFilter {\n  catch(exception: ForbiddenException, host: ArgumentsHost) {\n    const ctx = host.switchToHttp();\n    const response = ctx.getResponse();\n\n    response.status(403).json({\n      statusCode: 403,\n      message: \"Access Denied\",\n      timestamp: new Date().toISOString(),\n    });\n  }\n}\n```\n\n## How It Works\n\n1. The `@PermissionPoint` decorator marks an endpoint with a permission action ID\n2. When a request comes in, the `PermissionPointGuard` intercepts it\n3. The guard extracts user information from the request\n4. It sends a permission check request to the Arkveil service\n5. If permission is granted, the request proceeds; otherwise, a `ForbiddenException` is thrown\n\n## Request Flow\n\n```\nRequest → @PermissionPoint Decorator → PermissionPointGuard → Arkveil Service → Permission Check → Endpoint Handler\n```\n\n## Row-level data protection\n\nThe module provides the core `Arkveil` client, so you can inject it and use\nthe data-protection methods — `buildReadCondition` (a SQL condition to AND\ninto your SELECTs), `buildWriteChecks` (the pre-state `touchSql` / post-state\n`resultSql` checks to run inside a mutation's transaction, over the ids it\ntargets), and `buildTouchCondition` (a condition to compose into a bulk\n`UPDATE`/`DELETE`'s WHERE clause):\n\n```typescript\nimport { Injectable } from \"@nestjs/common\";\nimport { Arkveil } from \"arkveil\";\n\n@Injectable()\nexport class PaymentsService {\n  constructor(private readonly arkveil: Arkveil) {}\n\n  async listPayments(user: UserAttributes) {\n    const { readCondition } = await this.arkveil.buildReadCondition({\n      datasetCode: \"billing.public.payments\",\n      user,\n      context: {},\n      alias: \"p\",\n    });\n    return this.db.query(`SELECT * FROM payments p WHERE ${readCondition}`);\n  }\n}\n```\n\nSee the [`arkveil` core README](https://www.npmjs.com/package/arkveil) for the\nfull contract: which check exists for CREATE/UPDATE/DELETE and when it runs,\nthe CREATE `{{ids}}` template helper (`resolveCreateResultSql`), the two bulk\nrecipes, and the fail-closed semantics.\n\n## Best Practices\n\n1. **Always configure `getUserAttributes`** - This is how user identity and attributes reach the permission check\n2. **Use meaningful action IDs** - Follow a consistent naming pattern (e.g., `service.resource.action`)\n3. **Add context attributes** - Include relevant information like IP, organization, etc.\n4. **Handle exceptions gracefully** - Use exception filters for better error handling\n5. **Test permissions** - Write unit tests for your permission logic\n\n## Troubleshooting\n\n### User attributes are empty in the permission check\n\nMake sure your authentication middleware/guard runs before the Arkveil guard so\nthat `req.user` is populated, and that `getUserAttributes` reads from it:\n\n```typescript\nArkveilModule.forRoot({\n  // ...\n  getUserAttributes: (req) => ({ id: req.user?.id }),\n});\n```\n\n### \"Permission check failed\"\n\nCheck that:\n\n- Your Arkveil service URL is correct\n- Your API key is valid\n- The action ID exists in your Arkveil configuration\n\n### GraphQL context issues\n\nMake sure your GraphQL module is configured to pass the request:\n\n```typescript\nGraphQLModule.forRoot({\n  context: ({ req }) => ({ req }),\n});\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}