1"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([["213"],{1673(e,n,i){i.r(n),i.d(n,{metadata:()=>r,default:()=>h,frontMatter:()=>l,contentTitle:()=>t,toc:()=>a,assets:()=>d});var r=JSON.parse('{"id":"api-reference/Global Config File","title":"Global Config File","description":"Your app\'s global config file is found at src/main.ts.","source":"@site/docs/api-reference/Global Config File.md","sourceDirName":"api-reference","slug":"/api-reference/Global Config File","permalink":"/docs/api-reference/Global Config File","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":2,"frontMatter":{"sidebar_position":2},"sidebar":"tutorialSidebar","previous":{"title":"Env Files- Back End Setup","permalink":"/docs/api-reference/Env Files- Back End Setup"},"next":{"title":"Collection Files","permalink":"/docs/api-reference/Collection Files"}}'),s=i(1085),o=i(1184);let l={sidebar_position:2},t,d={},a=[{value:"General",id:"general",level:2},{value:"roles",id:"roles",level:3},{value:"appName",id:"appname",level:3},{value:"timezone",id:"timezone",level:3},{value:"disabledCollections",id:"disabledcollections",level:3},{value:"enableUserIDLogging",id:"enableuseridlogging",level:3},{value:"Auth Config",id:"auth-config",level:2},{value:"enableMultiFactorAuth",id:"enablemultifactorauth",level:3},{value:"authPersistenceType",id:"authpersistencetype",level:3},{value:"offlinePersistenceType",id:"offlinepersistencetype",level:3},{value:"Parameters",id:"parameters",level:4},{value:"Return",id:"return",level:4},{value:"signOutOnPermissionsChange",id:"signoutonpermissionschange",level:3},{value:"clearPersistenceOnSignOut",id:"clearpersistenceonsignout",level:3},{value:"tabManager",id:"tabmanager",level:3},{value:"garbageCollectionStrategy",id:"garbagecollectionstrategy",level:3},{value:"maxCacheSize",id:"maxcachesize",level:3},{value:"maxWriteCacheSize",id:"maxwritecachesize",level:3},{value:"Admin UI Config",id:"admin-ui-config",level:2},{value:"access",id:"access",level:3},{value:"background",id:"background",level:3},{value:"logo",id:"logo",level:3},{value:"menu.groups",id:"menugroups",level:3},{value:"dateFormat",id:"dateformat",level:3},{value:"meta",id:"meta",level:3},{value:"homePage",id:"homepage",level:3},{value:"dashboard",id:"dashboard",level:3},{value:"Firebase Config",id:"firebase-config",level:2},{value:"enableEmulators",id:"enableemulators",level:3},{value:"enableAnalytics",id:"enableanalytics",level:3},{value:"analyticsSettings",id:"analyticssettings",level:3},{value:"analyticsConsentSettings",id:"analyticsconsentsettings",level:3},{value:"serverTimestampOptions",id:"servertimestampoptions",level:3},{value:"logLevel.dev",id:"logleveldev",level:3},{value:"logLevel.prod",id:"loglevelprod",level:3},{value:"writeLogTTL",id:"writelogttl",level:3},{value:"permissionsIndexExemption",id:"permissionsindexexemption",level:3},{value:"writeLogIndexExemption",id:"writelogindexexemption",level:3},{value:"GDPRSettings",id:"gdprsettings",level:3},{value:"Preload Cache Config",id:"preload-cache-config",level:2},{value:"async",id:"async",level:3},{value:"sync",id:"sync",level:3},{value:"Mail Config",id:"mail-config",level:2},{value:"emailVerification",id:"emailverification",level:3},{value:"Parameters",id:"parameters-1",level:4},{value:"Return",id:"return-1",level:4},{value:"Global Hooks",id:"global-hooks",level:2},{value:"preLogin",id:"prelogin",level:3},{value:"Parameters",id:"parameters-2",level:4},{value:"Return",id:"return-2",level:4},{value:"postLogin",id:"postlogin",level:3},{value:"Parameters",id:"parameters-3",level:4},{value:"preLogout",id:"prelogout",level:3},{value:"Parameters",id:"parameters-4",level:4},{value:"Return",id:"return-3",level:4},{value:"postLogout",id:"postlogout",level:3},{value:"preOperation",id:"preoperation",level:3},{value:"preRead",id:"preread",level:3},{value:"preValidate",id:"prevalidate",level:3},{value:"preWrite",id:"prewrite",level:3},{value:"preDuplicate",id:"preduplicate",level:3},{value:"postOperation",id:"postoperation",level:3},{value:"postRead",id:"postread",level:3},{value:"postWrite",id:"postwrite",level:3},{value:"postWriteError",id:"postwriteerror",level:3},{value:"preFileAdd",id:"prefileadd",level:3},{value:"preFileUpdate",id:"prefileupdate",level:3},{value:"postFileAdd",id:"postfileadd",level:3},{value:"postFileAddError",id:"postfileadderror",level:3},{value:"postFileUpdate",id:"postfileupdate",level:3},{value:"onVersionUpdate",id:"onversionupdate",level:3},{value:"onMaintenanceUpdate",id:"onmaintenanceupdate",level:3},{value:"onConnectionStatusChange",id:"onconnectionstatuschange",level:3},{value:"onFirestoreSlowConnection",id:"onfirestoreslowconnection",level:3},{value:"onFirestoreLoadFailure",id:"onfirestoreloadfailure",level:3},{value:"onIndexedDBConnectionLost",id:"onindexeddbconnectionlost",level:3},{value:"onAppCheckTokenFailure",id:"onappchecktokenfailure",level:3}];function c(e){let n={a:"a",admonition:"admonition",code:"code",h2:"h2",h3:"h3",h4:"h4",img:"img",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(n.p,{children:["Your app's global config file is found at ",(0,s.jsx)(n.code,{children:"src/main.ts"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"This file defines project-wide config for your app."}),"\n",(0,s.jsxs)(n.p,{children:["You can use ",(0,s.jsx)(n.a,{href:"/docs/api-reference/Application%20State",children:"application state"})," and the ",(0,s.jsx)(n.a,{href:"/docs/api-reference/Web%20SDK",children:"Web"})," and ",(0,s.jsx)(n.a,{href:"/docs/api-reference/Node%20SDK",children:"Node"})," SDKs in this file."]}),"\n",(0,s.jsx)(n.h2,{id:"general",children:"General"}),"\n",(0,s.jsx)(n.h3,{id:"roles",children:"roles"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"string[]"})}),"\n",(0,s.jsx)(n.p,{children:"This is the big one. Name the access roles that will be used in your app. Each role will have its own permissions."}),"\n",(0,s.jsxs)(n.p,{children:["For example: ",(0,s.jsx)(n.code,{children:'["Manager", "Supervisor", "Staff Member", "Client"]'})]}),"\n",(0,s.jsx)(n.h3,{id:"appname",children:"appName"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"string | (() => string | Promise<string>)"})}),"\n",(0,s.jsx)(n.p,{children:"The name of your app. Shorter is better, as this will be used for page titles etc."}),"\n",(0,s.jsx)(n.h3,{id:"timezone",children:"timezone"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"string | (() => string | Promise<string>)"})}),"\n",(0,s.jsx)(n.p,{children:"Your app will be based in this timezone."}),"\n",(0,s.jsx)(n.p,{children:"Must be a valid IANA timezone."}),"\n",(0,s.jsx)(n.h3,{id:"disabledcollections",children:"disabledCollections"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"string[]"})}),"\n",(0,s.jsxs)(n.p,{children:["An array of collection names that will be disabled in your app (on the next ",(0,s.jsx)(n.code,{children:"stoker deploy"}),")."]}),"\n",(0,s.jsx)(n.h3,{id:"enableuseridlogging",children:"enableUserIDLogging"}),"\n",(0,s.jsx)(n.p,{children:"Whether to log the user's ID in the client whenever Firebase prints logs. This can be useful for debugging, but may cause privacy concerns in some scenarios. For this reason, we disable it by default."}),"\n",(0,s.jsx)(n.h2,{id:"auth-config",children:"Auth Config"}),"\n",(0,s.jsxs)(n.p,{children:["Auth config is specified using the ",(0,s.jsx)(n.code,{children:"auth"})," property."]}),"\n",(0,s.jsx)(n.h3,{id:"enablemultifactorauth",children:"enableMultiFactorAuth"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"string[]"})}),"\n",(0,s.jsx)(n.p,{children:"An array of roles. App users with these roles will have the option to enable multi factor auth (using an Authenticator app)."}),"\n",(0,s.jsx)(n.h3,{id:"authpersistencetype",children:"authPersistenceType"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:'"LOCAL" | "SESSION"| "NONE" | (() => "LOCAL" | "SESSION" | "NONE" | Promise<"LOCAL" | "SESSION" | "NONE">)'})}),"\n",(0,s.jsx)(n.p,{children:"The auth persistence strategy for your app."}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:'"LOCAL"'}),": Auth state is persisted across sessions. The user will stay logged in even when the window is closed or refreshed."]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:'"SESSION"'}
1),": Auth state is persisted within the same session. The user will be logged out when the window is closed."]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:'"NONE"'}),": Auth state is not persisted. The user will be logged out when the window is closed or refreshed."]}),"\n",(0,s.jsx)(n.h3,{id:"offlinepersistencetype",children:"offlinePersistenceType"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:'"ALL" | "WRITE" | "NONE" | ((user: User, claims: ParsedToken) => "ALL" | "WRITE" | "NONE" | Promise<"ALL" | "WRITE" | "NONE">)'})}),"\n",(0,s.jsx)(n.p,{children:"The offline persistence strategy for your app."}),"\n",(0,s.jsx)(n.h4,{id:"parameters",children:"Parameters"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"user"}),": The currently logged in ",(0,s.jsx)(n.a,{href:"https://firebase.google.com/docs/reference/js/auth.user",children:"Firebase User"})]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"claims"}),": A Firebase Auth ",(0,s.jsx)(n.a,{href:"https://firebase.google.com/docs/reference/js/auth.parsedtoken",children:"ParsedToken"}),". The custom claims for the user, for example ",(0,s.jsx)(n.code,{children:"role"}),", can be found here."]}),"\n",(0,s.jsx)(n.h4,{id:"return",children:"Return"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:'"ALL"'}),": All data read and written is stored in IndexedDB and persisted across sessions. Offline writes will be retried when the connection is restored, even if the window is closed while still offline."]}),"\n",(0,s.jsx)(n.admonition,{type:"danger",children:(0,s.jsx)(n.p,{children:"This strategy creates a security risk if your app is used on public computers, as app data is stored in IndexedDB beyond the user's session."})}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:'"WRITE"'}),": Writes are persisted across sessions. Offline writes will be retried when the connection is restored, even if the window is closed while still offline. ",(0,s.jsx)(n.a,{href:"/docs/api-reference/Collection%20Files#enablewritelog",children:(0,s.jsx)(n.code,{children:"enableWriteLog"})})," must be set to ",(0,s.jsx)(n.code,{children:"true"})," for offline persistent writes to work for a collection."]}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsxs)(n.p,{children:["This strategy creates a security risk if your app is used on public computers, as app data is stored in IndexedDB beyond the user's session. However, this option is more secure than ",(0,s.jsx)(n.code,{children:'"ALL"'})," because read data is not persisted."]})}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:'"NONE"'}),": No offline persistence. Offline writes will fail if the window is closed before the connection is restored."]}),"\n",(0,s.jsx)(n.h3,{id:"signoutonpermissionschange",children:"signOutOnPermissionsChange"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"boolean"})}),"\n",(0,s.jsxs)(n.p,{children:["Set to ",(0,s.jsx)(n.code,{children:"true"})," to sign out a user when their permissions are changed. If falsy, the Admin UI will attempt to reload data affected by the permissions change."]}),"\n",(0,s.jsx)(n.h3,{id:"clearpersistenceonsignout",children:"clearPersistenceOnSignOut"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"boolean"})}),"\n",(0,s.jsxs)(n.p,{children:["Only relevant if ",(0,s.jsx)(n.code,{children:"auth.offlinePersistenceType"})," is set to ",(0,s.jsx)(n.code,{children:'"ALL"'})," or ",(0,s.jsx)(n.code,{children:'"WRITE"'}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["Set to ",(0,s.jsx)(n.code,{children:"true"})," to clear offline persistence data from IndexedDB on sign out."]}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsx)(n.p,{children:"The Firebase team does not recommend relying on this method for security purposes."})}),"\n",(0,s.jsx)(n.h3,{id:"tabmanager",children:"tabManager"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:'"SINGLE" | "MULTI"'})}),"\n",(0,s.jsxs)(n.p,{children:["Only relevant if ",(0,s.jsx)(n.code,{children:"auth.offlinePersistenceType"})," is set to ",(0,s.jsx)(n.code,{children:'"ALL"'})," or ",(0,s.jsx)(n.code,{children:'"WRITE"'}),"."]}),"\n",(0,s.jsx)(n.p,{children:"Whether to use offline persisted data across tabs."}),"\n",(0,s.jsxs)(n.p,{children:["Defaults to ",(0,s.jsx)(n.code,{children:'"MULTI"'}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["If set to ",(0,s.jsx)(n.code,{children:'"SINGLE"'}),", offline persistence will only be available in the first tab opened."]}),"\n",(0,s.jsx)(n.h3,{id:"garbagecollectionstrategy",children:"garbageCollectionStrategy"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:'"LRU" | "EAGER"'})}),"\n",(0,s.jsxs)(n.p,{children:["Only relevant if ",(0,s.jsx)(n.code,{children:"auth.offlinePersistenceType"})," is set to ",(0,s.jsx)(n.code,{children:'"WRITE"'})," or ",(0,s.jsx)(n.code,{children:'"NONE"'}),"."]}),"\n",(0,s.jsx)(n.p,{children:"The garbage collection strategy to use for in-memory data. We highly recommend using LRU."}),"\n",(0,s.jsxs)(n.p,{children:["Defaults to ",(0,s.jsx)(n.code,{children:'"LRU"'}),"."]}),"\n",(0,s.jsx)(n.h3,{id:"maxcachesize",children:"maxCacheSize"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"number"})}),"\n",(0,s.jsxs)(n.p,{children:["The maximum cache size for in-memory (",(0,s.jsx)(n.code,{children:'"LRU"'})," only) and persisted (",(0,s.jsx)(n.code,{children:'"ALL"'})," or ",(0,s.jsx)(n.code,{children:'"WRITE"'}
1)," only) caches."]}),"\n",(0,s.jsxs)(n.p,{children:["Use ",(0,s.jsx)(n.code,{children:"-1"})," to set an unlimited cache size."]}),"\n",(0,s.jsxs)(n.p,{children:["Defaults to ",(0,s.jsx)(n.code,{children:"-1"})]}),"\n",(0,s.jsx)(n.h3,{id:"maxwritecachesize",children:"maxWriteCacheSize"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"number"})}),"\n",(0,s.jsxs)(n.p,{children:["Overwrites ",(0,s.jsx)(n.code,{children:"auth.maxCacheSize"})," above for the write database instance only."]}),"\n",(0,s.jsxs)(n.p,{children:["Use ",(0,s.jsx)(n.code,{children:"-1"})," to set an unlimited cache size."]}),"\n",(0,s.jsxs)(n.p,{children:["Defaults to ",(0,s.jsx)(n.code,{children:"-1"})]}),"\n",(0,s.jsx)(n.h2,{id:"admin-ui-config",children:"Admin UI Config"}),"\n",(0,s.jsx)(n.h3,{id:"access",children:"access"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"string[] | (() => string[])"})}),"\n",(0,s.jsx)(n.p,{children:"If defined, only the roles listed will be able to see the Admin UI."}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsx)(n.p,{children:"This access restriction is only enforced on the client. Users can still log in, but they won't see anything."})}),"\n",(0,s.jsx)(n.h3,{id:"background",children:"background"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"type Background = {\n light?: {\n color: string\n image?: string\n }\n dark?: {\n color: string\n image?: string\n }\n}\n\n"})}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"Backgroun
1d | (() => Background)"})}),"\n",(0,s.jsxs)(n.p,{children:["Return ",(0,s.jsx)(n.code,{children:"Background"})," objects for light and dark mode. This lets you control the background properties of the ",(0,s.jsx)(n.code,{children:"body"}),"."]}),"\n",(0,s.jsx)(n.h3,{id:"logo",children:"logo"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"{ navbar?: string login?: string }"})}),"\n",(0,s.jsxs)(n.p,{children:["Return image urls to be used for the navbar title and the login page. If not provided, the icons in your ",(0,s.jsx)(n.code,{children:"icons"})," directory will be used."]}),"\n",(0,s.jsx)(n.h3,{id:"menugroups",children:"menu.groups"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"type MenuGroup = {\n title: string\n position: number\n collections: string[]\n roles?: string[]\n}\n"})}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"MenuGroup[]"})}),"\n",(0,s.jsxs)(n.p,{children:["Return an array of ",(0,s.jsx)(n.code,{children:"MenuGroup"})," objects defining the menu structures for the user roles in your system."]}),"\n",(0,s.jsx)(n.p,{children:'See the default "Messages" menu group in your project for an example.'}),"\n",(0,s.jsx)(n.h3,{id:"dateformat",children:"dateFormat"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"string | (() => string)"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.a,{href:"https://moment.github.io/luxon/#/formatting?id=table-of-tokens",children:"Luxon date format"})," to display dates in."]}),"\n",(0,s.jsx)(n.h3,{id:"meta",children:"meta"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:'type MetaIcon = {\n rel: string\n type: string\n url: string\n}\n\ni.e. <link key="favicon" rel="icon" type="image/png" href="./favicon.ico" />\n'})}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"{ description?: string, icons?: MetaIcon[] }"})}),"\n",(0,s.jsx)(n.p,{children:"Define the meta tag description and icons for your app's home page."}),"\n",(0,s.jsx)(n.h3,{id:"homepage",children:"homePage"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"Record<string, string> | (() => Record<string, string>)"})}),"\n",(0,s.jsx)(n.p,{children:"Return a set of key/value pairs defining user roles and the collection that will act as their homepage."}),"\n",(0,s.jsx)(n.p,{children:"If the user role has access to the Dashboard, that will take precedence."}),"\n",(0,s.jsx)(n.p,{children:"For example:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:'{\n Manager: "Projects",\n Client: "Invoices,\n}\n'})}),"\n",(0,s.jsx)(n.h3,{id:"dashboard",children:"dashboard"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.img,{alt:"Dashboard",src:i(6317).A+"",width:"2510",height:"1632"})}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"DashboardItem[]"})}),"\n",(0,s.jsx)(n.p,{children:"Return an array of Dashboard Items. These will be laid out in a grid."}),"\n",(0,s.jsx)(n.p,{children:"We recommend that each row contains any of:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"1-2 metrics and a chart"}),"\n",(0,s.jsx)(n.li,{children:"1 reminder and a chart"}),"\n",(0,s.jsx)(n.li,{children:"3 reminders"}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"Display a metric (numerical counter):"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:'type DashboardMetric = {\n kind: "metric"\n collection: string\n type: "sum" | "average" | "count"\n field?: string\n roles?: string[]\n title?: string\n decimal?: number\n prefix?: string\n suffix?: string\n textSize?: "text-xs" | "text-sm" | "text-base" | "text-lg" | "text-xl" | "text-2xl" | "text-3xl"\n constraints?: [string, WhereFilterOp, unknown][]\n}\n'})}),"\n",(0,s.jsx)(n.p,{children:"Display a chart:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:'type DashboardChart = {\n kind: "chart"\n collection: string\n type: "area"\n dateField: string\n metricField1?: string\n metricField2?: string\n formula1?: (record: StokerRecord) => number\n formula2?: (record: StokerRecord) => number\n label1?: string | (() => string)\n label2?: string | (() => string)\n yAxis?: { show?: boolean | (() => boolean) }\n roles?: string[]\n title?: string\n constraints?: [string, WhereFilterOp, unknown][]\n interval?: "day" | "month" | "year"\n numberOfIntervals?: number\n animate?: boolean\n offset?: number\n currency?: string | (() => string)\n}\n'})}),"\n",(0,s.jsx)(n.p,{children:"Display a reminder (a list of pertinent records):"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:'type DashboardReminder = {\
1n kind: "reminder"\n collection: string\n columns: string[]\n length?: 1 | 2 | 3\n title?: string\n roles?: string[]\n constraints?: [string, WhereFilterOp, unknown][]\n sort?: {\n field: string\n direction: "asc" | "desc"\n }\n}\n'})}),"\n",(0,s.jsx)(n.h2,{id:"firebase-config",children:"Firebase Config"}),"\n",(0,s.jsxs)(n.p,{children:["Firebase config is specified using the ",(0,s.jsx)(n.code,{children:"firebase"})," property."]}),"\n",(0,s.jsx)(n.h3,{id:"enableemulators",children:"enableEmulators"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"boolean | (() => boolean | Promise<boolean>)"})}),"\n",(0,s.jsxs)(n.p,{children:["Enable or disable the Firebase Emulators. The default value is a function that enables the emulators in development mode, which is necessary for ",(0,s.jsx)(n.code,{children:"npm run start"})," to function properly. You can disable the emulators in development mode to use your live back end in development."]}),"\n",(0,s.jsx)(n.h3,{id:"enableanalytics",children:"enableAnalytics"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"boolean | (() => boolean | Promise<boolean>)"})}),"\n",(0,s.jsx)(n.p,{children:"Enable or disable Google Analytics for your app."}),"\n",(0,s.jsx)(n.p,{children:"The default value is a function that enables analytics in production mode."}),"\n",(0,s.jsx)(n.h3,{id:"analyticssettings",children:"analyticsSettings"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"AnalyticsSettings | (() => AnalyticsSettings | Promise<AnalyticsSettings>)"})}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.a,{href:"https://firebase.google.com/docs/reference/js/analytics.analyticssettings.md#analyticssettings_interface",children:"Google Analytics config"})}),"\n",(0,s.jsx)(n.h3,{id:"analyticsconsentsettings",children:"analyticsConsentSettings"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"ConsentSettings | (() => ConsentSettings | Promise<ConsentSettings>)"})}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.a,{href:"https://firebase.google.com/docs/reference/js/analytics.consentsettings",children:"Google Analytics consent config"})}),"\n",(0,s.jsx)(n.h3,{id:"servertimestampoptions",children:"serverTimestampOptions"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:'"none" | "estimate" | "previous" | (() => "none" | "estimate" | "previous" | Promise<"none" | "estimate" | "previous">)'})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.a,{href:"https://firebase.google.com/docs/reference/js/firestore_.snapshotoptions",children:"strategy to use for Firestore server timestamps"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["We recommend setting this to ",(0,s.jsx)(n.code,{children:'"estimate"'})]}),"\n",(0,s.jsxs)(n.p,{children:["Defaults to ",(0,s.jsx)(n.code,{children:'"none"'})]}),"\n",(0,s.jsx)(n.h3,{id:"logleveldev",children:"logLevel.dev"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:'"debug" | "verbose" | "info" | "warn" | "error" | "silent"'})}),"\n",(0,s.jsx)(n.p,{children:"The Firebase log level for development mode."}),"\n",(0,s.jsx)(n.h3,{id:"loglevelprod",children:"logLevel.prod"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:'"debug" | "verbose" | "info" | "warn" | "error" | "silent"'})}),"\n",(0,s.jsx)(n.p,{children:"The Firebase log level for production mode."}),"\n",(0,s.jsx)(n.h3,{id:"writelogttl",children:"writeLogTTL"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"number"})}),"\n",(0,s.jsxs)(n.p,{children:["If set, this is the number of days after which ",(0,s.jsx)(n.a,{href:"/docs/api-reference/Collection%20Files#enablewritelog",children:"write log"})," entries will be deleted. We recommend leaving it out in order to keep records of write activity indefinitely. However, you may wish to reduce your storage costs by deleting write logs after a certain
1number of days."]}),"\n",(0,s.jsx)(n.h3,{id:"permissionsindexexemption",children:"permissionsIndexExemption"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"boolean"})}),"\n",(0,s.jsxs)(n.p,{children:["Exempt the user permissions collection from Cloud Firestore. We recommend setting this to ",(0,s.jsx)(n.code,{children:"true"})," for performance reasons, however you will need to set it to falsy in order to query the permissions collection by specific fields."]}),"\n",(0,s.jsx)(n.h3,{id:"writelogindexexemption",children:"writeLogIndexExemption"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"string[]"})}),"\n",(0,s.jsx)(n.p,{children:"Exempt individual fields from the write log. We recommend leaving this as an empty array unless you have a good reason to exempt fields."}),"\n",(0,s.jsx)(n.h3,{id:"gdprsettings",children:"GDPRSettings"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"boolean | (() => boolean | Promise<boolean>)"})}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.a,{href:"https://firebase.google.com/docs/reference/js/app.firebaseapp.md#firebaseappautomaticdatacollectionenabled",children:"The settable config flag for GDPR opt-in/opt-out"})}),"\n",(0,s.jsx)(n.h2,{id:"preload-cache-config",children:"Preload Cache Config"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.a,{href:"/docs/api-reference/Collection%20Files#preload-cache-config",children:"Preload cache"})," config is specified using the ",(0,s.jsx)(n.code,{children:"preload"})," property."]}),"\n",(0,s.jsx)(n.h3,{id:"async",children:"async"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"string[] | (() => string[] | Promise<string[]>)"})}),"\n",(0,s.jsx)(n.p,{children:"An array of collection names that have the preload cache enabled. These collections will be preloaded first, in parallel."}),"\n",(0,s.jsx)(n.h3,{id:"sync",children:"sync"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"string[] | (() => string[] | Promise<string[]>)"})}),"\n",(0,s.jsxs)(n.p,{children:["An array of collection names that have the preload cache enabled. These collections will be preloaded synchronously while the async collections above also load. Collections not listed in ",(0,s.jsx)(n.code,{children:"preload.async"})," or ",(0,s.jsx)(n.code,{children:"preload.sync"})," will load synchronously after the collections in this list."]}),"\n",(0,s.jsx)(n.h2,{id:"mail-config",children:"Mail Config"}),"\n",(0,s.jsxs)(n.p,{children:["Mail config is specified using the ",(0,s.jsx)(n.code,{children:"mail"})," property."]}),"\n",(0,s.jsx)(n.h3,{id:"emailverification",children:"emailVerification"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"(verificationLink: string, appName?: string) => { subject: string html: string }"})}),"\n",(0,s.jsx)(n.p,{children:"Customize the email address verification email sent out to your app's users."}),"\n",(0,s.jsx)(n.h4,{id:"parameters-1",children:"Parameters"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"verificationLink"}),": The verification link that the user will click to verify their email address."]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"appName"}),": The app name you provided in ",(0,s.jsx)(n.code,{children:"appName"})," above."]}),"\n",(0,s.jsx)(n.h4,{id:"return-1",children:"Return"}),"\n",(0,s.jsxs)(n.p,{children:["An object with a ",(0,s.jsx)(n.code,{children:"subject"})," and a ",(0,s.jsx)(n.code,{children:"html"})," message that will be sent to the user."]}),"\n",(0,s.jsx)(n.h2,{id:"global-hooks",children:"Global Hooks"}),"\n",(0,s.jsxs)(n.admonition,{type:"info",children:[(0,s.jsx)(n.p,{children:"When importing modules that are web-only or server-only, be sure to:"}),(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["Install them using ",(0,s.jsx)(n.a,{href:"Other%20Project%20Files",children:(0,s.jsx)(n.code,{children:"external.packages.json"})})]}),"\n",(0,s.jsxs)(n.li,{children:["Guard their use by wrapping code in:","\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:'if(sdk === "web") { \n ...your web code goes here...\n}\nif(sdk === "node") { \n ...your server code goes here...\n}\n'})}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["Import them dynamically i.e. ",(0,s.jsx)(n.code,{children:'await import("firebase/firestore")'})]}),"\n"]}),(0,s.jsx)(n.p,{children:"This lets you write web and server code in the same file."}),(0,s.jsxs)(n.p,{children:["You can also write your own modules in the ",(0,s.jsx)(n.code,{children:"src/web"})," and ",(0,s.jsx)(n.code,{children:"src/node"})," folders and import modules statically there. In this case, you can only use one import per line i.e. ",(0,s.jsx)(n.code,{children:'import { getAuth } from "firebase/auth"'})]})]}),"\n",(0,s.jsxs)(n.admonition,{type:"danger",children:[(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Server code protection:"})," During the build process, server-only code blocks are automatically stripped from the client bundle:"]}),(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:'if(sdk === "node")'})," blocks are removed"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"else"})," and ",(0,s.jsx)(n.code,{children:"else if"})," blocks following ",(0,s.jsx)(n.code,{children:'if (sdk === "web")'})," guards are removed"]}),"\n",(0,s.jsxs)(n.li,{children:["Code in ",(0,s.jsx)(n.code,{children:"src/node"})," is stripped to export names only"]}),"\n"]}),(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Important:"})," Code outside of these guard blocks WILL be sent to the client and will run on the client."]}),(0,s.jsxs)(n.p,{children:["For highly sensitive server operations, consider using ",(0,s.jsx)(n.a,{href:"Other%20Project%20Files",children:"custom cloud functions"})," instead."]})]}),"\n",(0,s.jsx)(n.h3,{id:"prelogin",children:"preLogin"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"(user: User) => boolean | void | Promise<boolean | void>"})}),"\n",(0,s.jsxs)(n.p,{children:["Fires before the user is logged in, prior to any other authentication logic being processed. You may block the sign in by returning ",(0,s.jsx)(n.code,{children:"false"}),"."]}),"\n",(0,s.jsx)(n.h4,{id:"parameters-2",children:"Parameters"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"user"}),": The currently logged in ",(0,s.jsx)(n.a,{href:"https://firebase.google.com/docs/reference/js/auth.user",children:"Firebase User"})]}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsxs)(n.p,{children:["This logic is client-side and is skippable. If you want to securely perform sign-in-blocking operations, use ",(0,s.jsx)(n.a,{href:"https://firebase.google.com/docs/auth/extend-with-blocking-functions",children:"Firebase Auth Blocking Cloud Functions"}),"."]})}),"\n",(0,s.jsx)(n.h4,{id:"return-2",children:"Return"}),"\n",(0,s.jsx)(n.p,{children:"A boolean defining whether or not the user may proceed with login."}),"\n",(0,s.jsx)(n.h3,{id:"postlogin",children:"postLogin"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"(user?: User, error?: unknown) => void | Promise<void>"})}),"\n",(0,s.jsx)(n.p,{children:"Fires after the user has successfully logged in."}),"\n",(0,s.jsx)(n.h4,{id:"parameters-3",children:"Parameters"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"user"}),": The currently logged in ",(0,s.jsx)(n.a,{href:"https://firebase.google.com/docs/reference/js/auth.user",children:"Firebase User"})]}),"\n",(0,s.jsx)(n.h3,{id:"prelogout",children:"preLogout"}),"\n",(0,s.jsxs)(n.p,{children:["Fires when the user attempts to log out. You may block the sign out by returning ",(0,s.jsx)(n.code,{children:"false"}),"."]}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"(user: User) => boolean | void | Promise<boolean | void>"})}),"\n",(0,s.jsx)(n.h4,{id:"parameters-4",children:"Parameters"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"user"}),": The currently logged in ",(0,s.jsx)(n.a,{href:"https://firebase.google.com/docs/reference/js/auth.user",children:"Firebase User"})]}),"\n",(0,s.jsx)(n.h4,{id:"return-3",children:"Return"}),"\n",(0,s.jsx)(n.p,{children:"A boolean defining whether or not the user may proceed with sign out."}),"\n",(0,s.jsx)(n.h3,{id:"postlogout",children:"postLogout"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:'(\n errorDetails: {\n error: boolean\n instances: {\n instance: "[DEFAULT]" | "firestoreWrite"\n code: "SIGN_OUT" | "TERMINATE_APP" | "CLEAR_CACHE"\n error: unknown\n }[]\n }\n) => void | Promise<void>\n'})}),"\n",(0,s.jsx)(n.p,{children:"Fires when the user has logged out. If an error is encountered during sign out, additional information is provided describing:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Which Firestore instances encountered the error"}),"\n",(0,s.jsx)(n.li,{children:"The operation that encountered the error for each affected
1instance"}),"\n",(0,s.jsx)(n.li,{children:"The error itself for each affected instance"}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"preoperation",children:"preOperation"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:'({\n operation: "read" | "create" | "update" | "delete"\n data?: StokerRecord\n recordId?: string\n context?: any\n batch?: WriteBatch\n originalRecord?: StokerRecord\n}) => boolean | void | Promise<boolean | void>\n'})}),"\n",(0,s.jsx)(n.p,{children:"Fires before all read and write operations."}),"\n",(0,s.jsxs)(n.p,{children:["Return ",(0,s.jsx)(n.code,{children:"false"})," to cancel the operation."]}),"\n",(0,s.jsx)(n.h3,{id:"preread",children:"preRead"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"({\n context: any\n refs: unknown[]\n multiple?: boolean\n listener?: boolean\n}) => void | Promise<void>\n"})}),"\n",(0,s.jsx)(n.p,{children:"Fires before all read operations."}),"\n",(0,s.jsx)(n.h3,{id:"prevalidate",children:"preValidate"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:'({\n operation: "create" | "update"\n data: StokerRecord\n context: any\n batch?: WriteBatch\n originalRecord?: StokerRecord\n}) => { valid: boolean; message?: string } | Promise<{ valid: boolean; message?: string }>\n'})}),"\n",(0,s.jsx)(n.p,{children:"Fires at write validation time for all write operations. This is where you can define custom validation logic."}),"\n",(0,s.jsx)(n.p,{children:"Return an object with a boolean indicating whether validation passed, and a message to display to the user if validation has failed."}),"\n",(0,s.jsxs)(n.p,{children:["When ",(0,s.jsx)(n.code,{children:"serverWriteOnly"})," is set to true, this hook will fire in the Web SDK before the write is handed off to the Node SDK. This lets you run web code such as warning dialogs before the write is sent to the server. Be sure to guard web code in ",(0,s.jsx)(n.a,{href:"/docs/api-reference/Application%20State#sdk",children:(0,s.jsx)(n.code,{children:'if(sdk === "web")'})})," to ensure it doesn't run on the server."]}),"\n",(0,s.jsx)(n.h3,{id:"prewrite",children:"preWrite"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:'({\n operation: "create" | "update" | "delete"\n data: StokerRecord\n recordId: string\n context: any\n batch?: WriteBatch\n originalRecord?: StokerRecord\n}) => boolean | void | Promise<boolean | void>\n'})}),"\n",(0,s.jsx)(n.p,{children:"Fires before all write operations."}),"\n",(0,s.jsxs)(n.p,{children:["Return ",(0,s.jsx)(n.code,{children:"false"})," to cancel the operation."]}),"\n",(0,s.jsx)(n.h3,{id:"preduplicate",children:"preDuplicate"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"({ data: Partial<StokerRecord> }) => boolean | void | Promise<boolean | void>\n"})}),"\n",(0,s.jsx)(n.p,{children:"Fires before all duplicate operations in the Admin UI."}),"\n",(0,s.jsxs)(n.p,{children:["Return ",(0,s.jsx)(n.code,{children:"false"})," to cancel the operation."]}),"\n",(0,s.jsx)(n.h3,{id:"postoperation",children:"postOperation"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:'({\n operation: "read" | "create" | "update" | "delete"\n data?: StokerRecord\n recordId?: string\n context?: any\n retry?: boolean\n originalRecord?: StokerRecord\n}) => void | Promise<void>\n'})}),"\n",(0,s.jsx)(n.p,{children:"Fires after all read and write operations."}),"\n",(0,s.jsx)(n.h3,{id:"postread",children:"postRead"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"({\n context: any\n refs: unknown[]\n record: StokerRecord | undefined\n listener?: boolean\n}) => void | Promise<void>\n"})}),"\n",(0,s.jsx)(n.p,{children:"Fires after all read operations."}),"\n",(0,s.jsx)(n.h3,{id:"postwrite",children:"postWrite"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:'({\n operation: "create" | "update" | "delete"\n data: StokerRecord\n recordId: string\n context: any\n retry?: boolean\n originalRecord?: StokerRecord\n}) => void | Promise<void>\n'})}),"\n",(0,s.jsx)(n.p,{children:"Fires after all write operations."}),"\n",(0,s.jsx)(n.h3,{id:"postwriteerror",children:"postWriteError"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:'({\n operation: "create" | "update" | "delete"\n data: StokerRecord\n recordId: string\n context: any\n error: unknown\n batch?: WriteBatch\n retry?: boolean\n retries?: number\n originalRecord?: StokerRecord\n}) => void | Promise<void>\n'})}),"\n",(0,s.jsx)(n.p,{children:"Fires when a write operation encounters an error."}),"\n",(0,s.jsx)(n.p,{children:"We provide a default function for this hook. The default function sends you an email whenever an error is encountered."}),"\n",(0,s.jsx)(n.p,{children:"This hook may fire multiple times per write, so be sure to write idempotent code."}),"\n",(0,s.jsx)(n.h3,{id:"prefileadd",children:"preFileAdd"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"({\n record: StokerRecord\n fullPath: string\n filename: string\n permissions: FilePermissions\n}) => boolean | void | Promise<boolean | void>\n"})}),"\n",(0,s.jsx)(n.p,{children:"Fires before a file is uploaded."}),"\n",(0,s.jsxs)(n.p,{children:["Return ",(0,s.jsx)(n.code,{children:"false"})," to cancel the operation."]}),"\n",(0,s.jsx)(n.h3,{id:"prefileupdate",children:"preFileUpdate"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:'({\n record: StokerRecord\n update:\n { type: "rename"; oldPath: string; newPath: string } |\n {\n type: "permissions"\n path: string\n originalPermissions: FilePermissions\n permissions: FilePermissions\n }\n}) => boolean | void | Promise<boolean | void>\n'})}),"\n",(0,s.jsx)(n.p,{children:"Fires before a file is updated."}),"\n",(0,s.jsxs)(n.p,{children:["Return ",(0,s.jsx)(n.code,{children:"false"})," to cancel the operation."]}),"\n",(0,s.jsx)(n.h3,{id:"postfileadd",children:"postFileAdd"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"({\n record: StokerRecord\n fullPath: string\n filename: string\n permissions: FilePermissions\n}) => void | Promise<void>\n"})}),"\n",(0,s.jsx)(n.p,{children:"Fires after a file is uploaded."}),"\n",(0,s.jsx)(n.h3,{id:"postfileadderror",children:"postFileAddError"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"({\n record: StokerRecord\n fullPath: string\n filename: string\n permissions: FilePermissions\n error: unknown\n}) => void | Promise<void>\n"})}),"\n",(0,s.jsx)(n.p,{children:"Fires when a file upload fails."}),"\n",(0,s.jsx)(n.h3,{id:"postfileupdate",children:"postFileUpdate"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:'({\n record: StokerRecord\n update:\n { type: "rename"; oldPath: string; newPath: string } |\n {\n type: "permissions"\n path: string\n originalPermissions: FilePermissions\n permissions: FilePermissions\n }\n}) => void | Promise<void>\n'})}),"\n",(0,s.jsx)(n.p,{children:"Fires after a file is updated."}),"\n",(0,s.jsx)(n.h3,{id:"onversionupdate",children:"onVersionUpdate"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ts",children:"(\n versionInfo: {\n version: number\n force: boolean\n refresh: boolean\n time: Timestamp | FieldValue\n payload: unknown\n }, numberOfUpdates: number\n) => void | Promise<void>\n"})}),"\n",(0,s.jsx)(n.p,{children:"Fires when the schema version is updated."}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsxs)(n.p,{children:["If ",(0,s.jsx)(n.code,{children:"refresh"})," is ",(0,s.jsx)(n.code,{children:"true"})," for the schema update, the page will automatically refresh and this hook will not fire."]})}),"\n",(0,s.jsx)(n.h3,{id:"onmaintenanceupdate",children:"onMaintenanceUpdate"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:'(status: "on" | "off") => void | Promise<void>'})}),"\n",(0,s.jsx)(n.p,{children:"Fires when maintenance mode is engaged / disengaged."}),"\n",(0,s.jsx)(n.h3,{id:"onconnectionstatuschange",children:"onConnectionStatusChange"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:'(status: "Online" | "Offline", first: boolean) => void | Promise<void>'})}),"\n",(0,s.jsx)(n.p,{children:"Fires when the app goes online / offline."}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"first"})," will be true for the initial value read on app startup."]}),"\n",(0,s.jsx)(n.h3,{id:"onfirestoreslowconnection",children:"onFirestoreSlowConnection"}
1),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"() => void | Promise<void>"})}),"\n",(0,s.jsx)(n.p,{children:"Fires when Cloud Firestore detects a slow internet connection."}),"\n",(0,s.jsx)(n.h3,{id:"onfirestoreloadfailure",children:"onFirestoreLoadFailure"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"() => void | Promise<void>"})}),"\n",(0,s.jsx)(n.p,{children:"Fires when Cloud Firestore experiences a read failure, usually due to excessive contention on documents or exceeded quotas."}),"\n",(0,s.jsx)(n.h3,{id:"onindexeddbconnectionlost",children:"onIndexedDBConnectionLost"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"() => void | Promise<void>"})}),"\n",(0,s.jsx)(n.p,{children:"Fires in rare cases where Firestore IndexedDB persistence fails."}),"\n",(0,s.jsx)(n.h3,{id:"onappchecktokenfailure",children:"onAppCheckTokenFailure"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.code,{children:"(error: FirebaseError) => void | Promise<void>"})}),"\n",(0,s.jsx)(n.p,{children:"Fires when App Check token refresh fails."})]})}function h(e={}){let{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},6317(e,n,i){i.d(n,{A:()=>r});let r=i.p+"assets/images/dashboard-dark-24e7485d67daf3af9312ab392d9bb8f4.png"},1184(e,n,i){i.d(n,{R:()=>l,x:()=>t});var r=i(4041);let s={},o=r.createContext(s);function l(e){let n=r.useContext(o);return r.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function t(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:l(e.components),r.createElement(o.Provider,{value:n},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.