/** * NFC tag writing. * * Two paths, one purpose — write ONLY the verify URL (the same pointer the QR * carries). A tag is passive and clonable, exactly like copying a QR; the trust * still comes from the signature on the relay. * * • Native (Capacitor APK): the local `SkateSpotsNfc` Android plugin, registered * by name — Web NFC isn't exposed in the WebView. * • Web (Chrome on Android over HTTPS): Web NFC (`NDEFReader`). * * iOS can't write tags either way; reading works everywhere by tapping. */ import { Capacitor, registerPlugin } from '@capacitor/core'; interface NativeNfc { isSupported(): Promise<{ supported: boolean }>; writeUrl(options: { url: string }): Promise; cancel(): Promise; } const NativeNfc = registerPlugin('SkateSpotsNfc'); interface NdefWriter { write(message: { records: Array<{ recordType: string; data: string }> }): Promise; } type NdefCtor = new () => NdefWriter; function ndefCtor(): NdefCtor | undefined { if (typeof window === 'undefined') return undefined; return (window as unknown as { NDEFReader?: NdefCtor }).NDEFReader; } /** Whether we can attempt a write here. On native the plugin validates the adapter. */ export function isNfcSupported(): boolean { if (Capacitor.isNativePlatform()) return true; return !!ndefCtor(); } /** Write a URL record to an NFC tag. Rejects if unsupported or the write fails. */ export async function writeNfcUrl(url: string): Promise { if (Capacitor.isNativePlatform()) { await NativeNfc.writeUrl({ url }); return; } const Ctor = ndefCtor(); if (!Ctor) throw new Error('NFC writing is not supported on this device/browser.'); const writer = new Ctor(); await writer.write({ records: [{ recordType: 'url', data: url }] }); }