{"_id":"@eduvia-app/nuxt-can","_rev":"4-dfe59dea240a6137161982a2a1cc1199","name":"@eduvia-app/nuxt-can","dist-tags":{"latest":"1.1.1"},"versions":{"1.0.0":{"name":"@eduvia-app/nuxt-can","version":"1.0.0","keywords":["nuxt","nuxt3","nuxt-module","permissions","vue","directive","v-can"],"author":{"name":"Eduvia","email":"engineering@eduvia.app"},"license":"MIT","_id":"@eduvia-app/nuxt-can@1.0.0","maintainers":[{"name":"stanig2106","email":"stanig2106@gmail.com"}],"homepage":"https://github.com/eduvia-app/nuxt-can#readme","bugs":{"url":"https://github.com/eduvia-app/nuxt-can/issues"},"dist":{"shasum":"2b89f913fb4f1f1ebd3b12cddb3df1e544299d09","tarball":"https://registry.npmjs.org/@eduvia-app/nuxt-can/-/nuxt-can-1.0.0.tgz","fileCount":28,"integrity":"sha512-vbxCW3+JFaLQWrgwKVmgC9mIyz6O3G8ug9BjwXb3yhbjNCKs4ThA5Qsuqv3eM6MPdGMQzF/J+aBUId86sCks5A==","signatures":[{"sig":"MEQCICsIN4HpkyYqhQ1R481kRvJ0U1rAk6lO/TOI0ZQbgCf2AiA0ZxZ+71GldI3SoYbRU5fTjR0Hy61PdARS3hVd1fUAVA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":25658},"main":"./dist/module.mjs","type":"module","module":"./dist/module.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/types.d.mts","import":"./dist/module.mjs"}},"gitHead":"fca4233c0bfdce1d32b0453532d47f9ff68c75d3","scripts":{"dev":"npm run dev:prepare && nuxi dev playground","lint":"eslint .","test":"vitest run","prepack":"nuxt-module-build build","release":"npm run lint && npm run test && npm run prepack && changelogen --release && npm publish && git push --follow-tags","dev:build":"nuxi build playground","test:types":"vue-tsc --noEmit && cd playground && vue-tsc --noEmit","test:watch":"vitest watch","dev:prepare":"nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground"},"_npmUser":{"name":"stanig2106","email":"stanig2106@gmail.com"},"repository":{"url":"git+https://github.com/eduvia-app/nuxt-can.git","type":"git"},"_npmVersion":"10.9.3","description":"Nuxt directives (`v-can`, `v-cannot`) to layer permissions without touching business v-ifs.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","dependencies":{"diff":"^8.0.2","@nuxt/kit":"^4.2.1","@vue/language-core":"^3.1.3"},"publishConfig":{"access":"public"},"typesVersions":{"*":{".":["./dist/types.d.mts"]}},"_hasShrinkwrap":false,"devDependencies":{"nuxt":"^4.2.1","eslint":"^9.39.1","vitest":"^4.0.8","vue-tsc":"^3.1.3","typescript":"~5.9.3","@types/node":"latest","changelogen":"^0.6.2","@nuxt/schema":"^4.2.1","@nuxt/devtools":"^3.1.0","@nuxt/test-utils":"^3.20.1","@nuxt/eslint-config":"^1.10.0","@nuxt/module-builder":"^1.0.2"},"peerDependencies":{"nuxt":"^3.0.0 || ^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nuxt-can_1.0.0_1763098679893_0.12013851896116123","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@eduvia-app/nuxt-can","version":"1.0.1","keywords":["nuxt","nuxt3","nuxt-module","permissions","vue","directive","v-can"],"author":{"name":"Eduvia","email":"engineering@eduvia.app"},"license":"MIT","_id":"@eduvia-app/nuxt-can@1.0.1","maintainers":[{"name":"stanig2106","email":"stanig2106@gmail.com"}],"homepage":"https://github.com/eduvia-app/nuxt-can#readme","bugs":{"url":"https://github.com/eduvia-app/nuxt-can/issues"},"dist":{"shasum":"ca6eb935ce04e1937bb82189c082a5e578e91690","tarball":"https://registry.npmjs.org/@eduvia-app/nuxt-can/-/nuxt-can-1.0.1.tgz","fileCount":28,"integrity":"sha512-g7s0G4g213MAtNICtKQpiRKtC0foBr3CHURAWPKtkncuC9UcJ1Yw1Clnoq2fMw6+pLEG6MoE+hPuXuFHUgPjkw==","signatures":[{"sig":"MEUCIBD0GoMdKlzFGKnThUR5iHIuPRTwsFrzoNSgzJc9XgBdAiEAmTTUb4IRQJm0NvWL9ef0G1tsLVvdjL6KS173wW22w9s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":25778},"main":"./dist/module.mjs","type":"module","module":"./dist/module.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/types.d.mts","import":"./dist/module.mjs"}},"gitHead":"2c4fe3f35398ca59312330f98c5f81e170cb9406","scripts":{"dev":"npm run dev:prepare && nuxi dev playground","lint":"eslint .","test":"vitest run","prepack":"nuxt-module-build build","release":"npm run lint && npm run test && npm run prepack && changelogen --release && npm publish && git push --follow-tags","dev:build":"nuxi build playground","test:types":"vue-tsc --noEmit && cd playground && vue-tsc --noEmit","test:watch":"vitest watch","dev:prepare":"nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground"},"_npmUser":{"name":"stanig2106","email":"stanig2106@gmail.com"},"repository":{"url":"git+https://github.com/eduvia-app/nuxt-can.git","type":"git"},"_npmVersion":"10.9.3","description":"Nuxt directives (`v-can`, `v-cannot`) to layer permissions without touching business v-ifs.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","dependencies":{"diff":"^8.0.2","@nuxt/kit":"^4.2.1","@vue/language-core":"^3.1.3"},"publishConfig":{"access":"public"},"typesVersions":{"*":{".":["./dist/types.d.mts"]}},"_hasShrinkwrap":false,"devDependencies":{"nuxt":"^4.2.1","eslint":"^9.39.1","vitest":"^4.0.8","vue-tsc":"^3.1.3","typescript":"~5.9.3","@types/node":"latest","changelogen":"^0.6.2","@nuxt/schema":"^4.2.1","@nuxt/devtools":"^3.1.0","@nuxt/test-utils":"^3.20.1","@nuxt/eslint-config":"^1.10.0","@nuxt/module-builder":"^1.0.2"},"peerDependencies":{"nuxt":"^3.0.0 || ^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nuxt-can_1.0.1_1763099003478_0.30340619393882373","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@eduvia-app/nuxt-can","version":"1.1.0","keywords":["nuxt","nuxt3","nuxt-module","permissions","vue","directive","v-can"],"author":{"name":"Eduvia","email":"engineering@eduvia.app"},"license":"MIT","_id":"@eduvia-app/nuxt-can@1.1.0","maintainers":[{"name":"stanig2106","email":"stanig2106@gmail.com"}],"homepage":"https://github.com/eduvia-app/nuxt-can#readme","bugs":{"url":"https://github.com/eduvia-app/nuxt-can/issues"},"dist":{"shasum":"2f9b62603d1a152f6fae3e0a4ac000dfdc8aee06","tarball":"https://registry.npmjs.org/@eduvia-app/nuxt-can/-/nuxt-can-1.1.0.tgz","fileCount":28,"integrity":"sha512-xPCz6EX6mJmoDjhB3c74sPoGsZ4MbzIjvIB/i1MbFYvdTUrcHL6lq1fwzqQH+5jOrHUuxc9dFDMsBrr68VCAkg==","signatures":[{"sig":"MEUCIEOBhq4a5IsRablwBIJQ4ZlhSijUgtV3T+qAKbQ67J93AiEA4EyiSrEYL7/J7lu2E+ToR13enQ0I3Vt0tnPKH/sPp9k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":35130},"main":"./dist/module.mjs","type":"module","module":"./dist/module.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/types.d.mts","import":"./dist/module.mjs"}},"gitHead":"7d823307fa3b8a3d42953590fd55cf8686e97395","scripts":{"dev":"npm run dev:prepare && nuxi dev playground","lint":"eslint .","test":"vitest run","prepack":"nuxt-module-build build","release":"npm run lint && npm run test && npm run prepack && changelogen --release && npm publish && git push --follow-tags","dev:build":"nuxi build playground","test:types":"vue-tsc --noEmit && cd playground && vue-tsc --noEmit","test:watch":"vitest watch","dev:prepare":"nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground"},"_npmUser":{"name":"stanig2106","email":"stanig2106@gmail.com"},"repository":{"url":"git+https://github.com/eduvia-app/nuxt-can.git","type":"git"},"_npmVersion":"10.9.3","description":"Nuxt directives (`v-can`, `v-cannot`) to layer permissions without touching business v-ifs.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","dependencies":{"diff":"^8.0.2","@nuxt/kit":"^4.2.1","@vue/language-core":"^3.1.3"},"publishConfig":{"access":"public"},"typesVersions":{"*":{".":["./dist/types.d.mts"]}},"_hasShrinkwrap":false,"devDependencies":{"nuxt":"^4.2.1","eslint":"^9.39.1","vitest":"^4.0.8","vue-tsc":"^3.1.3","typescript":"~5.9.3","@types/node":"latest","changelogen":"^0.6.2","@nuxt/schema":"^4.2.1","@nuxt/devtools":"^3.1.0","@nuxt/test-utils":"^3.20.1","@nuxt/eslint-config":"^1.10.0","@nuxt/module-builder":"^1.0.2"},"peerDependencies":{"nuxt":"^3.0.0 || ^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nuxt-can_1.1.0_1763145145361_0.040362818226695074","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@eduvia-app/nuxt-can","version":"1.1.1","description":"Nuxt directives (`v-can`, `v-cannot`) to layer permissions without touching business v-ifs.","author":{"name":"Eduvia","email":"engineering@eduvia.app"},"homepage":"https://github.com/eduvia-app/nuxt-can#readme","bugs":{"url":"https://github.com/eduvia-app/nuxt-can/issues"},"repository":{"type":"git","url":"git+https://github.com/eduvia-app/nuxt-can.git"},"license":"MIT","type":"module","keywords":["nuxt","nuxt3","nuxt-module","permissions","vue","directive","v-can"],"publishConfig":{"access":"public"},"sideEffects":false,"exports":{".":{"types":"./dist/types.d.mts","import":"./dist/module.mjs"}},"main":"./dist/module.mjs","module":"./dist/module.mjs","typesVersions":{"*":{".":["./dist/types.d.mts"]}},"engines":{"node":">=20"},"scripts":{"prepack":"nuxt-module-build build","dev":"npm run dev:prepare && nuxi dev playground","dev:build":"nuxi build playground","dev:prepare":"nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground","release":"npm run lint && npm run test && npm run prepack && changelogen --release && npm publish && git push --follow-tags","lint":"eslint .","test":"vitest run","test:watch":"vitest watch","test:types":"vue-tsc --noEmit && cd playground && vue-tsc --noEmit"},"dependencies":{"@nuxt/kit":"^4.2.1","@vue/language-core":"^3.1.3","diff":"^8.0.2"},"peerDependencies":{"nuxt":"^3.0.0 || ^4.0.0"},"devDependencies":{"@nuxt/devtools":"^3.1.0","@nuxt/eslint-config":"^1.10.0","@nuxt/module-builder":"^1.0.2","@nuxt/schema":"^4.2.1","@nuxt/test-utils":"^3.20.1","@types/node":"latest","changelogen":"^0.6.2","eslint":"^9.39.1","nuxt":"^4.2.1","typescript":"~5.9.3","vitest":"^4.0.8","vue-tsc":"^3.1.3"},"_id":"@eduvia-app/nuxt-can@1.1.1","gitHead":"29d9c23800bbef49fdb09012ddb0247f4241ef88","_nodeVersion":"22.18.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-2HV2DmHKkckrDRRaE2gNQ68+rc43SJNhH9Vl81NZTuGXcT3cLQmzW0E7xkORROj1MH3QYFwofBIfgEMXsAVnOg==","shasum":"e148f552bd0ff726aef3a2c39820301ba8c8403e","tarball":"https://registry.npmjs.org/@eduvia-app/nuxt-can/-/nuxt-can-1.1.1.tgz","fileCount":28,"unpackedSize":35130,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDIomaWNrZ/XdqPkhmBbR/BxeeQX8PxEwLcn9j0ml4wSAiEA1gg1ErTmH5GO+52+PCNNiurHayIN3y6jCpZ1g/mxsHQ="}]},"_npmUser":{"name":"stanig2106","email":"stanig2106@gmail.com"},"directories":{},"maintainers":[{"name":"stanig2106","email":"stanig2106@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/nuxt-can_1.1.1_1763145502778_0.000482326044775494"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-14T05:37:59.817Z","modified":"2025-11-14T18:38:23.206Z","1.0.0":"2025-11-14T05:38:00.098Z","1.0.1":"2025-11-14T05:43:23.659Z","1.1.0":"2025-11-14T18:32:25.637Z","1.1.1":"2025-11-14T18:38:22.983Z"},"bugs":{"url":"https://github.com/eduvia-app/nuxt-can/issues"},"author":{"name":"Eduvia","email":"engineering@eduvia.app"},"license":"MIT","homepage":"https://github.com/eduvia-app/nuxt-can#readme","keywords":["nuxt","nuxt3","nuxt-module","permissions","vue","directive","v-can"],"repository":{"type":"git","url":"git+https://github.com/eduvia-app/nuxt-can.git"},"description":"Nuxt directives (`v-can`, `v-cannot`) to layer permissions without touching business v-ifs.","maintainers":[{"name":"stanig2106","email":"stanig2106@gmail.com"}],"readme":"# nuxt-can\n\n[![npm version][npm-version-src]][npm-version-href]\n[![npm downloads][npm-downloads-src]][npm-downloads-href]\n[![License][license-src]][license-href]\n[![Nuxt][nuxt-src]][nuxt-href]\n\n`nuxt-can` ships two Vue directives (`v-can`, `v-cannot`) so you can encode permissions directly in Nuxt templates. Each directive is transformed at build time into a composable `__can__` call provided by your app, keeping the runtime lean, tree-shake friendly, and fully typed.\n\n- [✨ Release Notes](/CHANGELOG.md)\n\n## Highlights\n\n- ✅ Cleanly adds permissions to existing templates without rewriting your business `v-if`s\n- ✅ Compile-time transform of `v-can` / `v-cannot` into `v-if` guards\n- ✅ Smart merge with existing `v-if` conditions (no extra wrappers)\n- ✅ Auto-generated `can` proxy with types derived from your permissions map\n- ✅ Pluggable import of the host `__can__` function (stores, APIs, etc.)\n- ✅ Helpful DX errors for unsupported directive shapes\n\n## Quick Start\n\nInstall the module in your Nuxt app:\n\n```bash\nnpm install @eduvia-app/nuxt-can\n# or\nnpx nuxi module add @eduvia-app/nuxt-can\n```\n\nEnable it inside `nuxt.config.ts` and describe the permissions tree:\n\n```ts\n// nuxt.config.ts\nimport NuxtCan from '@eduvia-app/nuxt-can'\n\nexport default defineNuxtConfig({\n  modules: [NuxtCan],\n  nuxtCan: {\n    permissions: {\n      employee: ['view', 'edit'],\n      contract: ['create'],\n    },\n    canFunctionImport: '~/permissions/can', // path to your __can__ implementation\n  },\n})\n```\n\nProvide the `__can__` implementation referenced above:\n\n```ts\n// permissions/can.ts\nconst permissionsStore = usePermissionsStore()\n\nexport function __can__(...path: string[]) {\n  return permissionsStore.check(path.join('.'))\n}\n```\n\nNow you can write directives that stay type-safe:\n\n```vue\n<template>\n  <button v-can=\"can.employee.view\">View profile</button>\n  <button v-if=\"isReady\" v-can=\"can.employee.edit\">\n    Edit profile\n  </button>\n  <p v-cannot>Access denied</p>\n</template>\n```\n\n…and the compiler rewrites them into plain conditionals:\n\n```vue\n<button v-if=\"__can__('employee', 'view')\">View profile</button>\n<button v-if=\"__can__('employee', 'edit') && (isReady)\">Edit profile</button>\n<p v-if=\"!(__can__('employee', 'edit'))\">Access denied</p>\n```\n\n## Directive Patterns\n\n### Guard entire `v-if` / `v-else-if` / `v-else` chains\n\nOnce the first branch of a conditional chain carries `v-can`, the transformer automatically mirrors that guard (with the same permission path) on every subsequent `v-else-if` and `v-else`. You can still repeat the directive manually for clarity, but it’s no longer required.\n\n```vue\n<div v-if=\"status === 'draft'\" v-can=\"can.foo.bar\">\n  Draft state\n</div>\n<div v-else-if=\"status === 'pending'\">\n  Pending state\n</div>\n<div v-else>\n  Fallback state\n</div>\n<div v-cannot=\"can.foo.bar\">\n  Missing permission\n</div>\n```\n\nTransforms into:\n\n```vue\n<div v-if=\"__can__('foo', 'bar') && (status === 'draft')\">\n  Draft state\n</div>\n<div v-else-if=\"__can__('foo', 'bar') && (status === 'pending')\">\n  Pending state\n</div>\n<div v-else-if=\"__can__('foo', 'bar')\">\n  Fallback state\n</div>\n<div v-if=\"!__can__('foo', 'bar')\">\n  Missing permission\n</div>\n```\n\n### Pass arguments to `v-cannot`\n\n`v-cannot` can mirror the permission expression used by its matching `v-can` by adding the same argument (`v-cannot=\"can.foo.bar\"`). When no argument is specified, the directive must immediately follow the preceding `v-can` block so the transformer can re-use that context.\n\n```vue\n<button v-can=\"can.contract.submit\">Submit contract</button>\n<p v-cannot=\"can.contract.submit\">Contact your admin to unlock submissions.</p>\n\n<template>\n  <button v-if=\"isReady\" v-can=\"can.contract.edit\">Edit</button>\n  <p v-cannot>Only editors can update this contract.</p>\n</template>\n\n<!-- Need to wrap the fallback? pass the expression explicitly -->\n<div class=\"notice\">\n  <p v-cannot=\"can.contract.edit\">Only editors can update this contract.</p>\n</div>\n```\n\nBoth `v-cannot` branches above compile to `v-if=\"!__can__('contract', 'submit')\"` and `v-if=\"!__can__('contract', 'edit')\"` respectively.\n\n### Keep `v-cannot` next to its `v-can`\n\nWhen `v-cannot` omits an expression, it must immediately follow the guarded block:\n\n```vue\n<div v-if=\"isReady\" v-can=\"can.foo.bar\">Ready!</div>\n<p v-cannot>Not allowed</p> <!-- ✅ adjacent, guard is inferred -->\n\n<div>\n  <p v-cannot>Not allowed</p> <!-- ❌ wrapped, missing explicit expression -->\n</div>\n\n<div>\n  <p v-cannot=\"can.foo.bar\">Not allowed</p> <!-- ✅ wrapper + explicit permission -->\n</div>\n```\n\n## Usage Rules & Errors\n\nThe transformer validates every template and throws descriptive errors when:\n\n- `v-can` expressions differ within the same `v-if` / `v-else-if` / `v-else` block (the guard is mirrored automatically, but mixed expressions are disallowed).\n- `v-cannot` without an argument is separated from its originating `v-can`.\n- `v-cannot` mixes in modifiers or a `v-if` condition (keep it standalone).\n- Multiple `v-cannot` blocks exist for the same `v-can`.\n- The expression is not a static dotted path like `can.resource.action`.\n\n## Generated Types\n\nThe `permissions` map feeds a generated `types/nuxt-can.d.ts` declaration that augments:\n\n- `ComponentCustomProperties` with `can`, `$can`, and `__can__`.\n- `NuxtApp` with `$can` and `$__can__`.\n- Runtime typings for the `#build/nuxt-can/can-import.mjs` bridge.\n\nNo extra setup is required for editors or strict TypeScript projects.\n\n## Why `v-can`?\n\nRetrofitting authorization into an existing codebase often means revisiting every `v-if` to sprinkle permission checks alongside business logic. That makes templates harder to read, increases the risk of regressions, and couples security rules with UI state management. `v-can` and `v-cannot` isolate the permission layer: you keep your original conditions untouched while the transformer injects the `__can__` guards for you. As a result, business logic stays readable, authorization lives in one place, and code reviews can focus on either concern without stepping on each other.\n\n## Playground\n\nRun `npm run dev` to explore the playground app located in `/playground`. It demonstrates:\n\n- Stacked `v-can` / `v-cannot` pairs.\n- Interaction with existing `v-if`s and `v-for`s.\n- Template blocks that share the same permission guard.\n- A live permission summary powered by the injected `__can__` function.\n\nFeel free to wire your own `~/playground/permissions/__can__.ts` to mimic a real backend.\n\n## Local Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Prepare type stubs and the playground\nnpm run dev:prepare\n\n# Playground dev server\nnpm run dev\n\n# Build the playground\nnpm run dev:build\n\n# Lint & tests\nnpm run lint\nnpm run test\nnpm run test:watch\n\n# Type checks (module + playground)\nnpm run test:types\n\n# Release pipeline\nnpm run release\n```\n\n## Contributing\n\n1. Fork & clone the repo.\n2. Run `npm run dev:prepare` once to scaffold stubs.\n3. Use the playground (`npm run dev`) to reproduce issues.\n4. Add tests under `test/` and fixtures under `test/fixtures/*`.\n5. Open a PR following Conventional Commits (e.g. `feat:`, `fix:`).\n\n---\n\n<!-- Badges -->\n[npm-version-src]: https://img.shields.io/npm/v/%40eduvia-app%2Fnuxt-can/latest.svg?style=flat&colorA=020420&colorB=00DC82\n[npm-version-href]: https://npmjs.com/package/@eduvia-app/nuxt-can\n\n[npm-downloads-src]: https://img.shields.io/npm/dm/%40eduvia-app%2Fnuxt-can.svg?style=flat&colorA=020420&colorB=00DC82\n[npm-downloads-href]: https://npm.chart.dev/@eduvia-app/nuxt-can\n\n[license-src]: https://img.shields.io/npm/l/%40eduvia-app%2Fnuxt-can.svg?style=flat&colorA=020420&colorB=00DC82\n[license-href]: https://npmjs.com/package/@eduvia-app/nuxt-can\n\n[nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt.js\n[nuxt-href]: https://nuxt.com\n","readmeFilename":"README.md"}