import fs from 'node:fs'; import { PNG } from 'pngjs'; const appConfigPath = new URL('../app.json', import.meta.url); const appConfig = JSON.parse(fs.readFileSync(appConfigPath, 'utf8')).expo; const appPath = new URL('../App.tsx', import.meta.url); const appSource = fs.readFileSync(appPath, 'utf8'); const iconPath = new URL('../assets/icon.png', import.meta.url); const icon = PNG.sync.read(fs.readFileSync(iconPath)); if (appConfig.scheme !== 'genarrative') { throw new Error('mobile shell scheme must be genarrative'); } if (appConfig.icon !== './assets/icon.png') { throw new Error('mobile shell must use the real brand icon asset'); } if (icon.width < 512 || icon.height < 512) { throw new Error('mobile shell icon must be a production-size brand asset'); } if (!appConfig.ios?.associatedDomains?.includes('applinks:app.genarrative.world')) { throw new Error('mobile shell iOS associated domain is missing'); } const androidFilter = appConfig.android?.intentFilters?.find((filter) => filter?.data?.some( (entry) => entry?.scheme === 'https' && entry?.host === 'app.genarrative.world', ), ); if (!androidFilter) { throw new Error('mobile shell Android app link filter is missing'); } for (const snippet of [ 'Linking.getInitialURL()', "Linking.addEventListener('url'", 'buildMobileShellUrlFromDeepLink', 'configureMobileHostBridgeNavigation', 'navigation.canGoBack', 'buildHostBridgeMessageScript', ]) { if (!appSource.includes(snippet)) { throw new Error(`mobile shell App missing ${snippet}`); } }