{"_id":"@admicaa/netpress-permissions","_rev":"3-9f5a536fda7b58a2559b3268c7bd2670","name":"@admicaa/netpress-permissions","dist-tags":{"latest":"0.2.3"},"versions":{"0.2.0":{"name":"@admicaa/netpress-permissions","version":"0.2.0","keywords":["netpress","permissions","roles","authorization","laravel"],"license":"MIT","_id":"@admicaa/netpress-permissions@0.2.0","maintainers":[{"name":"admicaa","email":"a_a199799@ymail.com"}],"dist":{"shasum":"d31de9f8fc59c4afc2bdf7d03554592f4ae5b76c","tarball":"https://registry.npmjs.org/@admicaa/netpress-permissions/-/netpress-permissions-0.2.0.tgz","fileCount":16,"integrity":"sha512-GYCG8BM2kzYAHjTmNXkGiQmncPsYVrGRGQ3IY0ntCK5oo3fBXVV6cWfpl3YUsV7eKuFKvs/eUH8G82P3NYS8Eg==","signatures":[{"sig":"MEQCIC1xVptS10bDHU+ZVKfYZGY4XwE32sSdg5hlLhOiCZsgAiASAV1oTgY4S3PnYGNXYLWxjwVvELngHqWYMSrCTbfQFw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":39219},"main":"./index.js","type":"module","types":"./index.d.ts","exports":{".":"./index.js","./publisher":"./src/publisher.js","./package.json":"./package.json"},"gitHead":"5541733f80be2a57934afc97a931d918028a856b","scripts":{"test":"NODE_OPTIONS='--experimental-vm-modules --import tsx' jest --config ./jest.config.js --runInBand --detectOpenHandles"},"_npmUser":{"name":"admicaa","email":"a_a199799@ymail.com"},"_npmVersion":"11.9.0","description":"Laravel-style roles, permissions, policies, and auth guard package for NetPress.","directories":{},"_nodeVersion":"24.14.0","_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","jest":"^29.7.0","knex":"^3.2.9","@jest/globals":"^29.7.0","better-sqlite3":"^11.0.0"},"peerDependencies":{"@admicaa/netpress":">=0.1.4"},"_npmOperationalInternal":{"tmp":"tmp/netpress-permissions_0.2.0_1776637062671_0.9162016064417977","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@admicaa/netpress-permissions","version":"0.2.1","keywords":["netpress","permissions","roles","authorization","laravel"],"license":"MIT","_id":"@admicaa/netpress-permissions@0.2.1","maintainers":[{"name":"admicaa","email":"a_a199799@ymail.com"}],"dist":{"shasum":"962e1698c6cc0db0b35a1670a92bbff6b289a81f","tarball":"https://registry.npmjs.org/@admicaa/netpress-permissions/-/netpress-permissions-0.2.1.tgz","fileCount":16,"integrity":"sha512-Hc5h6oPWSWkCwuI14Tdwy0KBaFoovnEZM+ZMq5T8XCYKo6JtPRDn9gwq2t6HE/92A8tFrBq8//zM5uhqnEZHIQ==","signatures":[{"sig":"MEUCIEFZOxAogFrWzMZLCULfs8pyagjr85LyQM7pbbgaYXGRAiEAtuP8cD5diYAemwjkeOFGtMBlKUjOTQlG2uhlU8yQb8M=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":39218},"main":"./index.js","type":"module","types":"./index.d.ts","exports":{".":"./index.js","./publisher":"./src/publisher.js","./package.json":"./package.json"},"gitHead":"5541733f80be2a57934afc97a931d918028a856b","scripts":{"test":"NODE_OPTIONS='--experimental-vm-modules --import tsx' jest --config ./jest.config.js --runInBand --detectOpenHandles"},"_npmUser":{"name":"admicaa","email":"a_a199799@ymail.com"},"_npmVersion":"11.9.0","description":"Laravel-style roles, permissions, policies, and auth guard package for NetPress.","directories":{},"_nodeVersion":"24.14.0","_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","jest":"^29.7.0","knex":"^3.2.9","@jest/globals":"^29.7.0","better-sqlite3":"^11.0.0"},"peerDependencies":{"@admicaa/netpress":">=0.1.4"},"_npmOperationalInternal":{"tmp":"tmp/netpress-permissions_0.2.1_1776637126755_0.6937795028167593","host":"s3://npm-registry-packages-npm-production"}},"0.2.3":{"name":"@admicaa/netpress-permissions","version":"0.2.3","description":"Laravel-style roles, permissions, policies, and auth guard package for NetPress.","type":"module","main":"./index.js","types":"./index.d.ts","exports":{".":"./index.js","./publisher":"./src/publisher.js","./package.json":"./package.json"},"scripts":{"test":"NODE_OPTIONS='--experimental-vm-modules --import tsx' jest --config ./jest.config.js --runInBand --detectOpenHandles"},"keywords":["netpress","permissions","roles","authorization","laravel"],"license":"MIT","peerDependencies":{"@admicaa/netpress":">=0.1.6"},"devDependencies":{"@jest/globals":"^29.7.0","better-sqlite3":"^11.0.0","jest":"^29.7.0","knex":"^3.2.9","tsx":"^4.19.0"},"gitHead":"d6da2eb4a40acb8a49ff1f96873fbc7008219803","_id":"@admicaa/netpress-permissions@0.2.3","_nodeVersion":"24.14.0","_npmVersion":"11.9.0","dist":{"integrity":"sha512-sJ7hp75YWQ8D2gxStOjtbkzOEs7b1AOVtK3TIB8I32r/9PdzNuX0YBotBDDHvnux/d0NMo6POYT+18soVnquxg==","shasum":"90be9a45edae1b3d866f49386b33a495bafa27e1","tarball":"https://registry.npmjs.org/@admicaa/netpress-permissions/-/netpress-permissions-0.2.3.tgz","fileCount":16,"unpackedSize":48082,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBFWDAHT9G4u0xHs3I5yvHB6uDeSBuxaS/FKGjY674DMAiEAra1HfJFl5HZFwV7pqnNagOHCAUZgH7sx99MDQnC+QVg="}]},"_npmUser":{"name":"admicaa","email":"a_a199799@ymail.com"},"directories":{},"maintainers":[{"name":"admicaa","email":"a_a199799@ymail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/netpress-permissions_0.2.3_1776684576440_0.10706424233928269"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-19T22:17:42.579Z","modified":"2026-04-20T11:29:36.699Z","0.2.0":"2026-04-19T22:17:42.822Z","0.2.1":"2026-04-19T22:18:46.894Z","0.2.3":"2026-04-20T11:29:36.596Z"},"license":"MIT","keywords":["netpress","permissions","roles","authorization","laravel"],"description":"Laravel-style roles, permissions, policies, and auth guard package for NetPress.","maintainers":[{"name":"admicaa","email":"a_a199799@ymail.com"}],"readme":"# NetPress Permissions\n\nLaravel-style roles, permissions, morph assignments, and `can()` integration for NetPress.\n\n## What It Includes\n\n- `Role` and `Permission` models\n- Polymorphic model assignments for roles and direct permissions\n- Trait-style mixins for authorizable models\n- `can()` support that works with both registered policies and direct permissions\n- Migration helpers for creating the package tables\n- **Guard-scoped roles and permissions** (`guardName`) — the same role/permission name can coexist across multiple auth guards (`web`, `api`, `admin`, …)\n- `AuthGuard` route middleware for `authenticated`/`can`/`role`/`permission`/`guest` gates\n- A publishable config, migration, and service provider via `vendor:publish`\n\n## Publish Into An App\n\nFrom a NetPress application:\n\n```bash\nnpm run artisan -- vendor:publish --provider=NetpressPermissionsServiceProvider\n```\n\nThe publish flow will:\n\n- ask which configured database connection should store the permissions data\n- publish `config/permissions.js`\n- publish `database/migrations/*_create_permission_tables.js`\n- publish `app/Providers/PermissionsServiceProvider.js`\n- register the provider in `bootstrap/providers.js`\n\nIf you pick a Mongo connection, the published migration targets that Mongo connection automatically.\n\n## Quick Start\n\n```js\nimport { BaseModel, registerPolicy } from '@admicaa/netpress';\nimport {\n  Authorizable,\n  Role,\n  Permission,\n  createPermissionTables,\n} from '@admicaa/netpress-permissions';\n\nclass User extends Authorizable(BaseModel) {\n  static table = 'users';\n}\n\nclass Post extends BaseModel {\n  static table = 'posts';\n}\n\nclass PostPolicy {\n  async update(authUser, post) {\n    return authUser.id === post.userId;\n  }\n}\n\nregisterPolicy(Post, PostPolicy);\n```\n\n## Migrations\n\nCreate an application migration that delegates to the package helper:\n\n```js\nimport { createPermissionTables, dropPermissionTables } from '@admicaa/netpress-permissions';\n\nexport async function up(schema) {\n  await createPermissionTables(schema);\n}\n\nexport async function down(schema) {\n  await dropPermissionTables(schema);\n}\n```\n\n## Usage\n\n```js\nconst editor = await Role.findOrCreate('editor');\nconst publishPosts = await Permission.findOrCreate('posts.publish');\n\nawait editor.givePermissionTo(publishPosts);\n\nconst user = await User.create({ name: 'Amina' });\nawait user.assignRole(editor);\n\nawait user.can('posts.publish'); // true\nawait user.can('update', post);  // policy-aware\n```\n\n## Guards (`guardName`)\n\nEvery role and permission has a `guardName` column, mirroring Laravel Spatie. It lets the\nsame name live in different auth guards (for example `admin` under `web` and `admin` under `api`).\n\nThe default guard is resolved in this order:\n\n1. `config.permissions.defaultGuard` (if set)\n2. The core `Auth.defaultGuard()` (i.e. whatever you called `Auth.setDefaultGuard(...)` with)\n3. `'web'` as a final fallback\n\n```js\n// Create role/permission scoped to a specific guard:\nconst webAdmin = await Role.findOrCreate('admin', 'web');\nconst apiAdmin = await Role.findOrCreate('admin', 'api');\n\n// Second argument may be guard *or* values (Spatie-style convenience):\nconst perm = await Permission.findOrCreate('posts.publish', { group: 'posts' });\n```\n\nPin a user model to a specific guard by declaring it on the class — this is the hook the\ntraits use (`getDefaultGuardName()`), equivalent to Spatie's model method of the same name:\n\n```js\nclass ApiUser extends Authorizable(BaseModel) {\n  static table = 'users';\n  static guardName = 'api'; // roles/permissions resolved under the 'api' guard\n}\n\nconst apiUser = await ApiUser.create({ name: 'Amina' });\nawait apiUser.assignRole('admin');       // resolves 'admin' in the 'api' guard\nawait apiUser.hasRole('admin');          // only matches api-scoped admin rows\nawait apiUser.hasPermissionTo('posts.publish');\n```\n\nString-based lookups (`assignRole('admin')`, `hasRole('admin')`, `hasPermissionTo('posts.publish')`, …)\nare all filtered by the user's resolved guard, so a role named `admin` under `web` will not\nsatisfy a check made by an `api` user.\n\n## `AuthGuard` middleware\n\nExpress-compatible middleware factories for the most common authorization gates. All\nmiddleware resolves the current user via the core `Auth` layer and responds with the\nconventional 401/403 status codes.\n\n```js\nimport { AuthGuard } from '@admicaa/netpress-permissions';\n\nrouter.get('/dashboard',     AuthGuard.authenticated(),      showDashboard);\nrouter.get('/posts/:id/edit', AuthGuard.can('posts.update', 'id'), editPost);\nrouter.post('/posts',         AuthGuard.permission('posts.publish'), createPost);\nrouter.delete('/users/:id',   AuthGuard.role('admin', 'owner'), deleteUser);\nrouter.get('/billing',        AuthGuard.roles('admin', 'billing'),   billing);\nrouter.get('/login',          AuthGuard.guest(),              loginPage);\n```\n\nAvailable gates:\n\n| Gate | Allows a request through when… |\n| --- | --- |\n| `AuthGuard.authenticated()` | a user is authenticated on the active guard (else **401**) |\n| `AuthGuard.can(ability, resource?)` | the user passes `can(ability, resource)` — integrates with registered policies (else **403**) |\n| `AuthGuard.canAny(abilities, resource?)` | any of the listed abilities succeed |\n| `AuthGuard.canAll(abilities, resource?)` | every listed ability succeeds |\n| `AuthGuard.role(...names)` | user has **any** of the given roles |\n| `AuthGuard.roles(...names)` | user has **all** of the given roles |\n| `AuthGuard.permission(...names)` | user has **any** of the given permissions |\n| `AuthGuard.permissions(...names)` | user has **all** of the given permissions |\n| `AuthGuard.guest()` | no authenticated user on the active guard (else **403**) |\n\nThe `resource` argument of `can/canAny/canAll` may be:\n\n- a string — read as `req.params[resource]` (e.g. `'id'` → `req.params.id`)\n- a function — called with `req`, return the resource to authorize against\n- any value — passed through as-is\n\nBecause the role/permission checks flow through the same `getDefaultGuardName()` hook on the\nuser model, `AuthGuard` naturally respects guard scoping: an `api` user will only match\n`api`-scoped roles and permissions.\n","readmeFilename":"README.md"}