[{"data":1,"prerenderedAt":4887},["ShallowReactive",2],{"navigation-landing-en":3,"navigation-nuxt-auto-en":180,"navigation-nuxt-protokit-en":365,"\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fpermissions-cookbook-en":507,"\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fpermissions-cookbook-surround-en":4882},[4,8,13,28,41,51,64,77,94,110,134,150,157,172],{"title":5,"path":6,"stem":7},"Overview","\u002Fdocs\u002Flanding","0.docs\u002F1.landing\u002F001.index",{"title":9,"path":10,"stem":11,"badge":12},"Built-in Features","\u002Fdocs\u002Flanding\u002Fbuilt-in-features","0.docs\u002F1.landing\u002F002.built-in-features","New",{"title":14,"path":15,"stem":16,"children":17,"icon":27},"Content Foundation","\u002Fdocs\u002Flanding\u002Fcontent","0.docs\u002F1.landing\u002F02.content\u002F1.index",[18,19,23],{"title":5,"path":15,"stem":16},{"title":20,"path":21,"stem":22},"Details","\u002Fdocs\u002Flanding\u002Fcontent\u002Fdetails","0.docs\u002F1.landing\u002F02.content\u002F2.details",{"title":24,"path":25,"stem":26},"Technical","\u002Fdocs\u002Flanding\u002Fcontent\u002Ftechnical","0.docs\u002F1.landing\u002F02.content\u002F4.technical","i-heroicons-document-text",{"title":29,"path":30,"stem":31,"children":32,"icon":40},"Regional Content","\u002Fdocs\u002Flanding\u002Fregional","0.docs\u002F1.landing\u002F03.regional\u002F1.index",[33,34,37],{"title":5,"path":30,"stem":31},{"title":20,"path":35,"stem":36},"\u002Fdocs\u002Flanding\u002Fregional\u002Fdetails","0.docs\u002F1.landing\u002F03.regional\u002F2.details",{"title":24,"path":38,"stem":39},"\u002Fdocs\u002Flanding\u002Fregional\u002Ftechnical","0.docs\u002F1.landing\u002F03.regional\u002F4.technical","i-heroicons-globe-alt",{"title":42,"path":43,"stem":44,"children":45,"icon":50},"Multi-language","\u002Fdocs\u002Flanding\u002Fmultilang","0.docs\u002F1.landing\u002F04.multilang\u002F1.index",[46,47],{"title":5,"path":43,"stem":44},{"title":20,"path":48,"stem":49},"\u002Fdocs\u002Flanding\u002Fmultilang\u002Fdetails","0.docs\u002F1.landing\u002F04.multilang\u002F2.details","i-heroicons-language",{"title":52,"path":53,"stem":54,"children":55,"icon":63},"Blog","\u002Fdocs\u002Flanding\u002Fblog","0.docs\u002F1.landing\u002F05.blog\u002F1.index",[56,57,60],{"title":5,"path":53,"stem":54},{"title":20,"path":58,"stem":59},"\u002Fdocs\u002Flanding\u002Fblog\u002Fdetails","0.docs\u002F1.landing\u002F05.blog\u002F2.details",{"title":24,"path":61,"stem":62},"\u002Fdocs\u002Flanding\u002Fblog\u002Ftechnical","0.docs\u002F1.landing\u002F05.blog\u002F4.technical","i-heroicons-pencil-square",{"title":65,"path":66,"stem":67,"children":68,"icon":76},"Documentation","\u002Fdocs\u002Flanding\u002Fdocs","0.docs\u002F1.landing\u002F06.docs\u002F1.index",[69,70,73],{"title":5,"path":66,"stem":67},{"title":20,"path":71,"stem":72},"\u002Fdocs\u002Flanding\u002Fdocs\u002Fdetails","0.docs\u002F1.landing\u002F06.docs\u002F2.details",{"title":24,"path":74,"stem":75},"\u002Fdocs\u002Flanding\u002Fdocs\u002Ftechnical","0.docs\u002F1.landing\u002F06.docs\u002F4.technical","i-heroicons-book-open",{"title":78,"path":79,"stem":80,"children":81,"icon":93},"Forms","\u002Fdocs\u002Flanding\u002Fforms","0.docs\u002F1.landing\u002F07.forms\u002F1.index",[82,83,86,90],{"title":5,"path":79,"stem":80},{"title":20,"path":84,"stem":85},"\u002Fdocs\u002Flanding\u002Fforms\u002Fdetails","0.docs\u002F1.landing\u002F07.forms\u002F2.details",{"title":87,"path":88,"stem":89},"Admin","\u002Fdocs\u002Flanding\u002Fforms\u002Fadmin","0.docs\u002F1.landing\u002F07.forms\u002F3.admin",{"title":24,"path":91,"stem":92},"\u002Fdocs\u002Flanding\u002Fforms\u002Ftechnical","0.docs\u002F1.landing\u002F07.forms\u002F4.technical","i-heroicons-clipboard-document-list",{"title":95,"path":96,"stem":97,"children":98,"icon":109},"Email","\u002Fdocs\u002Flanding\u002Femail","0.docs\u002F1.landing\u002F08.email\u002F1.index",[99,100,103,106],{"title":5,"path":96,"stem":97},{"title":20,"path":101,"stem":102},"\u002Fdocs\u002Flanding\u002Femail\u002Fdetails","0.docs\u002F1.landing\u002F08.email\u002F2.details",{"title":87,"path":104,"stem":105},"\u002Fdocs\u002Flanding\u002Femail\u002Fadmin","0.docs\u002F1.landing\u002F08.email\u002F3.admin",{"title":24,"path":107,"stem":108},"\u002Fdocs\u002Flanding\u002Femail\u002Ftechnical","0.docs\u002F1.landing\u002F08.email\u002F4.technical","i-heroicons-envelope",{"title":111,"path":112,"stem":113,"children":114,"icon":133},"Feedback Platform","\u002Fdocs\u002Flanding\u002Ffeedback","0.docs\u002F1.landing\u002F09.feedback\u002F1.index",[115,116,119,122,125,129],{"title":5,"path":112,"stem":113},{"title":20,"path":117,"stem":118},"\u002Fdocs\u002Flanding\u002Ffeedback\u002Fdetails","0.docs\u002F1.landing\u002F09.feedback\u002F2.details",{"title":87,"path":120,"stem":121},"\u002Fdocs\u002Flanding\u002Ffeedback\u002Fadmin","0.docs\u002F1.landing\u002F09.feedback\u002F3.admin",{"title":24,"path":123,"stem":124},"\u002Fdocs\u002Flanding\u002Ffeedback\u002Ftechnical","0.docs\u002F1.landing\u002F09.feedback\u002F4.technical",{"title":126,"path":127,"stem":128},"Compare vs SaaS","\u002Fdocs\u002Flanding\u002Ffeedback\u002Fcompare","0.docs\u002F1.landing\u002F09.feedback\u002F5.compare",{"title":130,"path":131,"stem":132},"FAQ","\u002Fdocs\u002Flanding\u002Ffeedback\u002Ffaq","0.docs\u002F1.landing\u002F09.feedback\u002F6.faq","i-heroicons-chat-bubble-left-right",{"title":135,"path":136,"stem":137,"children":138,"icon":149},"Storage","\u002Fdocs\u002Flanding\u002Fstorage","0.docs\u002F1.landing\u002F10.storage\u002F1.index",[139,140,143,146],{"title":5,"path":136,"stem":137},{"title":20,"path":141,"stem":142},"\u002Fdocs\u002Flanding\u002Fstorage\u002Fdetails","0.docs\u002F1.landing\u002F10.storage\u002F2.details",{"title":87,"path":144,"stem":145},"\u002Fdocs\u002Flanding\u002Fstorage\u002Fadmin","0.docs\u002F1.landing\u002F10.storage\u002F3.admin",{"title":24,"path":147,"stem":148},"\u002Fdocs\u002Flanding\u002Fstorage\u002Ftechnical","0.docs\u002F1.landing\u002F10.storage\u002F4.technical","i-heroicons-circle-stack",{"title":151,"path":152,"stem":153,"children":154,"icon":156},"Offline First","\u002Fdocs\u002Flanding\u002Foffline-first","0.docs\u002F1.landing\u002F11.offline-first\u002F1.index",[155],{"title":151,"path":152,"stem":153},"i-heroicons-users",{"title":158,"path":159,"stem":160,"children":161,"icon":156},"Yjs Sync","\u002Fdocs\u002Flanding\u002Fyjs-sync","0.docs\u002F1.landing\u002F12.yjs-sync\u002F1.index",[162,163,166,169],{"title":5,"path":159,"stem":160},{"title":20,"path":164,"stem":165},"\u002Fdocs\u002Flanding\u002Fyjs-sync\u002Fdetails","0.docs\u002F1.landing\u002F12.yjs-sync\u002F2.details",{"title":87,"path":167,"stem":168},"\u002Fdocs\u002Flanding\u002Fyjs-sync\u002Fadmin","0.docs\u002F1.landing\u002F12.yjs-sync\u002F3.admin",{"title":24,"path":170,"stem":171},"\u002Fdocs\u002Flanding\u002Fyjs-sync\u002Ftechnical","0.docs\u002F1.landing\u002F12.yjs-sync\u002F4.technical",{"title":173,"path":174,"stem":175,"children":176,"badge":178,"icon":179},"Newsletter","\u002Fdocs\u002Flanding\u002Fnewsletter","0.docs\u002F1.landing\u002F13.newsletter\u002Findex",[177],{"title":173,"path":174,"stem":175,"badge":178},"Coming Soon","i-lucide-send",[181,184,202,318,358],{"title":5,"path":182,"stem":183},"\u002Fdocs\u002Fnuxt-auto","0.docs\u002F3.nuxt-auto\u002Findex",{"title":185,"path":186,"stem":187,"children":188,"page":201},"Getting Started","\u002Fdocs\u002Fnuxt-auto\u002Fgetting-started","0.docs\u002F3.nuxt-auto\u002F1.getting-started",[189,193,197],{"title":190,"path":191,"stem":192},"Introduction","\u002Fdocs\u002Fnuxt-auto\u002Fgetting-started\u002Fintroduction","0.docs\u002F3.nuxt-auto\u002F1.getting-started\u002F1.introduction",{"title":194,"path":195,"stem":196},"Installation","\u002Fdocs\u002Fnuxt-auto\u002Fgetting-started\u002Finstallation","0.docs\u002F3.nuxt-auto\u002F1.getting-started\u002F2.installation",{"title":198,"path":199,"stem":200},"Quick Start","\u002Fdocs\u002Fnuxt-auto\u002Fgetting-started\u002Fquick-start","0.docs\u002F3.nuxt-auto\u002F1.getting-started\u002F3.quick-start",false,{"title":203,"path":204,"stem":205,"children":206,"page":201},"Auto API","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api","0.docs\u002F3.nuxt-auto\u002F2.auto-api",[207,210,214,218,222,226,230,234,238,242,246,250,254,258,262,266,270,274,278,282,286,290,294,298,302,306,310,314],{"title":185,"path":208,"stem":209},"\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fgetting-started","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F1.getting-started",{"title":211,"path":212,"stem":213},"Aggregations","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Faggregations","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F10.aggregations",{"title":215,"path":216,"stem":217},"Lifecycle Hooks","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Flifecycle-hooks","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F11.lifecycle-hooks",{"title":219,"path":220,"stem":221},"Many-to-Many (M2M) Relationships","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fm2m-relationships","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F12.m2m-relationships",{"title":223,"path":224,"stem":225},"Plugin System","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fplugin-system","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F13.plugin-system",{"title":227,"path":228,"stem":229},"Database Adapters","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fdatabase-adapters","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F14.database-adapters",{"title":231,"path":232,"stem":233},"Custom Endpoints","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fcustom-endpoints","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F15.custom-endpoints",{"title":235,"path":236,"stem":237},"Multi-Tenancy","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fmulti-tenancy","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F16.multi-tenancy",{"title":239,"path":240,"stem":241},"Schema Presets (Cross-engine)","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fschema-presets","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F17.schema-presets",{"title":243,"path":244,"stem":245},"Permissions Cookbook","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fpermissions-cookbook","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F18.permissions-cookbook",{"title":247,"path":248,"stem":249},"Billing & Plan Gating","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fbilling","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F19.billing",{"title":251,"path":252,"stem":253},"Validation","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fvalidation","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F2.validation",{"title":255,"path":256,"stem":257},"Rate Limiting","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Frate-limiting","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F20.rate-limiting",{"title":259,"path":260,"stem":261},"Request Metadata Plugin","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Frequest-metadata","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F21.request-metadata",{"title":263,"path":264,"stem":265},"Plugin Catalog","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fplugin-catalog","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F22.plugin-catalog",{"title":267,"path":268,"stem":269},"Configuration Reference","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fconfiguration","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F23.configuration",{"title":271,"path":272,"stem":273},"Handler Overrides","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fhandler-overrides","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F3.handler-overrides",{"title":275,"path":276,"stem":277},"Cloudflare D1","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fcloudflare-d1","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F30.cloudflare-d1",{"title":279,"path":280,"stem":281},"SQLite to D1 Migration","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fmigration-sqlite-d1","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F31.migration-sqlite-d1",{"title":283,"path":284,"stem":285},"Frontend Composables","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Ffrontend-composables","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F32.frontend-composables",{"title":287,"path":288,"stem":289},"Testing","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Ftesting","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F33.testing",{"title":291,"path":292,"stem":293},"Pagination","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fpagination","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F4.pagination",{"title":295,"path":296,"stem":297},"Upgrading","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fupgrading","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F40.upgrading",{"title":299,"path":300,"stem":301},"Soft Deletes","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fsoft-deletes","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F5.soft-deletes",{"title":303,"path":304,"stem":305},"Authentication & Authorization","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fauthentication-authorization","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F6.authentication-authorization",{"title":307,"path":308,"stem":309},"Better-Auth Integration","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fbetter-auth","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F7.better-auth",{"title":311,"path":312,"stem":313},"Nested Relations","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fnested-relationships","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F8.nested-relationships",{"title":315,"path":316,"stem":317},"Bulk Operations","\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fbulk-operations","0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F9.bulk-operations",{"title":319,"path":320,"stem":321,"children":322,"page":201},"Auto Admin","\u002Fdocs\u002Fnuxt-auto\u002Fauto-admin","0.docs\u002F3.nuxt-auto\u002F3.auto-admin",[323,326,330,334,338,342,346,350,354],{"title":185,"path":324,"stem":325},"\u002Fdocs\u002Fnuxt-auto\u002Fauto-admin\u002Fgetting-started","0.docs\u002F3.nuxt-auto\u002F3.auto-admin\u002F1.getting-started",{"title":327,"path":328,"stem":329},"Configuration & Theming","\u002Fdocs\u002Fnuxt-auto\u002Fauto-admin\u002Fconfiguration-theming","0.docs\u002F3.nuxt-auto\u002F3.auto-admin\u002F2.configuration-theming",{"title":331,"path":332,"stem":333},"Resource Configuration","\u002Fdocs\u002Fnuxt-auto\u002Fauto-admin\u002Fresource-configuration","0.docs\u002F3.nuxt-auto\u002F3.auto-admin\u002F3.resource-configuration",{"title":335,"path":336,"stem":337},"Form Fields & Widgets","\u002Fdocs\u002Fnuxt-auto\u002Fauto-admin\u002Fform-fields-widgets","0.docs\u002F3.nuxt-auto\u002F3.auto-admin\u002F4.form-fields-widgets",{"title":339,"path":340,"stem":341},"Permissions","\u002Fdocs\u002Fnuxt-auto\u002Fauto-admin\u002Fpermissions","0.docs\u002F3.nuxt-auto\u002F3.auto-admin\u002F5.permissions",{"title":343,"path":344,"stem":345},"Custom Pages","\u002Fdocs\u002Fnuxt-auto\u002Fauto-admin\u002Fcustom-pages","0.docs\u002F3.nuxt-auto\u002F3.auto-admin\u002F6.custom-pages",{"title":347,"path":348,"stem":349},"M2M Relationships","\u002Fdocs\u002Fnuxt-auto\u002Fauto-admin\u002Fm2m-relationships","0.docs\u002F3.nuxt-auto\u002F3.auto-admin\u002F7.m2m-relationships",{"title":351,"path":352,"stem":353},"Custom Actions","\u002Fdocs\u002Fnuxt-auto\u002Fauto-admin\u002Fcustom-actions","0.docs\u002F3.nuxt-auto\u002F3.auto-admin\u002F8.custom-actions",{"title":355,"path":356,"stem":357},"Composables","\u002Fdocs\u002Fnuxt-auto\u002Fauto-admin\u002Fcomposables","0.docs\u002F3.nuxt-auto\u002F3.auto-admin\u002F9.composables",{"title":359,"path":360,"stem":361,"children":362,"icon":364},"Claude Code Skills","\u002Fdocs\u002Fnuxt-auto\u002Fclaude-code-skills","0.docs\u002F3.nuxt-auto\u002F4.claude-code-skills\u002F1.index",[363],{"title":5,"path":360,"stem":361},"i-lucide-bot",[366,369,382,409,427,450,472,502],{"title":5,"path":367,"stem":368},"\u002Fdocs\u002Fnuxt-protokit","0.docs\u002F4.nuxt-protokit\u002Findex",{"title":185,"path":370,"stem":371,"children":372,"icon":381},"\u002Fdocs\u002Fnuxt-protokit\u002Fgetting-started","0.docs\u002F4.nuxt-protokit\u002F1.getting-started\u002F1.index",[373,374,378],{"title":190,"path":370,"stem":371},{"title":375,"path":376,"stem":377},"Core Concepts","\u002Fdocs\u002Fnuxt-protokit\u002Fgetting-started\u002Fconcepts","0.docs\u002F4.nuxt-protokit\u002F1.getting-started\u002F2.concepts",{"title":198,"path":379,"stem":380},"\u002Fdocs\u002Fnuxt-protokit\u002Fgetting-started\u002Fquick-start","0.docs\u002F4.nuxt-protokit\u002F1.getting-started\u002F3.quick-start","i-lucide-rocket",{"title":383,"path":384,"stem":385,"children":386,"icon":408},"Schemas","\u002Fdocs\u002Fnuxt-protokit\u002Fschemas","0.docs\u002F4.nuxt-protokit\u002F2.schemas\u002F1.index",[387,388,392,396,400,404],{"title":5,"path":384,"stem":385},{"title":389,"path":390,"stem":391},"Field Types","\u002Fdocs\u002Fnuxt-protokit\u002Fschemas\u002Ffields","0.docs\u002F4.nuxt-protokit\u002F2.schemas\u002F2.fields",{"title":393,"path":394,"stem":395},"Collections","\u002Fdocs\u002Fnuxt-protokit\u002Fschemas\u002Fcollections","0.docs\u002F4.nuxt-protokit\u002F2.schemas\u002F3.collections",{"title":397,"path":398,"stem":399},"Derived & Computed","\u002Fdocs\u002Fnuxt-protokit\u002Fschemas\u002Fderived-computed","0.docs\u002F4.nuxt-protokit\u002F2.schemas\u002F4.derived-computed",{"title":401,"path":402,"stem":403},"Connections","\u002Fdocs\u002Fnuxt-protokit\u002Fschemas\u002Fconnections","0.docs\u002F4.nuxt-protokit\u002F2.schemas\u002F5.connections",{"title":405,"path":406,"stem":407},"Visualizations & Layouts","\u002Fdocs\u002Fnuxt-protokit\u002Fschemas\u002Fvisualizations","0.docs\u002F4.nuxt-protokit\u002F2.schemas\u002F6.visualizations","i-lucide-file-code",{"title":355,"path":410,"stem":411,"children":412,"icon":426},"\u002Fdocs\u002Fnuxt-protokit\u002Fcomposables","0.docs\u002F4.nuxt-protokit\u002F3.composables\u002F1.index",[413,414,418,422],{"title":5,"path":410,"stem":411},{"title":415,"path":416,"stem":417},"usePrototype","\u002Fdocs\u002Fnuxt-protokit\u002Fcomposables\u002Fuse-prototype","0.docs\u002F4.nuxt-protokit\u002F3.composables\u002F2.use-prototype",{"title":419,"path":420,"stem":421},"useProtoDoc","\u002Fdocs\u002Fnuxt-protokit\u002Fcomposables\u002Fuse-proto-doc","0.docs\u002F4.nuxt-protokit\u002F3.composables\u002F3.use-proto-doc",{"title":423,"path":424,"stem":425},"useProtoCollection","\u002Fdocs\u002Fnuxt-protokit\u002Fcomposables\u002Fuse-proto-collection","0.docs\u002F4.nuxt-protokit\u002F3.composables\u002F4.use-proto-collection","i-lucide-layers",{"title":428,"path":429,"stem":430,"children":431,"icon":449},"Components","\u002Fdocs\u002Fnuxt-protokit\u002Fcomponents","0.docs\u002F4.nuxt-protokit\u002F4.components\u002F1.index",[432,433,437,441,445],{"title":5,"path":429,"stem":430},{"title":434,"path":435,"stem":436},"ProtoTool","\u002Fdocs\u002Fnuxt-protokit\u002Fcomponents\u002Fproto-tool","0.docs\u002F4.nuxt-protokit\u002F4.components\u002F2.proto-tool",{"title":438,"path":439,"stem":440},"ProtoCrudModal","\u002Fdocs\u002Fnuxt-protokit\u002Fcomponents\u002Fproto-crud-modal","0.docs\u002F4.nuxt-protokit\u002F4.components\u002F3.proto-crud-modal",{"title":442,"path":443,"stem":444},"ProtoCalendar","\u002Fdocs\u002Fnuxt-protokit\u002Fcomponents\u002Fproto-calendar","0.docs\u002F4.nuxt-protokit\u002F4.components\u002F4.proto-calendar",{"title":446,"path":447,"stem":448},"ProtoItemPanel variants","\u002Fdocs\u002Fnuxt-protokit\u002Fcomponents\u002Fproto-item-panels","0.docs\u002F4.nuxt-protokit\u002F4.components\u002F5.proto-item-panels","i-lucide-puzzle",{"title":151,"path":451,"stem":452,"children":453,"icon":471},"\u002Fdocs\u002Fnuxt-protokit\u002Foffline-first","0.docs\u002F4.nuxt-protokit\u002F5.offline-first\u002F1.index",[454,455,459,463,467],{"title":151,"path":451,"stem":452},{"title":456,"path":457,"stem":458},"Corruption Recovery","\u002Fdocs\u002Fnuxt-protokit\u002Foffline-first\u002Fcorruption-recovery","0.docs\u002F4.nuxt-protokit\u002F5.offline-first\u002F2.corruption-recovery",{"title":460,"path":461,"stem":462},"Size & GC","\u002Fdocs\u002Fnuxt-protokit\u002Foffline-first\u002Fdocument-size-and-gc","0.docs\u002F4.nuxt-protokit\u002F5.offline-first\u002F3.document-size-and-gc",{"title":464,"path":465,"stem":466},"Multi-tenant Isolation","\u002Fdocs\u002Fnuxt-protokit\u002Foffline-first\u002Fmulti-tenant-isolation","0.docs\u002F4.nuxt-protokit\u002F5.offline-first\u002F4.multi-tenant-isolation",{"title":468,"path":469,"stem":470},"Encryption at Rest","\u002Fdocs\u002Fnuxt-protokit\u002Foffline-first\u002Fencryption","0.docs\u002F4.nuxt-protokit\u002F5.offline-first\u002F5.encryption","i-lucide-wifi-off",{"title":473,"icon":474,"path":475,"stem":476,"children":477},"Advanced","i-lucide-graduation-cap","\u002Fdocs\u002Fnuxt-protokit\u002Fadvanced","0.docs\u002F4.nuxt-protokit\u002F6.advanced\u002F1.index",[478,479,483,487,491,494,498],{"title":5,"path":475,"stem":476},{"title":480,"path":481,"stem":482},"Multi-Tool Apps","\u002Fdocs\u002Fnuxt-protokit\u002Fadvanced\u002Fbuilding-a-toolkit","0.docs\u002F4.nuxt-protokit\u002F6.advanced\u002F1.building-a-toolkit",{"title":484,"path":485,"stem":486},"Schema Patterns","\u002Fdocs\u002Fnuxt-protokit\u002Fadvanced\u002Fcustom-schema-patterns","0.docs\u002F4.nuxt-protokit\u002F6.advanced\u002F2.custom-schema-patterns",{"title":488,"path":489,"stem":490},"Custom Fields & Viz","\u002Fdocs\u002Fnuxt-protokit\u002Fadvanced\u002Fextensibility","0.docs\u002F4.nuxt-protokit\u002F6.advanced\u002F3.extensibility",{"title":339,"path":492,"stem":493},"\u002Fdocs\u002Fnuxt-protokit\u002Fadvanced\u002Fpermissions","0.docs\u002F4.nuxt-protokit\u002F6.advanced\u002F4.permissions",{"title":495,"path":496,"stem":497},"Business Logic Guards","\u002Fdocs\u002Fnuxt-protokit\u002Fadvanced\u002Fpermissions-business-logic","0.docs\u002F4.nuxt-protokit\u002F6.advanced\u002F5.permissions-business-logic",{"title":499,"path":500,"stem":501},"Headless Mode","\u002Fdocs\u002Fnuxt-protokit\u002Fadvanced\u002Fheadless-mode","0.docs\u002F4.nuxt-protokit\u002F6.advanced\u002F6.headless-mode",{"title":359,"path":503,"stem":504,"children":505,"icon":364},"\u002Fdocs\u002Fnuxt-protokit\u002Fclaude-code-skills","0.docs\u002F4.nuxt-protokit\u002F7.claude-code-skills\u002F1.index",[506],{"title":5,"path":503,"stem":504},{"page":508,"fallbackPage":4878},{"id":509,"title":243,"body":510,"description":4876,"extension":4877,"links":4878,"meta":4879,"navigation":4878,"ogImage":4878,"path":244,"seo":4880,"stem":245,"__hash__":4881},"nuxt_auto\u002F0.docs\u002F3.nuxt-auto\u002F2.auto-api\u002F18.permissions-cookbook.md",{"type":511,"value":512,"toc":4854},"minimark",[513,517,525,530,533,700,711,715,872,885,888,892,897,1096,1106,1193,1207,1211,1220,1373,1377,1455,1461,1465,1468,1769,1832,1836,1843,2108,2118,2122,2347,2411,2427,2431,2442,2598,2695,2698,2702,2708,2793,2797,2812,3215,3446,3575,3580,3584,3593,3638,3642,3738,3751,3755,3772,3934,3938,3949,4057,4061,4064,4275,4282,4284,4288,4294,4607,4610,4614,4834,4850],[514,515,243],"h1",{"id":516},"permissions-cookbook",[518,519,520,521,524],"p",{},"Recipes for fine-grained access control, from \"public blog\" to \"plan-gated, per-field, per-organization\". The\nconcepts behind them are in ",[522,523,303],"a",{"href":304},".",[526,527,529],"h2",{"id":528},"how-a-request-is-decided","How a request is decided",[518,531,532],{},"Every request passes these layers in order; each one can only narrow what the previous allowed:",[534,535,536,555],"table",{},[537,538,539],"thead",{},[540,541,542,546,549,552],"tr",{},[543,544,545],"th",{},"#",[543,547,548],{},"Layer",[543,550,551],{},"Declared with",[543,553,554],{},"Denied as",[556,557,558,594,613,632,657,680],"tbody",{},[540,559,560,564,586,591],{},[561,562,563],"td",{},"1",[561,565,566,570,571,575,576,575,579,575,582,585],{},[567,568,569],"strong",{},"Operation"," — may this caller ",[572,573,574],"code",{},"read"," \u002F ",[572,577,578],{},"create",[572,580,581],{},"update",[572,583,584],{},"delete"," this resource at all?",[561,587,588],{},[572,589,590],{},"permissions",[561,592,593],{},"401 \u002F 403",[540,595,596,599,605,610],{},[561,597,598],{},"2",[561,600,601,604],{},[567,602,603],{},"Tenant"," — only the caller's organization",[561,606,607],{},[572,608,609],{},"multiTenancy",[561,611,612],{},"404",[540,614,615,618,624,630],{},[561,616,617],{},"3",[561,619,620,623],{},[567,621,622],{},"Row visibility"," — which rows exist for this caller",[561,625,626,629],{},[572,627,628],{},"listFilter"," (SQL)",[561,631,612],{},[540,633,634,637,648,654],{},[561,635,636],{},"4",[561,638,639,642,643,647],{},[567,640,641],{},"Object"," — may they act on ",[644,645,646],"em",{},"this"," row?",[561,649,650,653],{},[572,651,652],{},"objectLevel"," (function)",[561,655,656],{},"403 (dropped from lists)",[540,658,659,662,668,677],{},[561,660,661],{},"5",[561,663,664,667],{},[567,665,666],{},"Fields"," — which columns they see \u002F may write",[561,669,670,673,674],{},[572,671,672],{},"fields",", ",[572,675,676],{},"hiddenFields",[561,678,679],{},"stripped \u002F 403",[540,681,682,685,691,697],{},[561,683,684],{},"6",[561,686,687,690],{},[567,688,689],{},"Server-owned columns"," — ids, tenant, audit, soft-delete",[561,692,693,694],{},"automatic + ",[572,695,696],{},"protectedFields",[561,698,699],{},"silently dropped",[518,701,702,703,706,707,710],{},"Anything not declared at layer 1 is ",[567,704,705],{},"denied",". Layers 3–4 apply to every route that touches the row — get,\nupdate, delete, restore, bulk, aggregate, ",[572,708,709],{},"?include=",", M2M — not only lists.",[526,712,714],{"id":713},"permission-values","Permission values",[716,717,722],"pre",{"className":718,"code":719,"language":720,"meta":721,"style":721},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","permissions: {\n  read: true, \u002F\u002F everyone, signed in or not\n  create: ctx => !!ctx.user, \u002F\u002F a function: sync or async\n  update: 'posts:write', \u002F\u002F callers whose ctx.permissions holds this string\n  delete: ['posts:delete', 'admin'], \u002F\u002F …any of these\n  aggregate: false, \u002F\u002F no one — not even '*'\n}\n","ts","",[572,723,724,739,758,791,814,850,866],{"__ignoreMap":721},[725,726,729,732,736],"span",{"class":727,"line":728},"line",1,[725,730,590],{"class":731},"sBMFI",[725,733,735],{"class":734},"sMK4o",":",[725,737,738],{"class":734}," {\n",[725,740,742,745,747,751,754],{"class":727,"line":741},2,[725,743,744],{"class":731},"  read",[725,746,735],{"class":734},[725,748,750],{"class":749},"sfNiH"," true",[725,752,753],{"class":734},",",[725,755,757],{"class":756},"sHwdD"," \u002F\u002F everyone, signed in or not\n",[725,759,761,764,766,770,774,777,781,783,786,788],{"class":727,"line":760},3,[725,762,763],{"class":731},"  create",[725,765,735],{"class":734},[725,767,769],{"class":768},"sHdIc"," ctx",[725,771,773],{"class":772},"spNyl"," =>",[725,775,776],{"class":734}," !!",[725,778,780],{"class":779},"sTEyZ","ctx",[725,782,524],{"class":734},[725,784,785],{"class":779},"user",[725,787,753],{"class":734},[725,789,790],{"class":756}," \u002F\u002F a function: sync or async\n",[725,792,794,797,799,802,806,809,811],{"class":727,"line":793},4,[725,795,796],{"class":731},"  update",[725,798,735],{"class":734},[725,800,801],{"class":734}," '",[725,803,805],{"class":804},"sfazB","posts:write",[725,807,808],{"class":734},"'",[725,810,753],{"class":734},[725,812,813],{"class":756}," \u002F\u002F callers whose ctx.permissions holds this string\n",[725,815,817,820,822,826,828,831,833,835,837,840,842,845,847],{"class":727,"line":816},5,[725,818,819],{"class":731},"  delete",[725,821,735],{"class":734},[725,823,825],{"class":824},"swJcz"," [",[725,827,808],{"class":734},[725,829,830],{"class":804},"posts:delete",[725,832,808],{"class":734},[725,834,753],{"class":734},[725,836,801],{"class":734},[725,838,839],{"class":804},"admin",[725,841,808],{"class":734},[725,843,844],{"class":824},"]",[725,846,753],{"class":734},[725,848,849],{"class":756}," \u002F\u002F …any of these\n",[725,851,853,856,858,861,863],{"class":727,"line":852},6,[725,854,855],{"class":731},"  aggregate",[725,857,735],{"class":734},[725,859,860],{"class":749}," false",[725,862,753],{"class":734},[725,864,865],{"class":756}," \u002F\u002F no one — not even '*'\n",[725,867,869],{"class":727,"line":868},7,[725,870,871],{"class":734},"}\n",[518,873,874,877,878,881,882,524],{},[572,875,876],{},"'*'"," in ",[572,879,880],{},"ctx.permissions"," is a super-admin: it passes everything except an explicit ",[572,883,884],{},"false",[886,887],"hr",{},[526,889,891],{"id":890},"recipes","Recipes",[893,894,896],"h3",{"id":895},"public-read-signed-in-write","Public read, signed-in write",[716,898,900],{"className":718,"code":899,"language":720,"meta":721,"style":721},"export const commentsAuth: ResourceAuthConfig = {\n  permissions: { read: true, create: ctx => !!ctx.user, update: ctx => !!ctx.user, delete: ctx => !!ctx.user },\n  \u002F\u002F …but only your own comment can be changed or removed\n  objectLevel: (row, ctx) => ctx.operation === 'list' || ctx.operation === 'get' || row.authorId === ctx.user?.id,\n}\n",[572,901,902,924,1003,1008,1092],{"__ignoreMap":721},[725,903,904,908,911,914,916,919,922],{"class":727,"line":728},[725,905,907],{"class":906},"s7zQu","export",[725,909,910],{"class":772}," const",[725,912,913],{"class":779}," commentsAuth",[725,915,735],{"class":734},[725,917,918],{"class":731}," ResourceAuthConfig",[725,920,921],{"class":734}," =",[725,923,738],{"class":734},[725,925,926,929,931,934,937,939,941,943,947,949,951,953,955,957,959,961,963,966,968,970,972,974,976,978,980,982,985,987,989,991,993,995,997,1000],{"class":727,"line":741},[725,927,928],{"class":824},"  permissions",[725,930,735],{"class":734},[725,932,933],{"class":734}," {",[725,935,936],{"class":824}," read",[725,938,735],{"class":734},[725,940,750],{"class":749},[725,942,753],{"class":734},[725,944,946],{"class":945},"s2Zo4"," create",[725,948,735],{"class":734},[725,950,769],{"class":768},[725,952,773],{"class":772},[725,954,776],{"class":734},[725,956,780],{"class":779},[725,958,524],{"class":734},[725,960,785],{"class":779},[725,962,753],{"class":734},[725,964,965],{"class":945}," update",[725,967,735],{"class":734},[725,969,769],{"class":768},[725,971,773],{"class":772},[725,973,776],{"class":734},[725,975,780],{"class":779},[725,977,524],{"class":734},[725,979,785],{"class":779},[725,981,753],{"class":734},[725,983,984],{"class":945}," delete",[725,986,735],{"class":734},[725,988,769],{"class":768},[725,990,773],{"class":772},[725,992,776],{"class":734},[725,994,780],{"class":779},[725,996,524],{"class":734},[725,998,999],{"class":779},"user ",[725,1001,1002],{"class":734},"},\n",[725,1004,1005],{"class":727,"line":760},[725,1006,1007],{"class":756},"  \u002F\u002F …but only your own comment can be changed or removed\n",[725,1009,1010,1013,1015,1018,1021,1023,1025,1028,1030,1032,1034,1037,1040,1042,1045,1047,1050,1052,1054,1056,1058,1060,1063,1065,1067,1070,1072,1075,1077,1079,1081,1083,1086,1089],{"class":727,"line":793},[725,1011,1012],{"class":945},"  objectLevel",[725,1014,735],{"class":734},[725,1016,1017],{"class":734}," (",[725,1019,1020],{"class":768},"row",[725,1022,753],{"class":734},[725,1024,769],{"class":768},[725,1026,1027],{"class":734},")",[725,1029,773],{"class":772},[725,1031,769],{"class":779},[725,1033,524],{"class":734},[725,1035,1036],{"class":779},"operation ",[725,1038,1039],{"class":734},"===",[725,1041,801],{"class":734},[725,1043,1044],{"class":804},"list",[725,1046,808],{"class":734},[725,1048,1049],{"class":734}," ||",[725,1051,769],{"class":779},[725,1053,524],{"class":734},[725,1055,1036],{"class":779},[725,1057,1039],{"class":734},[725,1059,801],{"class":734},[725,1061,1062],{"class":804},"get",[725,1064,808],{"class":734},[725,1066,1049],{"class":734},[725,1068,1069],{"class":779}," row",[725,1071,524],{"class":734},[725,1073,1074],{"class":779},"authorId ",[725,1076,1039],{"class":734},[725,1078,769],{"class":779},[725,1080,524],{"class":734},[725,1082,785],{"class":779},[725,1084,1085],{"class":734},"?.",[725,1087,1088],{"class":779},"id",[725,1090,1091],{"class":734},",\n",[725,1093,1094],{"class":727,"line":816},[725,1095,871],{"class":734},[518,1097,1098,1099,1102,1103,1105],{},"Stamp ",[572,1100,1101],{},"authorId"," on create from the server, never from the body — list it in the registration's\n",[572,1104,696],{}," so a client cannot forge it, and set it in a hook:",[716,1107,1109],{"className":718,"code":1108,"language":720,"meta":721,"style":721},"export const commentsHooks = {\n  beforeCreate: (data: any, ctx: any) => ({ ...data, authorId: ctx.user.id }),\n}\n",[572,1110,1111,1125,1189],{"__ignoreMap":721},[725,1112,1113,1115,1117,1120,1123],{"class":727,"line":728},[725,1114,907],{"class":906},[725,1116,910],{"class":772},[725,1118,1119],{"class":779}," commentsHooks ",[725,1121,1122],{"class":734},"=",[725,1124,738],{"class":734},[725,1126,1127,1130,1132,1134,1137,1139,1142,1144,1146,1148,1150,1152,1154,1156,1159,1162,1164,1166,1169,1171,1173,1175,1177,1179,1182,1185,1187],{"class":727,"line":741},[725,1128,1129],{"class":945},"  beforeCreate",[725,1131,735],{"class":734},[725,1133,1017],{"class":734},[725,1135,1136],{"class":768},"data",[725,1138,735],{"class":734},[725,1140,1141],{"class":731}," any",[725,1143,753],{"class":734},[725,1145,769],{"class":768},[725,1147,735],{"class":734},[725,1149,1141],{"class":731},[725,1151,1027],{"class":734},[725,1153,773],{"class":772},[725,1155,1017],{"class":779},[725,1157,1158],{"class":734},"{",[725,1160,1161],{"class":734}," ...",[725,1163,1136],{"class":779},[725,1165,753],{"class":734},[725,1167,1168],{"class":824}," authorId",[725,1170,735],{"class":734},[725,1172,769],{"class":779},[725,1174,524],{"class":734},[725,1176,785],{"class":779},[725,1178,524],{"class":734},[725,1180,1181],{"class":779},"id ",[725,1183,1184],{"class":734},"}",[725,1186,1027],{"class":779},[725,1188,1091],{"class":734},[725,1190,1191],{"class":727,"line":760},[725,1192,871],{"class":734},[518,1194,1195,1196,1202,1203,1206],{},"(or add the ",[522,1197,1198,1201],{"href":240},[572,1199,1200],{},"audit()"," schema preset",": ",[572,1204,1205],{},"createdBy"," is stamped for you.)",[893,1208,1210],{"id":1209},"private-rows-everyone-sees-only-their-own","Private rows: everyone sees only their own",[518,1212,1213,1215,1216,1219],{},[572,1214,628],{}," is SQL, so pagination and ",[572,1217,1218],{},"total"," stay correct, and it applies to get\u002Fupdate\u002Fdelete too — another\nuser's note is a 404, not a 403:",[716,1221,1223],{"className":718,"code":1222,"language":720,"meta":721,"style":721},"export const notesAuth: ResourceAuthConfig = {\n  permissions: { read: ctx => !!ctx.user, create: ctx => !!ctx.user, update: ctx => !!ctx.user, delete: ctx => !!ctx.user },\n  listFilter: (notes, ctx) => eq(notes.ownerId, ctx.user!.id),\n}\n",[572,1224,1225,1242,1322,1369],{"__ignoreMap":721},[725,1226,1227,1229,1231,1234,1236,1238,1240],{"class":727,"line":728},[725,1228,907],{"class":906},[725,1230,910],{"class":772},[725,1232,1233],{"class":779}," notesAuth",[725,1235,735],{"class":734},[725,1237,918],{"class":731},[725,1239,921],{"class":734},[725,1241,738],{"class":734},[725,1243,1244,1246,1248,1250,1252,1254,1256,1258,1260,1262,1264,1266,1268,1270,1272,1274,1276,1278,1280,1282,1284,1286,1288,1290,1292,1294,1296,1298,1300,1302,1304,1306,1308,1310,1312,1314,1316,1318,1320],{"class":727,"line":741},[725,1245,928],{"class":824},[725,1247,735],{"class":734},[725,1249,933],{"class":734},[725,1251,936],{"class":945},[725,1253,735],{"class":734},[725,1255,769],{"class":768},[725,1257,773],{"class":772},[725,1259,776],{"class":734},[725,1261,780],{"class":779},[725,1263,524],{"class":734},[725,1265,785],{"class":779},[725,1267,753],{"class":734},[725,1269,946],{"class":945},[725,1271,735],{"class":734},[725,1273,769],{"class":768},[725,1275,773],{"class":772},[725,1277,776],{"class":734},[725,1279,780],{"class":779},[725,1281,524],{"class":734},[725,1283,785],{"class":779},[725,1285,753],{"class":734},[725,1287,965],{"class":945},[725,1289,735],{"class":734},[725,1291,769],{"class":768},[725,1293,773],{"class":772},[725,1295,776],{"class":734},[725,1297,780],{"class":779},[725,1299,524],{"class":734},[725,1301,785],{"class":779},[725,1303,753],{"class":734},[725,1305,984],{"class":945},[725,1307,735],{"class":734},[725,1309,769],{"class":768},[725,1311,773],{"class":772},[725,1313,776],{"class":734},[725,1315,780],{"class":779},[725,1317,524],{"class":734},[725,1319,999],{"class":779},[725,1321,1002],{"class":734},[725,1323,1324,1327,1329,1331,1334,1336,1338,1340,1342,1345,1348,1350,1353,1355,1357,1359,1361,1364,1367],{"class":727,"line":760},[725,1325,1326],{"class":945},"  listFilter",[725,1328,735],{"class":734},[725,1330,1017],{"class":734},[725,1332,1333],{"class":768},"notes",[725,1335,753],{"class":734},[725,1337,769],{"class":768},[725,1339,1027],{"class":734},[725,1341,773],{"class":772},[725,1343,1344],{"class":945}," eq",[725,1346,1347],{"class":779},"(notes",[725,1349,524],{"class":734},[725,1351,1352],{"class":779},"ownerId",[725,1354,753],{"class":734},[725,1356,769],{"class":779},[725,1358,524],{"class":734},[725,1360,785],{"class":779},[725,1362,1363],{"class":734},"!.",[725,1365,1366],{"class":779},"id)",[725,1368,1091],{"class":734},[725,1370,1371],{"class":727,"line":793},[725,1372,871],{"class":734},[893,1374,1376],{"id":1375},"drafts-vs-published","Drafts vs published",[716,1378,1380],{"className":718,"code":1379,"language":720,"meta":721,"style":721},"listFilter: (posts, ctx) =>\n  ctx.permissions.includes('posts:write') ? undefined : eq(posts.published, true),\n",[572,1381,1382,1402],{"__ignoreMap":721},[725,1383,1384,1386,1388,1390,1393,1395,1397,1399],{"class":727,"line":728},[725,1385,628],{"class":731},[725,1387,735],{"class":734},[725,1389,1017],{"class":734},[725,1391,1392],{"class":768},"posts",[725,1394,753],{"class":734},[725,1396,769],{"class":768},[725,1398,1027],{"class":734},[725,1400,1401],{"class":772}," =>\n",[725,1403,1404,1407,1409,1411,1413,1416,1419,1421,1423,1425,1428,1431,1434,1437,1439,1442,1444,1447,1449,1451,1453],{"class":727,"line":741},[725,1405,1406],{"class":779},"  ctx",[725,1408,524],{"class":734},[725,1410,590],{"class":779},[725,1412,524],{"class":734},[725,1414,1415],{"class":945},"includes",[725,1417,1418],{"class":779},"(",[725,1420,808],{"class":734},[725,1422,805],{"class":804},[725,1424,808],{"class":734},[725,1426,1427],{"class":779},") ",[725,1429,1430],{"class":734},"?",[725,1432,1433],{"class":734}," undefined",[725,1435,1436],{"class":734}," :",[725,1438,1344],{"class":945},[725,1440,1441],{"class":779},"(posts",[725,1443,524],{"class":734},[725,1445,1446],{"class":779},"published",[725,1448,753],{"class":734},[725,1450,750],{"class":749},[725,1452,1027],{"class":779},[725,1454,1091],{"class":734},[518,1456,1457,1460],{},[572,1458,1459],{},"undefined"," means \"no restriction\".",[893,1462,1464],{"id":1463},"roles-permission-strings-rbac","Roles → permission strings (RBAC)",[518,1466,1467],{},"Keep roles out of resource files: map them to permission strings once, where the caller is resolved, and let\nresources name capabilities.",[716,1469,1471],{"className":718,"code":1470,"language":720,"meta":721,"style":721},"\u002F\u002F server\u002Fautoapi-plugins.ts\nconst ROLE_PERMISSIONS: Record\u003Cstring, string[]> = {\n  admin: ['*'],\n  editor: ['posts:write', 'posts:publish', 'media:write'],\n  author: ['posts:write'],\n}\n\nexport default [\n  createBetterAuthPlugin({\n    getSession: event => serverAuth().api.getSession({ headers: event.headers }),\n    getPermissions: user => (user.role ?? '').split(',').flatMap((r: string) => ROLE_PERMISSIONS[r.trim()] ?? []),\n  }),\n]\n",[572,1472,1473,1478,1512,1532,1569,1588,1592,1598,1609,1620,1671,1753,1763],{"__ignoreMap":721},[725,1474,1475],{"class":727,"line":728},[725,1476,1477],{"class":756},"\u002F\u002F server\u002Fautoapi-plugins.ts\n",[725,1479,1480,1483,1486,1488,1491,1494,1497,1499,1502,1505,1508,1510],{"class":727,"line":741},[725,1481,1482],{"class":772},"const",[725,1484,1485],{"class":779}," ROLE_PERMISSIONS",[725,1487,735],{"class":734},[725,1489,1490],{"class":731}," Record",[725,1492,1493],{"class":734},"\u003C",[725,1495,1496],{"class":731},"string",[725,1498,753],{"class":734},[725,1500,1501],{"class":731}," string",[725,1503,1504],{"class":779},"[]",[725,1506,1507],{"class":734},">",[725,1509,921],{"class":734},[725,1511,738],{"class":734},[725,1513,1514,1517,1519,1521,1523,1526,1528,1530],{"class":727,"line":760},[725,1515,1516],{"class":824},"  admin",[725,1518,735],{"class":734},[725,1520,825],{"class":779},[725,1522,808],{"class":734},[725,1524,1525],{"class":804},"*",[725,1527,808],{"class":734},[725,1529,844],{"class":779},[725,1531,1091],{"class":734},[725,1533,1534,1537,1539,1541,1543,1545,1547,1549,1551,1554,1556,1558,1560,1563,1565,1567],{"class":727,"line":793},[725,1535,1536],{"class":824},"  editor",[725,1538,735],{"class":734},[725,1540,825],{"class":779},[725,1542,808],{"class":734},[725,1544,805],{"class":804},[725,1546,808],{"class":734},[725,1548,753],{"class":734},[725,1550,801],{"class":734},[725,1552,1553],{"class":804},"posts:publish",[725,1555,808],{"class":734},[725,1557,753],{"class":734},[725,1559,801],{"class":734},[725,1561,1562],{"class":804},"media:write",[725,1564,808],{"class":734},[725,1566,844],{"class":779},[725,1568,1091],{"class":734},[725,1570,1571,1574,1576,1578,1580,1582,1584,1586],{"class":727,"line":816},[725,1572,1573],{"class":824},"  author",[725,1575,735],{"class":734},[725,1577,825],{"class":779},[725,1579,808],{"class":734},[725,1581,805],{"class":804},[725,1583,808],{"class":734},[725,1585,844],{"class":779},[725,1587,1091],{"class":734},[725,1589,1590],{"class":727,"line":852},[725,1591,871],{"class":734},[725,1593,1594],{"class":727,"line":868},[725,1595,1597],{"emptyLinePlaceholder":1596},true,"\n",[725,1599,1601,1603,1606],{"class":727,"line":1600},8,[725,1602,907],{"class":906},[725,1604,1605],{"class":906}," default",[725,1607,1608],{"class":779}," [\n",[725,1610,1612,1615,1617],{"class":727,"line":1611},9,[725,1613,1614],{"class":945},"  createBetterAuthPlugin",[725,1616,1418],{"class":779},[725,1618,1619],{"class":734},"{\n",[725,1621,1623,1626,1628,1631,1633,1636,1639,1641,1644,1646,1649,1651,1653,1656,1658,1660,1662,1665,1667,1669],{"class":727,"line":1622},10,[725,1624,1625],{"class":945},"    getSession",[725,1627,735],{"class":734},[725,1629,1630],{"class":768}," event",[725,1632,773],{"class":772},[725,1634,1635],{"class":945}," serverAuth",[725,1637,1638],{"class":779},"()",[725,1640,524],{"class":734},[725,1642,1643],{"class":779},"api",[725,1645,524],{"class":734},[725,1647,1648],{"class":945},"getSession",[725,1650,1418],{"class":779},[725,1652,1158],{"class":734},[725,1654,1655],{"class":824}," headers",[725,1657,735],{"class":734},[725,1659,1630],{"class":779},[725,1661,524],{"class":734},[725,1663,1664],{"class":779},"headers ",[725,1666,1184],{"class":734},[725,1668,1027],{"class":779},[725,1670,1091],{"class":734},[725,1672,1674,1677,1679,1682,1684,1687,1689,1692,1695,1698,1700,1702,1705,1707,1709,1711,1713,1715,1717,1720,1722,1724,1727,1729,1731,1733,1735,1738,1740,1743,1746,1748,1751],{"class":727,"line":1673},11,[725,1675,1676],{"class":945},"    getPermissions",[725,1678,735],{"class":734},[725,1680,1681],{"class":768}," user",[725,1683,773],{"class":772},[725,1685,1686],{"class":779}," (user",[725,1688,524],{"class":734},[725,1690,1691],{"class":779},"role ",[725,1693,1694],{"class":734},"??",[725,1696,1697],{"class":734}," ''",[725,1699,1027],{"class":779},[725,1701,524],{"class":734},[725,1703,1704],{"class":945},"split",[725,1706,1418],{"class":779},[725,1708,808],{"class":734},[725,1710,753],{"class":804},[725,1712,808],{"class":734},[725,1714,1027],{"class":779},[725,1716,524],{"class":734},[725,1718,1719],{"class":945},"flatMap",[725,1721,1418],{"class":779},[725,1723,1418],{"class":734},[725,1725,1726],{"class":768},"r",[725,1728,735],{"class":734},[725,1730,1501],{"class":731},[725,1732,1027],{"class":734},[725,1734,773],{"class":772},[725,1736,1737],{"class":779}," ROLE_PERMISSIONS[r",[725,1739,524],{"class":734},[725,1741,1742],{"class":945},"trim",[725,1744,1745],{"class":779},"()] ",[725,1747,1694],{"class":734},[725,1749,1750],{"class":779}," [])",[725,1752,1091],{"class":734},[725,1754,1756,1759,1761],{"class":727,"line":1755},12,[725,1757,1758],{"class":734},"  }",[725,1760,1027],{"class":779},[725,1762,1091],{"class":734},[725,1764,1766],{"class":727,"line":1765},13,[725,1767,1768],{"class":779},"]\n",[716,1770,1772],{"className":718,"code":1771,"language":720,"meta":721,"style":721},"\u002F\u002F modules\u002Fblog\u002Fauth.ts\npermissions: { read: true, create: 'posts:write', update: 'posts:write', delete: 'posts:publish' },\n",[572,1773,1774,1779],{"__ignoreMap":721},[725,1775,1776],{"class":727,"line":728},[725,1777,1778],{"class":756},"\u002F\u002F modules\u002Fblog\u002Fauth.ts\n",[725,1780,1781,1783,1785,1787,1789,1791,1793,1795,1797,1799,1801,1803,1805,1807,1809,1811,1813,1815,1817,1819,1821,1823,1825,1827,1829],{"class":727,"line":741},[725,1782,590],{"class":731},[725,1784,735],{"class":734},[725,1786,933],{"class":734},[725,1788,936],{"class":731},[725,1790,735],{"class":734},[725,1792,750],{"class":749},[725,1794,753],{"class":734},[725,1796,946],{"class":731},[725,1798,735],{"class":734},[725,1800,801],{"class":734},[725,1802,805],{"class":804},[725,1804,808],{"class":734},[725,1806,753],{"class":734},[725,1808,965],{"class":731},[725,1810,735],{"class":734},[725,1812,801],{"class":734},[725,1814,805],{"class":804},[725,1816,808],{"class":734},[725,1818,753],{"class":734},[725,1820,984],{"class":731},[725,1822,735],{"class":734},[725,1824,801],{"class":734},[725,1826,1553],{"class":804},[725,1828,808],{"class":734},[725,1830,1831],{"class":734}," },\n",[893,1833,1835],{"id":1834},"roles-inside-an-organization","Roles inside an organization",[518,1837,1838,1839,1842],{},"With ",[522,1840,1841],{"href":236},"multi-tenancy"," the tenant layer already limits rows to the active organization; the\nmember's role decides what they may do there:",[716,1844,1846],{"className":718,"code":1845,"language":720,"meta":721,"style":721},"const orgRole = (ctx: HandlerContext) => ctx.user?.orgRole as string | undefined\nconst atLeast = (...roles: string[]) => (ctx: HandlerContext) => roles.includes(orgRole(ctx) ?? '')\n\nexport const invoicesAuth: ResourceAuthConfig = {\n  permissions: {\n    read: atLeast('owner', 'admin', 'member'),\n    create: atLeast('owner', 'admin'),\n    update: atLeast('owner', 'admin'),\n    delete: atLeast('owner'),\n  },\n}\n",[572,1847,1848,1892,1951,1955,1972,1980,2020,2049,2078,2099,2104],{"__ignoreMap":721},[725,1849,1850,1852,1855,1857,1859,1861,1863,1866,1868,1870,1872,1874,1876,1878,1881,1884,1886,1889],{"class":727,"line":728},[725,1851,1482],{"class":772},[725,1853,1854],{"class":779}," orgRole ",[725,1856,1122],{"class":734},[725,1858,1017],{"class":734},[725,1860,780],{"class":768},[725,1862,735],{"class":734},[725,1864,1865],{"class":731}," HandlerContext",[725,1867,1027],{"class":734},[725,1869,773],{"class":772},[725,1871,769],{"class":779},[725,1873,524],{"class":734},[725,1875,785],{"class":779},[725,1877,1085],{"class":734},[725,1879,1880],{"class":779},"orgRole ",[725,1882,1883],{"class":906},"as",[725,1885,1501],{"class":731},[725,1887,1888],{"class":734}," |",[725,1890,1891],{"class":731}," undefined\n",[725,1893,1894,1896,1899,1901,1904,1907,1909,1911,1913,1915,1917,1919,1921,1923,1925,1927,1929,1932,1934,1936,1938,1941,1944,1946,1948],{"class":727,"line":741},[725,1895,1482],{"class":772},[725,1897,1898],{"class":779}," atLeast ",[725,1900,1122],{"class":734},[725,1902,1903],{"class":734}," (...",[725,1905,1906],{"class":768},"roles",[725,1908,735],{"class":734},[725,1910,1501],{"class":731},[725,1912,1504],{"class":779},[725,1914,1027],{"class":734},[725,1916,773],{"class":772},[725,1918,1017],{"class":734},[725,1920,780],{"class":768},[725,1922,735],{"class":734},[725,1924,1865],{"class":731},[725,1926,1027],{"class":734},[725,1928,773],{"class":772},[725,1930,1931],{"class":779}," roles",[725,1933,524],{"class":734},[725,1935,1415],{"class":945},[725,1937,1418],{"class":779},[725,1939,1940],{"class":945},"orgRole",[725,1942,1943],{"class":779},"(ctx) ",[725,1945,1694],{"class":734},[725,1947,1697],{"class":734},[725,1949,1950],{"class":779},")\n",[725,1952,1953],{"class":727,"line":760},[725,1954,1597],{"emptyLinePlaceholder":1596},[725,1956,1957,1959,1961,1964,1966,1968,1970],{"class":727,"line":793},[725,1958,907],{"class":906},[725,1960,910],{"class":772},[725,1962,1963],{"class":779}," invoicesAuth",[725,1965,735],{"class":734},[725,1967,918],{"class":731},[725,1969,921],{"class":734},[725,1971,738],{"class":734},[725,1973,1974,1976,1978],{"class":727,"line":816},[725,1975,928],{"class":824},[725,1977,735],{"class":734},[725,1979,738],{"class":734},[725,1981,1982,1985,1987,1990,1992,1994,1997,1999,2001,2003,2005,2007,2009,2011,2014,2016,2018],{"class":727,"line":852},[725,1983,1984],{"class":824},"    read",[725,1986,735],{"class":734},[725,1988,1989],{"class":945}," atLeast",[725,1991,1418],{"class":779},[725,1993,808],{"class":734},[725,1995,1996],{"class":804},"owner",[725,1998,808],{"class":734},[725,2000,753],{"class":734},[725,2002,801],{"class":734},[725,2004,839],{"class":804},[725,2006,808],{"class":734},[725,2008,753],{"class":734},[725,2010,801],{"class":734},[725,2012,2013],{"class":804},"member",[725,2015,808],{"class":734},[725,2017,1027],{"class":779},[725,2019,1091],{"class":734},[725,2021,2022,2025,2027,2029,2031,2033,2035,2037,2039,2041,2043,2045,2047],{"class":727,"line":868},[725,2023,2024],{"class":824},"    create",[725,2026,735],{"class":734},[725,2028,1989],{"class":945},[725,2030,1418],{"class":779},[725,2032,808],{"class":734},[725,2034,1996],{"class":804},[725,2036,808],{"class":734},[725,2038,753],{"class":734},[725,2040,801],{"class":734},[725,2042,839],{"class":804},[725,2044,808],{"class":734},[725,2046,1027],{"class":779},[725,2048,1091],{"class":734},[725,2050,2051,2054,2056,2058,2060,2062,2064,2066,2068,2070,2072,2074,2076],{"class":727,"line":1600},[725,2052,2053],{"class":824},"    update",[725,2055,735],{"class":734},[725,2057,1989],{"class":945},[725,2059,1418],{"class":779},[725,2061,808],{"class":734},[725,2063,1996],{"class":804},[725,2065,808],{"class":734},[725,2067,753],{"class":734},[725,2069,801],{"class":734},[725,2071,839],{"class":804},[725,2073,808],{"class":734},[725,2075,1027],{"class":779},[725,2077,1091],{"class":734},[725,2079,2080,2083,2085,2087,2089,2091,2093,2095,2097],{"class":727,"line":1611},[725,2081,2082],{"class":824},"    delete",[725,2084,735],{"class":734},[725,2086,1989],{"class":945},[725,2088,1418],{"class":779},[725,2090,808],{"class":734},[725,2092,1996],{"class":804},[725,2094,808],{"class":734},[725,2096,1027],{"class":779},[725,2098,1091],{"class":734},[725,2100,2101],{"class":727,"line":1622},[725,2102,2103],{"class":734},"  },\n",[725,2105,2106],{"class":727,"line":1673},[725,2107,871],{"class":734},[518,2109,2110,2111,2113,2114,524],{},"How ",[572,2112,1940],{}," gets onto the user: ",[522,2115,2117],{"href":2116},"\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fbetter-auth#the-callers-role-in-the-active-organization","Better-Auth › organization role",[893,2119,2121],{"id":2120},"read-only-and-secret-fields","Read-only and secret fields",[716,2123,2125],{"className":718,"code":2124,"language":720,"meta":721,"style":721},"export const usersAuth: ResourceAuthConfig = {\n  permissions: { read: ctx => !!ctx.user, update: ctx => !!ctx.user },\n  objectLevel: (u, ctx) => ctx.operation === 'list' || ctx.operation === 'get' || u.id === ctx.user?.id,\n  fields: {\n    email: { read: ctx => ctx.permissions.includes('users:admin') }, \u002F\u002F stripped for everyone else, not filterable\n    role: { write: 'users:admin' }, \u002F\u002F anyone else setting it gets a 403\n  },\n}\n",[572,2126,2127,2144,2188,2260,2269,2313,2339,2343],{"__ignoreMap":721},[725,2128,2129,2131,2133,2136,2138,2140,2142],{"class":727,"line":728},[725,2130,907],{"class":906},[725,2132,910],{"class":772},[725,2134,2135],{"class":779}," usersAuth",[725,2137,735],{"class":734},[725,2139,918],{"class":731},[725,2141,921],{"class":734},[725,2143,738],{"class":734},[725,2145,2146,2148,2150,2152,2154,2156,2158,2160,2162,2164,2166,2168,2170,2172,2174,2176,2178,2180,2182,2184,2186],{"class":727,"line":741},[725,2147,928],{"class":824},[725,2149,735],{"class":734},[725,2151,933],{"class":734},[725,2153,936],{"class":945},[725,2155,735],{"class":734},[725,2157,769],{"class":768},[725,2159,773],{"class":772},[725,2161,776],{"class":734},[725,2163,780],{"class":779},[725,2165,524],{"class":734},[725,2167,785],{"class":779},[725,2169,753],{"class":734},[725,2171,965],{"class":945},[725,2173,735],{"class":734},[725,2175,769],{"class":768},[725,2177,773],{"class":772},[725,2179,776],{"class":734},[725,2181,780],{"class":779},[725,2183,524],{"class":734},[725,2185,999],{"class":779},[725,2187,1002],{"class":734},[725,2189,2190,2192,2194,2196,2199,2201,2203,2205,2207,2209,2211,2213,2215,2217,2219,2221,2223,2225,2227,2229,2231,2233,2235,2237,2239,2242,2244,2246,2248,2250,2252,2254,2256,2258],{"class":727,"line":760},[725,2191,1012],{"class":945},[725,2193,735],{"class":734},[725,2195,1017],{"class":734},[725,2197,2198],{"class":768},"u",[725,2200,753],{"class":734},[725,2202,769],{"class":768},[725,2204,1027],{"class":734},[725,2206,773],{"class":772},[725,2208,769],{"class":779},[725,2210,524],{"class":734},[725,2212,1036],{"class":779},[725,2214,1039],{"class":734},[725,2216,801],{"class":734},[725,2218,1044],{"class":804},[725,2220,808],{"class":734},[725,2222,1049],{"class":734},[725,2224,769],{"class":779},[725,2226,524],{"class":734},[725,2228,1036],{"class":779},[725,2230,1039],{"class":734},[725,2232,801],{"class":734},[725,2234,1062],{"class":804},[725,2236,808],{"class":734},[725,2238,1049],{"class":734},[725,2240,2241],{"class":779}," u",[725,2243,524],{"class":734},[725,2245,1181],{"class":779},[725,2247,1039],{"class":734},[725,2249,769],{"class":779},[725,2251,524],{"class":734},[725,2253,785],{"class":779},[725,2255,1085],{"class":734},[725,2257,1088],{"class":779},[725,2259,1091],{"class":734},[725,2261,2262,2265,2267],{"class":727,"line":793},[725,2263,2264],{"class":824},"  fields",[725,2266,735],{"class":734},[725,2268,738],{"class":734},[725,2270,2271,2274,2276,2278,2280,2282,2284,2286,2288,2290,2292,2294,2296,2298,2300,2303,2305,2307,2310],{"class":727,"line":816},[725,2272,2273],{"class":824},"    email",[725,2275,735],{"class":734},[725,2277,933],{"class":734},[725,2279,936],{"class":945},[725,2281,735],{"class":734},[725,2283,769],{"class":768},[725,2285,773],{"class":772},[725,2287,769],{"class":779},[725,2289,524],{"class":734},[725,2291,590],{"class":779},[725,2293,524],{"class":734},[725,2295,1415],{"class":945},[725,2297,1418],{"class":779},[725,2299,808],{"class":734},[725,2301,2302],{"class":804},"users:admin",[725,2304,808],{"class":734},[725,2306,1427],{"class":779},[725,2308,2309],{"class":734},"},",[725,2311,2312],{"class":756}," \u002F\u002F stripped for everyone else, not filterable\n",[725,2314,2315,2318,2320,2322,2325,2327,2329,2331,2333,2336],{"class":727,"line":852},[725,2316,2317],{"class":824},"    role",[725,2319,735],{"class":734},[725,2321,933],{"class":734},[725,2323,2324],{"class":824}," write",[725,2326,735],{"class":734},[725,2328,801],{"class":734},[725,2330,2302],{"class":804},[725,2332,808],{"class":734},[725,2334,2335],{"class":734}," },",[725,2337,2338],{"class":756}," \u002F\u002F anyone else setting it gets a 403\n",[725,2340,2341],{"class":727,"line":868},[725,2342,2103],{"class":734},[725,2344,2345],{"class":727,"line":1600},[725,2346,871],{"class":734},[534,2348,2349,2359],{},[537,2350,2351],{},[540,2352,2353,2356],{},[543,2354,2355],{},"You want",[543,2357,2358],{},"Use",[556,2360,2361,2372,2382,2397],{},[540,2362,2363,2366],{},[561,2364,2365],{},"Never returned, never filterable, for anyone",[561,2367,2368,2371],{},[572,2369,2370],{},"hiddenFields: ['passwordHash']"," on the registration",[540,2373,2374,2377],{},[561,2375,2376],{},"Returned only to some callers",[561,2378,2379],{},[572,2380,2381],{},"fields.x.read",[540,2383,2384,2391],{},[561,2385,2386,2387,2390],{},"Setting it is an ",[567,2388,2389],{},"error"," for some callers",[561,2392,2393,2396],{},[572,2394,2395],{},"fields.x.write"," → 403",[540,2398,2399,2406],{},[561,2400,2401,2402,2405],{},"Setting it is ",[567,2403,2404],{},"ignored"," for everyone (server-owned)",[561,2407,2408,2371],{},[572,2409,2410],{},"protectedFields: ['x']",[518,2412,2413,2414,673,2417,673,2420,2423,2424,2426],{},"Hidden and unreadable fields cannot be used in ",[572,2415,2416],{},"filter",[572,2418,2419],{},"sort",[572,2421,2422],{},"groupBy"," or ",[572,2425,709],{}," field lists either — a\nquery on them is a 400, so values cannot be probed.",[893,2428,2430],{"id":2429},"close-an-operation-open-one-endpoint","Close an operation, open one endpoint",[518,2432,2433,2434,2437,2438,2441],{},"A resource can refuse generic writes and still expose a specific action. ",[572,2435,2436],{},"create: false"," closes ",[572,2439,2440],{},"POST \u002Fapi\u002Forders",";\nthe named gate opens one custom endpoint:",[716,2443,2445],{"className":718,"code":2444,"language":720,"meta":721,"style":721},"export const ordersAuth: ResourceAuthConfig = {\n  permissions: { read: ctx => !!ctx.user, create: false, update: false, delete: false },\n  custom: {\n    checkout: { permissions: { create: ctx => !!ctx.user } },\n    refund: { permissions: { update: 'orders:refund' } },\n  },\n}\n",[572,2446,2447,2464,2514,2523,2559,2590,2594],{"__ignoreMap":721},[725,2448,2449,2451,2453,2456,2458,2460,2462],{"class":727,"line":728},[725,2450,907],{"class":906},[725,2452,910],{"class":772},[725,2454,2455],{"class":779}," ordersAuth",[725,2457,735],{"class":734},[725,2459,918],{"class":731},[725,2461,921],{"class":734},[725,2463,738],{"class":734},[725,2465,2466,2468,2470,2472,2474,2476,2478,2480,2482,2484,2486,2488,2490,2492,2494,2496,2498,2500,2502,2504,2506,2508,2510,2512],{"class":727,"line":741},[725,2467,928],{"class":824},[725,2469,735],{"class":734},[725,2471,933],{"class":734},[725,2473,936],{"class":945},[725,2475,735],{"class":734},[725,2477,769],{"class":768},[725,2479,773],{"class":772},[725,2481,776],{"class":734},[725,2483,780],{"class":779},[725,2485,524],{"class":734},[725,2487,785],{"class":779},[725,2489,753],{"class":734},[725,2491,946],{"class":824},[725,2493,735],{"class":734},[725,2495,860],{"class":749},[725,2497,753],{"class":734},[725,2499,965],{"class":824},[725,2501,735],{"class":734},[725,2503,860],{"class":749},[725,2505,753],{"class":734},[725,2507,984],{"class":824},[725,2509,735],{"class":734},[725,2511,860],{"class":749},[725,2513,1831],{"class":734},[725,2515,2516,2519,2521],{"class":727,"line":760},[725,2517,2518],{"class":824},"  custom",[725,2520,735],{"class":734},[725,2522,738],{"class":734},[725,2524,2525,2528,2530,2532,2535,2537,2539,2541,2543,2545,2547,2549,2551,2553,2555,2557],{"class":727,"line":793},[725,2526,2527],{"class":824},"    checkout",[725,2529,735],{"class":734},[725,2531,933],{"class":734},[725,2533,2534],{"class":824}," permissions",[725,2536,735],{"class":734},[725,2538,933],{"class":734},[725,2540,946],{"class":945},[725,2542,735],{"class":734},[725,2544,769],{"class":768},[725,2546,773],{"class":772},[725,2548,776],{"class":734},[725,2550,780],{"class":779},[725,2552,524],{"class":734},[725,2554,999],{"class":779},[725,2556,1184],{"class":734},[725,2558,1831],{"class":734},[725,2560,2561,2564,2566,2568,2570,2572,2574,2576,2578,2580,2583,2585,2588],{"class":727,"line":816},[725,2562,2563],{"class":824},"    refund",[725,2565,735],{"class":734},[725,2567,933],{"class":734},[725,2569,2534],{"class":824},[725,2571,735],{"class":734},[725,2573,933],{"class":734},[725,2575,965],{"class":824},[725,2577,735],{"class":734},[725,2579,801],{"class":734},[725,2581,2582],{"class":804},"orders:refund",[725,2584,808],{"class":734},[725,2586,2587],{"class":734}," }",[725,2589,1831],{"class":734},[725,2591,2592],{"class":727,"line":852},[725,2593,2103],{"class":734},[725,2595,2596],{"class":727,"line":868},[725,2597,871],{"class":734},[716,2599,2601],{"className":718,"code":2600,"language":720,"meta":721,"style":721},"\u002F\u002F server\u002Fapi\u002Forders\u002Fcheckout.post.ts\nexport default createEndpoint({\n  resource: 'orders',\n  operation: 'create',\n  endpointName: 'checkout',\n  async handler(ctx) { \u002F* create the order from the cart, server-side *\u002F },\n})\n",[572,2602,2603,2608,2621,2637,2652,2668,2689],{"__ignoreMap":721},[725,2604,2605],{"class":727,"line":728},[725,2606,2607],{"class":756},"\u002F\u002F server\u002Fapi\u002Forders\u002Fcheckout.post.ts\n",[725,2609,2610,2612,2614,2617,2619],{"class":727,"line":741},[725,2611,907],{"class":906},[725,2613,1605],{"class":906},[725,2615,2616],{"class":945}," createEndpoint",[725,2618,1418],{"class":779},[725,2620,1619],{"class":734},[725,2622,2623,2626,2628,2630,2633,2635],{"class":727,"line":760},[725,2624,2625],{"class":824},"  resource",[725,2627,735],{"class":734},[725,2629,801],{"class":734},[725,2631,2632],{"class":804},"orders",[725,2634,808],{"class":734},[725,2636,1091],{"class":734},[725,2638,2639,2642,2644,2646,2648,2650],{"class":727,"line":793},[725,2640,2641],{"class":824},"  operation",[725,2643,735],{"class":734},[725,2645,801],{"class":734},[725,2647,578],{"class":804},[725,2649,808],{"class":734},[725,2651,1091],{"class":734},[725,2653,2654,2657,2659,2661,2664,2666],{"class":727,"line":816},[725,2655,2656],{"class":824},"  endpointName",[725,2658,735],{"class":734},[725,2660,801],{"class":734},[725,2662,2663],{"class":804},"checkout",[725,2665,808],{"class":734},[725,2667,1091],{"class":734},[725,2669,2670,2673,2676,2678,2680,2682,2684,2687],{"class":727,"line":852},[725,2671,2672],{"class":772},"  async",[725,2674,2675],{"class":824}," handler",[725,2677,1418],{"class":734},[725,2679,780],{"class":768},[725,2681,1027],{"class":734},[725,2683,933],{"class":734},[725,2685,2686],{"class":756}," \u002F* create the order from the cart, server-side *\u002F",[725,2688,1831],{"class":734},[725,2690,2691,2693],{"class":727,"line":868},[725,2692,1184],{"class":734},[725,2694,1950],{"class":779},[518,2696,2697],{},"An operation the named gate does not declare falls back to the resource's permission — never to \"allowed\".",[893,2699,2701],{"id":2700},"gate-by-subscription-plan","Gate by subscription plan",[518,2703,2704,2705,2707],{},"Load the caller's plan once per request in a context extender, then gate on it — see\n",[522,2706,247],{"href":248}," for the full setup:",[716,2709,2711],{"className":718,"code":2710,"language":720,"meta":721,"style":721},"permissions: {\n  read: ctx => !!ctx.user,\n  create: ctx => ctx.requestMeta?.billing?.features.includes('projects') ?? false,\n}\n",[572,2712,2713,2721,2741,2789],{"__ignoreMap":721},[725,2714,2715,2717,2719],{"class":727,"line":728},[725,2716,590],{"class":731},[725,2718,735],{"class":734},[725,2720,738],{"class":734},[725,2722,2723,2725,2727,2729,2731,2733,2735,2737,2739],{"class":727,"line":741},[725,2724,744],{"class":731},[725,2726,735],{"class":734},[725,2728,769],{"class":768},[725,2730,773],{"class":772},[725,2732,776],{"class":734},[725,2734,780],{"class":779},[725,2736,524],{"class":734},[725,2738,785],{"class":779},[725,2740,1091],{"class":734},[725,2742,2743,2745,2747,2749,2751,2753,2755,2758,2760,2763,2765,2768,2770,2772,2774,2776,2779,2781,2783,2785,2787],{"class":727,"line":760},[725,2744,763],{"class":731},[725,2746,735],{"class":734},[725,2748,769],{"class":768},[725,2750,773],{"class":772},[725,2752,769],{"class":779},[725,2754,524],{"class":734},[725,2756,2757],{"class":779},"requestMeta",[725,2759,1085],{"class":734},[725,2761,2762],{"class":779},"billing",[725,2764,1085],{"class":734},[725,2766,2767],{"class":779},"features",[725,2769,524],{"class":734},[725,2771,1415],{"class":945},[725,2773,1418],{"class":824},[725,2775,808],{"class":734},[725,2777,2778],{"class":804},"projects",[725,2780,808],{"class":734},[725,2782,1427],{"class":824},[725,2784,1694],{"class":734},[725,2786,860],{"class":749},[725,2788,1091],{"class":734},[725,2790,2791],{"class":727,"line":793},[725,2792,871],{"class":734},[893,2794,2796],{"id":2795},"declarative-policies-with-a-permission-evaluator","Declarative policies with a permission evaluator",[518,2798,2799,2800,2803,2804,2807,2808,2811],{},"Functions are flexible but opaque: the client cannot see ",[644,2801,2802],{},"why"," something is blocked. A permission can instead be a\nplain ",[567,2805,2806],{},"object"," that a registered evaluator understands — the same object can drive the server decision, the\n",[572,2809,2810],{},"\u002Fpermissions"," endpoint and your UI:",[716,2813,2815],{"className":718,"code":2814,"language":720,"meta":721,"style":721},"\u002F\u002F shared\u002Fpolicy.ts — pure, importable from server and client\nexport interface Policy { roles?: string[], orgRoles?: string[], feature?: string }\n\nexport function evaluatePolicy(p: Policy, facts: { roles: string[], orgRole?: string | null, features: string[] }) {\n  if (p.roles && !p.roles.some(r => facts.roles.includes(r))) return false\n  if (p.orgRoles && !p.orgRoles.includes(facts.orgRole ?? '')) return false\n  if (p.feature && !facts.features.includes(p.feature)) return false\n  return true\n}\n\nexport const isPolicy = (v: unknown): v is Policy =>\n  !!v && typeof v === 'object' && ['roles', 'orgRoles', 'feature'].some(k => k in (v as object))\n",[572,2816,2817,2822,2866,2870,2936,2995,3043,3084,3092,3096,3100,3134],{"__ignoreMap":721},[725,2818,2819],{"class":727,"line":728},[725,2820,2821],{"class":756},"\u002F\u002F shared\u002Fpolicy.ts — pure, importable from server and client\n",[725,2823,2824,2826,2829,2832,2834,2836,2839,2841,2843,2845,2848,2850,2852,2854,2856,2859,2861,2863],{"class":727,"line":741},[725,2825,907],{"class":906},[725,2827,2828],{"class":772}," interface",[725,2830,2831],{"class":731}," Policy",[725,2833,933],{"class":734},[725,2835,1931],{"class":824},[725,2837,2838],{"class":734},"?:",[725,2840,1501],{"class":731},[725,2842,1504],{"class":779},[725,2844,753],{"class":734},[725,2846,2847],{"class":824}," orgRoles",[725,2849,2838],{"class":734},[725,2851,1501],{"class":731},[725,2853,1504],{"class":779},[725,2855,753],{"class":734},[725,2857,2858],{"class":824}," feature",[725,2860,2838],{"class":734},[725,2862,1501],{"class":731},[725,2864,2865],{"class":734}," }\n",[725,2867,2868],{"class":727,"line":760},[725,2869,1597],{"emptyLinePlaceholder":1596},[725,2871,2872,2874,2877,2880,2882,2884,2886,2888,2890,2893,2895,2897,2899,2901,2903,2905,2907,2910,2912,2914,2916,2919,2921,2924,2926,2928,2931,2934],{"class":727,"line":793},[725,2873,907],{"class":906},[725,2875,2876],{"class":772}," function",[725,2878,2879],{"class":945}," evaluatePolicy",[725,2881,1418],{"class":734},[725,2883,518],{"class":768},[725,2885,735],{"class":734},[725,2887,2831],{"class":731},[725,2889,753],{"class":734},[725,2891,2892],{"class":768}," facts",[725,2894,735],{"class":734},[725,2896,933],{"class":734},[725,2898,1931],{"class":824},[725,2900,735],{"class":734},[725,2902,1501],{"class":731},[725,2904,1504],{"class":779},[725,2906,753],{"class":734},[725,2908,2909],{"class":824}," orgRole",[725,2911,2838],{"class":734},[725,2913,1501],{"class":731},[725,2915,1888],{"class":734},[725,2917,2918],{"class":731}," null",[725,2920,753],{"class":734},[725,2922,2923],{"class":824}," features",[725,2925,735],{"class":734},[725,2927,1501],{"class":731},[725,2929,2930],{"class":779},"[] ",[725,2932,2933],{"class":734},"})",[725,2935,738],{"class":734},[725,2937,2938,2941,2943,2945,2947,2949,2952,2955,2957,2959,2961,2963,2966,2968,2970,2972,2974,2976,2978,2980,2982,2984,2986,2989,2992],{"class":727,"line":816},[725,2939,2940],{"class":906},"  if",[725,2942,1017],{"class":824},[725,2944,518],{"class":779},[725,2946,524],{"class":734},[725,2948,1906],{"class":779},[725,2950,2951],{"class":734}," &&",[725,2953,2954],{"class":734}," !",[725,2956,518],{"class":779},[725,2958,524],{"class":734},[725,2960,1906],{"class":779},[725,2962,524],{"class":734},[725,2964,2965],{"class":945},"some",[725,2967,1418],{"class":824},[725,2969,1726],{"class":768},[725,2971,773],{"class":772},[725,2973,2892],{"class":779},[725,2975,524],{"class":734},[725,2977,1906],{"class":779},[725,2979,524],{"class":734},[725,2981,1415],{"class":945},[725,2983,1418],{"class":824},[725,2985,1726],{"class":779},[725,2987,2988],{"class":824},"))) ",[725,2990,2991],{"class":906},"return",[725,2993,2994],{"class":749}," false\n",[725,2996,2997,2999,3001,3003,3005,3008,3010,3012,3014,3016,3018,3020,3022,3024,3027,3029,3031,3034,3036,3039,3041],{"class":727,"line":852},[725,2998,2940],{"class":906},[725,3000,1017],{"class":824},[725,3002,518],{"class":779},[725,3004,524],{"class":734},[725,3006,3007],{"class":779},"orgRoles",[725,3009,2951],{"class":734},[725,3011,2954],{"class":734},[725,3013,518],{"class":779},[725,3015,524],{"class":734},[725,3017,3007],{"class":779},[725,3019,524],{"class":734},[725,3021,1415],{"class":945},[725,3023,1418],{"class":824},[725,3025,3026],{"class":779},"facts",[725,3028,524],{"class":734},[725,3030,1940],{"class":779},[725,3032,3033],{"class":734}," ??",[725,3035,1697],{"class":734},[725,3037,3038],{"class":824},")) ",[725,3040,2991],{"class":906},[725,3042,2994],{"class":749},[725,3044,3045,3047,3049,3051,3053,3056,3058,3060,3062,3064,3066,3068,3070,3072,3074,3076,3078,3080,3082],{"class":727,"line":868},[725,3046,2940],{"class":906},[725,3048,1017],{"class":824},[725,3050,518],{"class":779},[725,3052,524],{"class":734},[725,3054,3055],{"class":779},"feature",[725,3057,2951],{"class":734},[725,3059,2954],{"class":734},[725,3061,3026],{"class":779},[725,3063,524],{"class":734},[725,3065,2767],{"class":779},[725,3067,524],{"class":734},[725,3069,1415],{"class":945},[725,3071,1418],{"class":824},[725,3073,518],{"class":779},[725,3075,524],{"class":734},[725,3077,3055],{"class":779},[725,3079,3038],{"class":824},[725,3081,2991],{"class":906},[725,3083,2994],{"class":749},[725,3085,3086,3089],{"class":727,"line":1600},[725,3087,3088],{"class":906},"  return",[725,3090,3091],{"class":749}," true\n",[725,3093,3094],{"class":727,"line":1611},[725,3095,871],{"class":734},[725,3097,3098],{"class":727,"line":1622},[725,3099,1597],{"emptyLinePlaceholder":1596},[725,3101,3102,3104,3106,3109,3111,3113,3116,3118,3121,3124,3127,3130,3132],{"class":727,"line":1673},[725,3103,907],{"class":906},[725,3105,910],{"class":772},[725,3107,3108],{"class":779}," isPolicy ",[725,3110,1122],{"class":734},[725,3112,1017],{"class":734},[725,3114,3115],{"class":768},"v",[725,3117,735],{"class":734},[725,3119,3120],{"class":731}," unknown",[725,3122,3123],{"class":734},"):",[725,3125,3126],{"class":768}," v",[725,3128,3129],{"class":734}," is",[725,3131,2831],{"class":731},[725,3133,1401],{"class":772},[725,3135,3136,3139,3142,3145,3148,3151,3153,3155,3157,3159,3161,3163,3165,3167,3169,3171,3173,3175,3177,3179,3181,3183,3185,3187,3189,3191,3193,3196,3198,3201,3204,3207,3209,3212],{"class":727,"line":1755},[725,3137,3138],{"class":734},"  !!",[725,3140,3141],{"class":779},"v ",[725,3143,3144],{"class":734},"&&",[725,3146,3147],{"class":734}," typeof",[725,3149,3150],{"class":779}," v ",[725,3152,1039],{"class":734},[725,3154,801],{"class":734},[725,3156,2806],{"class":804},[725,3158,808],{"class":734},[725,3160,2951],{"class":734},[725,3162,825],{"class":779},[725,3164,808],{"class":734},[725,3166,1906],{"class":804},[725,3168,808],{"class":734},[725,3170,753],{"class":734},[725,3172,801],{"class":734},[725,3174,3007],{"class":804},[725,3176,808],{"class":734},[725,3178,753],{"class":734},[725,3180,801],{"class":734},[725,3182,3055],{"class":804},[725,3184,808],{"class":734},[725,3186,844],{"class":779},[725,3188,524],{"class":734},[725,3190,2965],{"class":945},[725,3192,1418],{"class":779},[725,3194,3195],{"class":768},"k",[725,3197,773],{"class":772},[725,3199,3200],{"class":779}," k ",[725,3202,3203],{"class":734},"in",[725,3205,3206],{"class":779}," (v ",[725,3208,1883],{"class":906},[725,3210,3211],{"class":731}," object",[725,3213,3214],{"class":779},"))\n",[716,3216,3218],{"className":718,"code":3217,"language":720,"meta":721,"style":721},"\u002F\u002F server\u002Fplugins\u002Fpolicy.ts\nimport { registerPermissionEvaluator } from '@websideproject\u002Fnuxt-auto-api\u002Fplugins'\nimport { evaluatePolicy, isPolicy } from '~~\u002Fshared\u002Fpolicy'\n\nexport default defineNitroPlugin(() => {\n  registerPermissionEvaluator((value, ctx) => {\n    if (!isPolicy(value)) return undefined \u002F\u002F not mine — the next evaluator may handle it\n    return evaluatePolicy(value, {\n      roles: ctx.user?.roles ?? [],\n      orgRole: ctx.user?.orgRole,\n      features: ctx.requestMeta?.billing?.features ?? [],\n    })\n  })\n})\n",[572,3219,3220,3225,3248,3272,3276,3293,3315,3341,3356,3380,3399,3426,3433,3439],{"__ignoreMap":721},[725,3221,3222],{"class":727,"line":728},[725,3223,3224],{"class":756},"\u002F\u002F server\u002Fplugins\u002Fpolicy.ts\n",[725,3226,3227,3230,3232,3235,3237,3240,3242,3245],{"class":727,"line":741},[725,3228,3229],{"class":906},"import",[725,3231,933],{"class":734},[725,3233,3234],{"class":779}," registerPermissionEvaluator",[725,3236,2587],{"class":734},[725,3238,3239],{"class":906}," from",[725,3241,801],{"class":734},[725,3243,3244],{"class":804},"@websideproject\u002Fnuxt-auto-api\u002Fplugins",[725,3246,3247],{"class":734},"'\n",[725,3249,3250,3252,3254,3256,3258,3261,3263,3265,3267,3270],{"class":727,"line":760},[725,3251,3229],{"class":906},[725,3253,933],{"class":734},[725,3255,2879],{"class":779},[725,3257,753],{"class":734},[725,3259,3260],{"class":779}," isPolicy",[725,3262,2587],{"class":734},[725,3264,3239],{"class":906},[725,3266,801],{"class":734},[725,3268,3269],{"class":804},"~~\u002Fshared\u002Fpolicy",[725,3271,3247],{"class":734},[725,3273,3274],{"class":727,"line":793},[725,3275,1597],{"emptyLinePlaceholder":1596},[725,3277,3278,3280,3282,3285,3287,3289,3291],{"class":727,"line":816},[725,3279,907],{"class":906},[725,3281,1605],{"class":906},[725,3283,3284],{"class":945}," defineNitroPlugin",[725,3286,1418],{"class":779},[725,3288,1638],{"class":734},[725,3290,773],{"class":772},[725,3292,738],{"class":734},[725,3294,3295,3298,3300,3302,3305,3307,3309,3311,3313],{"class":727,"line":852},[725,3296,3297],{"class":945},"  registerPermissionEvaluator",[725,3299,1418],{"class":824},[725,3301,1418],{"class":734},[725,3303,3304],{"class":768},"value",[725,3306,753],{"class":734},[725,3308,769],{"class":768},[725,3310,1027],{"class":734},[725,3312,773],{"class":772},[725,3314,738],{"class":734},[725,3316,3317,3320,3322,3325,3328,3330,3332,3334,3336,3338],{"class":727,"line":868},[725,3318,3319],{"class":906},"    if",[725,3321,1017],{"class":824},[725,3323,3324],{"class":734},"!",[725,3326,3327],{"class":945},"isPolicy",[725,3329,1418],{"class":824},[725,3331,3304],{"class":779},[725,3333,3038],{"class":824},[725,3335,2991],{"class":906},[725,3337,1433],{"class":734},[725,3339,3340],{"class":756}," \u002F\u002F not mine — the next evaluator may handle it\n",[725,3342,3343,3346,3348,3350,3352,3354],{"class":727,"line":1600},[725,3344,3345],{"class":906},"    return",[725,3347,2879],{"class":945},[725,3349,1418],{"class":824},[725,3351,3304],{"class":779},[725,3353,753],{"class":734},[725,3355,738],{"class":734},[725,3357,3358,3361,3363,3365,3367,3369,3371,3373,3375,3378],{"class":727,"line":1611},[725,3359,3360],{"class":824},"      roles",[725,3362,735],{"class":734},[725,3364,769],{"class":779},[725,3366,524],{"class":734},[725,3368,785],{"class":779},[725,3370,1085],{"class":734},[725,3372,1906],{"class":779},[725,3374,3033],{"class":734},[725,3376,3377],{"class":824}," []",[725,3379,1091],{"class":734},[725,3381,3382,3385,3387,3389,3391,3393,3395,3397],{"class":727,"line":1622},[725,3383,3384],{"class":824},"      orgRole",[725,3386,735],{"class":734},[725,3388,769],{"class":779},[725,3390,524],{"class":734},[725,3392,785],{"class":779},[725,3394,1085],{"class":734},[725,3396,1940],{"class":779},[725,3398,1091],{"class":734},[725,3400,3401,3404,3406,3408,3410,3412,3414,3416,3418,3420,3422,3424],{"class":727,"line":1673},[725,3402,3403],{"class":824},"      features",[725,3405,735],{"class":734},[725,3407,769],{"class":779},[725,3409,524],{"class":734},[725,3411,2757],{"class":779},[725,3413,1085],{"class":734},[725,3415,2762],{"class":779},[725,3417,1085],{"class":734},[725,3419,2767],{"class":779},[725,3421,3033],{"class":734},[725,3423,3377],{"class":824},[725,3425,1091],{"class":734},[725,3427,3428,3431],{"class":727,"line":1755},[725,3429,3430],{"class":734},"    }",[725,3432,1950],{"class":824},[725,3434,3435,3437],{"class":727,"line":1765},[725,3436,1758],{"class":734},[725,3438,1950],{"class":824},[725,3440,3442,3444],{"class":727,"line":3441},14,[725,3443,1184],{"class":734},[725,3445,1950],{"class":779},[716,3447,3449],{"className":718,"code":3448,"language":720,"meta":721,"style":721},"\u002F\u002F modules\u002Freports\u002Fauth.ts\npermissions: {\n  read: { orgRoles: ['owner', 'admin', 'member'] },\n  create: { orgRoles: ['owner', 'admin'], feature: 'reports' },\n  aggregate: { feature: 'analytics' },\n}\n",[572,3450,3451,3456,3464,3505,3550,3571],{"__ignoreMap":721},[725,3452,3453],{"class":727,"line":728},[725,3454,3455],{"class":756},"\u002F\u002F modules\u002Freports\u002Fauth.ts\n",[725,3457,3458,3460,3462],{"class":727,"line":741},[725,3459,590],{"class":731},[725,3461,735],{"class":734},[725,3463,738],{"class":734},[725,3465,3466,3468,3470,3472,3474,3476,3478,3480,3482,3484,3486,3488,3490,3492,3494,3496,3498,3500,3503],{"class":727,"line":760},[725,3467,744],{"class":731},[725,3469,735],{"class":734},[725,3471,933],{"class":734},[725,3473,2847],{"class":731},[725,3475,735],{"class":734},[725,3477,825],{"class":824},[725,3479,808],{"class":734},[725,3481,1996],{"class":804},[725,3483,808],{"class":734},[725,3485,753],{"class":734},[725,3487,801],{"class":734},[725,3489,839],{"class":804},[725,3491,808],{"class":734},[725,3493,753],{"class":734},[725,3495,801],{"class":734},[725,3497,2013],{"class":804},[725,3499,808],{"class":734},[725,3501,3502],{"class":824},"] ",[725,3504,1002],{"class":734},[725,3506,3507,3509,3511,3513,3515,3517,3519,3521,3523,3525,3527,3529,3531,3533,3535,3537,3539,3541,3543,3546,3548],{"class":727,"line":793},[725,3508,763],{"class":731},[725,3510,735],{"class":734},[725,3512,933],{"class":734},[725,3514,2847],{"class":731},[725,3516,735],{"class":734},[725,3518,825],{"class":824},[725,3520,808],{"class":734},[725,3522,1996],{"class":804},[725,3524,808],{"class":734},[725,3526,753],{"class":734},[725,3528,801],{"class":734},[725,3530,839],{"class":804},[725,3532,808],{"class":734},[725,3534,844],{"class":824},[725,3536,753],{"class":734},[725,3538,2858],{"class":731},[725,3540,735],{"class":734},[725,3542,801],{"class":734},[725,3544,3545],{"class":804},"reports",[725,3547,808],{"class":734},[725,3549,1831],{"class":734},[725,3551,3552,3554,3556,3558,3560,3562,3564,3567,3569],{"class":727,"line":816},[725,3553,855],{"class":731},[725,3555,735],{"class":734},[725,3557,933],{"class":734},[725,3559,2858],{"class":731},[725,3561,735],{"class":734},[725,3563,801],{"class":734},[725,3565,3566],{"class":804},"analytics",[725,3568,808],{"class":734},[725,3570,1831],{"class":734},[725,3572,3573],{"class":727,"line":852},[725,3574,871],{"class":734},[518,3576,3577,3578,524],{},"An object no evaluator claims is ",[567,3579,705],{},[893,3581,3583],{"id":3582},"different-rules-for-reading-and-aggregating","Different rules for reading and aggregating",[518,3585,3586,3589,3590,3592],{},[572,3587,3588],{},"aggregate"," falls back to ",[572,3591,574],{},"; declare it to make totals a paid or privileged feature:",[716,3594,3596],{"className":718,"code":3595,"language":720,"meta":721,"style":721},"permissions: { read: ctx => !!ctx.user, aggregate: 'reports:view' }\n",[572,3597,3598],{"__ignoreMap":721},[725,3599,3600,3602,3604,3606,3608,3610,3612,3614,3616,3618,3620,3622,3624,3627,3629,3631,3634,3636],{"class":727,"line":728},[725,3601,590],{"class":731},[725,3603,735],{"class":734},[725,3605,933],{"class":734},[725,3607,936],{"class":731},[725,3609,735],{"class":734},[725,3611,769],{"class":768},[725,3613,773],{"class":772},[725,3615,776],{"class":734},[725,3617,780],{"class":779},[725,3619,524],{"class":734},[725,3621,785],{"class":779},[725,3623,753],{"class":734},[725,3625,3626],{"class":731}," aggregate",[725,3628,735],{"class":734},[725,3630,801],{"class":734},[725,3632,3633],{"class":804},"reports:view",[725,3635,808],{"class":734},[725,3637,2865],{"class":734},[893,3639,3641],{"id":3640},"trash-who-may-see-restore-and-purge","Trash: who may see, restore and purge",[716,3643,3645],{"className":718,"code":3644,"language":720,"meta":721,"style":721},"permissions: {\n  update: 'posts:write',\n  delete: 'posts:write',\n  viewDeleted: 'posts:write', \u002F\u002F ?includeDeleted \u002F ?onlyDeleted\n  restore: 'posts:write',\n  purge: 'admin', \u002F\u002F DELETE ?force=true — permanent\n}\n",[572,3646,3647,3655,3669,3683,3701,3716,3734],{"__ignoreMap":721},[725,3648,3649,3651,3653],{"class":727,"line":728},[725,3650,590],{"class":731},[725,3652,735],{"class":734},[725,3654,738],{"class":734},[725,3656,3657,3659,3661,3663,3665,3667],{"class":727,"line":741},[725,3658,796],{"class":731},[725,3660,735],{"class":734},[725,3662,801],{"class":734},[725,3664,805],{"class":804},[725,3666,808],{"class":734},[725,3668,1091],{"class":734},[725,3670,3671,3673,3675,3677,3679,3681],{"class":727,"line":760},[725,3672,819],{"class":731},[725,3674,735],{"class":734},[725,3676,801],{"class":734},[725,3678,805],{"class":804},[725,3680,808],{"class":734},[725,3682,1091],{"class":734},[725,3684,3685,3688,3690,3692,3694,3696,3698],{"class":727,"line":793},[725,3686,3687],{"class":731},"  viewDeleted",[725,3689,735],{"class":734},[725,3691,801],{"class":734},[725,3693,805],{"class":804},[725,3695,808],{"class":734},[725,3697,753],{"class":734},[725,3699,3700],{"class":756}," \u002F\u002F ?includeDeleted \u002F ?onlyDeleted\n",[725,3702,3703,3706,3708,3710,3712,3714],{"class":727,"line":816},[725,3704,3705],{"class":731},"  restore",[725,3707,735],{"class":734},[725,3709,801],{"class":734},[725,3711,805],{"class":804},[725,3713,808],{"class":734},[725,3715,1091],{"class":734},[725,3717,3718,3721,3723,3725,3727,3729,3731],{"class":727,"line":852},[725,3719,3720],{"class":731},"  purge",[725,3722,735],{"class":734},[725,3724,801],{"class":734},[725,3726,839],{"class":804},[725,3728,808],{"class":734},[725,3730,753],{"class":734},[725,3732,3733],{"class":756}," \u002F\u002F DELETE ?force=true — permanent\n",[725,3735,3736],{"class":727,"line":868},[725,3737,871],{"class":734},[518,3739,3740,3741,575,3743,575,3745,3748,3749,524],{},"Unset, they fall back to ",[572,3742,581],{},[572,3744,584],{},[572,3746,3747],{},"restore",". See ",[522,3750,299],{"href":300},[893,3752,3754],{"id":3753},"who-may-link-what-many-to-many","Who may link what (many-to-many)",[518,3756,3757,3758,3760,3761,3763,3764,3767,3768,3771],{},"Linking needs ",[572,3759,581],{}," on the resource and ",[572,3762,574],{}," on the related one. Tighten it per relation — keys are\n",[567,3765,3766],{},"relation names",", the ",[572,3769,3770],{},":relation"," route segment (which is the related resource's registered name):",[716,3773,3775],{"className":718,"code":3774,"language":720,"meta":721,"style":721},"permissions: {\n  update: 'posts:write',\n  m2m: {\n    requireUpdateOnRelated: ['categories'], \u002F\u002F must be allowed to edit a category to attach it\n    relations: {\n      tags: { check: ({ right, user }) => right.records!.every(t => !t.locked || user?.roles?.includes('admin')) },\n    },\n  },\n}\n",[572,3776,3777,3785,3799,3808,3831,3840,3921,3926,3930],{"__ignoreMap":721},[725,3778,3779,3781,3783],{"class":727,"line":728},[725,3780,590],{"class":731},[725,3782,735],{"class":734},[725,3784,738],{"class":734},[725,3786,3787,3789,3791,3793,3795,3797],{"class":727,"line":741},[725,3788,796],{"class":731},[725,3790,735],{"class":734},[725,3792,801],{"class":734},[725,3794,805],{"class":804},[725,3796,808],{"class":734},[725,3798,1091],{"class":734},[725,3800,3801,3804,3806],{"class":727,"line":760},[725,3802,3803],{"class":731},"  m2m",[725,3805,735],{"class":734},[725,3807,738],{"class":734},[725,3809,3810,3813,3815,3817,3819,3822,3824,3826,3828],{"class":727,"line":793},[725,3811,3812],{"class":731},"    requireUpdateOnRelated",[725,3814,735],{"class":734},[725,3816,825],{"class":824},[725,3818,808],{"class":734},[725,3820,3821],{"class":804},"categories",[725,3823,808],{"class":734},[725,3825,844],{"class":824},[725,3827,753],{"class":734},[725,3829,3830],{"class":756}," \u002F\u002F must be allowed to edit a category to attach it\n",[725,3832,3833,3836,3838],{"class":727,"line":816},[725,3834,3835],{"class":731},"    relations",[725,3837,735],{"class":734},[725,3839,738],{"class":734},[725,3841,3842,3845,3847,3849,3852,3854,3857,3860,3862,3864,3867,3869,3871,3873,3876,3878,3881,3883,3886,3888,3890,3892,3894,3897,3899,3901,3903,3905,3907,3909,3911,3913,3915,3917,3919],{"class":727,"line":852},[725,3843,3844],{"class":731},"      tags",[725,3846,735],{"class":734},[725,3848,933],{"class":734},[725,3850,3851],{"class":731}," check",[725,3853,735],{"class":734},[725,3855,3856],{"class":734}," ({",[725,3858,3859],{"class":768}," right",[725,3861,753],{"class":734},[725,3863,1681],{"class":768},[725,3865,3866],{"class":734}," })",[725,3868,773],{"class":772},[725,3870,3859],{"class":779},[725,3872,524],{"class":734},[725,3874,3875],{"class":779},"records",[725,3877,1363],{"class":734},[725,3879,3880],{"class":945},"every",[725,3882,1418],{"class":824},[725,3884,3885],{"class":768},"t",[725,3887,773],{"class":772},[725,3889,2954],{"class":734},[725,3891,3885],{"class":779},[725,3893,524],{"class":734},[725,3895,3896],{"class":779},"locked",[725,3898,1049],{"class":734},[725,3900,1681],{"class":779},[725,3902,1085],{"class":734},[725,3904,1906],{"class":779},[725,3906,1085],{"class":734},[725,3908,1415],{"class":945},[725,3910,1418],{"class":824},[725,3912,808],{"class":734},[725,3914,839],{"class":804},[725,3916,808],{"class":734},[725,3918,3038],{"class":824},[725,3920,1002],{"class":734},[725,3922,3923],{"class":727,"line":868},[725,3924,3925],{"class":734},"    },\n",[725,3927,3928],{"class":727,"line":1600},[725,3929,2103],{"class":734},[725,3931,3932],{"class":727,"line":1611},[725,3933,871],{"class":734},[893,3935,3937],{"id":3936},"tighten-a-modules-defaults-from-the-app","Tighten a module's defaults from the app",[518,3939,3940,3941,3944,3945,3948],{},"A module ships its ",[572,3942,3943],{},"auth.ts","; an app can override individual keys from ",[572,3946,3947],{},"nuxt.config"," — strings and arrays only\n(config is serialized, so functions cannot travel):",[716,3950,3952],{"className":718,"code":3951,"language":720,"meta":721,"style":721},"\u002F\u002F nuxt.config.ts\nautoApi: {\n  authorization: {\n    posts: {\n      permissions: { delete: 'admin' },\n      custom: { export: { permissions: { read: 'admin' } } },\n    },\n  },\n},\n",[572,3953,3954,3959,3968,3977,3986,4007,4045,4049,4053],{"__ignoreMap":721},[725,3955,3956],{"class":727,"line":728},[725,3957,3958],{"class":756},"\u002F\u002F nuxt.config.ts\n",[725,3960,3961,3964,3966],{"class":727,"line":741},[725,3962,3963],{"class":731},"autoApi",[725,3965,735],{"class":734},[725,3967,738],{"class":734},[725,3969,3970,3973,3975],{"class":727,"line":760},[725,3971,3972],{"class":731},"  authorization",[725,3974,735],{"class":734},[725,3976,738],{"class":734},[725,3978,3979,3982,3984],{"class":727,"line":793},[725,3980,3981],{"class":731},"    posts",[725,3983,735],{"class":734},[725,3985,738],{"class":734},[725,3987,3988,3991,3993,3995,3997,3999,4001,4003,4005],{"class":727,"line":816},[725,3989,3990],{"class":731},"      permissions",[725,3992,735],{"class":734},[725,3994,933],{"class":734},[725,3996,984],{"class":731},[725,3998,735],{"class":734},[725,4000,801],{"class":734},[725,4002,839],{"class":804},[725,4004,808],{"class":734},[725,4006,1831],{"class":734},[725,4008,4009,4012,4014,4016,4019,4021,4023,4025,4027,4029,4031,4033,4035,4037,4039,4041,4043],{"class":727,"line":852},[725,4010,4011],{"class":731},"      custom",[725,4013,735],{"class":734},[725,4015,933],{"class":734},[725,4017,4018],{"class":772}," export",[725,4020,1202],{"class":824},[725,4022,1158],{"class":734},[725,4024,2534],{"class":824},[725,4026,735],{"class":734},[725,4028,933],{"class":734},[725,4030,936],{"class":824},[725,4032,735],{"class":734},[725,4034,801],{"class":734},[725,4036,839],{"class":804},[725,4038,808],{"class":734},[725,4040,2587],{"class":734},[725,4042,2587],{"class":734},[725,4044,1831],{"class":734},[725,4046,4047],{"class":727,"line":868},[725,4048,3925],{"class":734},[725,4050,4051],{"class":727,"line":1600},[725,4052,2103],{"class":734},[725,4054,4055],{"class":727,"line":1611},[725,4056,1002],{"class":734},[893,4058,4060],{"id":4059},"checks-inside-custom-endpoints","Checks inside custom endpoints",[518,4062,4063],{},"The resource gate decides whether the caller may use the operation; rows are still your query. Use the same\nhelpers the generated routes use:",[716,4065,4067],{"className":718,"code":4066,"language":720,"meta":721,"style":721},"export default createEndpoint({\n  resource: 'projects',\n  operation: 'update',\n  async handler(ctx) {\n    const project = await findAuthorizedRow(ctx, 'projects', ctx.params.id) \u002F\u002F tenant + listFilter + objectLevel\n    await assertResourcePermission('invoices', 'create', ctx) \u002F\u002F a different resource's rule\n    if (!(await checkPermission('update', getAuthConfig(ctx, 'clients'), ctx))) { \u002F* degrade gracefully *\u002F }\n    \u002F\u002F …\n  },\n})\n",[572,4068,4069,4081,4095,4109,4123,4169,4203,4260,4265,4269],{"__ignoreMap":721},[725,4070,4071,4073,4075,4077,4079],{"class":727,"line":728},[725,4072,907],{"class":906},[725,4074,1605],{"class":906},[725,4076,2616],{"class":945},[725,4078,1418],{"class":779},[725,4080,1619],{"class":734},[725,4082,4083,4085,4087,4089,4091,4093],{"class":727,"line":741},[725,4084,2625],{"class":824},[725,4086,735],{"class":734},[725,4088,801],{"class":734},[725,4090,2778],{"class":804},[725,4092,808],{"class":734},[725,4094,1091],{"class":734},[725,4096,4097,4099,4101,4103,4105,4107],{"class":727,"line":760},[725,4098,2641],{"class":824},[725,4100,735],{"class":734},[725,4102,801],{"class":734},[725,4104,581],{"class":804},[725,4106,808],{"class":734},[725,4108,1091],{"class":734},[725,4110,4111,4113,4115,4117,4119,4121],{"class":727,"line":793},[725,4112,2672],{"class":772},[725,4114,2675],{"class":824},[725,4116,1418],{"class":734},[725,4118,780],{"class":768},[725,4120,1027],{"class":734},[725,4122,738],{"class":734},[725,4124,4125,4128,4131,4133,4136,4139,4141,4143,4145,4147,4149,4151,4153,4155,4157,4160,4162,4164,4166],{"class":727,"line":816},[725,4126,4127],{"class":772},"    const",[725,4129,4130],{"class":779}," project",[725,4132,921],{"class":734},[725,4134,4135],{"class":906}," await",[725,4137,4138],{"class":945}," findAuthorizedRow",[725,4140,1418],{"class":824},[725,4142,780],{"class":779},[725,4144,753],{"class":734},[725,4146,801],{"class":734},[725,4148,2778],{"class":804},[725,4150,808],{"class":734},[725,4152,753],{"class":734},[725,4154,769],{"class":779},[725,4156,524],{"class":734},[725,4158,4159],{"class":779},"params",[725,4161,524],{"class":734},[725,4163,1088],{"class":779},[725,4165,1427],{"class":824},[725,4167,4168],{"class":756},"\u002F\u002F tenant + listFilter + objectLevel\n",[725,4170,4171,4174,4177,4179,4181,4184,4186,4188,4190,4192,4194,4196,4198,4200],{"class":727,"line":852},[725,4172,4173],{"class":906},"    await",[725,4175,4176],{"class":945}," assertResourcePermission",[725,4178,1418],{"class":824},[725,4180,808],{"class":734},[725,4182,4183],{"class":804},"invoices",[725,4185,808],{"class":734},[725,4187,753],{"class":734},[725,4189,801],{"class":734},[725,4191,578],{"class":804},[725,4193,808],{"class":734},[725,4195,753],{"class":734},[725,4197,769],{"class":779},[725,4199,1427],{"class":824},[725,4201,4202],{"class":756},"\u002F\u002F a different resource's rule\n",[725,4204,4205,4207,4209,4211,4213,4216,4219,4221,4223,4225,4227,4229,4232,4234,4236,4238,4240,4243,4245,4247,4249,4251,4253,4255,4258],{"class":727,"line":868},[725,4206,3319],{"class":906},[725,4208,1017],{"class":824},[725,4210,3324],{"class":734},[725,4212,1418],{"class":824},[725,4214,4215],{"class":906},"await",[725,4217,4218],{"class":945}," checkPermission",[725,4220,1418],{"class":824},[725,4222,808],{"class":734},[725,4224,581],{"class":804},[725,4226,808],{"class":734},[725,4228,753],{"class":734},[725,4230,4231],{"class":945}," getAuthConfig",[725,4233,1418],{"class":824},[725,4235,780],{"class":779},[725,4237,753],{"class":734},[725,4239,801],{"class":734},[725,4241,4242],{"class":804},"clients",[725,4244,808],{"class":734},[725,4246,1027],{"class":824},[725,4248,753],{"class":734},[725,4250,769],{"class":779},[725,4252,2988],{"class":824},[725,4254,1158],{"class":734},[725,4256,4257],{"class":756}," \u002F* degrade gracefully *\u002F",[725,4259,2865],{"class":734},[725,4261,4262],{"class":727,"line":1600},[725,4263,4264],{"class":756},"    \u002F\u002F …\n",[725,4266,4267],{"class":727,"line":1611},[725,4268,2103],{"class":734},[725,4270,4271,4273],{"class":727,"line":1622},[725,4272,1184],{"class":734},[725,4274,1950],{"class":779},[518,4276,4277,4278,524],{},"More in ",[522,4279,4281],{"href":4280},"\u002Fdocs\u002Fnuxt-auto\u002Fauto-api\u002Fcustom-endpoints#row-access","Custom Endpoints › Row access",[886,4283],{},[526,4285,4287],{"id":4286},"reflect-permissions-in-the-ui","Reflect permissions in the UI",[518,4289,4290,4293],{},[572,4291,4292],{},"GET \u002Fapi\u002Fpermissions"," answers, for the current caller, what every resource allows — including function and\nevaluator rules, evaluated on the server:",[716,4295,4299],{"className":4296,"code":4297,"language":4298,"meta":721,"style":721},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Cscript setup lang=\"ts\">\nconst { canCreate, canUpdate, canDelete, permissions } = usePermissions('invoices')\nconst canEditTotal = computed(() => permissions.value?.fields?.total?.canWrite ?? false)\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CUButton v-if=\"canCreate\" label=\"New invoice\" icon=\"i-lucide-plus\" \u002F>\n  \u003CUInput v-model=\"form.total\" :disabled=\"!canEditTotal\" \u002F>\n  \u003CUTooltip v-if=\"!canDelete\" text=\"Only owners can delete invoices\">\n    \u003CUButton label=\"Delete\" color=\"error\" variant=\"soft\" disabled \u002F>\n  \u003C\u002FUTooltip>\n\u003C\u002Ftemplate>\n","vue",[572,4300,4301,4326,4367,4410,4419,4423,4432,4479,4512,4544,4590,4599],{"__ignoreMap":721},[725,4302,4303,4305,4308,4311,4314,4316,4319,4321,4323],{"class":727,"line":728},[725,4304,1493],{"class":734},[725,4306,4307],{"class":824},"script",[725,4309,4310],{"class":772}," setup",[725,4312,4313],{"class":772}," lang",[725,4315,1122],{"class":734},[725,4317,4318],{"class":734},"\"",[725,4320,720],{"class":804},[725,4322,4318],{"class":734},[725,4324,4325],{"class":734},">\n",[725,4327,4328,4330,4332,4335,4337,4340,4342,4345,4347,4350,4352,4354,4357,4359,4361,4363,4365],{"class":727,"line":741},[725,4329,1482],{"class":772},[725,4331,933],{"class":734},[725,4333,4334],{"class":779}," canCreate",[725,4336,753],{"class":734},[725,4338,4339],{"class":779}," canUpdate",[725,4341,753],{"class":734},[725,4343,4344],{"class":779}," canDelete",[725,4346,753],{"class":734},[725,4348,4349],{"class":779}," permissions ",[725,4351,1184],{"class":734},[725,4353,921],{"class":734},[725,4355,4356],{"class":945}," usePermissions",[725,4358,1418],{"class":779},[725,4360,808],{"class":734},[725,4362,4183],{"class":804},[725,4364,808],{"class":734},[725,4366,1950],{"class":779},[725,4368,4369,4371,4374,4376,4379,4381,4383,4385,4387,4389,4391,4393,4395,4397,4399,4401,4404,4406,4408],{"class":727,"line":760},[725,4370,1482],{"class":772},[725,4372,4373],{"class":779}," canEditTotal ",[725,4375,1122],{"class":734},[725,4377,4378],{"class":945}," computed",[725,4380,1418],{"class":779},[725,4382,1638],{"class":734},[725,4384,773],{"class":772},[725,4386,2534],{"class":779},[725,4388,524],{"class":734},[725,4390,3304],{"class":779},[725,4392,1085],{"class":734},[725,4394,672],{"class":779},[725,4396,1085],{"class":734},[725,4398,1218],{"class":779},[725,4400,1085],{"class":734},[725,4402,4403],{"class":779},"canWrite ",[725,4405,1694],{"class":734},[725,4407,860],{"class":749},[725,4409,1950],{"class":779},[725,4411,4412,4415,4417],{"class":727,"line":793},[725,4413,4414],{"class":734},"\u003C\u002F",[725,4416,4307],{"class":824},[725,4418,4325],{"class":734},[725,4420,4421],{"class":727,"line":816},[725,4422,1597],{"emptyLinePlaceholder":1596},[725,4424,4425,4427,4430],{"class":727,"line":852},[725,4426,1493],{"class":734},[725,4428,4429],{"class":824},"template",[725,4431,4325],{"class":734},[725,4433,4434,4437,4440,4443,4445,4447,4450,4452,4455,4457,4459,4462,4464,4467,4469,4471,4474,4476],{"class":727,"line":868},[725,4435,4436],{"class":734},"  \u003C",[725,4438,4439],{"class":824},"UButton",[725,4441,4442],{"class":772}," v-if",[725,4444,1122],{"class":734},[725,4446,4318],{"class":734},[725,4448,4449],{"class":804},"canCreate",[725,4451,4318],{"class":734},[725,4453,4454],{"class":772}," label",[725,4456,1122],{"class":734},[725,4458,4318],{"class":734},[725,4460,4461],{"class":804},"New invoice",[725,4463,4318],{"class":734},[725,4465,4466],{"class":772}," icon",[725,4468,1122],{"class":734},[725,4470,4318],{"class":734},[725,4472,4473],{"class":804},"i-lucide-plus",[725,4475,4318],{"class":734},[725,4477,4478],{"class":734}," \u002F>\n",[725,4480,4481,4483,4486,4489,4491,4493,4496,4498,4501,4503,4505,4508,4510],{"class":727,"line":1600},[725,4482,4436],{"class":734},[725,4484,4485],{"class":824},"UInput",[725,4487,4488],{"class":772}," v-model",[725,4490,1122],{"class":734},[725,4492,4318],{"class":734},[725,4494,4495],{"class":804},"form.total",[725,4497,4318],{"class":734},[725,4499,4500],{"class":772}," :disabled",[725,4502,1122],{"class":734},[725,4504,4318],{"class":734},[725,4506,4507],{"class":804},"!canEditTotal",[725,4509,4318],{"class":734},[725,4511,4478],{"class":734},[725,4513,4514,4516,4519,4521,4523,4525,4528,4530,4533,4535,4537,4540,4542],{"class":727,"line":1611},[725,4515,4436],{"class":734},[725,4517,4518],{"class":824},"UTooltip",[725,4520,4442],{"class":772},[725,4522,1122],{"class":734},[725,4524,4318],{"class":734},[725,4526,4527],{"class":804},"!canDelete",[725,4529,4318],{"class":734},[725,4531,4532],{"class":772}," text",[725,4534,1122],{"class":734},[725,4536,4318],{"class":734},[725,4538,4539],{"class":804},"Only owners can delete invoices",[725,4541,4318],{"class":734},[725,4543,4325],{"class":734},[725,4545,4546,4549,4551,4553,4555,4557,4560,4562,4565,4567,4569,4571,4573,4576,4578,4580,4583,4585,4588],{"class":727,"line":1622},[725,4547,4548],{"class":734},"    \u003C",[725,4550,4439],{"class":824},[725,4552,4454],{"class":772},[725,4554,1122],{"class":734},[725,4556,4318],{"class":734},[725,4558,4559],{"class":804},"Delete",[725,4561,4318],{"class":734},[725,4563,4564],{"class":772}," color",[725,4566,1122],{"class":734},[725,4568,4318],{"class":734},[725,4570,2389],{"class":804},[725,4572,4318],{"class":734},[725,4574,4575],{"class":772}," variant",[725,4577,1122],{"class":734},[725,4579,4318],{"class":734},[725,4581,4582],{"class":804},"soft",[725,4584,4318],{"class":734},[725,4586,4587],{"class":772}," disabled",[725,4589,4478],{"class":734},[725,4591,4592,4595,4597],{"class":727,"line":1673},[725,4593,4594],{"class":734},"  \u003C\u002F",[725,4596,4518],{"class":824},[725,4598,4325],{"class":734},[725,4600,4601,4603,4605],{"class":727,"line":1755},[725,4602,4414],{"class":734},[725,4604,4429],{"class":824},[725,4606,4325],{"class":734},[518,4608,4609],{},"This is UX. The server enforces the same rules on every request, whatever the UI shows.",[526,4611,4613],{"id":4612},"test-the-rules","Test the rules",[716,4615,4617],{"className":718,"code":4616,"language":720,"meta":721,"style":721},"import { evaluatePermission } from '@websideproject\u002Fnuxt-auto-api\u002Futils'\n\nit('only owners delete invoices', async () => {\n  const ctx = (orgRole: string) => ({ user: { id: 1, orgRole }, permissions: [] }) as any\n  expect(await evaluatePermission(invoicesAuth.permissions!.delete, ctx('admin'))).toBe(false)\n  expect(await evaluatePermission(invoicesAuth.permissions!.delete, ctx('owner'))).toBe(true)\n})\n",[572,4618,4619,4639,4643,4669,4731,4781,4828],{"__ignoreMap":721},[725,4620,4621,4623,4625,4628,4630,4632,4634,4637],{"class":727,"line":728},[725,4622,3229],{"class":906},[725,4624,933],{"class":734},[725,4626,4627],{"class":779}," evaluatePermission",[725,4629,2587],{"class":734},[725,4631,3239],{"class":906},[725,4633,801],{"class":734},[725,4635,4636],{"class":804},"@websideproject\u002Fnuxt-auto-api\u002Futils",[725,4638,3247],{"class":734},[725,4640,4641],{"class":727,"line":741},[725,4642,1597],{"emptyLinePlaceholder":1596},[725,4644,4645,4648,4650,4652,4655,4657,4659,4662,4665,4667],{"class":727,"line":760},[725,4646,4647],{"class":945},"it",[725,4649,1418],{"class":779},[725,4651,808],{"class":734},[725,4653,4654],{"class":804},"only owners delete invoices",[725,4656,808],{"class":734},[725,4658,753],{"class":734},[725,4660,4661],{"class":772}," async",[725,4663,4664],{"class":734}," ()",[725,4666,773],{"class":772},[725,4668,738],{"class":734},[725,4670,4671,4674,4676,4678,4680,4682,4684,4686,4688,4690,4692,4694,4696,4698,4700,4703,4705,4709,4711,4713,4715,4717,4719,4722,4724,4726,4728],{"class":727,"line":793},[725,4672,4673],{"class":772},"  const",[725,4675,769],{"class":779},[725,4677,921],{"class":734},[725,4679,1017],{"class":734},[725,4681,1940],{"class":768},[725,4683,735],{"class":734},[725,4685,1501],{"class":731},[725,4687,1027],{"class":734},[725,4689,773],{"class":772},[725,4691,1017],{"class":824},[725,4693,1158],{"class":734},[725,4695,1681],{"class":824},[725,4697,735],{"class":734},[725,4699,933],{"class":734},[725,4701,4702],{"class":824}," id",[725,4704,735],{"class":734},[725,4706,4708],{"class":4707},"sbssI"," 1",[725,4710,753],{"class":734},[725,4712,2909],{"class":779},[725,4714,2335],{"class":734},[725,4716,2534],{"class":824},[725,4718,735],{"class":734},[725,4720,4721],{"class":824}," [] ",[725,4723,1184],{"class":734},[725,4725,1427],{"class":824},[725,4727,1883],{"class":906},[725,4729,4730],{"class":731}," any\n",[725,4732,4733,4736,4738,4740,4742,4744,4747,4749,4751,4753,4755,4757,4759,4761,4763,4765,4767,4770,4772,4775,4777,4779],{"class":727,"line":816},[725,4734,4735],{"class":945},"  expect",[725,4737,1418],{"class":824},[725,4739,4215],{"class":906},[725,4741,4627],{"class":945},[725,4743,1418],{"class":824},[725,4745,4746],{"class":779},"invoicesAuth",[725,4748,524],{"class":734},[725,4750,590],{"class":779},[725,4752,1363],{"class":734},[725,4754,584],{"class":779},[725,4756,753],{"class":734},[725,4758,769],{"class":945},[725,4760,1418],{"class":824},[725,4762,808],{"class":734},[725,4764,839],{"class":804},[725,4766,808],{"class":734},[725,4768,4769],{"class":824},")))",[725,4771,524],{"class":734},[725,4773,4774],{"class":945},"toBe",[725,4776,1418],{"class":824},[725,4778,884],{"class":749},[725,4780,1950],{"class":824},[725,4782,4783,4785,4787,4789,4791,4793,4795,4797,4799,4801,4803,4805,4807,4809,4811,4813,4815,4817,4819,4821,4823,4826],{"class":727,"line":852},[725,4784,4735],{"class":945},[725,4786,1418],{"class":824},[725,4788,4215],{"class":906},[725,4790,4627],{"class":945},[725,4792,1418],{"class":824},[725,4794,4746],{"class":779},[725,4796,524],{"class":734},[725,4798,590],{"class":779},[725,4800,1363],{"class":734},[725,4802,584],{"class":779},[725,4804,753],{"class":734},[725,4806,769],{"class":945},[725,4808,1418],{"class":824},[725,4810,808],{"class":734},[725,4812,1996],{"class":804},[725,4814,808],{"class":734},[725,4816,4769],{"class":824},[725,4818,524],{"class":734},[725,4820,4774],{"class":945},[725,4822,1418],{"class":824},[725,4824,4825],{"class":749},"true",[725,4827,1950],{"class":824},[725,4829,4830,4832],{"class":727,"line":868},[725,4831,1184],{"class":734},[725,4833,1950],{"class":779},[518,4835,4836,4839,4840,673,4842,4844,4845,4847,4848,524],{},[572,4837,4838],{},"evaluatePermission"," is the pipeline's own function (undeclared → ",[572,4841,884],{},[572,4843,876],{}," → ",[572,4846,4825],{},"). For row visibility and\ntenancy, test through the routes — see ",[522,4849,287],{"href":288},[4851,4852,4853],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":721,"searchDepth":741,"depth":741,"links":4855},[4856,4857,4858,4874,4875],{"id":528,"depth":741,"text":529},{"id":713,"depth":741,"text":714},{"id":890,"depth":741,"text":891,"children":4859},[4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,4870,4871,4872,4873],{"id":895,"depth":760,"text":896},{"id":1209,"depth":760,"text":1210},{"id":1375,"depth":760,"text":1376},{"id":1463,"depth":760,"text":1464},{"id":1834,"depth":760,"text":1835},{"id":2120,"depth":760,"text":2121},{"id":2429,"depth":760,"text":2430},{"id":2700,"depth":760,"text":2701},{"id":2795,"depth":760,"text":2796},{"id":3582,"depth":760,"text":3583},{"id":3640,"depth":760,"text":3641},{"id":3753,"depth":760,"text":3754},{"id":3936,"depth":760,"text":3937},{"id":4059,"depth":760,"text":4060},{"id":4286,"depth":741,"text":4287},{"id":4612,"depth":741,"text":4613},"Recipes for fine-grained access control, from \"public blog\" to \"plan-gated, per-field, per-organization\". The\nconcepts behind them are in Authentication & Authorization.","md",null,{},{"title":243,"description":4876},"2s3LGsvY4xmC3nbM2JP9T3gaK_ndrIreAA_brRj7lko",[4883,4885],{"title":239,"path":240,"stem":241,"description":4884,"children":-1},"nuxt-auto-api ships per-dialect column preset helpers so every table gets timestamps, softDelete, tenant, id, audit, and json columns with one import — and because auto-api's features are convention-driven (detect deletedAt by name; updatedAt self-manages via drizzle $onUpdate), importing a preset activates the feature automatically. No extra config.",{"title":247,"path":248,"stem":249,"description":4886,"children":-1},"Subscriptions, plan-gated features and usage quotas on top of auto-api: the payment provider owns the money, a\nwebhook keeps a subscriptions table in sync, a context extender puts the caller's plan on every request, and\nresources gate on it like on any other permission. The UI uses Nuxt UI's pricing components.",1791106762662]