// Load environment variables with proper priority (system > .env) import "./scripts/load-env.js"; import type { ExpoConfig } from "expo/config"; // Bundle ID format: space.manus.. // e.g., "my-app" created at 2024-01-15 10:30:45 -> "space.manus.my.app.t20240115103045" // Bundle ID can only contain letters, numbers, and dots // Android requires each dot-separated segment to start with a letter const rawBundleId = "space.manus.timmy.chat.t20260226211148"; const bundleId = rawBundleId .replace(/[-_]/g, ".") // Replace hyphens/underscores with dots .replace(/[^a-zA-Z0-9.]/g, "") // Remove invalid chars .replace(/\.+/g, ".") // Collapse consecutive dots .replace(/^\.+|\.+$/g, "") // Trim leading/trailing dots .toLowerCase() .split(".") .map((segment) => { // Android requires each segment to start with a letter // Prefix with 'x' if segment starts with a digit return /^[a-zA-Z]/.test(segment) ? segment : "x" + segment; }) .join(".") || "space.manus.app"; // Extract timestamp from bundle ID and prefix with "manus" for deep link scheme // e.g., "space.manus.my.app.t20240115103045" -> "manus20240115103045" const timestamp = bundleId.split(".").pop()?.replace(/^t/, "") ?? ""; const schemeFromBundleId = `manus${timestamp}`; const env = { // App branding - update these values directly (do not use env vars) appName: "Timmy Chat", appSlug: "timmy-chat", // S3 URL of the app logo - set this to the URL returned by generate_image when creating custom logo // Leave empty to use the default icon from assets/images/icon.png logoUrl: "https://files.manuscdn.com/user_upload_by_module/session_file/310519663286296482/kuSmtQpNVBtvECMG.png", scheme: schemeFromBundleId, iosBundleId: bundleId, androidPackage: bundleId, }; const config: ExpoConfig = { name: env.appName, slug: env.appSlug, version: "1.0.0", orientation: "portrait", icon: "./assets/images/icon.png", scheme: env.scheme, userInterfaceStyle: "automatic", newArchEnabled: true, ios: { supportsTablet: true, bundleIdentifier: env.iosBundleId, "infoPlist": { "ITSAppUsesNonExemptEncryption": false } }, android: { adaptiveIcon: { backgroundColor: "#080412", foregroundImage: "./assets/images/android-icon-foreground.png", backgroundImage: "./assets/images/android-icon-background.png", monochromeImage: "./assets/images/android-icon-monochrome.png", }, edgeToEdgeEnabled: true, predictiveBackGestureEnabled: false, package: env.androidPackage, permissions: ["POST_NOTIFICATIONS"], intentFilters: [ { action: "VIEW", autoVerify: true, data: [ { scheme: env.scheme, host: "*", }, ], category: ["BROWSABLE", "DEFAULT"], }, ], }, web: { bundler: "metro", output: "static", favicon: "./assets/images/favicon.png", }, plugins: [ "expo-router", [ "expo-audio", { microphonePermission: "Allow $(PRODUCT_NAME) to access your microphone.", }, ], [ "expo-video", { supportsBackgroundPlayback: true, supportsPictureInPicture: true, }, ], [ "expo-splash-screen", { image: "./assets/images/splash-icon.png", imageWidth: 200, resizeMode: "contain", backgroundColor: "#080412", dark: { backgroundColor: "#080412", }, }, ], [ "expo-build-properties", { android: { buildArchs: ["armeabi-v7a", "arm64-v8a"], minSdkVersion: 24, }, }, ], ], experiments: { typedRoutes: true, reactCompiler: true, }, }; export default config;