1"use strict";(self.webpackChunkelectronjs=self.webpackChunkelectronjs||[]).push([["10987"],{80388(e,t,n){n.r(t),n.d(t,{metadata:()=>a,default:()=>h,frontMatter:()=>l,contentTitle:()=>d,toc:()=>u,assets:()=>c});var a=JSON.parse('{"id":"latest/tutorial/updates","title":"Updating Applications","description":"There are several ways to update an Electron application. The easiest and officially supported one is taking advantage of the built-in Squirrel framework and Electron\'s autoUpdater module.","source":"@site/docs/latest/tutorial/updates.md","sourceDirName":"latest/tutorial","slug":"/latest/tutorial/updates","permalink":"/docs/latest/tutorial/updates","draft":false,"unlisted":false,"editUrl":"https://github.com/electron/electron/edit/main/docs/tutorial/updates.md","tags":[],"version":"current","frontMatter":{"title":"Updating Applications","description":"There are several ways to update an Electron application. The easiest and officially supported one is taking advantage of the built-in Squirrel framework and Electron\'s autoUpdater module.","slug":"updates","hide_title":false},"sidebar":"docs","previous":{"title":"Code Signing","permalink":"/docs/latest/tutorial/code-signing"},"next":{"title":"Mac App Store Submission Guide","permalink":"/docs/latest/tutorial/mac-app-store-submission-guide"}}'),r=n(74848),s=n(28453),i=n(50773),o=n(57250);let l={title:"Updating Applications",description:"There are several ways to update an Electron application. The easiest and officially supported one is taking advantage of the built-in Squirrel framework and Electron's autoUpdater module.",slug:"updates",hide_title:!1},d,c={},u=[{value:"Using cloud object storage (serverless)",id:"using-cloud-object-storage-serverless",level:2},{value:"Publishing release metadata",id:"publishing-release-metadata",level:3},{value:"Reading release metadata",id:"reading-release-metadata",level:3},{value:"Using update.electronjs.org",id:"using-updateelectronjsorg",level:2},{value:"Using other update services",id:"using-other-update-services",level:2},{value:"Step 1: Deploying an update server",id:"step-1-deploying-an-update-server",level:3},{value:"Step 2: Receiving updates in your app",id:"step-2-receiving-updates-in-your-app",level:3},{value:"Step 3: Notifying users when updates are available",id:"step-3-notifying-users-when-updates-are-available",level:3},{value:"Update server specification",id:"update-server-specification",level:2},{value:"Windows",id:"windows",level:3},{value:"macOS",id:"macos",level:3}];function p(e){let t={a:"a",admonition:"admonition",code:"code",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components},{Details:n}=t;return n||function(e,t){throw Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)(t.p,{children:["There are several ways to provide automatic updates to your Electron application.\nThe easiest and officially supported one is taking advantage of the built-in\n",(0,r.jsx)(t.a,{href:"https://github.com/Squirrel",children:"Squirrel"})," framework and\nElectron's ",(0,r.jsx)(t.a,{href:"/docs/latest/api/auto-updater",children:"autoUpdater"})," module."]}),"\n",(0,r.jsx)(t.h2,{id:"using-cloud-object-storage-serverless",children:"Using cloud object storage (serverless)"}),"\n",(0,r.jsx)(t.p,{children:"For a simple serverless update flow, Electron's autoUpdater module can\ncheck if updates are available by pointing to a static storage URL\ncontaining latest release metadata."}),"\n",(0,r.jsx)(t.p,{children:"When a new release is available, this metadata needs to be published to\ncloud storage alongside the release itself. The metadata format is\ndifferent for macOS and Windows."}),"\n",(0,r.jsx)(t.h3,{id:"publishing-release-metadata",children:"Publishing release metadata"}),"\n",(0,r.jsxs)(t.p,{children:["With Electron Forge, you can set up static file storage updates by publishing\nmetadata artifacts from the ZIP Maker (macOS) with ",(0,r.jsx)(t.code,{children:"macUpdateManifestBaseUrl"}),"\nand the Squirrel.Windows Maker (Windows) with ",(0,r.jsx)(t.code,{children:"remoteReleases"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["See Forge's ",(0,r.jsx)(t.a,{href:"https://www.electronforge.io/config/publishers/s3#auto-updating-from-s3",children:"Auto updating from S3"}
1),"\nguide for an end-to-end example."]}),"\n",(0,r.jsxs)(n,{children:[(0,r.jsx)("summary",{children:"Manual publishing"}),(0,r.jsxs)(t.p,{children:["On macOS, Squirrel.Mac can receive updates by reading a ",(0,r.jsx)(t.code,{children:"releases.json"})," file with the\nfollowing JSON format:"]}),(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-json",metastring:"title='releases.json'",children:'{\n "currentRelease": "1.2.3",\n "releases": [\n {\n "version": "1.2.1",\n "updateTo": {\n "version": "1.2.1",\n "pub_date": "2023-09-18T12:29:53+01:00",\n "notes": "These are some release notes innit",\n "name": "1.2.1",\n "url": "https://mycompany.example.com/myapp/releases/myrelease"\n }\n },\n {\n "version": "1.2.3",\n "updateTo": {\n "version": "1.2.3",\n "pub_date": "2024-09-18T12:29:53+01:00",\n "notes": "These are some more release notes innit",\n "name": "1.2.3",\n "url": "https://mycompany.example.com/myapp/releases/myrelease3"\n }\n }\n ]\n}\n'})}),(0,r.jsxs)(t.p,{children:["On Windows, Squirrel.Windows can receive updates by reading from the RELEASES\nfile generated during the build process. This file details the ",(0,r.jsx)(t.code,{children:".nupkg"})," delta\npackage to update to."]}),(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-plaintext",metastring:"title='RELEASES'",children:"B0892F3C7AC91D72A6271FF36905FEF8FE993520 electron-fiddle-0.36.3-full.nupkg 103298365\n"})}),(0,r.jsx)(t.p,{children:"These files should live in the same directory as your release, under a folder\nstructure that is aware of your app's platform and architecture."}),(0,r.jsx)(t.p,{children:"For example:"}),(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-plaintext",children:"my-app-updates/\n\u251C\u2500 darwin/\n\u2502 \u251C\u2500 x64/\n\u2502 \u2502 \u251C\u2500 my-app-1.0.0-darwin-x64.zip\n\u2502 \u2502 \u251C\u2500 my-app-1.1.0-darwin-x64.zip\n\u2502 \u2502 \u251C\u2500 RELEASES.json\n\u2502 \u251C\u2500 arm64/\n\u2502 \u2502 \u251C\u2500 my-app-1.0.0-darwin-arm64.zip\n\u2502 \u2502 \u251C\u2500 my-app-1.1.0-darwin-arm64.zip\n\u2502 \u2502 \u251C\u2500 RELEASES.json\n\u251C\u2500 win32/\n\u2502 \u251C\u2500 x64/\n\u2502 \u2502 \u251C\u2500 my-app-1.0.0-win32-x64.exe\n\u2502 \u2502 \u251C\u2500 my-app-1.0.0-win32-x64.nupkg\n\u2502 \u2502 \u251C\u2500 my-app-1.1.0-win32-x64.exe\n\u2502 \u2502 \u251C\u2500 my-app-1.1.0-win32-x64.nupkg\n\u2502 \u2502 \u251C\u2500 RELEASES\n"})})]}),"\n",(0,r.jsx)(t.h3,{id:"reading-release-metadata",children:"Reading release metadata"}),"\n",(0,r.jsxs)(t.p,{children:["The easiest way to consume metadata is by installing ",(0,r.jsx)(t.a,{href:"https://github.com/electron/update-electron-app",children:"update-electron-app"}),",\na drop-in Node.js module that sets up autoUpdater and prompts the user with\na native dialog."]}),"\n",(0,r.jsxs)(t.p,{children:["For static storage updates, point the ",(0,r.jsx)(t.code,{children:"updateSource.baseUrl"})," parameter to\nthe directory containing your release metadata files."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:'title="main.js" @ts-nocheck',children:"const { updateElectronApp, UpdateSourceType } = require('update-electron-app')\n\nupdateElectronApp({\n updateSource: {\n type: UpdateSourceType.StaticStorage,\n baseUrl: `https://my-bucket.s3.amazonaws.com/my-app-updates/${process.platform}/${process.arch}`\n }\n})\n"})}),"\n",(0,r.jsx)(t.h2,{id:"using-updateelectronjsorg",children:"Using update.electronjs.org"}),"\n",(0,r.jsxs)(t.p,{children:["The Electron team maintains ",(0,r.jsx)(t.a,{href:"https://github.com/electron/update.electronjs.org",children:"update.electronjs.org"}),", a free and open-source\nwebservice that Electron apps can use to self-update. The service is designed\nfor Electron apps that meet the following criteria:"]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"App runs on macOS or Windows"}),"\n",(0,r.jsx)(t.li,{children:"App has a public GitHub repository"}),"\n",(0,r.jsxs)(t.li,{children:["Builds are published to ",(0,r.jsx)(t.a,{href:"https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository#creating-a-release",children:"GitHub Releases"})]}),"\n",(0,r.jsxs)(t.li,{children:["Builds are ",(0,r.jsx)(t.a,{href:"/docs/latest/tutorial/code-signing",children:"code-signed"})," ",(0,r.jsx)(t.strong,{children:"(macOS only)"})]}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["The easiest way to use this service is by installing ",(0,r.jsx)(t.a,{href:"https://github.com/electron/update-electron-app",children:"update-electron-app"}
1),",\na Node.js module preconfigured for use with update.electronjs.org."]}),"\n",(0,r.jsx)(t.p,{children:"Install the module using your Node.js package manager of choice:"}),"\n",(0,r.jsxs)(i.A,{groupId:"npm2yarn",children:[(0,r.jsx)(o.A,{value:"npm",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"npm install update-electron-app\n"})})}),(0,r.jsx)(o.A,{value:"yarn",label:"Yarn",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-sh",children:"yarn add update-electron-app\n"})})})]}),"\n",(0,r.jsx)(t.p,{children:"Then, invoke the updater from your app's main process file:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:'title="main.js" @ts-nocheck',children:"require('update-electron-app')()\n"})}),"\n",(0,r.jsx)(t.p,{children:"By default, this module will check for updates at app startup, then every ten\nminutes. When an update is found, it will automatically be downloaded in the background.\nWhen the download completes, a dialog is displayed allowing the user to restart the app."}),"\n",(0,r.jsxs)(t.p,{children:["If you need to customize your configuration, you can\n",(0,r.jsx)(t.a,{href:"https://github.com/electron/update-electron-app",children:"pass options to update-electron-app"}),"\nor\n",(0,r.jsx)(t.a,{href:"https://github.com/electron/update.electronjs.org",children:"use the update service directly"}),"."]}),"\n",(0,r.jsx)(t.h2,{id:"using-other-update-services",children:"Using other update services"}),"\n",(0,r.jsx)(t.p,{children:"If you're developing a private Electron application, or if you're not\npublishing releases to GitHub Releases, it may be necessary to run your own\nupdate server."}),"\n",(0,r.jsx)(t.h3,{id:"step-1-deploying-an-update-server",children:"Step 1: Deploying an update server"}),"\n",(0,r.jsx)(t.p,{children:"Depending on your needs, you can choose from one of these:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"https://github.com/vercel/hazel",children:"Hazel"})," \u2013 Update server for private or open-source apps which can be\ndeployed for free on ",(0,r.jsx)(t.a,{href:"https://vercel.com",children:"Vercel"}),". It pulls from ",(0,r.jsx)(t.a,{href:"https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository#creating-a-release",children:"GitHub Releases"}),"\nand leverages the power of GitHub's CDN."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"https://github.com/GitbookIO/nuts",children:"Nuts"})," \u2013 Also uses ",(0,r.jsx)(t.a,{href:"https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository#creating-a-release",children:"GitHub Releases"}),", but caches app\nupdates on disk and supports private repositories."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"https://github.com/ArekSredzki/electron-release-server",children:"electron-release-server"})," \u2013 Provides a dashboard for\nhandling releases and does not require releases to originate on GitHub."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"https://github.com/atlassian/nucleus",children:"Nucleus"})," \u2013 A complete update server for Electron apps maintained by\nAtlassian. Supports multiple applications and channels; uses a static file store\nto minify server cost."]}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["Once you've deployed your update server, you can instrument your app code to receive and\napply the updates with Electron's ",(0,r.jsx)(t.a,{href:"/docs/latest/api/auto-updater",children:"autoUpdater"})," module."]}),"\n",(0,r.jsx)(t.h3,{id:"step-2-receiving-updates-in-your-app",children:"Step 2: Receiving updates in your app"}),"\n",(0,r.jsxs)(t.p,{children:["First, import the required modules in your main process code. The following code might\nvary for different server software, but it works like described when using ",(0,r.jsx)(t.a,{href:"https://github.com/vercel/hazel",children:"Hazel"}),"."]}),"\n",(0,r.jsx)(t.admonition,{title:"Check your execution environment!",type:"warning",children:(0,r.jsxs)(t.p,{children:["Please ensure that the code below will only be executed in your packaged app, and not in development.\nYou can use the ",(0,r.jsx)(t.a,{href:"/docs/latest/api/app#appispackaged-readonly",children:"app.isPackaged"})," API to check the environment."]})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:"title='main.js'",children:"const { app, autoUpdater, dialog } = require('electron')\n"})}),"\n",(0,r.jsxs)(t.p,{children:["Next, construct the URL of the update server feed and tell\n",(0,r.jsx)(t.a,{href:"/docs/latest/api/auto-updater",children:"autoUpdater"})," about it:"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:"title='main.js'",children:"const server = 'https://your-deployment-url.com'\nconst url = `${server}/update/${process.platform}/${app.getVersion()}`\n\nautoUpdater.setFeedURL({ url })\n"})}),"\n",(0,r.jsx)(t.p,{children:"As the final step, check for updates. The example below will check every minute:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:"title='main.js'",children:"setInterval(() =>
1 {\n autoUpdater.checkForUpdates()\n}, 60000)\n"})}),"\n",(0,r.jsxs)(t.p,{children:["Once your application is ",(0,r.jsx)(t.a,{href:"/docs/latest/tutorial/application-distribution",children:"packaged"}),",\nit will receive an update for each new ",(0,r.jsx)(t.a,{href:"https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository#creating-a-release",children:"GitHub Release"})," that you\npublish."]}),"\n",(0,r.jsx)(t.h3,{id:"step-3-notifying-users-when-updates-are-available",children:"Step 3: Notifying users when updates are available"}),"\n",(0,r.jsxs)(t.p,{children:["Now that you've configured the basic update mechanism for your application, you\nneed to ensure that the user will get notified when there's an update. This\ncan be achieved using the ",(0,r.jsx)(t.a,{href:"/docs/latest/api/auto-updater#events",children:"autoUpdater API events"}),":"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:'title="main.js" @ts-expect-error=[10]',children:"autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName) => {\n const dialogOpts = {\n type: 'info',\n buttons: ['Restart', 'Later'],\n title: 'Application Update',\n message: process.platform === 'win32' ? releaseNotes : releaseName,\n detail: 'A new version has been downloaded. Restart the application to apply the updates.'\n }\n\n dialog.showMessageBox(dialogOpts).then((returnValue) => {\n if (returnValue.response === 0) autoUpdater.quitAndInstall()\n })\n})\n"})}),"\n",(0,r.jsxs)(t.p,{children:["Also make sure that errors are\n",(0,r.jsx)(t.a,{href:"/docs/latest/api/auto-updater#event-error",children:"being handled"}),". Here's an example\nfor logging them to ",(0,r.jsx)(t.code,{children:"stderr"}),":"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:'title="main.js"',children:"autoUpdater.on('error', (message) => {\n console.error('There was a problem updating the application')\n console.error(message)\n})\n"})}),"\n",(0,r.jsx)(t.admonition,{title:"Handling updates manually",type:"info",children:(0,r.jsxs)(t.p,{children:["Because the requests made by autoUpdate aren't under your direct control, you may find situations\nthat are difficult to handle (such as if the update server is behind authentication). The ",(0,r.jsx)(t.code,{children:"url"}),"\nfield supports the ",(0,r.jsx)(t.code,{children:"file://"})," protocol, which means that with some effort, you can sidestep the\nserver-communication aspect of the process by loading your update from a local directory.\n",(0,r.jsx)(t.a,{href:"https://github.com/electron/electron/issues/5020#issuecomment-477636990",children:"Here's an example of how this could work"}),"."]})}),"\n",(0,r.jsx)(t.h2,{id:"update-server-specification",children:"Update server specification"}),"\n",(0,r.jsx)(t.p,{children:"For advanced deployment needs, you can also roll out your own Squirrel-compatible update server.\nFor example, you may want to have percentage-based rollouts, distribute your app through separate\nrelease channels, or put your update server behind an authentication check."}),"\n",(0,r.jsxs)(t.p,{children:["Squirrel.Windows and Squirrel.Mac clients require different response formats,\nbut you can use a single server for both platforms by sending requests to\ndifferent endpoints depending on the value of ",(0,r.jsx)(t.code,{children:"process.platform"}),"."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:"title='main.js'",children:"const { app, autoUpdater } = require('electron')\n\nconst server = 'https://your-deployment-url.com'\n// e.g. for Windows and app version 1.2.3\n// https://your-deployment-url.com/update/win32/1.2.3\nconst url = `${server}/update/${process.platform}/${app.getVersion()}`\n\nautoUpdater.setFeedURL({ url })\n"})}),"\n",(0,r.jsx)(t.h3,{id:"windows",children:"Windows"}),"\n",(0,r.jsxs)(t.p,{children:["A Squirrel.Windows client expects the update server to return the ",(0,r.jsx)(t.code,{children:"RELEASES"})," artifact\nof the latest available build at the ",(0,r.jsx)(t.code,{children:"/RELEASES"})," subpath of your endpoint."]}),"\n",(0,r.jsxs)(t.p,{children:["For example, if your feed URL is ",(0,r.jsx)(t.code,{children:"https://your-deployment-url.com/update/win32/1.2.3"}),",\nthen the ",(0,r.jsx)(t.code,{children:"https://your-deployment-url.com/update/win32/1.2.3/RELEASES"})," endpoint\nshould return the contents of the ",(0,r.jsx)(t.code,{children:"RELEASES"})," artifact of the version you want to serve."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-plaintext",metastring:"title='https://your-deployment-url.com/update/win32/1.2.3/RELEASES'",children:"B0892F3C7AC91D72A6271FF36905FEF8FE993520 https://your-static.storage/your-app-1.2.3-full.nupkg 103298365\n"})}),"\n",(0,r.jsxs)(t.p,{children:["Squirrel.Windows does the comparison check to see if the current app should update to\nthe version returned in ",(0,r.jsx)(t.code,{children:"RELEASES"}),", so you should return a response even when no update\nis available."]}),"\n",(0,r.jsx)(t.h3,{id:"macos",children:"macOS"}),"\n",(0,r.jsxs)(t.p,{children:["When an update is available, the Squirrel.Mac client expects a JSON response at the feed URL's endpoint.\nThis object has a mandatory ",(0,r.jsx)(t.code,{children:"url"})," property that maps to a ZIP archive of the\napp update. All other properties in the object are optional."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-json",metastring:"title='https://your-deployment-url.com/update/darwin/0.31.0'",children:'{\n "url": "https://your-static.storage/your-app-1.2.3-darwin.zip",\n "name": "1.2.3",\n "notes": "These are some release notes innit",\n "pub_date": "2024-09-18T12:29:53+01:00"\n}\n'})}),"\n",(0,r.jsxs)(t.p,{children:["If no update is available, the server should return a ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/204",children:(0,r.jsx)(t.code,{children:"204 No Content"})}),"\nHTTP response."]})]})}function h(e={}){let{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(p,{...e})}):p(e)}},57250(e,t,n){n.d(t,{A:()=>
1o});var a=n(74848);n(96540);var r=n(18215),s=n(57663);function i({children:e,className:t,hidden:n}){return(0,a.jsx)("div",{role:"tabpanel",className:(0,r.A)("tabItem_Ymn6",t),hidden:n,children:e})}function o({children:e,className:t,value:n}){let{selectedValue:r,lazy:l}=(0,s.uc)(),d=n===r;return!d&&l?null:(0,a.jsx)(i,{className:t,hidden:!d,children:e})}},50773(e,t,n){n.d(t,{A:()=>p});var a=n(74848);n(96540);var r=n(18215),s=n(88287),i=n(57663),o=n(28584),l=n(19863);function d({className:e}){let{selectedValue:t,selectValue:n,tabValues:s,block:l}=(0,i.uc)(),c=[],{blockElementScrollPositionUntilNextRender:u}=(0,o.a_)(),p=e=>{let a=e.currentTarget,r=s[c.indexOf(a)].value;r!==t&&(u(a),n(r))},h=e=>{let t=null;switch(e.key){case"Enter":p(e);break;case"ArrowRight":{let n=c.indexOf(e.currentTarget)+1;t=c[n]??c[0];break}case"ArrowLeft":{let n=c.indexOf(e.currentTarget)-1;t=c[n]??c[c.length-1]}}t?.focus()};return(0,a.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,r.A)("tabs",{"tabs--block":l},e),children:s.map(({value:e,label:n,attributes:s})=>(0,a.jsx)("li",{role:"tab",tabIndex:t===e?0:-1,"aria-selected":t===e,ref:e=>{c.push(e)},onKeyDown:h,onClick:p,...s,className:(0,r.A)("tabs__item","tabItem_LNqP",s?.className,{"tabs__item--active":t===e}),children:n??e},e))})}function c({children:e}){return(0,a.jsx)("div",{className:"margin-top--md",children:e})}function u({className:e,children:t}){return(0,a.jsxs)("div",{className:(0,r.A)(s.G.tabs.container,"tabs-container","tabList__CuJ"),children:[(0,a.jsx)(d,{className:e}),(0,a.jsx)(c,{children:t})]})}function p(e){let t=(0,l.A)(),n=(0,i.OC)(e);return(0,a.jsx)(i.O_,{value:n,children:(0,a.jsx)(u,{className:e.className,children:(0,i.vT)(e.children)})},String(t))}},57663(e,t,n){n.d(t,{OC:()=>p,O_:()=>g,uc:()=>m,vT:()=>c});var a=n(74848),r=n(96540),s=n(56347),i=n(99989),o=n(96629),l=n(80618),d=n(41367);function c(e){return r.Children.toArray(e).filter(e=>"\n"!==e)}function u({value:e,tabValues:t}){return t.some(t=>t.value===e)}function p(e){let t,{defaultValue:n,queryString:a=!1,groupId:c}=e,p=function(e){let{values:t,children:n}=e;return(0,r.useMemo)(()=>{let e=t??r.Children.toArray(n).flatMap(e=>{if(!e)return[];if((0,r.isValidElement)(e)&&function(e){let{props:t}=e;return!!t&&"object"==typeof t&&"value"in t}(e))return[e];let t="string"==typeof e.type?e.type:e.type.name;throw Error(`Docusaurus error: Bad <Tabs> child <${t}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop. 2If you do not want to pass on a "value" prop to the direct children of <Tabs>, you can also pass an explicit <Tabs values={...}> prop.`)}).map(({props:{value:e,label:t,attributes:n,default:a}})=>({value:e,label:t,attributes:n,default:a})),a=(0,l.XI)(e,(e,t)=>e.value===t.value);if(a.length>0)throw Error(`Docusaurus error: Duplicate values "${a.map(e=>`'${e.value}'`).join(", ")}" found in <Tabs>. Every value needs to be unique.`);return e},[t,n])}(e),[h,m]=(0,r.useState)(()=>(function({defaultValue:e,tabValues:t}){if(0===t.length)throw Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(e){if(!u({value:e,tabValues:t}))throw Error(`Docusaurus error: The <Tabs> has a defaultValue "${e}" but none of its children has the corresponding value. Available values are: ${t.map(e=>e.value).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return e}let n=t.find(e=>e.default)??t[0];if(!n)throw Error("Unexpected error: 0 tabValues");return n.value})({defaultValue:n,tabValues:p})),[g,f]=function({queryString:e=!1,groupId:t}){let n=(0,s.W6)(),a=function({queryString:e=!1,groupId:t}){if("string"==typeof e)return e;if(!1===e)return null;if(!0===e&&!t)throw Error('Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return t??null}({queryString:e,groupId:t});return[(0,o.aZ)(a),(0,r.useCallback)(e=>{if(!a)return;let t=new URLSearchParams(n.location.search);t.set(a,e),n.replace({...n.location,search:t.toString()})},[a,n])]}({queryString:a,groupId:c}),[j,x]=function({groupId:e}){let t=e?`docusaurus.tab.${e}`:null,[n,a]=(0,d.Dv)(t);return[n,(0,r.useCallback)(e=>{t&&a.set(e)},[t,a])]}({groupId:c}),v=u({value:t=g??j,tabValues:p})?t:null;return(0,i.A)(()=>{v&&m(v)},[v]),{selectedValue:h,selectValue:(0,r.useCallback)(e=>{if(!u({value:e,tabValues:p}))throw Error(`Can't select invalid tab value=${e}`);m(e),f(e),x(e)},[f,x,p]),tabValues:p,lazy:e.lazy??!1,block:e.block??!1}}let h=(0,r.createContext)(null);function m(){let e=r.useContext(h);if(!e)throw Error("useTabsContext() must be used within a Tabs component");return e}function g(e){return(0,a.jsx)(h.Provider,{value:e.value,children:e.children})}},28453(e,t,n){n.d(t,{R:()=>i,x:()=>o});var a=n(96540);let r={},s=a.createContext(r);function i(e){let t=a.useContext(s);return a.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),a.createElement(s.Provider,{value:t},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.