import { useValue } from '@tldraw/state-react' import { createContext, ReactNode, useContext, useEffect, useState } from 'react' import { LicenseManager } from './LicenseManager' /** @internal */ export const LicenseContext = createContext({} as LicenseManager) /** @internal */ export const useLicenseContext = () => useContext(LicenseContext) function shouldHideEditorAfterDelay(licenseState: string): boolean { return licenseState === 'expired' || licenseState === 'unlicensed-production' } /** @internal */ export const LICENSE_TIMEOUT = 5000 /** @internal */ export function LicenseProvider({ licenseKey = getLicenseKeyFromEnv() ?? undefined, children, }: { licenseKey?: string children: ReactNode }) { const [licenseManager] = useState(() => new LicenseManager(licenseKey)) const licenseState = useValue(licenseManager.state) const [showEditor, setShowEditor] = useState(true) // When license expires or no license in production, show for 5 seconds then hide useEffect(() => { if (shouldHideEditorAfterDelay(licenseState) && showEditor) { // eslint-disable-next-line no-restricted-globals const timer = setTimeout(() => { setShowEditor(false) }, LICENSE_TIMEOUT) return () => clearTimeout(timer) } }, [licenseState, showEditor]) // If license is expired or no license in production and 5 seconds have passed, don't render anything (blank screen) if (shouldHideEditorAfterDelay(licenseState) && !showEditor) { return } return {children} } // Renders as a hidden div that can be detected by tests function LicenseGate() { return
} let envLicenseKey: string | undefined | null = undefined function getLicenseKeyFromEnv() { if (envLicenseKey !== undefined) { return envLicenseKey } // it's important here that we write out the full process.env.WHATEVER expression instead of // doing something like process.env[someVariable]. This is because most bundlers do something // like a find-replace inject environment variables, and so won't pick up on dynamic ones. It // also means we can't do checks like `process.env && process.env.WHATEVER`, which is why we use // the `getEnv` try/catch approach. // framework-specific prefixes borrowed from the ones vercel uses, but trimmed down to just the // react-y ones: https://vercel.com/docs/environment-variables/framework-environment-variables envLicenseKey = getEnv(() => process.env.TLDRAW_LICENSE_KEY) || getEnv(() => process.env.NEXT_PUBLIC_TLDRAW_LICENSE_KEY) || getEnv(() => process.env.REACT_APP_TLDRAW_LICENSE_KEY) || getEnv(() => process.env.GATSBY_TLDRAW_LICENSE_KEY) || getEnv(() => process.env.VITE_TLDRAW_LICENSE_KEY) || getEnv(() => process.env.PUBLIC_TLDRAW_LICENSE_KEY) || getEnv(() => (import.meta as any).env.TLDRAW_LICENSE_KEY) || getEnv(() => (import.meta as any).env.NEXT_PUBLIC_TLDRAW_LICENSE_KEY) || getEnv(() => (import.meta as any).env.REACT_APP_TLDRAW_LICENSE_KEY) || getEnv(() => (import.meta as any).env.GATSBY_TLDRAW_LICENSE_KEY) || getEnv(() => (import.meta as any).env.VITE_TLDRAW_LICENSE_KEY) || getEnv(() => (import.meta as any).env.PUBLIC_TLDRAW_LICENSE_KEY) || null return envLicenseKey } function getEnv(cb: () => string | undefined) { try { return cb() } catch { return undefined } }