1"use strict";(self.webpackChunkkurokuro=self.webpackChunkkurokuro||[]).push([["19967"],{62302:function(e,t,n){n.r(t),n.d(t,{metadata:()=>i,default:()=>p,frontMatter:()=>c,contentTitle:()=>l,toc:()=>u,assets:()=>d});var i=JSON.parse('{"id":"tutorials/restricting-api-access-with-statictoken","title":"How to restrict API access with Static Access Token","description":"Kuroco\'s API security","source":"@site/docs/tutorials/restricting-api-access-with-statictoken.mdx","sourceDirName":"tutorials","slug":"/tutorials/restricting-api-access-with-statictoken","permalink":"/docs/tutorials/restricting-api-access-with-statictoken","draft":false,"unlisted":false,"editUrl":"https://github.com/diverta/kuroco-documents/tree/main/packages/create-docusaurus/templates/shared/docs/tutorials/restricting-api-access-with-statictoken.mdx","tags":[],"version":"current","frontMatter":{"title":"How to restrict API access with Static Access Token","category":"API","weight":1},"sidebar":"documentationSidebar","previous":{"title":"How to check the API security using Swagger UI","permalink":"/docs/tutorials/how-to-use-swagger-ui"},"next":{"title":"How to get the origin country/region of API requests","permalink":"/docs/tutorials/how-to-add-region-data"}}'),s=n(74848),r=n(28453),a=n(78010),o=n(57250);let c={title:"How to restrict API access with Static Access Token",category:"API",weight:1},l,d={},u=[{value:"Kuroco's API security",id:"kurocos-api-security",level:2},{value:"How to restrict API access by Static Access Token",id:"how-to-restrict-api-access-by-static-access-token",level:2},{value:"1. Configure the security of Kuroco API",id:"1-configure-the-security-of-kuroco-api",level:3},{value:"2. Issue Static Access Token",id:"2-issue-static-access-token",level:3},{value:"3. API Access Configuration",id:"3-api-access-configuration",level:3},{value:"4. Setting Environment Variables",id:"4-setting-environment-variables",level:3},{value:"5. Updating Configuration Files",id:"5-updating-configuration-files",level:3},{value:"6. Setting Static Access Token in API Request Headers",id:"6-setting-static-access-token-in-api-request-headers",level:3},{value:"7. API Usage Examples",id:"7-api-usage-examples",level:3},{value:"How to restrict API access by Privileged Static Token",id:"how-to-restrict-api-access-by-privileged-static-token",level:2},{value:"1. Set the security to Privileged Static Token",id:"1-set-the-security-to-privileged-static-token",level:3},{value:"2. Issue the Privileged Static Token",id:"2-issue-the-privileged-static-token",level:3},{value:"3. API Access Configuration",id:"3-api-access-configuration-1",level:3},{value:"Reference",id:"reference",level:2},{value:"Related documents",id:"related-documents",level:2}];function h(e){let t={a:"a",admonition:"admonition",br:"br",code:"code",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h2,{id:"kurocos-api-security",children:"Kuroco's API security"}),"\n",(0,s.jsx)(t.p,{children:"You have following 5 options for Kuroco's API security:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"None"}),"\n",(0,s.jsx)(t.li,{children:"Static Access Token"}),"\n",(0,s.jsx)(t.li,{children:"Dynamic Access Token"}),"\n",(0,s.jsx)(t.li,{children:"Cookie"}),"\n",(0,s.jsx)(t.li,{children:"Privileged Static Token"}),"\n"]}),"\n",(0,s.jsxs)(t.p,{children:['You can set "None" if you want to create and test a temporary development API, or if you want to use completely open data.\n',(0,s.jsx)(t.img,{src:"https://rcms.g.kuroco-img.app/files/user/gyazo/ef/efb08ca3c9f21c088796adf02dcf073c.png?width=600","data-zoom-src":"https://rcms.g.kuroco-img.app/files/user/gyazo/ef/efb08ca3c9f21c088796adf02dcf073c.png",alt:"Image from Gyazo"})]}),"\n",(0,s.jsx)(t.p,{children:'However, if you set the API security setting to "None", anyone can use the API, and it will be possible to accept API requests indiscriminately from the outside.'}),"\n",(0,s.jsx)(t.p,{children:"If this situation is not as expected, you can use the Static Access Token function to impose some restrictions.\nThis tutorial explains how to apply access restrictions using Static Access Token."}),"\n",(0,s.jsxs)(t.p,{children:["Note:",(0,s.jsx)(t.br,{}),"\n","The character string of StaticToken becomes information that can be viewed from the outside by referring to the network communication of the public site and the description in the JS file. Therefore, if you want to restrict secure information, please do so by restricting login authentication by Dynamic Token / Cookie restriction instead of Static Access Token or by restricting API by browsing group."]}),"\n",(0,s.jsx)(t.h2,{id:"how-to-restrict-api-access-by-static-access-token",children:"How to restrict API access by Static Access Token"}),"\n",(0,s.jsx)(t.p,{children:"This section explains how to restrict API access by Static Access Token."}),"\n",(0,s.jsx)(t.h3,{id:"1-configure-the-security-of-kuroco-api",children:"1. Configure the security of Kuroco API"}),"\n",(0,s.jsxs)(t.p,{children:["On any API list page, click [Security].",(0,s.jsx)(t.br,{}),"\n",(0,s.jsx)(t.img,{src:"https://rcms.g.kuroco-img.app/files/user/gyazo/a3/a3a55f1ee37301a9df29df84ce1b4c32.png?width=600","data-zoom-src":"https://rcms.g.kuroco-img.app/files/user/gyazo/a3/a3a55f1ee37301a9df29df84ce1b4c32.png",alt:"Image from Gyazo"})]}),"\n",(0,s.jsxs)(t.p,{children:['Change the "Security" to ',(0,s.jsx)(t.code,{children:"Static Access Token"})," and click [Save]\n",(0,s.jsx)(t.img,{src:"https://rcms.g.kuroco-img.app/files/user/gyazo/96/964db1c6f8a645fed25b777f3d2d4f1c.png?width=600","data-zoom-src":"https://rcms.g.kuroco-img.app/files/user/gyazo/96/964db1c6f8a645fed25b777f3d2d4f1c.png",alt:"Image from Gyazo"})]}),"\n",(0,s.jsx)(t.h3,{id:"2-issue-static-access-token",children:"2. Issue Static Access Token"}),"\n",(0,s.jsxs)(t.p,{children:["Click [Swagger UI] on the API list page.",(0,s.jsx)(t.br,{}),"\n",(0,s.jsx)(t.img,{src:"https://rcms.g.kuroco-img.app/files/user/gyazo/db/db05d2056b6b378166495c378a8a4cf9.png?width=600","data-zoom-src":"https://rcms.g.kuroco-img.app/files/user/gyazo/db/db05d2056b6b378166495c378a8a4cf9.png",alt:"Image from Gyazo"})]}),"\n",(0,s.jsxs)(t.p,{children:['Enter "Valid Until" of "Generate Static Access Token" at the top of Swagger UI page and click [Generate].',(0,s.jsx)(t.br,{}),"\n",(0,s.jsx)(t.img,{src:"https://rcms.g.kuroco-img.app/files/user/gyazo/82/8269c6ba4d7334e2d8145d3ca0b8afad.png?width=600","data-zoom-src":"https://rcms.g.kuroco-img.app/files/user/gyazo/82/8269c6ba4d7334e2d8145d3ca0b8afad.png",alt:"Image from Gyazo"})]}),"\n",(0,s.jsxs)(t.p,{children:["Token will be issued. You will need it later so save it.",(0,s.jsx)(t.br,{}),"\n",(0,s.jsx)(t.img,{src:"https://rcms.g.kuroco-img.app/files/user/gyazo/b9/b944eebd7c83962562324408ac7bf798.png?width=600","data-zoom-src":"https://rcms.g.kuroco-img.app/files/user/gyazo/b9/b944eebd7c83962562324408ac7bf798.png",alt:"Image from Gyazo"})]}),"\n",(0,s.jsx)(t.p,{children:"The configuration on the Kuroco management page is now complete."}),"\n",(0,s.jsx)(t.h3,{id:"3-api-access-configuration",children:"3. API Access Configuration"}),"\n",(0,s.jsx)(t.p,{children:"As an example, here are code snippets for Nuxt 3 and Next.js."}),"\n",(0,s.jsxs)(t.admonition,{type:"info",children:[(0,s.jsx)(t.p,{children:"In this tutorial, the following versions are used:"}),(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Nuxt3: v3.14.0"}),"\n",(0,s.jsx)(t.li,{children:"Next.js: v15.0.3 (Using App Router)"}),"\n"]})]}),"\n",(0,s.jsx)(t.p,{children:"First, install the necessary packages for the tutorial:"}),"\n",(0,s.jsxs)(a.A,{children:[(0,s.jsx)(o.A,{value:"Nuxt3",label:"Nuxt3",default:!0,children:(0,s.jsx)(t.p,{children:"No additional packages are required for Nuxt 3."})}),(0,s.jsx)(o.A,{value:"Next.js",label:"Next.js",default:!0,children:(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",metastring:'title="terminal"',children:"npm install axios\n"})})})]}),"\n",(0,s.jsx)(t.h3,{id:"4-setting-environment-variables",children:"4. Setting Environment Variables"}),"\n",(0,s.jsxs)(a.A,{children:[(0,s.jsx)(o.A,{value:"Nuxt3",label:"Nuxt3",default:!0,children:(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-plaintext",metastring:'title=".env"',children:"NUXT_STATIC_TOKEN=YOUR_STATIC_TOKEN_HERE\nNUXT_PUBLIC_API_BASE_URL=https://your-api-endpoint.com\n"})})}),(0,s.jsx)(o.A,{value:"Next.js",label:"Next.js",default:!0,children:(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-plaintext",metastring:'title=".env"',children:"STATIC_TOKEN=YOUR_STATIC_TOKEN_HERE\nNEXT_PUBLIC_API_URL=https://your-api-endpoint.com\n"})})})]}),"\n",(0,s.jsxs)(t.admonition,{title:"Note",type:"caution",children:[(0,s.jsxs)(t.p,{children:["Environment variables prefixed with ",(0,s.jsx)(t.code,{children:"NUXT_PUBLIC_"}),"/",(0,s.jsx)(t.code,{children:"NEXT_PUBLIC_"})," are accessible on the client side. For more details, refer to the following links:"]}),(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"https://nuxt.com/docs/guide/going-further/runtime-config",children:"Nuxt 3 Documents - runtime-config"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"https://nextjs.org/docs/app/building-your-application/configuring/environment-variables",children:"Next.js Documents - environment-variables"})}),"\n"]})]}),"\n",(0,s.jsx)(t.h3,{id:"5-updating-configuration-files",children:"5. Updating Configuration Files"}),"\n",(0,s.jsxs)(a.A,{children:[(0,s.jsx)(o.A,{value:"Nuxt3",label:"Nuxt3",default:!0,children:(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-ts",metastring:'title="nuxt.config.ts"',children:"export default defineNuxtConfig({\n runtimeConfig: {\
1n public: {\n staticToken: process.env.NUXT_STATIC_TOKEN,\n publicApiBaseUrl: process.env.NUXT_PUBLIC_API_BASE_URL\n }\n }\n})\n"})})}),(0,s.jsx)(o.A,{value:"Next.js",label:"Next.js",default:!0,children:(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-ts",metastring:'title="next.config.js"',children:"/** @type {import('next').NextConfig} */\nconst nextConfig = {\n env: {\n STATIC_TOKEN: process.env.STATIC_TOKEN\n }\n}\n\nmodule.exports = nextConfig\n"})})})]}),"\n",(0,s.jsx)(t.h3,{id:"6-setting-static-access-token-in-api-request-headers",children:"6. Setting Static Access Token in API Request Headers"}),"\n",(0,s.jsxs)(a.A,{children:[(0,s.jsxs)(o.A,{value:"Nuxt3",label:"Nuxt3",default:!0,children:[(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-ts",metastring:'title="/plugins/fetch.ts"',children:"export default defineNuxtPlugin(() => {\n const config = useRuntimeConfig()\n\n return {\n provide: {\n customFetch: (url: string, options = {}) => {\n return useFetch(url, {\n baseURL: config.public.apiBase as string,\n headers: {\n 'x-rcms-api-access-token': config.public.staticToken as string\n },\n ...options\n })\n }\n }\n }\n})\n"})}),(0,s.jsxs)(t.admonition,{type:"info",children:[(0,s.jsxs)(t.p,{children:["The Kuroco Beginner's Guide does not cover the use of ",(0,s.jsx)(t.code,{children:"plugins"}),", but this is a good opportunity to explore it in the official documentation:"]}),(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"https://nuxt.com/docs/guide/directory-structure/plugins",children:"Nuxt 3 Documents - plugins"})}),"\n"]})]})]}),(0,s.jsx)(o.A,{value:"Next.js",label:"Next.js",default:!0,children:(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-ts",metastring:'title="/lib/axios.ts"',children:"import axios from 'axios'\n\nexport const api = axios.create({\n baseURL: process.env.NEXT_PUBLIC_API_URL,\n headers: {\n 'x-rcms-api-access-token': process.env.STATIC_TOKEN\n }\n})\n"})})})]}),"\n",(0,s.jsx)(t.h3,{id:"7-api-usage-examples",children:"7. API Usage Examples"}),"\n",(0,s.jsxs)(a.A,{children:[(0,s.jsx)(o.A,{value:"Nuxt3",label:"Nuxt3",default:!0,children:(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-markup",metastring:'title="/pages/example.vue"',children:"<script setup>\n// Basic usage\nconst { $customFetch } = useNuxtApp()\nconst { data: response } = await $customFetch('/api/endpoint');\n\n// Example of overriding headers\nconst { $customFetch } = useNuxtApp()\nconst { data: customData } = await $customFetch('/api/endpoint', {\n headers: {\n 'x-rcms-api-access-token': 'different-token'\n }\n}\n<\/script>\n<template>\n <div>\n <div v-if=\"pending\">Loading...</div>\n <div v-else>\n <pre>{{ data }}</pre>\n </div>\n </div>\n</template>\n"})})}),(0,s.jsx)(o.A,{value:"Next.js",label:"Next.js",default:!0,children:(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tsx",metastring:'title="/app/example.tsx"',children:"// Using API client\nimport { api } from '@/lib/axios'\n\nexport default function Page() {\n const [data, setData] = useState(null)\n\n useEffect(() => {\n const fetchData = async () => {\n const response = await api.get('/api/endpoint')\n setData(response.data)\n }\n fetchData()\n }, [])\n\n return <div>{/* Display data */}</div>\n}\n\n// Using built-in fetch\nasync function getData() {\n const res = await fetch('https://api-endpoint.com/api/endpoint', {\n headers: {\n 'x-rcms-api-access-token': process.env.STATIC_TOKEN\n }\n })\n return res.json()\n}\n\n// Using in App Router Server Component\nexport default async function Page() {\n const data = await getData()\n return <div>{/* Display data */}</div>\n}\n"})})})]}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["Nuxt 3: Examples of using ",(0,s.jsx)(t.code,{children:"useFetch"})," / ",(0,s.jsx)(t.code,{children:"$fetch"})," to automatically include the static token in headers."]}),"\n",(0,s.jsxs)(t.li,{children:["Next.js: Examples of using ",(0,s.jsx)(t.code,{children:"fetch"})," or ",(0,s.jsx)(t.code,{children:"axios"})," to set static tokens in request headers."]}),"\n"]})}),"\n",(0,s.jsx)(t.admonition,{type:"tip",children:(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["Set the static access token as a key in the request header ",(0,s.jsx)(t.code,{children:"X-RCMS-API-ACCESS-TOKEN"})," to send requests and retrieve data."]}),"\n"]})}),"\n",(0,s.jsx)(t.admonition,{type:"caution",children:(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["Depending on your project, it is recommended to write environment variables in separate files such as ",(0,s.jsx)(t.code,{children:".env"})," or ",(0,s.jsx)(t.code,{children:".env.local"})," etc... Make sure to add environment variable files to ",(0,s.jsx)(t.code,{children:".gitignore"})," to prevent committing sensitive information to the repository."]}),"\n"]})}),"\n",(0,s.jsx)(t.p,{children:"The configuration of API access restriction by Static Access Token is now complete."}),"\n",(0,s.jsx)(t.h2,{id:"how-to-restrict-api-access-by-privileged-static-token",children:"How to restrict API access by Privileged Static Token"}),"\n",(0,s.jsxs)(t.p,{children:["The privileged static token uses the same token-based authentication as the static access token, but requires specifying a member during token generation.",(0,s.jsx)(t.br,{}),"\n","Since requests are executed with the permissions of the specified member, you can access endpoints that have API request restrictions without going through the login or dynamic token generation flow.",(0,s.jsx)(t.br,{}),"\n","This is useful, for example, in server-to-server communication where you need to access the API with the permissions of a specific member."]}),"\n",(0,s.jsx)(t.p,{children:"Setting the token in the request header and using it from the frontend are the same as for the static access token. This section explains the management screen operations that differ from the static access token."}),"\n",(0,s.jsx)(t.h3,{id:"1-set-the-security-to-privileged-static-token",children:"1. Set the security to Privileged Static Token"}
1),"\n",(0,s.jsx)(t.p,{children:'On the API page, click the Security [Settings], change the "Security" to [Privileged Static Token], and click [Update].'}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.img,{src:"https://rcms.g.kuroco-img.app/files/user/gyazo/ee/ee5c18e8fba5e9c0867d34802d5a4fd4.png?width=600","data-zoom-src":"https://rcms.g.kuroco-img.app/files/user/gyazo/ee/ee5c18e8fba5e9c0867d34802d5a4fd4.png",alt:"Image from Gyazo"})}),"\n",(0,s.jsx)(t.h3,{id:"2-issue-the-privileged-static-token",children:"2. Issue the Privileged Static Token"}),"\n",(0,s.jsx)(t.p,{children:"Click [Generate] of [Privileged Static Token] on the API information page, and specify the following items in the displayed dialog:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Expiration date"}),": Specify the expiration date of the token."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Memo"}),": You can enter an optional memo."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Member ID"}),": Specify the ID of the member to associate with the token. API requests will be executed with the permissions of this member."]}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.img,{src:"https://rcms.g.kuroco-img.app/files/user/gyazo/2e/2e264184f3ad4ac0ee54b5bdef882a23.png?width=600","data-zoom-src":"https://rcms.g.kuroco-img.app/files/user/gyazo/2e/2e264184f3ad4ac0ee54b5bdef882a23.png",alt:"Image from Gyazo"})}),"\n",(0,s.jsx)(t.p,{children:"After entering the values, click [Generate]. The token will be issued. You will need it later, so save it."}),"\n",(0,s.jsx)(t.h3,{id:"3-api-access-configuration-1",children:"3. API Access Configuration"}),"\n",(0,s.jsxs)(t.p,{children:["Setting the privileged static token in the request header is the same as for the static access token.",(0,s.jsx)(t.br,{}),"\n",'You can reuse the code in "3. API Access Configuration" through "7. API Usage Examples" above by simply replacing the token value set in the environment variables with the privileged static token value.',(0,s.jsx)(t.br,{}),"\n","As with the static access token, set the token in the request header using ",(0,s.jsx)(t.code,{children:"X-RCMS-API-ACCESS-TOKEN"})," as the key."]}),"\n",(0,s.jsx)(t.admonition,{type:"caution",children:(0,s.jsxs)(t.p,{children:["The privileged static token executes requests with the permissions of the specified member. Therefore, generate the token by specifying a member with appropriate permissions.",(0,s.jsx)(t.br,{}),"\n","Also, as with the static access token, there is a risk that the token string may leak, so design your system assuming that tokens will be rotated, and make sure not to commit sensitive information to the repository."]})}),"\n",(0,s.jsx)(t.p,{children:"The configuration of API access restriction by Privileged Static Token is now complete."}),"\n",(0,s.jsx)(t.h2,{id:"reference",children:"Reference"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"/docs/reference/api-security/",children:"API Security"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"/docs/tutorials/how-to-use-swagger-ui/",children:"How to check the API security using Swagger UI"})}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"related-documents",children:"Related documents"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"/docs/reference/api-security/",children:"API security"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"/docs/tutorials/how-to-use-swagger-ui/",children:"How to check the API security using Swagger UI"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"/docs/tutorials/integrate-login/",children:"Building a login page"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"/docs/tutorials/points-to-note-after-endpoint-configuration/",children:"Points to note after endpoint configuration"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"/docs/faq/notification-before-static-access-token-expires/",children:"Will I be notified before a static access token expires?"})}),"\n"]})]})}function p(e={}){let{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},57250:function(e,t,n){n.d(t,{A:()=>r});var i=n(74848);n(96540);var s=n(18215);function r({children:e,hidden:t,className:n}){return(0,i.jsx)("div",{role:"tabpanel",className:(0,s.A)("tabItem_Ymn6",n),hidden:t,children:e})}},78010:function(e,t,n){n.d(t,{A:()=>v});var i=n(74848),s=n(96540),r=n(18215),a=n(88287),o=n(28584),c=n(56347),l=n(99989),d=n(96629),u=n(80618),h=n(41367);function p(e){return s.Children.toArray(e).filter(e=>"\n"!==e).map(e=>{if(!e||(0,s.isValidElement)(e)&&function(e){let{props:t}=e;return!!t&&"object"==typeof t&&"value"in t}(e))return e;throw Error(`Docusaurus error: Bad <Tabs>
1 child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`)})?.filter(Boolean)??[]}function g({value:e,tabValues:t}){return t.some(t=>t.value===e)}var f=n(19863);function m({className:e,block:t,selectedValue:n,selectValue:s,tabValues:a}){let c=[],{blockElementScrollPositionUntilNextRender:l}=(0,o.a_)(),d=e=>{let t=e.currentTarget,i=a[c.indexOf(t)].value;i!==n&&(l(t),s(i))},u=e=>{let t=null;switch(e.key){case"Enter":d(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,i.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,r.A)("tabs",{"tabs--block":t},e),children:a.map(({value:e,label:t,attributes:s})=>(0,i.jsx)("li",{role:"tab",tabIndex:n===e?0:-1,"aria-selected":n===e,ref:e=>{c.push(e)},onKeyDown:u,onClick:d,...s,className:(0,r.A)("tabs__item","tabItem_LNqP",s?.className,{"tabs__item--active":n===e}),children:t??e},e))})}function x({lazy:e,children:t,selectedValue:n}){let a=(Array.isArray(t)?t:[t]).filter(Boolean);if(e){let e=a.find(e=>e.props.value===n);return e?(0,s.cloneElement)(e,{className:(0,r.A)("margin-top--md",e.props.className)}):null}return(0,i.jsx)("div",{className:"margin-top--md",children:a.map((e,t)=>(0,s.cloneElement)(e,{key:t,hidden:e.props.value!==n}))})}function j(e){let t=function(e){let t,{defaultValue:n,queryString:i=!1,groupId:r}=e,a=function(e){let{values:t,children:n}=e;return(0,s.useMemo)(()=>{let e=t??p(n).map(({props:{value:e,label:t,attributes:n,default:i}})=>({value:e,label:t,attributes:n,default:i})),i=(0,u.XI)(e,(e,t)=>e.value===t.value);if(i.length>0)throw Error(`Docusaurus error: Duplicate values "${i.map(e=>e.value).join(", ")}" found in <Tabs>. Every value needs to be unique.`);return e},[t,n])}(e),[o,f]=(0,s.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(!g({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:a})),[m,x]=function({queryString:e=!1,groupId:t}){let n=(0,c.W6)(),i=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,d.aZ)(i),(0,s.useCallback)(e=>{if(!i)return;let t=new URLSearchParams(n.location.search);t.set(i,e),n.replace({...n.location,search:t.toString()})},[i,n])]}({queryString:i,groupId:r}),[j,v]=function({groupId:e}){let t=e?`docusaurus.tab.${e}`:null,[n,i]=(0,h.Dv)(t);return[n,(0,s.useCallback)(e=>{t&&i.set(e)},[t,i])]}({groupId:r}),b=g({value:t=m??j,tabValues:a})?t:null;return(0,l.A)(()=>{b&&f(b)},[b]),{selectedValue:o,selectValue:(0,s.useCallback)(e=>{if(!g({value:e,tabValues:a}))throw Error(`Can't select invalid tab value=${e}`);f(e),x(e),v(e)},[x,v,a]),tabValues:a}}(e);return(0,i.jsxs)("div",{className:(0,r.A)(a.G.tabs.container,"tabs-container","tabList__CuJ"),children:[(0,i.jsx)(m,{...t,...e}),(0,i.jsx)(x,{...t,...e})]})}function v(e){let t=(0,f.A)();return(0,i.jsx)(j,{...e,children:p(e.children)},String(t))}},28453:function(e,t,n){n.d(t,{R:()=>a,x:()=>o});var i=n(96540);let s={},r=i.createContext(s);function a(e){let t=i.useContext(r);return i.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(s):e.components||s:a(e.components),i.createElement(r.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.