Gate a feature
Register a server-backed access check and a fallback offer. The JavaScript and React gates open the offer only when access is missing, then give you a chance to refresh the customer's access after checkout. An HTML-only page can show the upgrade checkout, but cannot run the access check for a protected feature by itself.
Have your server render an upgrade button when access is missing. Your server must still check entitlement before serving the protected export, including after checkout.
<script defer src="https://your-org.plandalf.dev/js/plandalf-sdk.js"></script>
<button data-plandalf-present="upgrade">Unlock export</button>This is a checkout trigger, not a declarative gate(). Use the JavaScript or React tab when the page needs to check access and refresh it after checkout.
import { Plandalf } from '@plandalf/sdk'
async function readAccessFromServer() {
const response = await fetch('/api/access/export')
if (!response.ok) throw new Error('Could not check access')
return response.json()
}
const sdk = new Plandalf({ apiBase: 'https://your-org.plandalf.dev' })
let access = await readAccessFromServer()
sdk.addGate('export', 'upgrade', (fresh) =>
fresh?.canExport ?? access.canExport,
)
const result = await sdk.gate('export', async () => {
access = await readAccessFromServer()
return access
})
if (result.access) {
// Call your protected server endpoint; it must check access again.
}import { useCallback } from 'react'
import { PlandalfProvider, useGate } from '@plandalf/react'
async function readAccessFromServer() {
const response = await fetch('/api/access/export')
if (!response.ok) throw new Error('Could not check access')
return response.json()
}
function ExportButton() {
const check = useCallback(async () => (await readAccessFromServer()).canExport, [])
const { access, checking, trigger } = useGate('export', 'upgrade', check)
async function exportFile() {
const result = await trigger(readAccessFromServer)
if (result.access) {
// Call your protected server endpoint; it must check access again.
}
}
return <button disabled={checking} onClick={exportFile}>{access ? 'Export' : 'Unlock export'}</button>
}
export function ExportFeature() {
return (
<PlandalfProvider apiBase="https://your-org.plandalf.dev">
<ExportButton />
</PlandalfProvider>
)
}For the JavaScript and React gates, if the customer dismisses the offer, access is false. A failed check or sync returns status: 'error' and access: false. A denied gate has already handled its fallback offer; do not call present() again. The protected server endpoint must make its own access decision.
See GateResult, GateCheck, GateSyncCallback, and useGate() for exact types.