\n \n
\n Powered by zrok\n
\ndiff --git a/404.html b/404.html index 839821d9..7dc6d17f 100644 --- a/404.html +++ b/404.html @@ -10,8 +10,8 @@ - - + +
diff --git a/assets/js/11b43341.a279b12a.js b/assets/js/11b43341.a279b12a.js new file mode 100644 index 00000000..11b7a280 --- /dev/null +++ b/assets/js/11b43341.a279b12a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2256],{15293:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"current","label":"1.1","banner":null,"badge":true,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Getting Started","href":"/docs/getting-started","docId":"getting-started","unlisted":false},{"type":"category","label":"Concepts","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Private Shares","href":"/docs/concepts/sharing-private","docId":"concepts/sharing-private","unlisted":false},{"type":"link","label":"Public Shares","href":"/docs/concepts/sharing-public","docId":"concepts/sharing-public","unlisted":false},{"type":"link","label":"Reserved Shares","href":"/docs/concepts/sharing-reserved","docId":"concepts/sharing-reserved","unlisted":false},{"type":"link","label":"Sharing HTTP Servers","href":"/docs/concepts/http","docId":"concepts/http","unlisted":false},{"type":"link","label":"Sharing TCP and UDP Servers","href":"/docs/concepts/tunnels","docId":"concepts/tunnels","unlisted":false},{"type":"link","label":"Sharing Websites and Files","href":"/docs/concepts/files","docId":"concepts/files","unlisted":false},{"type":"link","label":"Open Source","href":"/docs/concepts/opensource","docId":"concepts/opensource","unlisted":false},{"type":"link","label":"Hosting","href":"/docs/concepts/hosting","docId":"concepts/hosting","unlisted":false}],"href":"/docs/concepts/"},{"type":"category","label":"Guides","collapsible":true,"collapsed":true,"items":[{"type":"category","label":"Install","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Linux","href":"/docs/guides/install/linux","docId":"guides/install/linux","unlisted":false},{"type":"link","label":"macOS","href":"/docs/guides/install/macos","docId":"guides/install/macos","unlisted":false},{"type":"link","label":"Windows","href":"/docs/guides/install/windows","docId":"guides/install/windows","unlisted":false}],"href":"/docs/guides/install/"},{"type":"category","label":"The zrok Agent","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Remoting","href":"/docs/guides/agent/remoting","docId":"guides/agent/remoting","unlisted":false},{"type":"link","label":"HTTP Health Checks","href":"/docs/guides/agent/http-healthcheck","docId":"guides/agent/http-healthcheck","unlisted":false},{"type":"link","label":"Linux Agent Service","href":"/docs/guides/agent/linux-service","docId":"guides/agent/linux-service","unlisted":false},{"type":"link","label":"Windows Agent Service","href":"/docs/guides/agent/windows-service/","docId":"guides/agent/windows-service/index","unlisted":false}],"href":"/docs/guides/agent/"},{"type":"link","label":"frontdoor","href":"/docs/guides/frontdoor","docId":"guides/frontdoor","unlisted":false},{"type":"link","label":"Permission Modes","href":"/docs/guides/permission-modes","docId":"guides/permission-modes","unlisted":false},{"type":"category","label":"Docker Share","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Public Share","href":"/docs/guides/docker-share/docker_public_share_guide","docId":"guides/docker-share/docker_public_share_guide","unlisted":false},{"type":"link","label":"Private Share","href":"/docs/guides/docker-share/docker_private_share_guide","docId":"guides/docker-share/docker_private_share_guide","unlisted":false}],"href":"/docs/guides/docker-share/"},{"type":"category","label":"Self Hosting","collapsible":true,"collapsed":true,"items":[{"type":"category","label":"Linux","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"NGINX TLS","href":"/docs/guides/self-hosting/linux/nginx","docId":"guides/self-hosting/linux/nginx","unlisted":false}],"href":"/docs/guides/self-hosting/linux/"},{"type":"link","label":"Personalized Frontend","href":"/docs/guides/self-hosting/personalized-frontend","docId":"guides/self-hosting/personalized-frontend","unlisted":false},{"type":"link","label":"Error Pages","href":"/docs/guides/self-hosting/error-pages","docId":"guides/self-hosting/error-pages","unlisted":false},{"type":"link","label":"Interstitial Pages","href":"/docs/guides/self-hosting/interstitial-page","docId":"guides/self-hosting/interstitial-page","unlisted":false},{"type":"link","label":"Organizations","href":"/docs/guides/self-hosting/organizations","docId":"guides/self-hosting/organizations","unlisted":false},{"type":"link","label":"Docker","href":"/docs/guides/self-hosting/docker","docId":"guides/self-hosting/docker","unlisted":false},{"type":"link","label":"Kubernetes","href":"/docs/guides/self-hosting/kubernetes","docId":"guides/self-hosting/kubernetes","unlisted":false},{"type":"category","label":"Metrics and Limits","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Configuring Metrics","href":"/docs/guides/self-hosting/metrics-and-limits/configuring-metrics","docId":"guides/self-hosting/metrics-and-limits/configuring-metrics","unlisted":false},{"type":"link","label":"Configuring Limits","href":"/docs/guides/self-hosting/metrics-and-limits/configuring-limits","docId":"guides/self-hosting/metrics-and-limits/configuring-limits","unlisted":false}],"href":"/docs/category/metrics-and-limits"},{"type":"category","label":"OAuth","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"OAuth Public Frontend Configuration","href":"/docs/guides/self-hosting/oauth/configuring-oauth","docId":"guides/self-hosting/oauth/configuring-oauth","unlisted":false},{"type":"category","label":"OAuth Integrations","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Google OAuth Setup","href":"/docs/guides/self-hosting/oauth/integrations/google","docId":"guides/self-hosting/oauth/integrations/google","unlisted":false},{"type":"link","label":"GitHub OAuth Setup","href":"/docs/guides/self-hosting/oauth/integrations/github","docId":"guides/self-hosting/oauth/integrations/github","unlisted":false},{"type":"link","label":"Generic OIDC Setup","href":"/docs/guides/self-hosting/oauth/integrations/oidc","docId":"guides/self-hosting/oauth/integrations/oidc","unlisted":false}],"href":"/docs/category/oauth-integrations"}],"href":"/docs/category/oauth"},{"type":"link","label":"Instance Config","href":"/docs/guides/self-hosting/instance-configuration","docId":"guides/self-hosting/instance-configuration","unlisted":false},{"type":"link","label":"Invitations","href":"/docs/guides/self-hosting/self-service-invite","docId":"guides/self-hosting/self-service-invite","unlisted":false}],"href":"/docs/category/self-hosting"},{"type":"link","label":"Drives","href":"/docs/guides/drives","docId":"guides/drives","unlisted":false},{"type":"link","label":"VPN","href":"/docs/guides/vpn/","docId":"guides/vpn/vpn","unlisted":false}],"href":"/docs/category/guides"},{"type":"category","label":"myzrok","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Custom Domains","href":"/docs/myzrok/custom-domains/","docId":"myzrok/custom-domains/index","unlisted":false},{"type":"link","label":"Limits","href":"/docs/myzrok/limits","docId":"myzrok/limits","unlisted":false},{"type":"link","label":"Upgrading From 0.4 to 1.0","href":"/docs/myzrok/upgrading","docId":"myzrok/upgrading","unlisted":false}],"href":"/docs/category/myzrok"}]},"docs":{"concepts/files":{"id":"concepts/files","title":"Sharing Websites and Files","description":"With zrok it is possible to share files quickly and easily as well. To share files using zrok use","sidebar":"tutorialSidebar"},"concepts/hosting":{"id":"concepts/hosting","title":"Hosting","description":"Self-Hosted","sidebar":"tutorialSidebar"},"concepts/http":{"id":"concepts/http","title":"Sharing HTTP Servers","description":"zrok can share HTTP and HTTPS resources natively. If you have an existing web server that you want to share with other users, you can use the zrok share command using the --backend-mode proxy flag.","sidebar":"tutorialSidebar"},"concepts/index":{"id":"concepts/index","title":"Concepts","description":"zrok was designed to make sharing local resources both secure and easy. In this section of the zrok documentation, we\'ll tour through all of the most important features.","sidebar":"tutorialSidebar"},"concepts/opensource":{"id":"concepts/opensource","title":"Open Source","description":"It\'s important to the zrok project that it remain free and open source software. The code is available on GitHub","sidebar":"tutorialSidebar"},"concepts/sharing-private":{"id":"concepts/sharing-private","title":"Private Shares","description":"zrok was built to share and access digital resources. A private share allows a resource to be","sidebar":"tutorialSidebar"},"concepts/sharing-public":{"id":"concepts/sharing-public","title":"Public Shares","description":"zrok supports public sharing for web-based (HTTP and HTTPS) resources. These resources are easily shared with the general internet through public access points.","sidebar":"tutorialSidebar"},"concepts/sharing-reserved":{"id":"concepts/sharing-reserved","title":"Reserved Shares","description":"By default, a public or private share is assigned a share token when you create a share using the zrok share command. The zrok share command is the bridge between your local environment and the users you are sharing with. When you terminate the zrok share, the bridge is eliminated and the share token is deleted. If you run zrok share again, you will be allocated a brand new share token.","sidebar":"tutorialSidebar"},"concepts/tunnels":{"id":"concepts/tunnels","title":"Sharing TCP and UDP Servers","description":"zrok includes support for sharing low-level TCP and UDP network resources using the tcpTunnel and udpTunnel backend modes.","sidebar":"tutorialSidebar"},"getting-started":{"id":"getting-started","title":"Getting Started","description":"Your Secure Internet Sharing Perimeter","sidebar":"tutorialSidebar"},"guides/agent/http-healthcheck":{"id":"guides/agent/http-healthcheck","title":"HTTP Health Checks","description":"As of v1.0.7 the zrok Agent supports health checks for proxy backend shares. Backend health checks are not yet implemented for other backend modes.","sidebar":"tutorialSidebar"},"guides/agent/index":{"id":"guides/agent/index","title":"Agent","description":"The zrok Agent centralizes management of your zrok shares and accesses. It provides both web-based and command-line interfaces, and changes how the zrok share and zrok access commands behave.","sidebar":"tutorialSidebar"},"guides/agent/linux-service":{"id":"guides/agent/linux-service","title":"Linux Agent Service","description":"Overview","sidebar":"tutorialSidebar"},"guides/agent/remoting":{"id":"guides/agent/remoting","title":"Agent Remoting","description":"As of v1.0.5 the zrok Agent and controller support secure, opt-in remote control for creating shares and accesses through the central zrok API.","sidebar":"tutorialSidebar"},"guides/agent/windows-service/index":{"id":"guides/agent/windows-service/index","title":"Configuring a Windows Service","description":"In Windows environments, it can be useful to run the zrok Agent as a service, allowing it to automatically restart with your system.","sidebar":"tutorialSidebar"},"guides/docker-share/docker_private_share_guide":{"id":"guides/docker-share/docker_private_share_guide","title":"Docker Private Share","description":"Goal","sidebar":"tutorialSidebar"},"guides/docker-share/docker_public_share_guide":{"id":"guides/docker-share/docker_public_share_guide","title":"Docker Compose Public Share","description":"Goal","sidebar":"tutorialSidebar"},"guides/docker-share/index":{"id":"guides/docker-share/index","title":"Getting Started with Docker","description":"Overview","sidebar":"tutorialSidebar"},"guides/drives":{"id":"guides/drives","title":"Drives","description":"The zrok drives CLI tools allow for simple, ergonomic management and synchronization of local and remote files.","sidebar":"tutorialSidebar"},"guides/frontdoor":{"id":"guides/frontdoor","title":"zrok frontdoor","description":"zrok frontdoor is the heavy-duty front door to your app or site. It makes your website or app available to your online audience through the shield of zrok.io\'s hardened, managed frontends.","sidebar":"tutorialSidebar"},"guides/install/index":{"id":"guides/install/index","title":"Install","description":"","sidebar":"tutorialSidebar"},"guides/install/linux":{"id":"guides/install/linux","title":"Install zrok in Linux","description":"Package Repository","sidebar":"tutorialSidebar"},"guides/install/macos":{"id":"guides/install/macos","title":"Install zrok in macOS","description":"Homebrew","sidebar":"tutorialSidebar"},"guides/install/windows":{"id":"guides/install/windows","title":"Install zrok in Windows","description":"Windows Binary","sidebar":"tutorialSidebar"},"guides/permission-modes":{"id":"guides/permission-modes","title":"Permission Modes","description":"As of v1.0.5 zrok sharing now defaults to the closed permission mode. The --closed flag has been removed and has been replaced with a new --open flag for users who want to retain the open permission model. Otherwise, the closed permission mode works exactly the same.","sidebar":"tutorialSidebar"},"guides/self-hosting/docker":{"id":"guides/self-hosting/docker","title":"Self-hosting guide for Docker","description":"","sidebar":"tutorialSidebar"},"guides/self-hosting/error-pages":{"id":"guides/self-hosting/error-pages","title":"Error Pages","description":"zrok includes a built-in error page template that displays user-friendly messages for various error conditions like \\"share not found\\", \\"unauthorized access\\", and \\"bad gateway\\" errors. This template can be replaced with your own custom HTML file to match your organization\'s branding or provide custom error handling.","sidebar":"tutorialSidebar"},"guides/self-hosting/instance-configuration":{"id":"guides/self-hosting/instance-configuration","title":"Use Another zrok Instance","description":"This guide is relevant if you are self-hosting or using a friend\'s zrok instance instead of using zrok-as-a-service from zrok.io.","sidebar":"tutorialSidebar"},"guides/self-hosting/interstitial-page":{"id":"guides/self-hosting/interstitial-page","title":"Interstitial Pages","description":"On large zrok installations that support open registration and shared public frontends, abuse can become an issue. In order to mitigate phishing and other similar forms of abuse, zrok offers an interstitial page that announces to the visiting user that the share is hosted through zrok, and probably isn\'t their financial institution.","sidebar":"tutorialSidebar"},"guides/self-hosting/kubernetes":{"id":"guides/self-hosting/kubernetes","title":"Self-host a zrok Instance in Kubernetes","description":"The Helm chart for zrok is available from the main OpenZiti charts repo.","sidebar":"tutorialSidebar"},"guides/self-hosting/linux/index":{"id":"guides/self-hosting/linux/index","title":"Self-Hosting Guide for Linux","description":"Walkthrough Video","sidebar":"tutorialSidebar"},"guides/self-hosting/linux/nginx":{"id":"guides/self-hosting/linux/nginx","title":"NGINX Reverse Proxy for zrok","description":"Walkthrough Video","sidebar":"tutorialSidebar"},"guides/self-hosting/metrics-and-limits/configuring-limits":{"id":"guides/self-hosting/metrics-and-limits/configuring-limits","title":"Configuring Limits","description":"This guide is current as of zrok version v0.4.31.","sidebar":"tutorialSidebar"},"guides/self-hosting/metrics-and-limits/configuring-metrics":{"id":"guides/self-hosting/metrics-and-limits/configuring-metrics","title":"Configuring Metrics","description":"A fully configured, production-scale zrok service instance looks like this:","sidebar":"tutorialSidebar"},"guides/self-hosting/oauth/configuring-oauth":{"id":"guides/self-hosting/oauth/configuring-oauth","title":"OAuth Public Frontend Configuration","description":"zrok includes OAuth integration for public frontends, allowing you to authenticate users through various OAuth providers before they can access your shared resources. You can configure multiple OAuth providers and restrict access based on email address patterns.","sidebar":"tutorialSidebar"},"guides/self-hosting/oauth/integrations/github":{"id":"guides/self-hosting/oauth/integrations/github","title":"GitHub OAuth Setup","description":"This guide covers setting up GitHub OAuth for your zrok public frontend.","sidebar":"tutorialSidebar"},"guides/self-hosting/oauth/integrations/google":{"id":"guides/self-hosting/oauth/integrations/google","title":"Google OAuth Setup","description":"This guide covers setting up Google OAuth for your zrok public frontend.","sidebar":"tutorialSidebar"},"guides/self-hosting/oauth/integrations/oidc":{"id":"guides/self-hosting/oauth/integrations/oidc","title":"Generic OIDC Setup","description":"This guide covers setting up OpenID Connect (OIDC) providers for your zrok public frontend. OIDC is supported by many identity providers including Keycloak, Auth0, Okta, Azure AD, and others.","sidebar":"tutorialSidebar"},"guides/self-hosting/organizations":{"id":"guides/self-hosting/organizations","title":"Organizations","description":"zrok (starting with v0.4.45) includes support for \\"organizations\\". Organizations are groups of related accounts that are typically centrally managed in some capacity. A zrok account can be a member of multiple organizations. Organization membership can also include an \\"admin\\" permission. As of v0.4.45 organization admins are able to retrieve an \\"overview\\" (zrok overview) from any other account in the organization, allowing the admin to see the details of the environments, shares, and accesses created within that account.","sidebar":"tutorialSidebar"},"guides/self-hosting/personalized-frontend":{"id":"guides/self-hosting/personalized-frontend","title":"Personalized Frontend","description":"This guide describes an approach that enables a zrok user to use a hosted, shared instance (zrok.io) and configure their own personalized frontend, which enables custom DNS and TLS for their shares.","sidebar":"tutorialSidebar"},"guides/self-hosting/self-service-invite":{"id":"guides/self-hosting/self-service-invite","title":"Invitations","description":"This is how to set up self-service invitations for your users to get an account on your self-hosted zrok instance.","sidebar":"tutorialSidebar"},"guides/vpn/vpn":{"id":"guides/vpn/vpn","title":"zrok VPN Guide","description":"zrok VPN backend allows for simple host-to-host VPN setup.","sidebar":"tutorialSidebar"},"myzrok/custom-domains/index":{"id":"myzrok/custom-domains/index","title":"Custom Domains","description":"Overview","sidebar":"tutorialSidebar"},"myzrok/limits":{"id":"myzrok/limits","title":"Limits","description":"NetFoundry\'s public zrok instance implements various limits based on pricing tier,","sidebar":"tutorialSidebar"},"myzrok/upgrading":{"id":"myzrok/upgrading","title":"Upgrading From 0.4 to 1.0","description":"Upgrading an existing 0.4 environment","sidebar":"tutorialSidebar"}}}}')}}]); \ No newline at end of file diff --git a/assets/js/11b43341.bfb531fc.js b/assets/js/11b43341.bfb531fc.js deleted file mode 100644 index e2a6b517..00000000 --- a/assets/js/11b43341.bfb531fc.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[2256],{15293:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"current","label":"1.1","banner":null,"badge":true,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"tutorialSidebar":[{"type":"link","label":"Getting Started","href":"/docs/getting-started","docId":"getting-started","unlisted":false},{"type":"category","label":"Concepts","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Private Shares","href":"/docs/concepts/sharing-private","docId":"concepts/sharing-private","unlisted":false},{"type":"link","label":"Public Shares","href":"/docs/concepts/sharing-public","docId":"concepts/sharing-public","unlisted":false},{"type":"link","label":"Reserved Shares","href":"/docs/concepts/sharing-reserved","docId":"concepts/sharing-reserved","unlisted":false},{"type":"link","label":"Sharing HTTP Servers","href":"/docs/concepts/http","docId":"concepts/http","unlisted":false},{"type":"link","label":"Sharing TCP and UDP Servers","href":"/docs/concepts/tunnels","docId":"concepts/tunnels","unlisted":false},{"type":"link","label":"Sharing Websites and Files","href":"/docs/concepts/files","docId":"concepts/files","unlisted":false},{"type":"link","label":"Open Source","href":"/docs/concepts/opensource","docId":"concepts/opensource","unlisted":false},{"type":"link","label":"Hosting","href":"/docs/concepts/hosting","docId":"concepts/hosting","unlisted":false}],"href":"/docs/concepts/"},{"type":"category","label":"Guides","collapsible":true,"collapsed":true,"items":[{"type":"category","label":"Install","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Linux","href":"/docs/guides/install/linux","docId":"guides/install/linux","unlisted":false},{"type":"link","label":"macOS","href":"/docs/guides/install/macos","docId":"guides/install/macos","unlisted":false},{"type":"link","label":"Windows","href":"/docs/guides/install/windows","docId":"guides/install/windows","unlisted":false}],"href":"/docs/guides/install/"},{"type":"category","label":"The zrok Agent","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Remoting","href":"/docs/guides/agent/remoting","docId":"guides/agent/remoting","unlisted":false},{"type":"link","label":"HTTP Health Checks","href":"/docs/guides/agent/http-healthcheck","docId":"guides/agent/http-healthcheck","unlisted":false},{"type":"link","label":"Linux Agent Service","href":"/docs/guides/agent/linux-service","docId":"guides/agent/linux-service","unlisted":false},{"type":"link","label":"Windows Agent Service","href":"/docs/guides/agent/windows-service/","docId":"guides/agent/windows-service/index","unlisted":false}],"href":"/docs/guides/agent/"},{"type":"link","label":"frontdoor","href":"/docs/guides/frontdoor","docId":"guides/frontdoor","unlisted":false},{"type":"link","label":"Permission Modes","href":"/docs/guides/permission-modes","docId":"guides/permission-modes","unlisted":false},{"type":"category","label":"Docker Share","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Public Share","href":"/docs/guides/docker-share/docker_public_share_guide","docId":"guides/docker-share/docker_public_share_guide","unlisted":false},{"type":"link","label":"Private Share","href":"/docs/guides/docker-share/docker_private_share_guide","docId":"guides/docker-share/docker_private_share_guide","unlisted":false}],"href":"/docs/guides/docker-share/"},{"type":"category","label":"Self Hosting","collapsible":true,"collapsed":true,"items":[{"type":"category","label":"Linux","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"NGINX TLS","href":"/docs/guides/self-hosting/linux/nginx","docId":"guides/self-hosting/linux/nginx","unlisted":false}],"href":"/docs/guides/self-hosting/linux/"},{"type":"link","label":"Interstitial Pages","href":"/docs/guides/self-hosting/interstitial-page","docId":"guides/self-hosting/interstitial-page","unlisted":false},{"type":"link","label":"Organizations","href":"/docs/guides/self-hosting/organizations","docId":"guides/self-hosting/organizations","unlisted":false},{"type":"link","label":"Personalized Frontend","href":"/docs/guides/self-hosting/personalized-frontend","docId":"guides/self-hosting/personalized-frontend","unlisted":false},{"type":"link","label":"Docker","href":"/docs/guides/self-hosting/docker","docId":"guides/self-hosting/docker","unlisted":false},{"type":"link","label":"Kubernetes","href":"/docs/guides/self-hosting/kubernetes","docId":"guides/self-hosting/kubernetes","unlisted":false},{"type":"category","label":"Metrics and Limits","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Configuring Metrics","href":"/docs/guides/self-hosting/metrics-and-limits/configuring-metrics","docId":"guides/self-hosting/metrics-and-limits/configuring-metrics","unlisted":false},{"type":"link","label":"Configuring Limits","href":"/docs/guides/self-hosting/metrics-and-limits/configuring-limits","docId":"guides/self-hosting/metrics-and-limits/configuring-limits","unlisted":false}],"href":"/docs/category/metrics-and-limits"},{"type":"category","label":"OAuth","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"OAuth Public Frontend Configuration","href":"/docs/guides/self-hosting/oauth/configuring-oauth","docId":"guides/self-hosting/oauth/configuring-oauth","unlisted":false},{"type":"category","label":"OAuth Integrations","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Google OAuth Setup","href":"/docs/guides/self-hosting/oauth/integrations/google","docId":"guides/self-hosting/oauth/integrations/google","unlisted":false},{"type":"link","label":"GitHub OAuth Setup","href":"/docs/guides/self-hosting/oauth/integrations/github","docId":"guides/self-hosting/oauth/integrations/github","unlisted":false},{"type":"link","label":"Generic OIDC Setup","href":"/docs/guides/self-hosting/oauth/integrations/oidc","docId":"guides/self-hosting/oauth/integrations/oidc","unlisted":false}],"href":"/docs/category/oauth-integrations"}],"href":"/docs/category/oauth"},{"type":"link","label":"Instance Config","href":"/docs/guides/self-hosting/instance-configuration","docId":"guides/self-hosting/instance-configuration","unlisted":false},{"type":"link","label":"Invitations","href":"/docs/guides/self-hosting/self-service-invite","docId":"guides/self-hosting/self-service-invite","unlisted":false}],"href":"/docs/category/self-hosting"},{"type":"link","label":"Drives","href":"/docs/guides/drives","docId":"guides/drives","unlisted":false},{"type":"link","label":"VPN","href":"/docs/guides/vpn/","docId":"guides/vpn/vpn","unlisted":false}],"href":"/docs/category/guides"},{"type":"category","label":"myzrok","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Custom Domains","href":"/docs/myzrok/custom-domains/","docId":"myzrok/custom-domains/index","unlisted":false},{"type":"link","label":"Limits","href":"/docs/myzrok/limits","docId":"myzrok/limits","unlisted":false},{"type":"link","label":"Upgrading From 0.4 to 1.0","href":"/docs/myzrok/upgrading","docId":"myzrok/upgrading","unlisted":false}],"href":"/docs/category/myzrok"}]},"docs":{"concepts/files":{"id":"concepts/files","title":"Sharing Websites and Files","description":"With zrok it is possible to share files quickly and easily as well. To share files using zrok use","sidebar":"tutorialSidebar"},"concepts/hosting":{"id":"concepts/hosting","title":"Hosting","description":"Self-Hosted","sidebar":"tutorialSidebar"},"concepts/http":{"id":"concepts/http","title":"Sharing HTTP Servers","description":"zrok can share HTTP and HTTPS resources natively. If you have an existing web server that you want to share with other users, you can use the zrok share command using the --backend-mode proxy flag.","sidebar":"tutorialSidebar"},"concepts/index":{"id":"concepts/index","title":"Concepts","description":"zrok was designed to make sharing local resources both secure and easy. In this section of the zrok documentation, we\'ll tour through all of the most important features.","sidebar":"tutorialSidebar"},"concepts/opensource":{"id":"concepts/opensource","title":"Open Source","description":"It\'s important to the zrok project that it remain free and open source software. The code is available on GitHub","sidebar":"tutorialSidebar"},"concepts/sharing-private":{"id":"concepts/sharing-private","title":"Private Shares","description":"zrok was built to share and access digital resources. A private share allows a resource to be","sidebar":"tutorialSidebar"},"concepts/sharing-public":{"id":"concepts/sharing-public","title":"Public Shares","description":"zrok supports public sharing for web-based (HTTP and HTTPS) resources. These resources are easily shared with the general internet through public access points.","sidebar":"tutorialSidebar"},"concepts/sharing-reserved":{"id":"concepts/sharing-reserved","title":"Reserved Shares","description":"By default, a public or private share is assigned a share token when you create a share using the zrok share command. The zrok share command is the bridge between your local environment and the users you are sharing with. When you terminate the zrok share, the bridge is eliminated and the share token is deleted. If you run zrok share again, you will be allocated a brand new share token.","sidebar":"tutorialSidebar"},"concepts/tunnels":{"id":"concepts/tunnels","title":"Sharing TCP and UDP Servers","description":"zrok includes support for sharing low-level TCP and UDP network resources using the tcpTunnel and udpTunnel backend modes.","sidebar":"tutorialSidebar"},"getting-started":{"id":"getting-started","title":"Getting Started","description":"Your Secure Internet Sharing Perimeter","sidebar":"tutorialSidebar"},"guides/agent/http-healthcheck":{"id":"guides/agent/http-healthcheck","title":"HTTP Health Checks","description":"As of v1.0.7 the zrok Agent supports health checks for proxy backend shares. Backend health checks are not yet implemented for other backend modes.","sidebar":"tutorialSidebar"},"guides/agent/index":{"id":"guides/agent/index","title":"Agent","description":"The zrok Agent centralizes management of your zrok shares and accesses. It provides both web-based and command-line interfaces, and changes how the zrok share and zrok access commands behave.","sidebar":"tutorialSidebar"},"guides/agent/linux-service":{"id":"guides/agent/linux-service","title":"Linux Agent Service","description":"Overview","sidebar":"tutorialSidebar"},"guides/agent/remoting":{"id":"guides/agent/remoting","title":"Agent Remoting","description":"As of v1.0.5 the zrok Agent and controller support secure, opt-in remote control for creating shares and accesses through the central zrok API.","sidebar":"tutorialSidebar"},"guides/agent/windows-service/index":{"id":"guides/agent/windows-service/index","title":"Configuring a Windows Service","description":"In Windows environments, it can be useful to run the zrok Agent as a service, allowing it to automatically restart with your system.","sidebar":"tutorialSidebar"},"guides/docker-share/docker_private_share_guide":{"id":"guides/docker-share/docker_private_share_guide","title":"Docker Private Share","description":"Goal","sidebar":"tutorialSidebar"},"guides/docker-share/docker_public_share_guide":{"id":"guides/docker-share/docker_public_share_guide","title":"Docker Compose Public Share","description":"Goal","sidebar":"tutorialSidebar"},"guides/docker-share/index":{"id":"guides/docker-share/index","title":"Getting Started with Docker","description":"Overview","sidebar":"tutorialSidebar"},"guides/drives":{"id":"guides/drives","title":"Drives","description":"The zrok drives CLI tools allow for simple, ergonomic management and synchronization of local and remote files.","sidebar":"tutorialSidebar"},"guides/frontdoor":{"id":"guides/frontdoor","title":"zrok frontdoor","description":"zrok frontdoor is the heavy-duty front door to your app or site. It makes your website or app available to your online audience through the shield of zrok.io\'s hardened, managed frontends.","sidebar":"tutorialSidebar"},"guides/install/index":{"id":"guides/install/index","title":"Install","description":"","sidebar":"tutorialSidebar"},"guides/install/linux":{"id":"guides/install/linux","title":"Install zrok in Linux","description":"Package Repository","sidebar":"tutorialSidebar"},"guides/install/macos":{"id":"guides/install/macos","title":"Install zrok in macOS","description":"Homebrew","sidebar":"tutorialSidebar"},"guides/install/windows":{"id":"guides/install/windows","title":"Install zrok in Windows","description":"Windows Binary","sidebar":"tutorialSidebar"},"guides/permission-modes":{"id":"guides/permission-modes","title":"Permission Modes","description":"As of v1.0.5 zrok sharing now defaults to the closed permission mode. The --closed flag has been removed and has been replaced with a new --open flag for users who want to retain the open permission model. Otherwise, the closed permission mode works exactly the same.","sidebar":"tutorialSidebar"},"guides/self-hosting/docker":{"id":"guides/self-hosting/docker","title":"Self-hosting guide for Docker","description":"","sidebar":"tutorialSidebar"},"guides/self-hosting/instance-configuration":{"id":"guides/self-hosting/instance-configuration","title":"Use Another zrok Instance","description":"This guide is relevant if you are self-hosting or using a friend\'s zrok instance instead of using zrok-as-a-service from zrok.io.","sidebar":"tutorialSidebar"},"guides/self-hosting/interstitial-page":{"id":"guides/self-hosting/interstitial-page","title":"Interstitial Pages","description":"On large zrok installations that support open registration and shared public frontends, abuse can become an issue. In order to mitigate phishing and other similar forms of abuse, zrok offers an interstitial page that announces to the visiting user that the share is hosted through zrok, and probably isn\'t their financial institution.","sidebar":"tutorialSidebar"},"guides/self-hosting/kubernetes":{"id":"guides/self-hosting/kubernetes","title":"Self-host a zrok Instance in Kubernetes","description":"The Helm chart for zrok is available from the main OpenZiti charts repo.","sidebar":"tutorialSidebar"},"guides/self-hosting/linux/index":{"id":"guides/self-hosting/linux/index","title":"Self-Hosting Guide for Linux","description":"Walkthrough Video","sidebar":"tutorialSidebar"},"guides/self-hosting/linux/nginx":{"id":"guides/self-hosting/linux/nginx","title":"NGINX Reverse Proxy for zrok","description":"Walkthrough Video","sidebar":"tutorialSidebar"},"guides/self-hosting/metrics-and-limits/configuring-limits":{"id":"guides/self-hosting/metrics-and-limits/configuring-limits","title":"Configuring Limits","description":"This guide is current as of zrok version v0.4.31.","sidebar":"tutorialSidebar"},"guides/self-hosting/metrics-and-limits/configuring-metrics":{"id":"guides/self-hosting/metrics-and-limits/configuring-metrics","title":"Configuring Metrics","description":"A fully configured, production-scale zrok service instance looks like this:","sidebar":"tutorialSidebar"},"guides/self-hosting/oauth/configuring-oauth":{"id":"guides/self-hosting/oauth/configuring-oauth","title":"OAuth Public Frontend Configuration","description":"zrok includes OAuth integration for public frontends, allowing you to authenticate users through various OAuth providers before they can access your shared resources. You can configure multiple OAuth providers and restrict access based on email address patterns.","sidebar":"tutorialSidebar"},"guides/self-hosting/oauth/integrations/github":{"id":"guides/self-hosting/oauth/integrations/github","title":"GitHub OAuth Setup","description":"This guide covers setting up GitHub OAuth for your zrok public frontend.","sidebar":"tutorialSidebar"},"guides/self-hosting/oauth/integrations/google":{"id":"guides/self-hosting/oauth/integrations/google","title":"Google OAuth Setup","description":"This guide covers setting up Google OAuth for your zrok public frontend.","sidebar":"tutorialSidebar"},"guides/self-hosting/oauth/integrations/oidc":{"id":"guides/self-hosting/oauth/integrations/oidc","title":"Generic OIDC Setup","description":"This guide covers setting up OpenID Connect (OIDC) providers for your zrok public frontend. OIDC is supported by many identity providers including Keycloak, Auth0, Okta, Azure AD, and others.","sidebar":"tutorialSidebar"},"guides/self-hosting/organizations":{"id":"guides/self-hosting/organizations","title":"Organizations","description":"zrok (starting with v0.4.45) includes support for \\"organizations\\". Organizations are groups of related accounts that are typically centrally managed in some capacity. A zrok account can be a member of multiple organizations. Organization membership can also include an \\"admin\\" permission. As of v0.4.45 organization admins are able to retrieve an \\"overview\\" (zrok overview) from any other account in the organization, allowing the admin to see the details of the environments, shares, and accesses created within that account.","sidebar":"tutorialSidebar"},"guides/self-hosting/personalized-frontend":{"id":"guides/self-hosting/personalized-frontend","title":"Personalized Frontend","description":"This guide describes an approach that enables a zrok user to use a hosted, shared instance (zrok.io) and configure their own personalized frontend, which enables custom DNS and TLS for their shares.","sidebar":"tutorialSidebar"},"guides/self-hosting/self-service-invite":{"id":"guides/self-hosting/self-service-invite","title":"Invitations","description":"This is how to set up self-service invitations for your users to get an account on your self-hosted zrok instance.","sidebar":"tutorialSidebar"},"guides/vpn/vpn":{"id":"guides/vpn/vpn","title":"zrok VPN Guide","description":"zrok VPN backend allows for simple host-to-host VPN setup.","sidebar":"tutorialSidebar"},"myzrok/custom-domains/index":{"id":"myzrok/custom-domains/index","title":"Custom Domains","description":"Overview","sidebar":"tutorialSidebar"},"myzrok/limits":{"id":"myzrok/limits","title":"Limits","description":"NetFoundry\'s public zrok instance implements various limits based on pricing tier,","sidebar":"tutorialSidebar"},"myzrok/upgrading":{"id":"myzrok/upgrading","title":"Upgrading From 0.4 to 1.0","description":"Upgrading an existing 0.4 environment","sidebar":"tutorialSidebar"}}}}')}}]); \ No newline at end of file diff --git a/assets/js/7452427d.04af226a.js b/assets/js/7452427d.04af226a.js new file mode 100644 index 00000000..30cd24b7 --- /dev/null +++ b/assets/js/7452427d.04af226a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[9476],{94674:(e,o,r)=>{r.r(o),r.d(o,{assets:()=>d,contentTitle:()=>a,default:()=>l,frontMatter:()=>t,metadata:()=>n,toc:()=>c});const n=JSON.parse('{"id":"guides/self-hosting/personalized-frontend","title":"Personalized Frontend","description":"This guide describes an approach that enables a zrok user to use a hosted, shared instance (zrok.io) and configure their own personalized frontend, which enables custom DNS and TLS for their shares.","source":"@site/../docs/guides/self-hosting/personalized-frontend.md","sourceDirName":"guides/self-hosting","slug":"/guides/self-hosting/personalized-frontend","permalink":"/docs/guides/self-hosting/personalized-frontend","draft":false,"unlisted":false,"editUrl":"https://github.com/openziti/zrok/blob/main/docs/../docs/guides/self-hosting/personalized-frontend.md","tags":[],"version":"current","sidebarPosition":15,"frontMatter":{"title":"Personalized Frontend","sidebar_label":"Personalized Frontend","sidebar_position":15},"sidebar":"tutorialSidebar","previous":{"title":"NGINX TLS","permalink":"/docs/guides/self-hosting/linux/nginx"},"next":{"title":"Error Pages","permalink":"/docs/guides/self-hosting/error-pages"}}');var s=r(74848),i=r(28453);const t={title:"Personalized Frontend",sidebar_label:"Personalized Frontend",sidebar_position:15},a=void 0,d={},c=[{value:"Overview",id:"overview",level:2},{value:"Privacy",id:"privacy",level:2}];function h(e){const o={a:"a",admonition:"admonition",code:"code",em:"em",h2:"h2",img:"img",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(o.p,{children:"This guide describes an approach that enables a zrok user to use a hosted, shared instance (zrok.io) and configure their own personalized frontend, which enables custom DNS and TLS for their shares."}),"\n",(0,s.jsx)(o.p,{children:"In order to accomplish this, the user will need to provide their own minimal VPS instance, or container hosting. The size and capacity of these resources will be entirely dependent on the workload that they will be used to service. But generally, for most modest workloads, the most inexpensive VPS option will suffice."}),"\n",(0,s.jsx)(o.p,{children:"This approach gives you complete control over the way that your shares are exposed publicly. This approach works for HTTPS shares, and also for TCP and UDP ports, allowing you to put all of these things onto the public internet, while maintaining strong security for your protected resources."}),"\n",(0,s.jsxs)(o.p,{children:["This guide isn't a detailed ",(0,s.jsx)(o.em,{children:"how to"})," with specific steps to follow. This is more of a description of the overall concept. You'll want to figure out your own specific steps to implement this style of deployment in your own environment."]}),"\n",(0,s.jsx)(o.h2,{id:"overview",children:"Overview"}),"\n",(0,s.jsxs)(o.p,{children:["Let's imagine a hypothetical scenario where you've got 3 different resources shared using zrok. We'll refer to these as ",(0,s.jsx)(o.code,{children:"A"}),", ",(0,s.jsx)(o.code,{children:"B"}),", and ",(0,s.jsx)(o.code,{children:"C"}),". Both ",(0,s.jsx)(o.code,{children:"A"})," and ",(0,s.jsx)(o.code,{children:"B"})," are shares using the ",(0,s.jsx)(o.code,{children:"proxy"})," backend mode, which are used to share private HTTPS resources. Share ",(0,s.jsx)(o.code,{children:"C"})," uses the ",(0,s.jsx)(o.code,{children:"tcpTunnel"})," backend to expose a listening port from a private server (like a game server, or a message queue)."]}),"\n",(0,s.jsx)(o.p,{children:"We're using the shared zrok instance at zrok.io to provide our secure sharing infrastructure."}),"\n",(0,s.jsx)(o.p,{children:"Our deployment will end up looking like this:"}),"\n",(0,s.jsx)(o.p,{children:(0,s.jsx)(o.img,{alt:"personalized-frontend-1",src:r(18396).A+"",width:"716",height:"357"})}),"\n",(0,s.jsxs)(o.p,{children:["We're using ",(0,s.jsx)(o.code,{children:"zrok reserve"})," to create the ",(0,s.jsx)(o.code,{children:"A"}),", ",(0,s.jsx)(o.code,{children:"B"}),", and ",(0,s.jsx)(o.code,{children:"C"})," shares as reserved shares (using the ",(0,s.jsx)(o.code,{children:"--unique-name"})," option to give them specific names). These shares could be located together in a single environment on a single host, or can be located at completely different spots on the planet on completely different hosts. You could want to use significantly more shares than 3, or less. The secure sharing fabric allows seamless secure connectivity for these shared resources. This implementation will scale up or down as needed (use multiple hosts behind a load balancer for really big workloads)."]}),"\n",(0,s.jsxs)(o.p,{children:["Because we're using ",(0,s.jsx)(o.code,{children:"private"})," zrok shares, they'll need to be accessed using a corresponding ",(0,s.jsx)(o.code,{children:"zrok access"})," private command. The ",(0,s.jsx)(o.code,{children:"zrok access private"}),' command binds a "network listener" where the share can be accessed on an address and port on the host where the command is executed. You can use ',(0,s.jsx)(o.code,{children:"zrok access private"})," to bind a network listener for a share in as many places as you want (up to the limit configuration of the service)."]}),"\n",(0,s.jsx)(o.admonition,{type:"note",children:(0,s.jsxs)(o.p,{children:["When you use ",(0,s.jsx)(o.code,{children:"zrok share public"}),", you are allowing your shared resources to be accessed using the shared, public frontend provided by the service instance (zrok.io). ",(0,s.jsx)(o.code,{children:"zrok share private"})," (or ",(0,s.jsx)(o.code,{children:"zrok reserve"}),"/",(0,s.jsx)(o.code,{children:"zrok share reserved"}),") creates the same kind of share, but does not provision the shared public frontend, and you'll need to use ",(0,s.jsx)(o.code,{children:"zrok access private"})," in order to ",(0,s.jsx)(o.em,{children:"bind"})," that share to a network address where it can be accessed."]})}),"\n",(0,s.jsxs)(o.p,{children:["Imagine that we own the domain ",(0,s.jsx)(o.code,{children:"example.com"}),". In our example, we want to expose our HTTPS shares ",(0,s.jsx)(o.code,{children:"A"})," and ",(0,s.jsx)(o.code,{children:"B"})," as ",(0,s.jsx)(o.code,{children:"a.example.com"})," and ",(0,s.jsx)(o.code,{children:"b.example.com"}),". And maybe our ",(0,s.jsx)(o.code,{children:"C"})," share represents a gaming server that we want to expose as ",(0,s.jsx)(o.code,{children:"gaming.example.com:25565"}),"."]}),"\n",(0,s.jsxs)(o.p,{children:["We can accomplish this easily with cheap VPS instance. You could also do it with containers through a container hosting service. The VPS will need an IP address exposed to the internet. You'll also need to be able to create DNS entries for the ",(0,s.jsx)(o.code,{children:"example.com"})," domain."]}),"\n",(0,s.jsxs)(o.p,{children:["To accomplish this, we're going to run 3 separate ",(0,s.jsx)(o.code,{children:"zrok access private"})," commands on our VPS (see the ",(0,s.jsx)(o.a,{href:"../../frontdoor/",children:"frontdoor guide"}),", or ",(0,s.jsx)(o.a,{href:"../../docker-share/docker_private_share_guide/#access-the-private-share",children:"zrok-private-access Docker Compose guide"})," for details on an approach for setting this up). One command each for shares ",(0,s.jsx)(o.code,{children:"A"}),", ",(0,s.jsx)(o.code,{children:"B"}),", and ",(0,s.jsx)(o.code,{children:"C"}),". The ",(0,s.jsx)(o.code,{children:"zrok access private"})," command works like this:"]}),"\n",(0,s.jsx)(o.pre,{children:(0,s.jsx)(o.code,{children:'$ zrok access private\nError: accepts 1 arg(s), received 0\nUsage:\n zrok access privatezrok access private
)",id:"private-access-zrok-access-private",level:3},{value:"Public Frontend (zrok access public
)",id:"public-frontend-zrok-access-public",level:3},{value:"Template Structure",id:"template-structure",level:2},{value:"Conditional Content",id:"conditional-content",level:3},{value:"Custom Template Example",id:"custom-template-example",level:2},{value:"Error Types",id:"error-types",level:2},{value:"Share Not Found (404)",id:"share-not-found-404",level:3},{value:"Unauthorized Access (401)",id:"unauthorized-access-401",level:3},{value:"Bad Gateway (502)",id:"bad-gateway-502",level:3},{value:"Health Check (200)",id:"health-check-200",level:3},{value:"Best Practices",id:"best-practices",level:2}];function c(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"custom-error-pages",children:"Custom Error Pages"})}),"\n",(0,i.jsx)(n.p,{children:'zrok includes a built-in error page template that displays user-friendly messages for various error conditions like "share not found", "unauthorized access", and "bad gateway" errors. This template can be replaced with your own custom HTML file to match your organization\'s branding or provide custom error handling.'}),"\n",(0,i.jsx)(n.h2,{id:"overview",children:"Overview"}),"\n",(0,i.jsxs)(n.p,{children:["The error page system uses Go's ",(0,i.jsx)(n.code,{children:"text/template"})," package to render HTML pages with dynamic content. The template receives data through a ",(0,i.jsx)(n.code,{children:"VariableData"})," struct containing:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"Title"}),": Page title (appears in browser tab)"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"Banner"}),": Main heading text"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"Message"}),": Optional explanatory message"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"Error"}),": Optional error details"]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"configuration-options",children:"Configuration Options"}),"\n",(0,i.jsxs)(n.h3,{id:"private-access-zrok-access-private",children:["Private Access (",(0,i.jsx)(n.code,{children:"zrok access private"}),")"]}),"\n",(0,i.jsxs)(n.p,{children:["For private access frontends, use the ",(0,i.jsx)(n.code,{children:"--template-path"})," flag:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"zrok access private --template-path /path/to/custom-template.html {{.Message}}
\n{{end}}\n\n{{if .Error}}\n
not found!"})]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Message"}),": ",(0,i.jsx)(n.code,{children:"are you running zrok share
for this share?"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"unauthorized-access-401",children:"Unauthorized Access (401)"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Title"}),": ",(0,i.jsx)(n.code,{children:"unauthorized!"})]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Banner"}),": ",(0,i.jsx)(n.code,{children:"user not authorized!"})," or ",(0,i.jsx)(n.code,{children:"
not authorized!"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"bad-gateway-502",children:"Bad Gateway (502)"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Title"}),": Custom title based on the error"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Banner"}),": Custom banner based on the error"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Error"}),": Detailed error information"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"health-check-200",children:"Health Check (200)"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Title"}),": ",(0,i.jsx)(n.code,{children:"healthy"})]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Banner"}),": ",(0,i.jsx)(n.code,{children:"healthy"})]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"best-practices",children:"Best Practices"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Keep it simple"}),": Error pages should load quickly and not depend on external resources that might also be failing."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Responsive design"}),": Ensure your template works well on mobile devices."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Clear messaging"}),": Provide helpful information to users about what went wrong and what they can do."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Consistent branding"}),": Match your organization's visual identity."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Escape user content"}),": Be cautious with user-provided content. The ",(0,i.jsx)(n.code,{children:"Banner"})," and ",(0,i.jsx)(n.code,{children:"Message"})," fields may contain HTML from the application."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Test thoroughly"}),": Test your template with different error conditions to ensure it renders correctly."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Fallback styling"}),": Include all CSS inline or use web fonts with fallbacks to ensure the page displays correctly even if external resources fail."]}),"\n"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},28453:(e,n,r)=>{r.d(n,{R:()=>o,x:()=>a});var s=r(96540);const i={},t=s.createContext(i);function o(e){const n=s.useContext(t);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(t.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/assets/js/e1dfe4fe.01f68557.js b/assets/js/e1dfe4fe.dfa8c381.js
similarity index 94%
rename from assets/js/e1dfe4fe.01f68557.js
rename to assets/js/e1dfe4fe.dfa8c381.js
index 8b122476..4b275747 100644
--- a/assets/js/e1dfe4fe.01f68557.js
+++ b/assets/js/e1dfe4fe.dfa8c381.js
@@ -1 +1 @@
-"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3423],{31181:(e,n,o)=>{o.d(n,{Ay:()=>c,RM:()=>t});var i=o(74848),r=o(28453);const t=[{value:"Docker Instance",id:"docker-instance",level:2},{value:"Create the Docker Compose Project",id:"create-the-docker-compose-project",level:3},{value:"YOLO",id:"yolo",level:4},{value:"I'll Do it Myself",id:"ill-do-it-myself",level:4},{value:"Basic Configuration (No TLS, Localhost Only)",id:"basic-configuration-no-tls-localhost-only",level:3},{value:"DNS Configuration (Optional for localhost-only setup)",id:"dns-configuration-optional-for-localhost-only-setup",level:4},{value:"Configure the Docker Compose Project Environment",id:"configure-the-docker-compose-project-environment",level:4},{value:"Start the Docker Compose Project",id:"start-the-docker-compose-project",level:4},{value:"Expanded Configuration with TLS (Caddy or Traefik)",id:"expanded-configuration-with-tls-caddy-or-traefik",level:3},{value:"DNS Configuration for TLS",id:"dns-configuration-for-tls",level:4},{value:"Configure the Docker Compose File",id:"configure-the-docker-compose-file",level:4},{value:"Caddy Configuration",id:"caddy-configuration",level:4},{value:"Traefik Configuration",id:"traefik-configuration",level:4},{value:"Start the Docker Compose Project",id:"start-the-docker-compose-project-1",level:4},{value:"Set up a User Account",id:"set-up-a-user-account",level:3},{value:"Enable the User Environment",id:"enable-the-user-environment",level:3},{value:"Firewall Configuration",id:"firewall-configuration",level:3},{value:"Additional Configuration Options",id:"additional-configuration-options",level:3},{value:"Troubleshooting",id:"troubleshooting",level:3}];function s(e){const n={a:"a",code:"code",h2:"h2",h3:"h3",h4:"h4",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h2,{id:"docker-instance",children:"Docker Instance"}),"\n",(0,i.jsx)("iframe",{width:"100%",height:"315",src:"https://www.youtube.com/embed/70zJ_h4uiD8",title:"YouTube video player",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",allowfullscreen:!0}),"\n",(0,i.jsx)(n.p,{children:"This Docker Compose project creates a zrok instance supported by a OpenZiti controller and router. It supports flexible deployment configurations:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Basic Configuration"}),": Services exposed on localhost only (no TLS)"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"With Caddy"}),": Services published using Caddy (TLS)"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"With Traefik"}),": Services published using Traefik (TLS)"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"create-the-docker-compose-project",children:"Create the Docker Compose Project"}),"\n",(0,i.jsx)(n.p,{children:"Create a working directory on your Docker host and save these Docker Compose project files."}),"\n",(0,i.jsx)(n.h4,{id:"yolo",children:"YOLO"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Run this script to download the files in the current directory."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"curl https://get.openziti.io/zrok-instance/fetch.bash | bash\n"})}),"\n",(0,i.jsx)(n.p,{children:"Or, specify the Compose project directory."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"curl https://get.openziti.io/zrok-instance/fetch.bash | bash -s /path/to/compose/project/dir\n"})}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.h4,{id:"ill-do-it-myself",children:"I'll Do it Myself"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Get the zrok repo ZIP file."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"wget https://github.com/openziti/zrok/archive/refs/heads/main.zip\n"})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Unzip the zrok-instance files into the project directory."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"unzip -j -d . main.zip '*/docker/compose/zrok-instance/*'\n"})}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"basic-configuration-no-tls-localhost-only",children:"Basic Configuration (No TLS, Localhost Only)"}),"\n",(0,i.jsx)(n.p,{children:"This is the simplest way to get started with zrok, exposing services on localhost only, without TLS."}),"\n",(0,i.jsx)(n.h4,{id:"dns-configuration-optional-for-localhost-only-setup",children:"DNS Configuration (Optional for localhost-only setup)"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["If you plan to use this beyond localhost, set up a wildcard record for the IP address where the zrok instance will run\n(e.g., if your DNS zone is ",(0,i.jsx)(n.code,{children:"share.example.com"}),", then your wildcard record is ",(0,i.jsx)(n.code,{children:"*.share.example.com"}),")."]}),"\n"]}),"\n",(0,i.jsx)(n.h4,{id:"configure-the-docker-compose-project-environment",children:"Configure the Docker Compose Project Environment"}),"\n",(0,i.jsxs)(n.p,{children:["Create an ",(0,i.jsx)(n.code,{children:".env"})," file in the working directory with the minimal required configuration:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",metastring:'title=".env minimal configuration"',children:"# Required settings\nZROK_DNS_ZONE=share.example.com\nZROK_USER_EMAIL=me@example.com\nZROK_USER_PWD=zrokuserpw\nZITI_PWD=zitiadminpw\nZROK_ADMIN_TOKEN=zroktoken\n\n# Expose services only on localhost (default)\nZROK_INSECURE_INTERFACE=127.0.0.1\n\n# Service ports\nZROK_CTRL_PORT=18080\nZROK_FRONTEND_PORT=8080\nZROK_OAUTH_PORT=8081\nZITI_CTRL_ADVERTISED_PORT=80\nZITI_ROUTER_PORT=3022\n"})}),"\n",(0,i.jsx)(n.h4,{id:"start-the-docker-compose-project",children:"Start the Docker Compose Project"}),"\n",(0,i.jsx)(n.p,{children:"Start the zrok instance:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"docker compose up --build --detach\n"})}),"\n",(0,i.jsx)(n.h3,{id:"expanded-configuration-with-tls-caddy-or-traefik",children:"Expanded Configuration with TLS (Caddy or Traefik)"}),"\n",(0,i.jsx)(n.p,{children:"For production deployments, you should use TLS. You can choose between Caddy or Traefik for TLS termination and reverse proxy to the zrok services. The ziti services are always published directly, not proxied, and they bring their own TLS."}),"\n",(0,i.jsx)(n.h4,{id:"dns-configuration-for-tls",children:"DNS Configuration for TLS"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["Ensure a wildcard record exists for the IP address where the zrok instance will run\n(e.g., if your DNS zone is ",(0,i.jsx)(n.code,{children:"share.example.com"}),", then your wildcard record is ",(0,i.jsx)(n.code,{children:"*.share.example.com"}),")."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Choose a DNS provider that supports automatic DNS challenge for obtaining wildcard certificates and for which a plugin is available in Caddy or Traefik."}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.h4,{id:"configure-the-docker-compose-file",children:"Configure the Docker Compose File"}),"\n",(0,i.jsxs)(n.p,{children:["Add this setting to your ",(0,i.jsx)(n.code,{children:".env"})," file to select which TLS provider to use:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"# Use one of the following:\nCOMPOSE_FILE=compose.yml:compose.caddy.yml # For Caddy\n# OR\nCOMPOSE_FILE=compose.yml:compose.traefik.yml # For Traefik\n"})}),"\n",(0,i.jsx)(n.h4,{id:"caddy-configuration",children:"Caddy Configuration"}),"\n",(0,i.jsxs)(n.p,{children:["If using Caddy, add these settings to your ",(0,i.jsx)(n.code,{children:".env"})," file:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",metastring:'title=".env for Caddy"',children:"# Caddy TLS configuration\nCADDY_DNS_PLUGIN=cloudflare # Plugin name for your DNS provider (see github.com/caddy-dns)\nCADDY_DNS_PLUGIN_TOKEN=abcd1234 # API token from your DNS provider\nCADDY_ACME_API=https://acme-v02.api.letsencrypt.org/directory # ACME API endpoint\nCADDY_HTTPS_PORT=443 # HTTPS port (optional, defaults to 443)\nCADDY_INTERFACE=0.0.0.0 # Interface to bind to (optional, defaults to all interfaces)\n\n# For AWS Route53, uncomment and set these instead of CADDY_DNS_PLUGIN_TOKEN:\n# AWS_ACCESS_KEY_ID=your-access-key\n# AWS_SECRET_ACCESS_KEY=your-secret-key\n# AWS_REGION=your-region\n# AWS_SESSION_TOKEN=your-session-token # Only if using temporary credentials\n"})}),"\n",(0,i.jsx)(n.h4,{id:"traefik-configuration",children:"Traefik Configuration"}),"\n",(0,i.jsxs)(n.p,{children:["If using Traefik, add these settings to your ",(0,i.jsx)(n.code,{children:".env"})," file:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",metastring:'title=".env for Traefik"',children:"# Traefik TLS configuration\nTRAEFIK_DNS_PROVIDER=digitalocean # DNS provider for Traefik\nTRAEFIK_DNS_PROVIDER_TOKEN=abcd1234 # API token from your DNS provider\nTRAEFIK_ACME_API=https://acme-v02.api.letsencrypt.org/directory # ACME API endpoint\nTRAEFIK_HTTPS_PORT=443 # HTTPS port (optional, defaults to 443)\nTRAEFIK_INTERFACE=0.0.0.0 # Interface to bind to (optional, defaults to all interfaces)\n\n# For AWS Route53, uncomment and set these instead of TRAEFIK_DNS_PROVIDER_TOKEN:\n# AWS_ACCESS_KEY_ID=your-access-key\n# AWS_SECRET_ACCESS_KEY=your-secret-key\n# AWS_REGION=your-region\n# AWS_SESSION_TOKEN=your-session-token # Only if using temporary credentials\n"})}),"\n",(0,i.jsx)(n.h4,{id:"start-the-docker-compose-project-1",children:"Start the Docker Compose Project"}),"\n",(0,i.jsx)(n.p,{children:"Start the zrok instance with TLS support:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"docker compose up --build --detach\n"})}),"\n",(0,i.jsx)(n.h3,{id:"set-up-a-user-account",children:"Set up a User Account"}),"\n",(0,i.jsxs)(n.p,{children:["This step creates a user account. You will log in to the zrok web console with the account password created in this step. The ZROK_USER_EMAIL and ZROK_USER_PWD variables are set in the ",(0,i.jsx)(n.code,{children:".env"})," file."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",metastring:'title="Create the first user account"',children:"docker compose exec zrok-controller bash -xc 'zrok admin create account ${ZROK_USER_EMAIL} ${ZROK_USER_PWD}'\n"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-buttonless",metastring:'title="Example output"',children:"+ zrok admin create account me@example.com zrokuserpw\n[ 0.000] INFO zrok/controller/store.Open: database connected\n[ 0.002] INFO zrok/controller/store.(*Store).migrate: applied 0 migrations\nheMqncCyxZcx\n"})}),"\n",(0,i.jsx)(n.p,{children:"Create additional users by running the command again with a different email and password."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",metastring:'title="Create another user"',children:"docker compose exec zrok-controller zrok admin create account .comment
can become .namespace--comment
) or replace them with your defined ones (like .editor__comment
). You can even add new classes.",owner:"dvkndn",noCSS:!0},"file-highlight":{title:"File Highlight",description:"Fetch external files and highlight them with Prism. Used on the Prism website itself.",noCSS:!0},"show-language":{title:"Show Language",description:"Display the highlighted language in code blocks (inline code does not show the label).",owner:"nauzilus",noCSS:!0,require:"toolbar"},"jsonp-highlight":{title:"JSONP Highlight",description:"Fetch content with JSONP and highlight some interesting content (e.g. GitHub/Gists or Bitbucket API).",noCSS:!0,owner:"nauzilus"},"highlight-keywords":{title:"Highlight Keywords",description:"Adds special CSS classes for each keyword for fine-grained highlighting.",owner:"vkbansal",noCSS:!0},"remove-initial-line-feed":{title:"Remove initial line feed",description:"Removes the initial line feed in code blocks.",owner:"Golmote",noCSS:!0},"inline-color":{title:"Inline color",description:"Adds a small inline preview for colors in style sheets.",require:"css-extras",owner:"RunDevelopment"},previewers:{title:"Previewers",description:"Previewers for angles, colors, gradients, easing and time.",require:"css-extras",owner:"Golmote"},autoloader:{title:"Autoloader",description:"Automatically loads the needed languages to highlight the code blocks.",owner:"Golmote",noCSS:!0},"keep-markup":{title:"Keep Markup",description:"Prevents custom markup from being dropped out during highlighting.",owner:"Golmote",optional:"normalize-whitespace",noCSS:!0},"command-line":{title:"Command Line",description:"Display a command line with a prompt and, optionally, the output/response from the commands.",owner:"chriswells0"},"unescaped-markup":{title:"Unescaped Markup",description:"Write markup without having to escape anything."},"normalize-whitespace":{title:"Normalize Whitespace",description:"Supports multiple operations to normalize whitespace in code blocks.",owner:"zeitgeist87",optional:"unescaped-markup",noCSS:!0},"data-uri-highlight":{title:"Data-URI Highlight",description:"Highlights data-URI contents.",owner:"Golmote",noCSS:!0},toolbar:{title:"Toolbar",description:"Attach a toolbar for plugins to easily register buttons on the top of a code block.",owner:"mAAdhaTTah"},"copy-to-clipboard":{title:"Copy to Clipboard Button",description:"Add a button that copies the code block to the clipboard when clicked.",owner:"mAAdhaTTah",require:"toolbar",noCSS:!0},"download-button":{title:"Download Button",description:"A button in the toolbar of a code block adding a convenient way to download a code file.",owner:"Golmote",require:"toolbar",noCSS:!0},"match-braces":{title:"Match braces",description:"Highlights matching braces.",owner:"RunDevelopment"},"diff-highlight":{title:"Diff Highlight",description:"Highlights the code inside diff blocks.",owner:"RunDevelopment",require:"diff"},"filter-highlight-all":{title:"Filter highlightAll",description:"Filters the elements the highlightAll
and highlightAllUnder
methods actually highlight.",owner:"RunDevelopment",noCSS:!0},treeview:{title:"Treeview",description:"A language with special styles to highlight file system tree structures.",owner:"Golmote"}}})},8722:(e,t,n)=>{const r=n(6969),o=n(98380),a=new Set;function i(e){void 0===e?e=Object.keys(r.languages).filter((e=>"meta"!=e)):Array.isArray(e)||(e=[e]);const t=[...a,...Object.keys(Prism.languages)];o(r,e,t).load((e=>{if(!(e in r.languages))return void(i.silent||console.warn("Language does not exist: "+e));const t="./prism-"+e;delete n.c[n(63157).resolve(t)],delete Prism.languages[e],n(63157)(t),a.add(e)}))}i.silent=!1,e.exports=i},19700:()=>{!function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,o,a){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(o,(function(e){if("function"==typeof a&&!a(e))return e;for(var o,s=i.length;-1!==n.code.indexOf(o=t(r,s));)++s;return i[s]=e,o})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var o=0,a=Object.keys(n.tokenStack);!function i(s){for(var l=0;l{const{plain:n}=e,r=e.styles.reduce(((e,n)=>{const{languages:r,style:o}=n;return r&&!r.includes(t)||n.types.forEach((t=>{const n=y(y({},e[t]),o);e[t]=n})),e}),{});return r.root=n,r.plain=v(y({},n),{backgroundColor:void 0}),r},Q=({children:e,language:t,code:n,theme:r,prism:o})=>{const s=t.toLowerCase(),l=K(r,s),c=(e=>(0,a.useCallback)((t=>{var n=t,{className:r,style:o,line:a}=n,s=w(n,["className","style","line"]);const l=v(y({},s),{className:(0,i.A)("token-line",r)});return"object"==typeof e&&"plain"in e&&(l.style=e.plain),"object"==typeof o&&(l.style=y(y({},l.style||{}),o)),l}),[e]))(l),u=(e=>{const t=(0,a.useCallback)((({types:t,empty:n})=>{if(null!=e)return 1===t.length&&"plain"===t[0]?null!=n?{display:"inline-block"}:void 0:1===t.length&&null!=n?e[t[0]]:Object.assign(null!=n?{display:"inline-block"}:{},...t.map((t=>e[t])))}),[e]);return(0,a.useCallback)((e=>{var n=e,{token:r,className:o,style:a}=n,s=w(n,["token","className","style"]);const l=v(y({},s),{className:(0,i.A)("token",...r.types,o),children:r.content,style:t(r)});return null!=a&&(l.style=y(y({},l.style||{}),a)),l}),[t])})(l),d=(({prism:e,code:t,grammar:n,language:r})=>(0,a.useMemo)((()=>{if(null==n)return W([t]);const o={code:t,grammar:n,language:r,tokens:[]};return e.hooks.run("before-tokenize",o),o.tokens=e.tokenize(t,n),e.hooks.run("after-tokenize",o),W(o.tokens)}),[t,n,r,e]))({prism:o,language:s,code:n,grammar:o.languages[s]});return e({tokens:d,className:`prism-code language-${s}`,style:null!=l?l.root:{},getLineProps:c,getTokenProps:u})},Y=e=>(0,a.createElement)(Q,v(y({},e),{prism:e.prism||S,theme:e.theme||D,code:e.code,language:e.language}))},15066:(e,t,n)=>{"use strict";function r(e){var t,n,o="";if("string"==typeof e||"number"==typeof e)o+=e;else if("object"==typeof e)if(Array.isArray(e)){var a=e.length;for(t=0;to});const o=function(){for(var e,t,n=0,o="",a=arguments.length;n{"use strict";n.d(t,{A:()=>a});var r=!0,o="Invariant failed";function a(e,t){if(!e){if(r)throw new Error(o);var n="function"==typeof t?t():t,a=n?"".concat(o,": ").concat(n):o;throw new Error(a)}}},31635:(e,t,n)=>{"use strict";n.r(t),n.d(t,{__addDisposableResource:()=>N,__assign:()=>a,__asyncDelegator:()=>E,__asyncGenerator:()=>_,__asyncValues:()=>j,__await:()=>x,__awaiter:()=>m,__classPrivateFieldGet:()=>P,__classPrivateFieldIn:()=>R,__classPrivateFieldSet:()=>I,__createBinding:()=>g,__decorate:()=>s,__disposeResources:()=>D,__esDecorate:()=>c,__exportStar:()=>b,__extends:()=>o,__generator:()=>h,__importDefault:()=>T,__importStar:()=>A,__makeTemplateObject:()=>C,__metadata:()=>f,__param:()=>l,__propKey:()=>d,__read:()=>v,__rest:()=>i,__runInitializers:()=>u,__setFunctionName:()=>p,__spread:()=>w,__spreadArray:()=>k,__spreadArrays:()=>S,__values:()=>y,default:()=>M});var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},r(e,t)};function o(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var a=function(){return a=Object.assign||function(e){for(var t,n=1,r=arguments.length;n{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return o.current=!0,void n(!1);n(!0)})),{navbarRef:i,isNavbarVisible:t}}(t);return(0,u.jsxs)("nav",{ref:i,"aria-label":(0,l.T)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,o.A)(g.G.layout.navbar.container,"navbar","navbar--fixed-top",t&&[ot.navbarHideable,!s&&ot.navbarHidden],{"navbar--dark":"dark"===n,"navbar--primary":"primary"===n,"navbar-sidebar--show":a.shown}),children:[e,(0,u.jsx)(at,{onClick:a.toggle}),(0,u.jsx)(rt,{})]})}var st=n(12181);const lt="right";function ct({width:e=30,height:t=30,className:n,...r}){return(0,u.jsx)("svg",{className:n,width:e,height:t,viewBox:"0 0 30 30","aria-hidden":"true",...r,children:(0,u.jsx)("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"})})}function ut(){const{toggle:e,shown:t}=(0,A.M)();return(0,u.jsx)("button",{onClick:e,"aria-label":(0,l.T)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button",children:(0,u.jsx)(ct,{})})}const dt={colorModeToggle:"colorModeToggle_DEke"};function pt({items:e}){return(0,u.jsx)(u.Fragment,{children:e.map(((e,t)=>(0,u.jsx)(st.k2,{onError:t=>new Error(`A theme navbar item failed to render.\nPlease double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:\n${JSON.stringify(e,null,2)}`,{cause:t}),children:(0,u.jsx)(Xe,{...e})},t)))})}function ft({left:e,right:t}){return(0,u.jsxs)("div",{className:"navbar__inner",children:[(0,u.jsx)("div",{className:(0,o.A)(g.G.layout.navbar.containerLeft,"navbar__items"),children:e}),(0,u.jsx)("div",{className:(0,o.A)(g.G.layout.navbar.containerRight,"navbar__items navbar__items--right"),children:t})]})}function mt(){const e=(0,A.M)(),t=(0,w.p)().navbar.items,[n,r]=function(e){function t(e){return"left"===(e.position??lt)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),o=t.find((e=>"search"===e.type));return(0,u.jsx)(ft,{left:(0,u.jsxs)(u.Fragment,{children:[!e.disabled&&(0,u.jsx)(ut,{}),(0,u.jsx)(ie,{}),(0,u.jsx)(pt,{items:n})]}),right:(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(pt,{items:r}),(0,u.jsx)(oe,{className:dt.colorModeToggle}),!o&&(0,u.jsx)(Ge,{children:(0,u.jsx)(He,{})})]})})}function ht(){return(0,u.jsx)(it,{children:(0,u.jsx)(mt,{})})}function gt({item:e}){const{to:t,href:n,label:r,prependBaseUrlToHref:a,className:i,...s}=e,l=(0,ue.Ay)(t),c=(0,ue.Ay)(n,{forcePrependBaseUrl:!0});return(0,u.jsxs)(ce.A,{className:(0,o.A)("footer__link-item",i),...n?{href:a?c:n}:{to:l},...s,children:[r,n&&!(0,de.A)(n)&&(0,u.jsx)(fe.A,{})]})}function bt({item:e}){return e.html?(0,u.jsx)("li",{className:(0,o.A)("footer__item",e.className),dangerouslySetInnerHTML:{__html:e.html}}):(0,u.jsx)("li",{className:"footer__item",children:(0,u.jsx)(gt,{item:e})},e.href??e.to)}function yt({column:e}){return(0,u.jsxs)("div",{className:(0,o.A)(g.G.layout.footer.column,"col footer__col",e.className),children:[(0,u.jsx)("div",{className:"footer__title",children:e.title}),(0,u.jsx)("ul",{className:"footer__items clean-list",children:e.items.map(((e,t)=>(0,u.jsx)(bt,{item:e},t)))})]})}function vt({columns:e}){return(0,u.jsx)("div",{className:"row footer__links",children:e.map(((e,t)=>(0,u.jsx)(yt,{column:e},t)))})}function wt(){return(0,u.jsx)("span",{className:"footer__link-separator",children:"\xb7"})}function St({item:e}){return e.html?(0,u.jsx)("span",{className:(0,o.A)("footer__link-item",e.className),dangerouslySetInnerHTML:{__html:e.html}}):(0,u.jsx)(gt,{item:e})}function kt({links:e}){return(0,u.jsx)("div",{className:"footer__links text--center",children:(0,u.jsx)("div",{className:"footer__links",children:e.map(((t,n)=>(0,u.jsxs)(r.Fragment,{children:[(0,u.jsx)(St,{item:t}),e.length!==n+1&&(0,u.jsx)(wt,{})]},n)))})})}function xt({links:e}){return function(e){return"title"in e[0]}(e)?(0,u.jsx)(vt,{columns:e}):(0,u.jsx)(kt,{links:e})}var _t=n(21122);const Et="footerLogoLink_BH7S";function jt({logo:e}){const{withBaseUrl:t}=(0,ue.hH)(),n={light:t(e.src),dark:t(e.srcDark??e.src)};return(0,u.jsx)(_t.A,{className:(0,o.A)("footer__logo",e.className),alt:e.alt,sources:n,width:e.width,height:e.height,style:e.style})}function Ct({logo:e}){return e.href?(0,u.jsx)(ce.A,{href:e.href,className:Et,target:e.target,children:(0,u.jsx)(jt,{logo:e})}):(0,u.jsx)(jt,{logo:e})}function Ot({copyright:e}){return(0,u.jsx)("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:e}})}function At({style:e,links:t,logo:n,copyright:r}){return(0,u.jsx)("footer",{className:(0,o.A)(g.G.layout.footer.container,"footer",{"footer--dark":"dark"===e}),children:(0,u.jsxs)("div",{className:"container container-fluid",children:[t,(n||r)&&(0,u.jsxs)("div",{className:"footer__bottom text--center",children:[n&&(0,u.jsx)("div",{className:"margin-bottom--sm",children:n}),r]})]})})}function Tt(){const{footer:e}=(0,w.p)();if(!e)return null;const{copyright:t,links:n,logo:r,style:o}=e;return(0,u.jsx)(At,{style:o,links:n&&n.length>0&&(0,u.jsx)(xt,{links:n}),logo:r&&(0,u.jsx)(Ct,{logo:r}),copyright:t&&(0,u.jsx)(Ot,{copyright:t})})}const Pt=r.memo(Tt),It=(0,P.fM)([B.a,S.o,T.Tv,Qe.VQ,i.Jx,function({children:e}){return(0,u.jsx)(I.y_,{children:(0,u.jsx)(A.e,{children:(0,u.jsx)(N,{children:e})})})}]);function Rt({children:e}){return(0,u.jsx)(It,{children:e})}var Nt=n(51107);function Lt({error:e,tryAgain:t}){return(0,u.jsx)("main",{className:"container margin-vert--xl",children:(0,u.jsx)("div",{className:"row",children:(0,u.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,u.jsx)(Nt.A,{as:"h1",className:"hero__title",children:(0,u.jsx)(l.A,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed",children:"This page crashed."})}),(0,u.jsx)("div",{className:"margin-vert--lg",children:(0,u.jsx)(st.a2,{onClick:t,className:"button button--primary shadow--lw"})}),(0,u.jsx)("hr",{}),(0,u.jsx)("div",{className:"margin-vert--md",children:(0,u.jsx)(st.bq,{error:e})})]})})})}const Dt={mainWrapper:"mainWrapper_z2l0"};function Mt(e){const{children:t,noFooter:n,wrapperClassName:r,title:s,description:l}=e;return(0,b.J)(),(0,u.jsxs)(Rt,{children:[(0,u.jsx)(i.be,{title:s,description:l}),(0,u.jsx)(v,{}),(0,u.jsx)(O,{}),(0,u.jsx)(ht,{}),(0,u.jsx)("div",{id:d,className:(0,o.A)(g.G.layout.main.container,g.G.wrapper.main,Dt.mainWrapper,r),children:(0,u.jsx)(a.A,{fallback:e=>(0,u.jsx)(Lt,{...e}),children:t})}),!n&&(0,u.jsx)(Pt,{})]})}},23465:(e,t,n)=>{"use strict";n.d(t,{A:()=>u});n(96540);var r=n(28774),o=n(86025),a=n(44586),i=n(6342),s=n(21122),l=n(74848);function c({logo:e,alt:t,imageClassName:n}){const r={light:(0,o.Ay)(e.src),dark:(0,o.Ay)(e.srcDark||e.src)},a=(0,l.jsx)(s.A,{className:e.className,sources:r,height:e.height,width:e.width,alt:t,style:e.style});return n?(0,l.jsx)("div",{className:n,children:a}):a}function u(e){const{siteConfig:{title:t}}=(0,a.A)(),{navbar:{title:n,logo:s}}=(0,i.p)(),{imageClassName:u,titleClassName:d,...p}=e,f=(0,o.Ay)(s?.href||"/"),m=n?"":t,h=s?.alt??m;return(0,l.jsxs)(r.A,{to:f,...p,...s?.target&&{target:s.target},children:[s&&(0,l.jsx)(c,{logo:s,alt:h,imageClassName:u}),null!=n&&(0,l.jsx)("b",{className:d,children:n})]})}},41463:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});n(96540);var r=n(5260),o=n(74848);function a({locale:e,version:t,tag:n}){const a=e;return(0,o.jsxs)(r.A,{children:[e&&(0,o.jsx)("meta",{name:"docusaurus_locale",content:e}),t&&(0,o.jsx)("meta",{name:"docusaurus_version",content:t}),n&&(0,o.jsx)("meta",{name:"docusaurus_tag",content:n}),a&&(0,o.jsx)("meta",{name:"docsearch:language",content:a}),t&&(0,o.jsx)("meta",{name:"docsearch:version",content:t}),n&&(0,o.jsx)("meta",{name:"docsearch:docusaurus_tag",content:n})]})}},21122:(e,t,n)=>{"use strict";n.d(t,{A:()=>u});var r=n(96540),o=n(15066),a=n(92303),i=n(95293);const s={themedComponent:"themedComponent_mlkZ","themedComponent--light":"themedComponent--light_NVdE","themedComponent--dark":"themedComponent--dark_xIcU"};var l=n(74848);function c({className:e,children:t}){const n=(0,a.A)(),{colorMode:c}=(0,i.G)();return(0,l.jsx)(l.Fragment,{children:(n?"dark"===c?["dark"]:["light"]:["light","dark"]).map((n=>{const a=t({theme:n,className:(0,o.A)(e,s.themedComponent,s[`themedComponent--${n}`])});return(0,l.jsx)(r.Fragment,{children:a},n)}))})}function u(e){const{sources:t,className:n,alt:r,...o}=e;return(0,l.jsx)(c,{className:n,children:({theme:e,className:n})=>(0,l.jsx)("img",{src:t[e],alt:r,className:n,...o})})}},41422:(e,t,n)=>{"use strict";n.d(t,{N:()=>h,u:()=>l});var r=n(96540),o=n(205),a=n(53109),i=n(74848);const s="ease-in-out";function l({initialState:e}){const[t,n]=(0,r.useState)(e??!1),o=(0,r.useCallback)((()=>{n((e=>!e))}),[]);return{collapsed:t,setCollapsed:n,toggleCollapsed:o}}const c={display:"none",overflow:"hidden",height:"0px"},u={display:"block",overflow:"visible",height:"auto"};function d(e,t){const n=t?c:u;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function p({collapsibleRef:e,collapsed:t,animation:n}){const o=(0,r.useRef)(!1);(0,r.useEffect)((()=>{const r=e.current;function i(){const e=r.scrollHeight,t=n?.duration??function(e){if((0,a.O)())return 1;const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(e);return{transition:`height ${t}ms ${n?.easing??s}`,height:`${e}px`}}function l(){const e=i();r.style.transition=e.transition,r.style.height=e.height}if(!o.current)return d(r,t),void(o.current=!0);return r.style.willChange="height",function(){const e=requestAnimationFrame((()=>{t?(l(),requestAnimationFrame((()=>{r.style.height=c.height,r.style.overflow=c.overflow}))):(r.style.display="block",requestAnimationFrame((()=>{l()})))}));return()=>cancelAnimationFrame(e)}()}),[e,t,n])}function f({as:e="div",collapsed:t,children:n,animation:o,onCollapseTransitionEnd:a,className:s}){const l=(0,r.useRef)(null);return p({collapsibleRef:l,collapsed:t,animation:o}),(0,i.jsx)(e,{ref:l,onTransitionEnd:e=>{"height"===e.propertyName&&(d(l.current,t),a?.(t))},className:s,children:n})}function m({collapsed:e,...t}){const[n,a]=(0,r.useState)(!e),[s,l]=(0,r.useState)(e);return(0,o.A)((()=>{e||a(!0)}),[e]),(0,o.A)((()=>{n&&l(e)}),[n,e]),n?(0,i.jsx)(f,{...t,collapsed:s}):null}function h({lazy:e,...t}){const n=e?m:f;return(0,i.jsx)(n,{...t})}},65041:(e,t,n)=>{"use strict";n.d(t,{M:()=>h,o:()=>m});var r=n(96540),o=n(92303),a=n(70679),i=n(89532),s=n(6342),l=n(74848);const c=(0,a.Wf)("docusaurus.announcement.dismiss"),u=(0,a.Wf)("docusaurus.announcement.id"),d=()=>"true"===c.get(),p=e=>c.set(String(e)),f=r.createContext(null);function m({children:e}){const t=function(){const{announcementBar:e}=(0,s.p)(),t=(0,o.A)(),[n,a]=(0,r.useState)((()=>!!t&&d()));(0,r.useEffect)((()=>{a(d())}),[]);const i=(0,r.useCallback)((()=>{p(!0),a(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=u.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;u.set(t),r&&p(!1),!r&&d()||a(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:i})),[e,n,i])}();return(0,l.jsx)(f.Provider,{value:t,children:e})}function h(){const e=(0,r.useContext)(f);if(!e)throw new i.dV("AnnouncementBarProvider");return e}},95293:(e,t,n)=>{"use strict";n.d(t,{G:()=>w,a:()=>v});var r=n(96540),o=n(89532),a=n(70679),i=n(6342),s=n(74848);function l(){return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function c(e){return function(e,t){const n=window.matchMedia(e);return n.addEventListener("change",t),()=>n.removeEventListener("change",t)}("(prefers-color-scheme: dark)",(()=>e(l())))}const u=r.createContext(void 0),d=(0,a.Wf)("theme"),p="system",f=e=>"dark"===e?"dark":"light",m=e=>null===e||e===p?null:f(e),h={get:()=>f(document.documentElement.getAttribute("data-theme")),set:e=>{document.documentElement.setAttribute("data-theme",f(e))}},g={get:()=>m(document.documentElement.getAttribute("data-theme-choice")),set:e=>{document.documentElement.setAttribute("data-theme-choice",m(e)??p)}},b=e=>{null===e?d.del():d.set(f(e))};function y(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,i.p)(),{colorMode:o,setColorModeState:a,colorModeChoice:s,setColorModeChoiceState:u}=function(){const{colorMode:{defaultMode:e}}=(0,i.p)(),[t,n]=(0,r.useState)(e),[o,a]=(0,r.useState)(null);return(0,r.useEffect)((()=>{n(h.get()),a(g.get())}),[]),{colorMode:t,setColorModeState:n,colorModeChoice:o,setColorModeChoiceState:a}}();(0,r.useEffect)((()=>{t&&d.del()}),[t]);const p=(0,r.useCallback)(((t,r={})=>{const{persist:o=!0}=r;if(null===t){const t=n?l():e;h.set(t),a(t),g.set(null),u(null)}else h.set(t),g.set(t),a(t),u(t);o&&b(t)}),[a,u,n,e]);return(0,r.useEffect)((()=>d.listen((e=>{p(m(e.newValue))}))),[p]),(0,r.useEffect)((()=>{if(null===s&&n)return c((e=>{a(e),h.set(e)}))}),[n,s,a]),(0,r.useMemo)((()=>({colorMode:o,colorModeChoice:s,setColorMode:p,get isDarkTheme(){return"dark"===o},setLightTheme(){p("light")},setDarkTheme(){p("dark")}})),[o,s,p])}function v({children:e}){const t=y();return(0,s.jsx)(u.Provider,{value:t,children:e})}function w(){const e=(0,r.useContext)(u);if(null==e)throw new o.dV("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},22069:(e,t,n)=>{"use strict";n.d(t,{M:()=>m,e:()=>f});var r=n(96540),o=n(75600),a=n(24581),i=n(57485),s=n(6342),l=n(89532),c=n(74848);const u=r.createContext(void 0);function d(){const e=function(){const e=(0,o.YL)(),{items:t}=(0,s.p)().navbar;return 0===t.length&&!e.component}(),t=(0,a.l)(),n=!e&&"mobile"===t,[i,l]=(0,r.useState)(!1),c=(0,r.useCallback)((()=>{l((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&l(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:c,shown:i})),[e,n,c,i])}function p({handler:e}){return(0,i.$Z)(e),null}function f({children:e}){const t=d();return(0,c.jsxs)(c.Fragment,{children:[t.shown&&(0,c.jsx)(p,{handler:()=>(t.toggle(),!1)}),(0,c.jsx)(u.Provider,{value:t,children:e})]})}function m(){const e=r.useContext(u);if(void 0===e)throw new l.dV("NavbarMobileSidebarProvider");return e}},75600:(e,t,n)=>{"use strict";n.d(t,{GX:()=>c,YL:()=>l,y_:()=>s});var r=n(96540),o=n(89532),a=n(74848);const i=r.createContext(null);function s({children:e}){const t=(0,r.useState)({component:null,props:null});return(0,a.jsx)(i.Provider,{value:t,children:e})}function l(){const e=(0,r.useContext)(i);if(!e)throw new o.dV("NavbarSecondaryMenuContentProvider");return e[0]}function c({component:e,props:t}){const n=(0,r.useContext)(i);if(!n)throw new o.dV("NavbarSecondaryMenuContentProvider");const[,a]=n,s=(0,o.Be)(t);return(0,r.useEffect)((()=>{a({component:e,props:s})}),[a,e,s]),(0,r.useEffect)((()=>()=>a({component:null,props:null})),[a]),null}},14090:(e,t,n)=>{"use strict";n.d(t,{w:()=>o,J:()=>a});var r=n(96540);const o="navigation-with-keyboard";function a(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(o),"mousedown"===e.type&&document.body.classList.remove(o)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(o),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},24255:(e,t,n)=>{"use strict";n.d(t,{b:()=>s,w:()=>l});var r=n(96540),o=n(44586),a=n(57485);const i="q";function s(){return(0,a.l)(i)}function l(){const{siteConfig:{baseUrl:e,themeConfig:t}}=(0,o.A)(),{algolia:{searchPagePath:n}}=t;return(0,r.useCallback)((t=>`${e}${n}?${i}=${encodeURIComponent(t)}`),[e,n])}},24581:(e,t,n)=>{"use strict";n.d(t,{l:()=>s});var r=n(96540),o=n(38193);const a={desktop:"desktop",mobile:"mobile",ssr:"ssr"},i=996;function s({desktopBreakpoint:e=i}={}){const[t,n]=(0,r.useState)((()=>"ssr"));return(0,r.useEffect)((()=>{function t(){n(function(e){if(!o.A.canUseDOM)throw new Error("getWindowSize() should only be called after React hydration");return window.innerWidth>e?a.desktop:a.mobile}(e))}return t(),window.addEventListener("resize",t),()=>{window.removeEventListener("resize",t)}}),[e]),t}},17559:(e,t,n)=>{"use strict";n.d(t,{G:()=>r});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",blogAuthorsListPage:"blog-authors-list-page",blogAuthorsPostsPage:"blog-authors-posts-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",unlistedBanner:"theme-unlisted-banner",draftBanner:"theme-draft-banner",admonitionType:e=>`theme-admonition-${e}`},announcementBar:{container:"theme-announcement-bar"},layout:{navbar:{container:"theme-layout-navbar",containerLeft:"theme-layout-navbar-left",containerRight:"theme-layout-navbar-right",mobileSidebar:{container:"theme-layout-navbar-sidebar",panel:"theme-layout-navbar-sidebar-panel"}},main:{container:"theme-layout-main"},footer:{container:"theme-layout-footer",column:"theme-layout-footer-column"}},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{blogFooterTagsRow:"theme-blog-footer-tags-row",blogFooterEditMetaRow:"theme-blog-footer-edit-meta-row"},pages:{pageFooterEditMetaRow:"theme-pages-footer-edit-meta-row"}}},53109:(e,t,n)=>{"use strict";function r(){return window.matchMedia("(prefers-reduced-motion: reduce)").matches}n.d(t,{O:()=>r})},12181:(e,t,n)=>{"use strict";n.d(t,{bq:()=>u,MN:()=>c,a2:()=>l,k2:()=>d});var r=n(96540),o=n(21312),a=n(70440);const i={errorBoundaryError:"errorBoundaryError_a6uf",errorBoundaryFallback:"errorBoundaryFallback_VBag"};var s=n(74848);function l(e){return(0,s.jsx)("button",{type:"button",...e,children:(0,s.jsx)(o.A,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again rendering when the React error boundary captures an error",children:"Try again"})})}function c({error:e,tryAgain:t}){return(0,s.jsxs)("div",{className:i.errorBoundaryFallback,children:[(0,s.jsx)("p",{children:e.message}),(0,s.jsx)(l,{onClick:t})]})}function u({error:e}){const t=(0,a.rA)(e).map((e=>e.message)).join("\n\nCause:\n");return(0,s.jsx)("p",{className:i.errorBoundaryError,children:t})}class d extends r.Component{componentDidCatch(e,t){throw this.props.onError(e,t)}render(){return this.props.children}}},57485:(e,t,n)=>{"use strict";n.d(t,{$Z:()=>i,aZ:()=>l,l:()=>c});var r=n(96540),o=n(56347),a=n(89532);function i(e){!function(e){const t=(0,o.W6)(),n=(0,a._q)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}function s(e){const t=(0,o.W6)();return(0,r.useSyncExternalStore)(t.listen,(()=>e(t)),(()=>e(t)))}function l(e){return s((t=>null===e?null:new URLSearchParams(t.location.search).get(e)))}function c(e){const t=l(e)??"",n=function(e){const t=(0,o.W6)();return(0,r.useCallback)(((n,r)=>{const o=new URLSearchParams(t.location.search);n?o.set(e,n):o.delete(e),(r?.push?t.push:t.replace)({search:o.toString()})}),[e,t])}(e);return[t,n]}},31682:(e,t,n)=>{"use strict";function r(e,t=(e,t)=>e===t){return e.filter(((n,r)=>e.findIndex((e=>t(e,n)))!==r))}function o(e){return Array.from(new Set(e))}n.d(t,{XI:()=>r,sb:()=>o})},45500:(e,t,n)=>{"use strict";n.d(t,{Jx:()=>b,be:()=>m,e3:()=>g});var r=n(96540),o=n(15066),a=n(5260),i=n(36803),s=n(86025),l=n(14563),c=n(74848);function u({title:e}){const t=(0,l.s$)().format(e);return(0,c.jsxs)(a.A,{children:[(0,c.jsx)("title",{children:t}),(0,c.jsx)("meta",{property:"og:title",content:t})]})}function d({description:e}){return(0,c.jsxs)(a.A,{children:[(0,c.jsx)("meta",{name:"description",content:e}),(0,c.jsx)("meta",{property:"og:description",content:e})]})}function p({image:e}){const{withBaseUrl:t}=(0,s.hH)(),n=t(e,{absolute:!0});return(0,c.jsxs)(a.A,{children:[(0,c.jsx)("meta",{property:"og:image",content:n}),(0,c.jsx)("meta",{name:"twitter:image",content:n})]})}function f({keywords:e}){return(0,c.jsx)(a.A,{children:(0,c.jsx)("meta",{name:"keywords",content:Array.isArray(e)?e.join(","):e})})}function m({title:e,description:t,keywords:n,image:r,children:o}){return(0,c.jsxs)(c.Fragment,{children:[e&&(0,c.jsx)(u,{title:e}),t&&(0,c.jsx)(d,{description:t}),n&&(0,c.jsx)(f,{keywords:n}),r&&(0,c.jsx)(p,{image:r}),o&&(0,c.jsx)(a.A,{children:o})]})}const h=r.createContext(void 0);function g({className:e,children:t}){const n=r.useContext(h),i=(0,o.A)(n,e);return(0,c.jsxs)(h.Provider,{value:i,children:[(0,c.jsx)(a.A,{children:(0,c.jsx)("html",{className:i})}),t]})}function b({children:e}){const t=(0,i.A)(),n=`plugin-${t.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const r=`plugin-id-${t.plugin.id}`;return(0,c.jsx)(g,{className:(0,o.A)(n,r),children:e})}},89532:(e,t,n)=>{"use strict";n.d(t,{Be:()=>c,ZC:()=>s,_q:()=>i,dV:()=>l,fM:()=>u});var r=n(96540),o=n(205),a=n(74848);function i(e){const t=(0,r.useRef)(e);return(0,o.A)((()=>{t.current=e}),[e]),(0,r.useCallback)(((...e)=>t.current(...e)),[])}function s(e){const t=(0,r.useRef)();return(0,o.A)((()=>{t.current=e})),t.current}class l extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?.comment
can become .namespace--comment
) or replace them with your defined ones (like .editor__comment
). You can even add new classes.",owner:"dvkndn",noCSS:!0},"file-highlight":{title:"File Highlight",description:"Fetch external files and highlight them with Prism. Used on the Prism website itself.",noCSS:!0},"show-language":{title:"Show Language",description:"Display the highlighted language in code blocks (inline code does not show the label).",owner:"nauzilus",noCSS:!0,require:"toolbar"},"jsonp-highlight":{title:"JSONP Highlight",description:"Fetch content with JSONP and highlight some interesting content (e.g. GitHub/Gists or Bitbucket API).",noCSS:!0,owner:"nauzilus"},"highlight-keywords":{title:"Highlight Keywords",description:"Adds special CSS classes for each keyword for fine-grained highlighting.",owner:"vkbansal",noCSS:!0},"remove-initial-line-feed":{title:"Remove initial line feed",description:"Removes the initial line feed in code blocks.",owner:"Golmote",noCSS:!0},"inline-color":{title:"Inline color",description:"Adds a small inline preview for colors in style sheets.",require:"css-extras",owner:"RunDevelopment"},previewers:{title:"Previewers",description:"Previewers for angles, colors, gradients, easing and time.",require:"css-extras",owner:"Golmote"},autoloader:{title:"Autoloader",description:"Automatically loads the needed languages to highlight the code blocks.",owner:"Golmote",noCSS:!0},"keep-markup":{title:"Keep Markup",description:"Prevents custom markup from being dropped out during highlighting.",owner:"Golmote",optional:"normalize-whitespace",noCSS:!0},"command-line":{title:"Command Line",description:"Display a command line with a prompt and, optionally, the output/response from the commands.",owner:"chriswells0"},"unescaped-markup":{title:"Unescaped Markup",description:"Write markup without having to escape anything."},"normalize-whitespace":{title:"Normalize Whitespace",description:"Supports multiple operations to normalize whitespace in code blocks.",owner:"zeitgeist87",optional:"unescaped-markup",noCSS:!0},"data-uri-highlight":{title:"Data-URI Highlight",description:"Highlights data-URI contents.",owner:"Golmote",noCSS:!0},toolbar:{title:"Toolbar",description:"Attach a toolbar for plugins to easily register buttons on the top of a code block.",owner:"mAAdhaTTah"},"copy-to-clipboard":{title:"Copy to Clipboard Button",description:"Add a button that copies the code block to the clipboard when clicked.",owner:"mAAdhaTTah",require:"toolbar",noCSS:!0},"download-button":{title:"Download Button",description:"A button in the toolbar of a code block adding a convenient way to download a code file.",owner:"Golmote",require:"toolbar",noCSS:!0},"match-braces":{title:"Match braces",description:"Highlights matching braces.",owner:"RunDevelopment"},"diff-highlight":{title:"Diff Highlight",description:"Highlights the code inside diff blocks.",owner:"RunDevelopment",require:"diff"},"filter-highlight-all":{title:"Filter highlightAll",description:"Filters the elements the highlightAll
and highlightAllUnder
methods actually highlight.",owner:"RunDevelopment",noCSS:!0},treeview:{title:"Treeview",description:"A language with special styles to highlight file system tree structures.",owner:"Golmote"}}})},8722:(e,t,n)=>{const r=n(6969),o=n(98380),a=new Set;function i(e){void 0===e?e=Object.keys(r.languages).filter((e=>"meta"!=e)):Array.isArray(e)||(e=[e]);const t=[...a,...Object.keys(Prism.languages)];o(r,e,t).load((e=>{if(!(e in r.languages))return void(i.silent||console.warn("Language does not exist: "+e));const t="./prism-"+e;delete n.c[n(63157).resolve(t)],delete Prism.languages[e],n(63157)(t),a.add(e)}))}i.silent=!1,e.exports=i},19700:()=>{!function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,o,a){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(o,(function(e){if("function"==typeof a&&!a(e))return e;for(var o,s=i.length;-1!==n.code.indexOf(o=t(r,s));)++s;return i[s]=e,o})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var o=0,a=Object.keys(n.tokenStack);!function i(s){for(var l=0;l