[{"data":1,"prerenderedAt":1456},["ShallowReactive",2],{"navigation":3,"\u002Fdeployment\u002Forigin-protection":553,"\u002Fdeployment\u002Forigin-protection-surround":1451},[4,22,64,89,215,503],{"title":5,"path":6,"stem":7,"children":8},"Introduction","\u002Fgetting-started","1.getting-started\u002F1.index",[9,10,14,18],{"title":5,"path":6,"stem":7},{"title":11,"path":12,"stem":13},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation",{"title":15,"path":16,"stem":17},"Key Ideas","\u002Fgetting-started\u002Fkey-ideas","1.getting-started\u002F3.key-ideas",{"title":19,"path":20,"stem":21},"Releases","\u002Fgetting-started\u002Freleases","1.getting-started\u002F4.releases",{"title":23,"path":24,"stem":25,"children":26},"Overview","\u002Fcore-concepts","2.core-concepts\u002F0.index",[27,28,32,36,40,44,48,52,56,60],{"title":23,"path":24,"stem":25},{"title":29,"path":30,"stem":31},"How It All Works","\u002Fcore-concepts\u002Farchitecture","2.core-concepts\u002F1.architecture",{"title":33,"path":34,"stem":35},"The Data Model","\u002Fcore-concepts\u002Fthe-data-model","2.core-concepts\u002F2.the-data-model",{"title":37,"path":38,"stem":39},"Layouts & Pages","\u002Fcore-concepts\u002Flayouts-and-pages","2.core-concepts\u002F3.layouts-and-pages",{"title":41,"path":42,"stem":43},"Dynamic Pages","\u002Fcore-concepts\u002Fdynamic-pages","2.core-concepts\u002F4.dynamic-pages",{"title":45,"path":46,"stem":47},"Components","\u002Fcore-concepts\u002Fcomponents","2.core-concepts\u002F5.components",{"title":49,"path":50,"stem":51},"Draft & Publish Workflow","\u002Fcore-concepts\u002Fdraft-and-publish","2.core-concepts\u002F6.draft-and-publish",{"title":53,"path":54,"stem":55},"The Admin Panel","\u002Fcore-concepts\u002Fadmin-panel","2.core-concepts\u002F7.admin-panel",{"title":57,"path":58,"stem":59},"Caching","\u002Fcore-concepts\u002Fcaching","2.core-concepts\u002F8.caching",{"title":61,"path":62,"stem":63},"Glossary","\u002Fcore-concepts\u002Fglossary","2.core-concepts\u002F9.glossary",{"title":23,"path":65,"stem":66,"children":67},"\u002Fguides","3.guides\u002F0.index",[68,69,73,77,81,85],{"title":23,"path":65,"stem":66},{"title":70,"path":71,"stem":72},"Your First Layout","\u002Fguides\u002Fyour-first-layout","3.guides\u002F1.your-first-layout",{"title":74,"path":75,"stem":76},"Your First Page Template","\u002Fguides\u002Fyour-first-page-template","3.guides\u002F2.your-first-page-template",{"title":78,"path":79,"stem":80},"Your First Component","\u002Fguides\u002Fyour-first-component","3.guides\u002F3.your-first-component",{"title":82,"path":83,"stem":84},"Alternative UI Variants","\u002Fguides\u002Falternative-ui-variants","3.guides\u002F4.alternative-ui-variants",{"title":86,"path":87,"stem":88},"Your First Dynamic Page","\u002Fguides\u002Fyour-first-dynamic-page","3.guides\u002F5.your-first-dynamic-page",{"title":23,"path":90,"stem":91,"children":92},"\u002Fapi","4.api\u002F0.index",[93,94,98,102,120,162,166,170,195,199,203,207,211],{"title":23,"path":90,"stem":91},{"title":95,"path":96,"stem":97},"Bundle Setup","\u002Fapi\u002Fbundle-setup","4.api\u002F02.bundle-setup",{"title":99,"path":100,"stem":101},"Configuration Reference","\u002Fapi\u002Fconfiguration","4.api\u002F03.configuration",{"title":103,"path":104,"stem":105,"children":106,"page":119},"Users","\u002Fapi\u002Fusers","4.api\u002F04.users",[107,111,115],{"title":108,"path":109,"stem":110},"Authentication","\u002Fapi\u002Fusers\u002Fauthentication","4.api\u002F04.users\u002F1.authentication",{"title":112,"path":113,"stem":114},"User Emails","\u002Fapi\u002Fusers\u002Fuser-emails","4.api\u002F04.users\u002F2.user-emails",{"title":116,"path":117,"stem":118},"Access Control","\u002Fapi\u002Fusers\u002Faccess-control","4.api\u002F04.users\u002F3.access-control",false,{"title":45,"path":121,"stem":122,"children":123,"page":119},"\u002Fapi\u002Fcomponents","4.api\u002F05.components",[124,128,149],{"title":125,"path":126,"stem":127},"Creating Components","\u002Fapi\u002Fcomponents\u002Fcreating-components","4.api\u002F05.components\u002F1.creating-components",{"title":129,"path":130,"stem":131,"children":132,"page":119},"Annotations","\u002Fapi\u002Fcomponents\u002Fannotations","4.api\u002F05.components\u002F2.annotations",[133,137,141,145],{"title":134,"path":135,"stem":136},"Publishable","\u002Fapi\u002Fcomponents\u002Fannotations\u002Fpublishable","4.api\u002F05.components\u002F2.annotations\u002F1.publishable",{"title":138,"path":139,"stem":140},"Uploadable","\u002Fapi\u002Fcomponents\u002Fannotations\u002Fuploadable","4.api\u002F05.components\u002F2.annotations\u002F2.uploadable",{"title":142,"path":143,"stem":144},"Timestamped","\u002Fapi\u002Fcomponents\u002Fannotations\u002Ftimestamped","4.api\u002F05.components\u002F2.annotations\u002F3.timestamped",{"title":146,"path":147,"stem":148},"Explicit Allow Only","\u002Fapi\u002Fcomponents\u002Fannotations\u002Fexplicit-allow-only","4.api\u002F05.components\u002F2.annotations\u002F4.explicit-allow-only",{"title":150,"path":151,"stem":152,"children":153,"page":119},"Built Ins","\u002Fapi\u002Fcomponents\u002Fbuilt-ins","4.api\u002F05.components\u002F3.built-ins",[154,158],{"title":155,"path":156,"stem":157},"Collection Component","\u002Fapi\u002Fcomponents\u002Fbuilt-ins\u002Fcollection-component","4.api\u002F05.components\u002F3.built-ins\u002F1.collection-component",{"title":159,"path":160,"stem":161},"Form Component","\u002Fapi\u002Fcomponents\u002Fbuilt-ins\u002Fform-component","4.api\u002F05.components\u002F3.built-ins\u002F2.form-component",{"title":163,"path":164,"stem":165},"Page Data & Nested Pages","\u002Fapi\u002Fdynamic-pages","4.api\u002F06.dynamic-pages",{"title":167,"path":168,"stem":169},"Routes","\u002Fapi\u002Froutes","4.api\u002F07.routes",{"title":171,"path":172,"stem":173,"children":174,"page":119},"Data Fixtures","\u002Fapi\u002Fdata-fixtures","4.api\u002F08.data-fixtures",[175,179,183,187,191],{"title":176,"path":177,"stem":178},"Getting Started with Fixtures","\u002Fapi\u002Fdata-fixtures\u002Fgetting-started","4.api\u002F08.data-fixtures\u002F1.getting-started",{"title":180,"path":181,"stem":182},"Builder Reference","\u002Fapi\u002Fdata-fixtures\u002Fbuilder-reference","4.api\u002F08.data-fixtures\u002F2.builder-reference",{"title":184,"path":185,"stem":186},"Seeding Content","\u002Fapi\u002Fdata-fixtures\u002Fseeding-content","4.api\u002F08.data-fixtures\u002F3.seeding-content",{"title":188,"path":189,"stem":190},"Appending & Multiple Scaffolds","\u002Fapi\u002Fdata-fixtures\u002Fappending","4.api\u002F08.data-fixtures\u002F4.appending",{"title":192,"path":193,"stem":194},"Generating Fixtures","\u002Fapi\u002Fdata-fixtures\u002Fgenerating-fixtures","4.api\u002F08.data-fixtures\u002F5.generating-fixtures",{"title":196,"path":197,"stem":198},"Real-Time (Mercure)","\u002Fapi\u002Freal-time","4.api\u002F09.real-time",{"title":200,"path":201,"stem":202},"HTTP Caching","\u002Fapi\u002Fhttp-caching","4.api\u002F10.http-caching",{"title":204,"path":205,"stem":206},"Orphaned Data","\u002Fapi\u002Forphaned-data","4.api\u002F11.orphaned-data",{"title":208,"path":209,"stem":210},"Console Commands","\u002Fapi\u002Fconsole-commands","4.api\u002F12.console-commands",{"title":212,"path":213,"stem":214},"Debugging & Errors","\u002Fapi\u002Fdebugging","4.api\u002F13.debugging",{"title":23,"path":216,"stem":217,"children":218},"\u002Fnuxt-module","5.nuxt-module\u002F0.index",[219,220,224,237,257,286,307,430,464,467,495,499],{"title":23,"path":216,"stem":217},{"title":221,"path":222,"stem":223},"Module Setup","\u002Fnuxt-module\u002Fmodule-setup","5.nuxt-module\u002F01.module-setup",{"title":225,"path":226,"stem":227,"children":228,"page":119},"Configuration","\u002Fnuxt-module\u002Fconfiguration","5.nuxt-module\u002F02.configuration",[229,233],{"title":230,"path":231,"stem":232},"Nuxt Config","\u002Fnuxt-module\u002Fconfiguration\u002Fnuxt-config","5.nuxt-module\u002F02.configuration\u002F1.nuxt-config",{"title":234,"path":235,"stem":236},"Site Config & SEO","\u002Fnuxt-module\u002Fconfiguration\u002Fsite-config-and-seo","5.nuxt-module\u002F02.configuration\u002F2.site-config-and-seo",{"title":238,"path":239,"stem":240,"children":241,"page":119},"Building Your Ui","\u002Fnuxt-module\u002Fbuilding-your-ui","5.nuxt-module\u002F03.building-your-ui",[242,246,250,253],{"title":243,"path":244,"stem":245},"Layouts","\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-layouts","5.nuxt-module\u002F03.building-your-ui\u002F1.creating-layouts",{"title":247,"path":248,"stem":249},"Page Templates","\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-page-templates","5.nuxt-module\u002F03.building-your-ui\u002F2.creating-page-templates",{"title":45,"path":251,"stem":252},"\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-components","5.nuxt-module\u002F03.building-your-ui\u002F3.creating-components",{"title":254,"path":255,"stem":256},"CLI Generator","\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcwa-cli","5.nuxt-module\u002F03.building-your-ui\u002F4.cwa-cli",{"title":258,"path":259,"stem":260,"children":261,"page":119},"Component Helpers","\u002Fnuxt-module\u002Fcomponent-helpers","5.nuxt-module\u002F04.component-helpers",[262,266,270,274,278,282],{"title":263,"path":264,"stem":265},"Images & Media","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fimages-and-uploads","5.nuxt-module\u002F04.component-helpers\u002F1.images-and-uploads",{"title":267,"path":268,"stem":269},"Collections & Pagination","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fcollections-and-pagination","5.nuxt-module\u002F04.component-helpers\u002F2.collections-and-pagination",{"title":271,"path":272,"stem":273},"HTML Content","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fhtml-content","5.nuxt-module\u002F04.component-helpers\u002F3.html-content",{"title":275,"path":276,"stem":277},"Rich-Text Editor","\u002Fnuxt-module\u002Fcomponent-helpers\u002Frich-text-editor","5.nuxt-module\u002F04.component-helpers\u002F4.rich-text-editor",{"title":279,"path":280,"stem":281},"Real-Time Updates","\u002Fnuxt-module\u002Fcomponent-helpers\u002Freal-time-updates","5.nuxt-module\u002F04.component-helpers\u002F5.real-time-updates",{"title":283,"path":284,"stem":285},"Forms","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fforms","5.nuxt-module\u002F04.component-helpers\u002F6.forms",{"title":287,"path":288,"stem":289,"children":290,"page":119},"Cwa Components","\u002Fnuxt-module\u002Fcwa-components","5.nuxt-module\u002F05.cwa-components",[291,295,299,303],{"title":292,"path":293,"stem":294},"\u003CCwaComponentGroup \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-component-group","5.nuxt-module\u002F05.cwa-components\u002F1.cwa-component-group",{"title":296,"path":297,"stem":298},"\u003CCwaPage \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-page","5.nuxt-module\u002F05.cwa-components\u002F2.cwa-page",{"title":300,"path":301,"stem":302},"\u003CCwaLink \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-link","5.nuxt-module\u002F05.cwa-components\u002F3.cwa-link",{"title":304,"path":305,"stem":306},"\u003CCwaDefaultLayout \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-default-layout","5.nuxt-module\u002F05.cwa-components\u002F5.cwa-default-layout",{"title":308,"path":309,"stem":310,"children":311,"page":119},"Composables","\u002Fnuxt-module\u002Fcomposables","5.nuxt-module\u002F06.composables",[312,315,323,348,368,385,405],{"title":23,"path":313,"stem":314},"\u002Fnuxt-module\u002Fcomposables\u002Foverview","5.nuxt-module\u002F06.composables\u002F0.overview",{"title":316,"path":317,"stem":318,"children":319,"page":119},"Layout","\u002Fnuxt-module\u002Fcomposables\u002Flayout","5.nuxt-module\u002F06.composables\u002F1.layout",[320],{"title":316,"path":321,"stem":322},"\u002Fnuxt-module\u002Fcomposables\u002Flayout\u002Fuse-cwa-layout","5.nuxt-module\u002F06.composables\u002F1.layout\u002F1.use-cwa-layout",{"title":324,"path":325,"stem":326,"children":327,"page":119},"Component","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent","5.nuxt-module\u002F06.composables\u002F2.component",[328,332,336,340,344],{"title":329,"path":330,"stem":331},"Component (recommended)","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-component","5.nuxt-module\u002F06.composables\u002F2.component\u002F1.use-cwa-component",{"title":333,"path":334,"stem":335},"Resource","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-resource","5.nuxt-module\u002F06.composables\u002F2.component\u002F2.use-cwa-resource",{"title":337,"path":338,"stem":339},"File Field","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-file-field","5.nuxt-module\u002F06.composables\u002F2.component\u002F3.use-cwa-file-field",{"title":341,"path":342,"stem":343},"Collection Pagination","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-collection-pagination","5.nuxt-module\u002F06.composables\u002F2.component\u002F4.use-cwa-collection-pagination",{"title":345,"path":346,"stem":347},"Collection Resource (deprecated)","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-collection-resource","5.nuxt-module\u002F06.composables\u002F2.component\u002F9.use-cwa-collection-resource",{"title":349,"path":350,"stem":351,"children":352,"page":119},"Form","\u002Fnuxt-module\u002Fcomposables\u002Fform","5.nuxt-module\u002F06.composables\u002F3.form",[353,356,360,364],{"title":349,"path":354,"stem":355},"\u002Fnuxt-module\u002Fcomposables\u002Fform\u002Fuse-cwa-form","5.nuxt-module\u002F06.composables\u002F3.form\u002F1.use-cwa-form",{"title":357,"path":358,"stem":359},"Form Input","\u002Fnuxt-module\u002Fcomposables\u002Fform\u002Fuse-cwa-form-input","5.nuxt-module\u002F06.composables\u002F3.form\u002F2.use-cwa-form-input",{"title":361,"path":362,"stem":363},"Form Repeated","\u002Fnuxt-module\u002Fcomposables\u002Fform\u002Fuse-cwa-form-repeated","5.nuxt-module\u002F06.composables\u002F3.form\u002F3.use-cwa-form-repeated",{"title":365,"path":366,"stem":367},"Form Collection","\u002Fnuxt-module\u002Fcomposables\u002Fform\u002Fuse-cwa-form-collection","5.nuxt-module\u002F06.composables\u002F3.form\u002F4.use-cwa-form-collection",{"title":369,"path":370,"stem":371,"children":372,"page":119},"Admin Manager","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager","5.nuxt-module\u002F06.composables\u002F4.admin-manager",[373,377,381],{"title":374,"path":375,"stem":376},"Manager Tab","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-manager-tab","5.nuxt-module\u002F06.composables\u002F4.admin-manager\u002F1.use-cwa-resource-manager-tab",{"title":378,"path":379,"stem":380},"Resource Model","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-model","5.nuxt-module\u002F06.composables\u002F4.admin-manager\u002F2.use-cwa-resource-model",{"title":382,"path":383,"stem":384},"Resource Upload","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-upload","5.nuxt-module\u002F06.composables\u002F4.admin-manager\u002F3.use-cwa-resource-upload",{"title":386,"path":387,"stem":388,"children":389,"page":119},"Utilities","\u002Fnuxt-module\u002Fcomposables\u002Futilities","5.nuxt-module\u002F06.composables\u002F5.utilities",[390,394,398,402],{"title":391,"path":392,"stem":393},"Resource Endpoint","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-cwa-resource-endpoint","5.nuxt-module\u002F06.composables\u002F5.utilities\u002F1.use-cwa-resource-endpoint",{"title":395,"path":396,"stem":397},"Query Model","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-query-bound-model","5.nuxt-module\u002F06.composables\u002F5.utilities\u002F2.use-query-bound-model",{"title":399,"path":400,"stem":401},"Resource Route","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-cwa-resource-route","5.nuxt-module\u002F06.composables\u002F5.utilities\u002F3.use-cwa-resource-route",{"title":271,"path":403,"stem":404},"\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-html-content","5.nuxt-module\u002F06.composables\u002F5.utilities\u002F4.use-html-content",{"title":406,"path":407,"stem":408,"children":409,"page":119},"Auth","\u002Fnuxt-module\u002Fcomposables\u002Fauth","5.nuxt-module\u002F06.composables\u002F6.auth",[410,414,418,422,426],{"title":411,"path":412,"stem":413},"Login","\u002Fnuxt-module\u002Fcomposables\u002Fauth\u002Fuse-login","5.nuxt-module\u002F06.composables\u002F6.auth\u002F1.use-login",{"title":415,"path":416,"stem":417},"Forgot Password","\u002Fnuxt-module\u002Fcomposables\u002Fauth\u002Fuse-forgot-password","5.nuxt-module\u002F06.composables\u002F6.auth\u002F2.use-forgot-password",{"title":419,"path":420,"stem":421},"Reset Password","\u002Fnuxt-module\u002Fcomposables\u002Fauth\u002Fuse-reset-password","5.nuxt-module\u002F06.composables\u002F6.auth\u002F3.use-reset-password",{"title":423,"path":424,"stem":425},"Verify Email","\u002Fnuxt-module\u002Fcomposables\u002Fauth\u002Fuse-verify-email","5.nuxt-module\u002F06.composables\u002F6.auth\u002F4.use-verify-email",{"title":427,"path":428,"stem":429},"Resend Verify Email","\u002Fnuxt-module\u002Fcomposables\u002Fauth\u002Fuse-resend-verify-email","5.nuxt-module\u002F06.composables\u002F6.auth\u002F5.use-resend-verify-email",{"title":431,"path":432,"stem":433,"children":434,"page":119},"Cwa Api","\u002Fnuxt-module\u002Fcwa-api","5.nuxt-module\u002F07.cwa-api",[435,438,442,446,449,452,456,460],{"title":23,"path":436,"stem":437},"\u002Fnuxt-module\u002Fcwa-api\u002Foverview","5.nuxt-module\u002F07.cwa-api\u002F1.overview",{"title":439,"path":440,"stem":441},"Resources","\u002Fnuxt-module\u002Fcwa-api\u002Fresources","5.nuxt-module\u002F07.cwa-api\u002F2.resources",{"title":443,"path":444,"stem":445},"Resources Manager","\u002Fnuxt-module\u002Fcwa-api\u002Fresources-manager","5.nuxt-module\u002F07.cwa-api\u002F3.resources-manager",{"title":406,"path":447,"stem":448},"\u002Fnuxt-module\u002Fcwa-api\u002Fauth","5.nuxt-module\u002F07.cwa-api\u002F4.auth",{"title":283,"path":450,"stem":451},"\u002Fnuxt-module\u002Fcwa-api\u002Fforms","5.nuxt-module\u002F07.cwa-api\u002F5.forms",{"title":453,"path":454,"stem":455},"Admin","\u002Fnuxt-module\u002Fcwa-api\u002Fadmin","5.nuxt-module\u002F07.cwa-api\u002F6.admin",{"title":457,"path":458,"stem":459},"Site Config","\u002Fnuxt-module\u002Fcwa-api\u002Fsite-config","5.nuxt-module\u002F07.cwa-api\u002F7.site-config",{"title":461,"path":462,"stem":463},"Orphaned Resources","\u002Fnuxt-module\u002Fcwa-api\u002Forphaned-resources","5.nuxt-module\u002F07.cwa-api\u002F8.orphaned-resources",{"title":108,"path":465,"stem":466},"\u002Fnuxt-module\u002Fauthentication","5.nuxt-module\u002F08.authentication",{"title":468,"path":469,"stem":470,"children":471,"page":119},"Cwa Layer","\u002Fnuxt-module\u002Fcwa-layer","5.nuxt-module\u002F9.cwa-layer",[472,475,479,483,487,491],{"title":23,"path":473,"stem":474},"\u002Fnuxt-module\u002Fcwa-layer\u002Foverview","5.nuxt-module\u002F9.cwa-layer\u002F1.overview",{"title":476,"path":477,"stem":478},"Auth Pages","\u002Fnuxt-module\u002Fcwa-layer\u002Fauth-pages","5.nuxt-module\u002F9.cwa-layer\u002F2.auth-pages",{"title":480,"path":481,"stem":482},"Admin Panel","\u002Fnuxt-module\u002Fcwa-layer\u002Fadmin-panel","5.nuxt-module\u002F9.cwa-layer\u002F3.admin-panel",{"title":484,"path":485,"stem":486},"Styling","\u002Fnuxt-module\u002Fcwa-layer\u002Fstyling","5.nuxt-module\u002F9.cwa-layer\u002F4.styling",{"title":488,"path":489,"stem":490},"Date Pickers","\u002Fnuxt-module\u002Fcwa-layer\u002Fdate-pickers","5.nuxt-module\u002F9.cwa-layer\u002F5.date-pickers",{"title":492,"path":493,"stem":494},"Maintenance","\u002Fnuxt-module\u002Fcwa-layer\u002Fmaintenance","5.nuxt-module\u002F9.cwa-layer\u002F6.maintenance",{"title":496,"path":497,"stem":498},"PWA & Offline","\u002Fnuxt-module\u002Fpwa","5.nuxt-module\u002F91.pwa",{"title":500,"path":501,"stem":502},"Page Caching","\u002Fnuxt-module\u002Fpage-caching","5.nuxt-module\u002F92.page-caching",{"title":504,"path":505,"stem":506,"children":507},"Deploying a CWA Site","\u002Fdeployment","6.deployment\u002F0.index",[508,509,513,517,521,525,529,533,537,541,545,549],{"title":504,"path":505,"stem":506},{"title":510,"path":511,"stem":512},"Docker","\u002Fdeployment\u002Fdocker","6.deployment\u002F1.docker",{"title":514,"path":515,"stem":516},"Kubernetes & Helm","\u002Fdeployment\u002Fkubernetes","6.deployment\u002F2.kubernetes",{"title":518,"path":519,"stem":520},"CI\u002FCD","\u002Fdeployment\u002Fci-cd","6.deployment\u002F3.ci-cd",{"title":522,"path":523,"stem":524},"CI\u002FCD Variables","\u002Fdeployment\u002Fvariables","6.deployment\u002F4.variables",{"title":526,"path":527,"stem":528},"Cloudflare","\u002Fdeployment\u002Fcloudflare","6.deployment\u002F5.cloudflare",{"title":530,"path":531,"stem":532},"Origin Protection","\u002Fdeployment\u002Forigin-protection","6.deployment\u002F5.origin-protection",{"title":534,"path":535,"stem":536},"Load Testing","\u002Fdeployment\u002Fload-testing","6.deployment\u002F6.load-testing",{"title":538,"path":539,"stem":540},"Performance Audit","\u002Fdeployment\u002Fperformance-audit","6.deployment\u002F6.performance-audit",{"title":542,"path":543,"stem":544},"Reading Lighthouse Scores","\u002Fdeployment\u002Freading-lighthouse-scores","6.deployment\u002F6.reading-lighthouse-scores",{"title":546,"path":547,"stem":548},"Faster Functional Tests","\u002Fdeployment\u002Ffaster-functional-tests","6.deployment\u002F7.faster-functional-tests",{"title":550,"path":551,"stem":552},"Troubleshooting","\u002Fdeployment\u002Ftroubleshooting","6.deployment\u002F7.troubleshooting",{"id":554,"title":530,"badge":555,"body":556,"description":1445,"extension":1446,"links":555,"meta":1447,"navigation":1448,"path":531,"seo":1449,"stem":532,"__hash__":1450},"docs\u002F6.deployment\u002F5.origin-protection.md",null,{"type":557,"value":558,"toc":1436},"minimark",[559,563,579,590,595,607,626,633,649,718,757,783,796,818,831,835,845,856,921,1002,1095,1099,1114,1138,1158,1163,1166,1218,1229,1241,1245,1260,1316,1331,1342,1371,1375,1382,1425,1432],[560,561,562],"p",{},"A cache only protects the origin if requests can't get past it. These settings stop made-up URLs and floods of requests from reaching Nuxt and php. They belong to the template's Caddyfile and Helm chart, not to the module or the bundle.",[560,564,565,568,569,573,574,578],{},[566,567,57],"a",{"href":58}," shows where these sit among the other layers. Every setting is also listed in ",[566,570,572],{"href":571},"\u002Fdeployment\u002Fvariables#origin-protection","CI\u002FCD Variables → Origin protection",", and the compose names are in ",[566,575,577],{"href":576},"\u002Fdeployment\u002Fdocker#origin-protection-settings","Docker → Origin protection settings",".",[580,581,583],"callout",{"icon":582},"i-heroicons-photo",[560,584,585,589],{},[586,587,588],"strong",{},"Image placeholder:"," a request flow through Caddy: tracking parameters stripped, then the query allowlist, then the Souin cache, with the rate limit counting only misses, and ingress-nginx's optional outer limit in front.",[591,592,594],"h2",{"id":593},"query-parameters-on-pages","Query Parameters on Pages",[560,596,597,598,602,603,606],{},"The query string is part of the cache key, so without help every new query string is a cache miss. ",[599,600,601],"code",{},"\u002F?x=1",", ",[599,604,605],{},"\u002F?x=2"," and so on would each cost a server-side render, and one client could get past the cache entirely by making up values.",[560,608,609,610,613,614,617,618,621,622,625],{},"The template's Caddyfile keeps only the query parameters that pages read, and drops every other one before the cache sees the request. ",[599,611,612],{},"\u002F?x=123"," is served the cached entry for ",[599,615,616],{},"\u002F",", and ",[599,619,620],{},"\u002Fblog?page=2&x=9"," reaches the cache and Nuxt as ",[599,623,624],{},"\u002Fblog?page=2",". The browser's address bar keeps the full URL.",[560,627,628,629,632],{},"The list is the ",[599,630,631],{},"CACHE_QUERY_ALLOWLIST"," variable on the php container. Its default is what the module's pages read:",[634,635,640],"pre",{"className":636,"code":637,"language":638,"meta":639,"style":639},"language-ini shiki shiki-themes github-light github-dark material-theme-palenight","CACHE_QUERY_ALLOWLIST=\"page search order\"\n","ini","",[599,641,642],{"__ignoreMap":639},[643,644,647],"span",{"class":645,"line":646},"line",1,[643,648,637],{},[650,651,652,663,669,704],"ul",{},[653,654,655,656,659,660,578],"li",{},"It's a space-separated list of names. A name also keeps its bracketed forms, so ",[599,657,658],{},"order"," keeps ",[599,661,662],{},"order[title]",[653,664,665,668],{},[599,666,667],{},"*"," turns the allowlist off. Wildcards aren't supported.",[653,670,671,672,675,676,602,679,602,682,602,685,602,688,602,691,602,694,602,697,700,701,578],{},"It only runs on pages that can be cached: paths with no file extension, with no auth cookie or ",[599,673,674],{},"Authorization"," header. It never touches ",[599,677,678],{},"\u002F_api",[599,680,681],{},"\u002F_nuxt",[599,683,684],{},"\u002F__*",[599,686,687],{},"\u002F.well-known",[599,689,690],{},"\u002Fuploads",[599,692,693],{},"\u002Fbundles",[599,695,696],{},"\u002F_cwa",[599,698,699],{},"\u002Fuser-area"," or the login, password and email-verification pages, which read their own parameters such as ",[599,702,703],{},"?redirect=",[653,705,706,708,709,712,713,717],{},[599,707,678],{}," keeps every parameter, because each API resource declares its own ",[599,710,711],{},"parameters:"," and collections take the page query. The ",[566,714,716],{"href":715},"#rate-limit-on-cache-misses","rate limit"," protects the API instead.",[580,719,722],{"icon":720,"color":721},"i-heroicons-exclamation-triangle","warning",[560,723,724,731,732,735,736,739,740,743,744,750,751,753,754,756],{},[586,725,726,727,730],{},"Never add ",[599,728,729],{},"cwa_force"," to the list."," Only the admin uses the parameter, and requests with a login cookie skip the allowlist, so admins still get it. Kept for anonymous requests, every made-up value would be a cache miss that reaches Nuxt, and on ",[599,733,734],{},"@cwa\u002Fnuxt"," ",[599,737,738],{},"2.0.0-alpha.3"," and earlier a value other than ",[599,741,742],{},"true"," sent the server render into an endless redirect (",[566,745,749],{"href":746,"rel":747},"https:\u002F\u002Fgithub.com\u002Fcomponents-web-app\u002Fcwa-nuxt-module\u002Freleases\u002Ftag\u002Fv2.0.0-alpha.4",[748],"nofollow","the module 2.0.0-alpha.4 release notes","). If you set ",[599,752,631],{}," yourself, check that ",[599,755,729],{}," isn't in it.",[580,758,759],{"icon":720,"color":721},[560,760,761,764,765,602,768,771,772,775,776,779,780,578],{},[586,762,763],{},"Add your own pages' parameters to the list."," If a page reads a query parameter other than ",[599,766,767],{},"page",[599,769,770],{},"search"," or ",[599,773,774],{},"order[...]",", for example a filter you bind with ",[599,777,778],{},"useQueryBoundModel('category')",", server-side rendering never sees it. Set ",[599,781,782],{},"CACHE_QUERY_ALLOWLIST=\"page search order category\"",[560,784,785,786,789,790,793,794,578],{},"Set it in ",[599,787,788],{},".env"," or the shell for compose, or as the CI variable ",[599,791,792],{},"CWA_API_CACHE_QUERY_ALLOWLIST"," for a Kubernetes deploy. See ",[566,795,572],{"href":571},[560,797,798,799,802,803,806,807,810,811,813,814,578],{},"The allowlist is the template's own Caddy handler, ",[599,800,801],{},"query_allowlist"," (",[599,804,805],{},"api\u002Ffrankenphp\u002Fcaddy\u002Fqueryallowlist","), because Caddy's ",[599,808,809],{},"uri query"," can only delete parameters it's told the names of. It removes whole pairs and leaves the rest of the query byte for byte, so it never re-encodes it the way ",[599,812,809],{}," does. The php image must be rebuilt to include it: see ",[566,815,817],{"href":816},"\u002Fdeployment\u002Ftroubleshooting#caddy-and-souin","Troubleshooting → Caddy and Souin",[580,819,821],{"icon":820},"i-heroicons-information-circle",[560,822,823,824,827,828,578],{},"If you edit the Caddyfile, keep the ",[599,825,826],{},"@page_query"," matcher's path exclusions in step with the HTML branch of ",[599,829,830],{},"@use_cache",[591,832,834],{"id":833},"tracking-parameters","Tracking Parameters",[560,836,837,838,771,841,844],{},"The query string is part of the cache key. Without help, every ",[599,839,840],{},"?utm_source=…",[599,842,843],{},"gclid"," value would render and store its own copy of a page, so ad clicks and shared links would always miss the cache. The API would be split the same way, because the module passes the page query on to Collection fetches.",[560,846,847,848,851,852,855],{},"The template's Caddyfile drops these parameters before the cache sees the request. A ",[599,849,850],{},"@tracking_query"," matcher decides when to run a ",[599,853,854],{},"uri query { … }"," block:",[634,857,861],{"className":858,"code":859,"language":860,"meta":639,"style":639},"language-caddyfile shiki shiki-themes github-light github-dark material-theme-palenight","@tracking_query {\n    not path \u002F_nuxt\u002F*\n    expression `{http.request.uri.query}.matches(\"(^|&)(utm_source|utm_medium|…|mc_eid)(=|&|$)\")`\n}\nuri @tracking_query query {\n    -utm_source\n    -utm_medium\n    -utm_campaign\n    # … the rest of the list\n}\n","caddyfile",[599,862,863,868,874,880,886,892,898,904,910,916],{"__ignoreMap":639},[643,864,865],{"class":645,"line":646},[643,866,867],{},"@tracking_query {\n",[643,869,871],{"class":645,"line":870},2,[643,872,873],{},"    not path \u002F_nuxt\u002F*\n",[643,875,877],{"class":645,"line":876},3,[643,878,879],{},"    expression `{http.request.uri.query}.matches(\"(^|&)(utm_source|utm_medium|…|mc_eid)(=|&|$)\")`\n",[643,881,883],{"class":645,"line":882},4,[643,884,885],{},"}\n",[643,887,889],{"class":645,"line":888},5,[643,890,891],{},"uri @tracking_query query {\n",[643,893,895],{"class":645,"line":894},6,[643,896,897],{},"    -utm_source\n",[643,899,901],{"class":645,"line":900},7,[643,902,903],{},"    -utm_medium\n",[643,905,907],{"class":645,"line":906},8,[643,908,909],{},"    -utm_campaign\n",[643,911,913],{"class":645,"line":912},9,[643,914,915],{},"    # … the rest of the list\n",[643,917,919],{"class":645,"line":918},10,[643,920,885],{},[560,922,923,924,602,927,602,930,602,933,602,936,602,939,602,942,602,945,602,948,602,951,602,953,602,956,602,959,602,962,602,965,602,968,602,971,602,974,602,977,602,980,602,983,602,986,602,989,602,992,602,995,998,999,578],{},"The full list is ",[599,925,926],{},"utm_source",[599,928,929],{},"utm_medium",[599,931,932],{},"utm_campaign",[599,934,935],{},"utm_term",[599,937,938],{},"utm_content",[599,940,941],{},"utm_id",[599,943,944],{},"utm_source_platform",[599,946,947],{},"utm_creative_format",[599,949,950],{},"utm_marketing_tactic",[599,952,843],{},[599,954,955],{},"gclsrc",[599,957,958],{},"gbraid",[599,960,961],{},"wbraid",[599,963,964],{},"dclid",[599,966,967],{},"srsltid",[599,969,970],{},"_gl",[599,972,973],{},"_ga",[599,975,976],{},"fbclid",[599,978,979],{},"msclkid",[599,981,982],{},"twclid",[599,984,985],{},"ttclid",[599,987,988],{},"li_fat_id",[599,990,991],{},"igshid",[599,993,994],{},"yclid",[599,996,997],{},"mc_cid"," and ",[599,1000,1001],{},"mc_eid",[650,1003,1004,1024,1045,1062,1068,1085],{},[653,1005,1006,1009,1010,1012,1013,1016,1017,1020,1021,1023],{},[586,1007,1008],{},"It only runs when the query contains a listed parameter."," Caddy's ",[599,1011,809],{}," rewrites the whole query whenever it runs, even with nothing to remove, and turns a key with no value (",[599,1014,1015],{},"?k",") into ",[599,1018,1019],{},"k=",". Other requests keep their query exactly as sent. A query with a tracking parameter and a valueless key still gets ",[599,1022,1019],{},", which is harmless for pages.",[653,1025,1026,1032,1033,1036,1037,1040,1041,1044],{},[586,1027,1028,1029,578],{},"It never runs for ",[599,1030,1031],{},"\u002F_nuxt\u002F*"," In ",[599,1034,1035],{},"nuxt dev",", Vite asks for style blocks with URLs such as ",[599,1038,1039],{},"?vue&type=style&index=0&lang.css",". Rewritten to ",[599,1042,1043],{},"?vue=&…",", Vite served them as raw CSS and the app never mounted.",[653,1046,1047,1053,1054,1058,1059,1061],{},[586,1048,1049,1050,1052],{},"Every other path is covered, ",[599,1051,678],{}," included."," A URL with these parameters gets the same cache entry as the URL without them. On pages, the ",[566,1055,1057],{"href":1056},"#query-parameters-on-pages","query allowlist"," would drop them anyway. On ",[599,1060,678],{}," and the paths the allowlist skips, any other query parameter still gets its own entry.",[653,1063,1064,1067],{},[586,1065,1066],{},"Only the server loses them."," Analytics scripts (Google Analytics, Meta Pixel and so on) read them from the browser's address bar, so tracking still works.",[653,1069,1070,1073,1074,1076,1077,1080,1081,1084],{},[586,1071,1072],{},"Nuxt and php never see them."," If your project needs one on the server, remove it from the block and from the matcher's expression, and for pages add it to ",[599,1075,631],{}," too. To strip another parameter, add a ",[599,1078,1079],{},"-name"," line and add the name to the expression. The two lists must match. Wildcards are not supported. The expression is CEL, so keep it on one line and put no ",[599,1082,1083],{},"#"," comments inside it.",[653,1086,1087,1090,1091,1094],{},[586,1088,1089],{},"The access log still shows the original URL."," A ",[599,1092,1093],{},"utm_"," parameter in Caddy's log does not mean the strip failed.",[591,1096,1098],{"id":1097},"rate-limit-on-cache-misses","Rate Limit on Cache Misses",[560,1100,1101,1102,1105,1106,1109,1110,1113],{},"The template's Caddyfile limits how many requests each visitor can send that ",[586,1103,1104],{},"miss"," the cache. Over the limit, the visitor gets a ",[599,1107,1108],{},"429"," with a ",[599,1111,1112],{},"Retry-After"," header. The default is 3,000 requests a minute per visitor, in a sliding window, so a burst of the whole amount is allowed.",[650,1115,1116,1122,1132],{},[653,1117,1118,1121],{},[586,1119,1120],{},"Cache hits are never counted or refused."," The limit runs inside the cache, so only requests that reach php or Nuxt count: misses, and paths the cache doesn't store.",[653,1123,1124],{},[586,1125,1126,998,1128,1131],{},[599,1127,1031],{},[599,1129,1130],{},"\u002F.well-known\u002F*"," (Mercure) are never limited.",[653,1133,1134,1137],{},[586,1135,1136],{},"Private client addresses are never limited."," Server-side rendering, the deploy's cache warm and the kubelet's probes all reach php from inside the cluster or the compose network, and one SSR pod makes the API calls of every visitor it renders for.",[560,1139,1140,1141,998,1144,1147,1148,1151,1152,1155,1156,578],{},"The default is deliberately generous. A signed-in editor's requests are never cached, so one admin page makes dozens of uncached API calls, and an office or mobile network puts many visitors behind one address. It still stops a single client from sending misses as fast as it can. Tune it with ",[599,1142,1143],{},"RATE_LIMIT_EVENTS",[599,1145,1146],{},"RATE_LIMIT_WINDOW",", or turn it off with ",[599,1149,1150],{},"RATE_LIMIT_ENABLED=false",". Those are the names on the php container and in compose; as CI variables they're ",[599,1153,1154],{},"CWA_API_RATE_LIMIT_EVENTS"," and so on. See ",[566,1157,572],{"href":571},[1159,1160,1162],"h3",{"id":1161},"counting-the-real-visitor","Counting the Real Visitor",[560,1164,1165],{},"The limit counts each visitor by their own address, never a proxy's. Counting by a proxy's address would throttle every visitor behind it at once.",[650,1167,1168,1180,1190,1206],{},[653,1169,1170,1173,1174,1177,1178,578],{},[586,1171,1172],{},"Behind Cloudflare"," there's nothing to configure. A request that arrives from one of Cloudflare's address ranges, directly or through ingress-nginx, is counted by its ",[599,1175,1176],{},"CF-Connecting-IP"," header. The header is ignored from anywhere else, because anyone can send it. See ",[566,1179,526],{"href":527},[653,1181,1182,1185,1186,1189],{},[586,1183,1184],{},"On Kubernetes with ingress-nginx",", the ingress is a trusted proxy on a private address, so the visitor is read from ",[599,1187,1188],{},"X-Forwarded-For",", right to left. Entries a client puts in front of the real one are ignored.",[653,1191,1192,602,1199,1202,1203,1205],{},[586,1193,1194,1195,1198],{},"On a single server (",[599,1196,1197],{},"compose.prod.yaml",")",[599,1200,1201],{},"CADDY_EDGE=true"," is the default, so a direct client is counted by its own address and an ",[599,1204,1188],{}," it sends is never believed.",[653,1207,1208,1211,1212,1214,1215,578],{},[586,1209,1210],{},"Behind another CDN or load balancer with public addresses",", visitors are still counted separately, by the proxy's address plus the ",[599,1213,1188],{}," header. A client could then avoid the limit by inventing headers, so add the proxy's ranges to ",[599,1216,1217],{},"CADDY_TRUSTED_PROXIES",[560,1219,1220,1221,1224,1225,1228],{},"To check what the limit sees, read ",[599,1222,1223],{},"visitor_ip"," in php's access log. It's the address the limit counts. ",[599,1226,1227],{},"client_ip"," is the address that connected to Caddy, which behind Cloudflare is Cloudflare's.",[580,1230,1231],{"icon":720,"color":721},[560,1232,1233,1240],{},[586,1234,1235,1236,1239],{},"A request with ",[599,1237,1238],{},"Cache-Control: no-cache"," always misses the cache."," Souin forwards it to php or Nuxt every time, so it's a second way past the cache that the query allowlist doesn't close. The rate limit still counts it.",[591,1242,1244],{"id":1243},"ingress-rate-limits","Ingress rate limits",[560,1246,1247,1248,1251,1252,1255,1256,1259],{},"Caddy's ",[566,1249,1250],{"href":715},"rate limit on cache misses"," is the main protection, and it's on by default. ingress-nginx can add a coarser outer limit, which is off unless you set ",[599,1253,1254],{},"CWA_CI_INGRESS_RATE_LIMIT_RPS",". ",[599,1257,1258],{},"bin\u002Fdevops\u002Fk8s.sh"," then adds these annotations to the ingress:",[1261,1262,1263,1276],"table",{},[1264,1265,1266],"thead",{},[1267,1268,1269,1273],"tr",{},[1270,1271,1272],"th",{},"Variable",[1270,1274,1275],{},"Annotation",[1277,1278,1279,1291,1304],"tbody",{},[1267,1280,1281,1286],{},[1282,1283,1284],"td",{},[599,1285,1254],{},[1282,1287,1288],{},[599,1289,1290],{},"nginx.ingress.kubernetes.io\u002Flimit-rps",[1267,1292,1293,1298],{},[1282,1294,1295],{},[599,1296,1297],{},"CWA_CI_INGRESS_RATE_LIMIT_BURST_MULTIPLIER",[1282,1299,1300,1303],{},[599,1301,1302],{},"nginx.ingress.kubernetes.io\u002Flimit-burst-multiplier"," (nginx's default is 5)",[1267,1305,1306,1311],{},[1282,1307,1308],{},[599,1309,1310],{},"CWA_CI_INGRESS_RATE_LIMIT_CONNECTIONS",[1282,1312,1313],{},[599,1314,1315],{},"nginx.ingress.kubernetes.io\u002Flimit-connections",[560,1317,1318,1319,1321,1322,1325,1326,1328,1329,578],{},"The last two are only added when ",[599,1320,1254],{}," is set. Unlike Caddy's limit, nginx counts ",[586,1323,1324],{},"every"," request, cache hits and ",[599,1327,681],{}," files included, and one page load is dozens of requests. Set it far above Caddy's ",[599,1330,1143],{},[580,1332,1333],{"icon":720,"color":721},[560,1334,1335,1341],{},[586,1336,1337,1338,1340],{},"Don't set ",[599,1339,1254],{}," behind Cloudflare."," nginx counts by the address that connected to it, which behind Cloudflare is a Cloudflare server shared by many visitors, so it would throttle real visitors together. Only use it there if the ingress controller itself is configured to read the visitor's address from Cloudflare.",[580,1343,1344],{"icon":720,"color":721},[560,1345,1346,1353,1354,1357,1358,1361,1362,1367,1368,1370],{},[586,1347,1348,1349,1352],{},"Caddy's per-visitor rate limit needs ",[599,1350,1351],{},"externalTrafficPolicy: Local"," on ingress-nginx's own Service."," With the default ",[599,1355,1356],{},"Cluster",", nginx sees node addresses instead of visitors' addresses. Those are private, so Caddy treats every visitor as internal and its rate limit never applies. That fails safe, with no limit at all. ",[599,1359,1360],{},"Local"," keeps the visitor's address; run the controller with 2 replicas and a PodDisruptionBudget, as the template's own cluster does (",[566,1363,1366],{"href":1364,"rel":1365},"https:\u002F\u002Fgithub.com\u002Fcomponents-web-app\u002Fcomponents-web-app\u002Fissues\u002F135",[748],"#135","). Check ",[599,1369,1223],{}," in php's access log before you rely on the limit.",[591,1372,1374],{"id":1373},"load-shedding","Load shedding",[560,1376,1377,1378,1381],{},"php runs a fixed pool of 4 workers. When they're all busy, new requests wait for one. Left to queue, they would wait until Souin's 10-second backend timeout turned them into ",[599,1379,1380],{},"504","s, and every request behind them would do the same.",[560,1383,1384,1385,1388,1389,1392,1393,1396,1397,1400,1401,1405,1406,1409,1410,1413,1414,1417,1418,1421,1422,1424],{},"The production image gives up sooner. A request that waits ",[599,1386,1387],{},"FRANKENPHP_MAX_WAIT_TIME"," (default ",[599,1390,1391],{},"5s",") for a free worker gets a ",[599,1394,1395],{},"503"," at once. A flood then costs fast errors, and the queue empties as soon as it stops. Set it as the CI variable ",[599,1398,1399],{},"CWA_API_FRANKENPHP_MAX_WAIT_TIME"," (see ",[566,1402,1404],{"href":1403},"\u002Fdeployment\u002Fkubernetes#site-settings","Site settings","): a lower value such as ",[599,1407,1408],{},"2s"," sheds sooner, and ",[599,1411,1412],{},"0"," turns it off, so requests queue. It's FrankenPHP's ",[599,1415,1416],{},"max_wait_time",", set in ",[599,1419,1420],{},"api\u002Ffrankenphp\u002Fworker.Caddyfile",", so it only applies to the production image's worker mode, here and in ",[599,1423,1197],{},". The dev stack has no worker pool.",[560,1426,1427,1428,1431],{},"5 seconds matches the probes' ",[599,1429,1430],{},"timeoutSeconds: 5",", so a probe that can't get a worker fails exactly as it would have without shedding. Liveness needs 6 failures in a row, so a pod that's surviving a flood is only restarted if every probe for a minute is shed. Readiness takes it out of service after 3.",[1433,1434,1435],"style",{},"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);}",{"title":639,"searchDepth":870,"depth":870,"links":1437},[1438,1439,1440,1443,1444],{"id":593,"depth":870,"text":594},{"id":833,"depth":870,"text":834},{"id":1097,"depth":870,"text":1098,"children":1441},[1442],{"id":1161,"depth":876,"text":1162},{"id":1243,"depth":870,"text":1244},{"id":1373,"depth":870,"text":1374},"How the template keeps made-up URLs and request floods from getting past the cache - the query allowlist, tracking parameters, the rate limit on cache misses, ingress rate limits and load shedding.","md",{},true,{"title":530,"description":1445},"-M2WZOEKSoBiSNorJZRgh_NNljhYfCwp-i_mC66VpKs",[1452,1454],{"title":526,"path":527,"stem":528,"description":1453,"children":-1},"Putting a CWA site behind Cloudflare. Proxy only is the recommended default. Edge caching has been tested end to end on the Free plan and is a supported choice, with an optional second rule for API responses.",{"title":534,"path":535,"stem":536,"description":1455,"children":-1},"Stress test a CWA site with the template's k6 script — how many visitors it serves, how quickly, and whether they got the page cache or a server-side render.",1791855274549]