diff --git a/.env.example b/.env.example index 843564b..640e080 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,9 @@ EXPO_PUBLIC_OPENDATING_RELAY_URL=wss://opendating-relay.jonathang132298.workers.dev EXPO_PUBLIC_OPENDATING_INFO_URL=https://opendating-relay.jonathang132298.workers.dev EXPO_PUBLIC_OPENDATING_PROTOCOL_VERSION=0.1 +# Both gates must be true before a paywall can appear. Keep feature readiness +# false until paid customization/convenience features and safety gates ship. +EXPO_PUBLIC_REVENUECAT_ENABLED=false +EXPO_PUBLIC_OPENDATING_PLUS_FEATURES_READY=false +EXPO_PUBLIC_REVENUECAT_IOS_API_KEY= +EXPO_PUBLIC_REVENUECAT_ANDROID_API_KEY= diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7fa38b3..d49b1db 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,25 @@ jobs: - run: bun install --frozen-lockfile - run: bun run lint + web-export: + name: Web export + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version-file: package.json + - run: bun install --frozen-lockfile + - run: bun run export:web + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: web-export + path: dist + if-no-files-found: error + retention-days: 7 + test: name: Tests runs-on: ubuntu-latest @@ -112,7 +131,7 @@ jobs: # Full check passes only when all release checks pass. ci: name: CI - needs: [typecheck, lint, test, security, dependency-review, sbom] + needs: [typecheck, lint, web-export, test, security, dependency-review, sbom] runs-on: ubuntu-latest steps: - run: echo "All checks passed" diff --git a/.gitignore b/.gitignore index 0832f4c..3c52517 100644 --- a/.gitignore +++ b/.gitignore @@ -63,3 +63,6 @@ coverage/ *.tmp screenshots/*.png screenshots/app-store/ + +# Local brand source exports; app-ready assets live under assets/brand. +/BrandAssetPack/animations/ diff --git a/bun.lock b/bun.lock index 591fca2..d63922e 100644 --- a/bun.lock +++ b/bun.lock @@ -5,28 +5,28 @@ "": { "name": "opendating-mobile", "dependencies": { - "@expo/ui": "~57.0.9", + "@expo/ui": "~57.0.12", "@noble/curves": "1.9.7", - "@nostr-dev-kit/ndk": "^2.15.2", - "@react-native-async-storage/async-storage": "^3.1.1", + "@nostr-dev-kit/ndk": "^2.18.1", + "@react-native-async-storage/async-storage": "2.2.0", "@scure/base": "^2.3.0", - "expo": "~57.0.11", + "expo": "~57.0.15", "expo-clipboard": "~57.0.1", - "expo-constants": "~57.0.9", + "expo-constants": "~57.0.13", "expo-crypto": "~57.0.1", - "expo-dev-client": "~57.0.10", + "expo-dev-client": "~57.0.14", "expo-device": "~57.0.1", "expo-font": "~57.0.1", "expo-glass-effect": "~57.0.1", "expo-haptics": "^57.0.1", - "expo-image": "~57.0.2", - "expo-image-picker": "^57.0.8", + "expo-image": "~57.0.3", + "expo-image-picker": "~57.0.12", "expo-linear-gradient": "~57.0.1", - "expo-linking": "~57.0.5", - "expo-location": "^57.0.8", - "expo-router": "~57.0.11", + "expo-linking": "~57.0.7", + "expo-location": "~57.0.12", + "expo-router": "~57.0.15", "expo-secure-store": "^57.0.1", - "expo-splash-screen": "~57.0.5", + "expo-splash-screen": "~57.0.7", "expo-sqlite": "~57.0.1", "expo-status-bar": "~57.0.1", "expo-symbols": "~57.0.2", @@ -39,34 +39,36 @@ "react-native": "0.86.2", "react-native-gesture-handler": "~2.32.0", "react-native-get-random-values": "^1.11.0", + "react-native-purchases": "^10.6.0", "react-native-reanimated": "4.5.1", "react-native-safe-area-context": "~5.7.0", - "react-native-screens": "~4.26.0", + "react-native-screens": "~4.26.2", "react-native-svg": "15.15.4", - "react-native-web": "~0.21.0", + "react-native-web": "~0.21.2", "react-native-worklets": "0.10.1", }, "devDependencies": { "@react-native/jest-preset": "^0.86.2", "@testing-library/react-native": "13.3.3", "@types/jest": "^29.5.14", - "@types/react": "~19.2.2", - "eslint": "^9.0.0", + "@types/react": "~19.2.18", + "eslint": "^9.39.5", "eslint-config-expo": "~57.0.1", "jest": "^29.7.0", - "jest-expo": "~57.0.3", + "jest-expo": "~57.0.4", "react-test-renderer": "19.2.3", "ts-jest": "^29.4.12", "typescript": "~6.0.3", }, }, }, + "patchedDependencies": { + "tseep@1.3.1": "patches/tseep@1.3.1.patch", + }, "overrides": { "uuid": ">=14.0.1", }, "packages": { - "@adobe/css-tools": ["@adobe/css-tools@4.5.0", "", {}, "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q=="], - "@babel/code-frame": ["@babel/code-frame@7.29.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw=="], "@babel/compat-data": ["@babel/compat-data@7.29.7", "", {}, "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg=="], @@ -271,11 +273,11 @@ "@expo-google-fonts/material-symbols": ["@expo-google-fonts/material-symbols@0.4.42", "", {}, "sha512-KZmHZRcthJ3KFZZlpzHjopA9guZgWR9fb3uVZlTR0BNlvG2pw1bnYBCpkze2PB0vRllwGhAM7lWXsfmcWCbXYg=="], - "@expo/cli": ["@expo/cli@57.0.15", "", { "dependencies": { "@expo/code-signing-certificates": "^0.0.6", "@expo/config": "~57.0.7", "@expo/config-plugins": "~57.0.8", "@expo/devcert": "^1.2.1", "@expo/env": "~2.4.2", "@expo/image-utils": "^0.11.4", "@expo/inline-modules": "^0.1.5", "@expo/json-file": "^11.0.1", "@expo/log-box": "^57.0.2", "@expo/metro": "~56.0.0", "@expo/metro-config": "~57.0.8", "@expo/metro-file-map": "^57.0.1", "@expo/osascript": "^2.7.1", "@expo/package-manager": "^1.13.1", "@expo/plist": "^0.8.1", "@expo/prebuild-config": "^57.0.12", "@expo/require-utils": "^57.0.4", "@expo/router-server": "^57.0.6", "@expo/schema-utils": "^57.0.2", "@expo/spawn-async": "^1.8.0", "@expo/ws-tunnel": "^2.0.0", "@expo/xcpretty": "^4.4.4", "@react-native/dev-middleware": "0.86.2", "accepts": "^1.3.8", "agent-cli-detector": "^0.1.2", "arg": "^5.0.2", "bplist-creator": "0.1.0", "bplist-parser": "^0.3.1", "chalk": "^4.0.0", "ci-info": "^3.3.0", "compression": "^1.7.4", "connect": "^3.7.0", "debug": "^4.3.4", "dnssd-advertise": "^1.1.4", "expo-server": "^57.0.3", "fetch-nodeshim": "^0.4.10", "getenv": "^2.0.0", "glob": "^13.0.0", "lan-network": "^0.2.1", "multitars": "^1.0.2", "node-forge": "^1.3.3", "npm-package-arg": "^11.0.0", "ora": "^3.4.0", "picomatch": "^4.0.4", "pretty-format": "^29.7.0", "progress": "^2.0.3", "prompts": "^2.3.2", "resolve-from": "^5.0.0", "sandbox-cli-detector": "^0.2.0", "semver": "^7.6.0", "send": "^0.19.0", "slugify": "^1.3.4", "stacktrace-parser": "^0.1.10", "structured-headers": "^0.4.1", "terminal-link": "^2.1.1", "toqr": "^0.1.1", "wrap-ansi": "^7.0.0", "ws": "^8.12.1", "zod": "^3.25.76" }, "peerDependencies": { "expo": "*", "expo-router": "*", "react-native": "*" }, "optionalPeers": ["expo-router", "react-native"], "bin": { "expo-internal": "main.js" } }, "sha512-YIE5xgZlkwx6OyjjVq/zAfqtYvczsWLEkOukDJwaZDaMQl8x5/CjoqC/Oe670DFQc5xjqguH6cmZUWHHL7yH3g=="], + "@expo/cli": ["@expo/cli@57.0.17", "", { "dependencies": { "@expo/code-signing-certificates": "^0.0.6", "@expo/config": "~57.0.8", "@expo/config-plugins": "~57.0.8", "@expo/devcert": "^1.2.1", "@expo/env": "~2.4.2", "@expo/image-utils": "^0.11.4", "@expo/inline-modules": "^0.1.6", "@expo/json-file": "^11.0.1", "@expo/log-box": "^57.0.3", "@expo/metro": "~56.0.0", "@expo/metro-config": "~57.0.9", "@expo/metro-file-map": "^57.0.1", "@expo/osascript": "^2.7.1", "@expo/package-manager": "^1.13.1", "@expo/plist": "^0.8.1", "@expo/prebuild-config": "^57.0.13", "@expo/require-utils": "^57.0.4", "@expo/router-server": "^57.0.7", "@expo/schema-utils": "^57.0.2", "@expo/spawn-async": "^1.8.0", "@expo/ws-tunnel": "^2.0.0", "@expo/xcpretty": "^4.4.4", "@react-native/dev-middleware": "0.86.2", "accepts": "^1.3.8", "agent-cli-detector": "0.1.6", "arg": "^5.0.2", "bplist-creator": "0.1.0", "bplist-parser": "^0.3.1", "chalk": "^4.0.0", "ci-info": "^3.3.0", "compression": "^1.7.4", "connect": "^3.7.0", "debug": "^4.3.4", "dnssd-advertise": "^1.1.4", "expo-server": "^57.0.3", "fetch-nodeshim": "^0.4.10", "getenv": "^2.0.0", "glob": "^13.0.0", "lan-network": "^0.2.1", "multitars": "^1.0.2", "node-forge": "^1.3.3", "npm-package-arg": "^11.0.0", "ora": "^3.4.0", "picomatch": "^4.0.4", "pretty-format": "^29.7.0", "progress": "^2.0.3", "prompts": "^2.3.2", "resolve-from": "^5.0.0", "sandbox-cli-detector": "^0.2.0", "semver": "^7.6.0", "send": "^0.19.0", "slugify": "^1.3.4", "stacktrace-parser": "^0.1.10", "structured-headers": "^0.4.1", "terminal-link": "^2.1.1", "toqr": "^0.1.1", "wrap-ansi": "^7.0.0", "ws": "^8.12.1", "zod": "^3.25.76" }, "peerDependencies": { "expo": "*", "expo-router": "*", "react-native": "*" }, "optionalPeers": ["expo-router", "react-native"], "bin": { "expo-internal": "main.js" } }, "sha512-PQc7if117dNh2qe+CHdlmSWpgwhFiP9CJ7XbwNF0w4KSKxFpJ2qUjDPoAcCMW1VZg1x30mEJ907bT8G1iDIZBQ=="], "@expo/code-signing-certificates": ["@expo/code-signing-certificates@0.0.6", "", { "dependencies": { "node-forge": "^1.3.3" } }, "sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w=="], - "@expo/config": ["@expo/config@57.0.7", "", { "dependencies": { "@expo/config-plugins": "~57.0.7", "@expo/config-types": "^57.0.2", "@expo/json-file": "^11.0.1", "@expo/require-utils": "^57.0.4", "deepmerge": "^4.3.1", "getenv": "^2.0.0", "glob": "^13.0.0", "resolve-workspace-root": "^2.0.0", "semver": "^7.6.0", "slugify": "^1.3.4" } }, "sha512-4A+V8x5OmQqNm76l84S+RrB6kVoeFrvcm/Xn/6d+ELPF/HeucDheAFchdYxYNy+NEvWzuNlI/oCvrftIeK+dbQ=="], + "@expo/config": ["@expo/config@57.0.8", "", { "dependencies": { "@expo/config-plugins": "~57.0.8", "@expo/config-types": "^57.0.2", "@expo/json-file": "^11.0.1", "@expo/require-utils": "^57.0.4", "deepmerge": "^4.3.1", "getenv": "^2.0.0", "glob": "^13.0.0", "resolve-workspace-root": "^2.0.0", "semver": "^7.6.0", "slugify": "^1.3.4" } }, "sha512-7VpAu2ZMXNZI0+Kn+nD3vQBIyST89LATNkZpnp/cXh8/aj7zUXO8d/T+hOxsvhOFwR8eQO+jKXEw8tQbidiMxA=="], "@expo/config-plugins": ["@expo/config-plugins@57.0.8", "", { "dependencies": { "@expo/config-types": "^57.0.2", "@expo/json-file": "~11.0.1", "@expo/plist": "^0.8.1", "@expo/require-utils": "^57.0.4", "@expo/sdk-runtime-versions": "^1.0.0", "chalk": "^4.1.2", "debug": "^4.3.5", "getenv": "^2.0.0", "glob": "^13.0.0", "semver": "^7.5.4", "slugify": "^1.6.6", "xcode": "^3.0.1", "xml2js": "0.6.0" } }, "sha512-x6lx4s/19i39/+1dMPwb9tFCc4WR843dG5Yi+C64lhKL3YHX+6oKrT2Kv72PCEalnUY+usQDkB3NrLSrYOWtDg=="], @@ -291,21 +293,21 @@ "@expo/expo-modules-macros-plugin": ["@expo/expo-modules-macros-plugin@0.6.1", "", {}, "sha512-cpsLZE4rqkc1Y3eZTkxB98jrqY1YXgetmtxFt8q89jBRmk3quRuk1BZo+VcnCSObZardjg99r1k5xijEMONFGA=="], - "@expo/fingerprint": ["@expo/fingerprint@0.20.7", "", { "dependencies": { "@expo/env": "^2.4.2", "@expo/spawn-async": "^1.8.0", "arg": "^5.0.2", "chalk": "^4.1.2", "debug": "^4.3.4", "getenv": "^2.0.0", "glob": "^13.0.0", "ignore": "^5.3.1", "minimatch": "^10.2.2", "resolve-from": "^5.0.0", "semver": "^7.6.0" }, "bin": { "fingerprint": "bin/cli.js" } }, "sha512-tYyZD4XZSn1C30pr9IvjN/BjAqpf6r9e1NL09lPvheO1DMLByOVdmMHFLSwW8Pu6veVgzue7GDWmq9P8mc8GMg=="], + "@expo/fingerprint": ["@expo/fingerprint@0.20.9", "", { "dependencies": { "@expo/env": "^2.4.2", "@expo/spawn-async": "^1.8.0", "arg": "^5.0.2", "chalk": "^4.1.2", "debug": "^4.3.4", "getenv": "^2.0.0", "glob": "^13.0.0", "ignore": "^5.3.1", "minimatch": "^10.2.2", "resolve-from": "^5.0.0", "semver": "^7.6.0" }, "bin": { "fingerprint": "bin/cli.js" } }, "sha512-h+YvPyNmeAUCCqaXvftiXklA2zGyRcIPv1B8fFS0YSIgNhwcxFGh1EyLOMsvJ2aWsBViNtIJ1HIFLzNu43/r4w=="], "@expo/image-utils": ["@expo/image-utils@0.11.4", "", { "dependencies": { "@expo/require-utils": "^57.0.4", "@expo/spawn-async": "^1.8.0", "chalk": "^4.0.0", "getenv": "^2.0.0", "jimp-compact": "0.16.1", "parse-png": "^2.1.0", "semver": "^7.6.0" } }, "sha512-pn/4770DIEOcYZr484uazuwg20FX/qaDkeMRF6J+oxejynDmEmO8wLsCudaNShFE0BhyKGQTYrs2rsRhqrqESw=="], - "@expo/inline-modules": ["@expo/inline-modules@0.1.5", "", { "dependencies": { "@expo/config-plugins": "~57.0.7" } }, "sha512-LC+kWeIwnvsGIvDaFBd8uzleWzWZiZTCG7CmtfxBLjW/Gify596X67ZqTi76iHzm5KToAfwwX0nppAKPDA9vQw=="], + "@expo/inline-modules": ["@expo/inline-modules@0.1.6", "", { "dependencies": { "@expo/config-plugins": "~57.0.8" } }, "sha512-5f6EiOIKsFj9zlrCBet4ZIQRPEa9dBUdQgTzpjYwdZ8Z/M8W5lqMVL9dEs4HYKvEmDnqv0dQuDkFLyRSwu/DAQ=="], "@expo/json-file": ["@expo/json-file@11.0.1", "", { "dependencies": { "@babel/code-frame": "^7.20.0", "json5": "^2.2.3" } }, "sha512-zxHWj4MKKMAL29ZQSY/Fssx4Thluk40JmuGNaeS078wy/NhlFhnVi+rHHunulE3xJAJ0CM73m8VK2+GkF9eRwQ=="], - "@expo/local-build-cache-provider": ["@expo/local-build-cache-provider@57.0.6", "", { "dependencies": { "@expo/config": "~57.0.7", "chalk": "^4.1.2" } }, "sha512-6aFMROb1SzIvrefpwhgS5QGNELU9T2lpK0Hcl6oiZ4/mbKgZRk0WEPauo/dHH6IgDmyK25InCMHF5nj7XY4LWg=="], + "@expo/local-build-cache-provider": ["@expo/local-build-cache-provider@57.0.7", "", { "dependencies": { "@expo/config": "~57.0.8", "chalk": "^4.1.2" } }, "sha512-Hq5xWhXJWuyH3CWh3uqDWoHtxM0XYqLs9h2OzRWImBJahCPfePOo4kmw2uTEB6qHT5T47eqO4jtDG3MRGGZCpw=="], - "@expo/log-box": ["@expo/log-box@57.0.2", "", { "dependencies": { "@expo/dom-webview": "^57.0.1", "anser": "^1.4.9", "stacktrace-parser": "^0.1.10" }, "peerDependencies": { "@expo/dom-webview": "^57.0.1", "expo": "*", "react": "*", "react-native": "*" } }, "sha512-ZsFyfIR7YCbQAdVLzuTUmMHofZC7ZS9ywYCJNPlLc78x59cI8GwXFEIVbRjjC0uJERpNtXx/tsNNnkhexXlzMw=="], + "@expo/log-box": ["@expo/log-box@57.0.3", "", { "dependencies": { "@expo/dom-webview": "^57.0.1", "anser": "^1.4.9", "stacktrace-parser": "^0.1.10" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-qv/cMliNax6es07Un/4IGJIcs4PUuhTKKTrJZX/0X2YRcOT5cqm/QicibZwTIbiZWi1i8P4YBRQTfFT2B17giw=="], "@expo/metro": ["@expo/metro@56.0.0", "", { "dependencies": { "metro": "0.84.4", "metro-babel-transformer": "0.84.4", "metro-cache": "0.84.4", "metro-cache-key": "0.84.4", "metro-config": "0.84.4", "metro-core": "0.84.4", "metro-file-map": "0.84.4", "metro-minify-terser": "0.84.4", "metro-resolver": "0.84.4", "metro-runtime": "0.84.4", "metro-source-map": "0.84.4", "metro-symbolicate": "0.84.4", "metro-transform-plugins": "0.84.4", "metro-transform-worker": "0.84.4" } }, "sha512-5gIgQHtEpjjvsjKfVtIv23a98LLRV0/y07PDShEwYSytAMlE3FSF8RHXqtHc1sUJL6dn7hnuIBpIbrLXXuVi0A=="], - "@expo/metro-config": ["@expo/metro-config@57.0.8", "", { "dependencies": { "@babel/code-frame": "^7.20.0", "@babel/core": "^7.20.0", "@babel/generator": "^7.20.5", "@expo/config": "~57.0.7", "@expo/env": "~2.4.2", "@expo/json-file": "~11.0.1", "@expo/metro": "~56.0.0", "@expo/require-utils": "^57.0.4", "@expo/spawn-async": "^1.8.0", "@jridgewell/gen-mapping": "^0.3.13", "@jridgewell/remapping": "^2.3.5", "@jridgewell/sourcemap-codec": "^1.5.5", "browserslist": "^4.25.0", "chalk": "^4.1.0", "debug": "^4.3.2", "getenv": "^2.0.0", "glob": "^13.0.0", "hermes-parser": "^0.36.0", "jsc-safe-url": "^0.2.4", "lightningcss": "^1.30.1", "picomatch": "^4.0.4", "postcss": "^8.5.14", "resolve-from": "^5.0.0" }, "peerDependencies": { "expo": "*" }, "optionalPeers": ["expo"] }, "sha512-cZOVjbljqRBMCXcloc5k23gsFOhWdiKXhDkp5jU/wY6IXR6G7cYtNOwxKfxI1QLhs0KcXY0gDmZ2UIueoHzY7g=="], + "@expo/metro-config": ["@expo/metro-config@57.0.9", "", { "dependencies": { "@babel/code-frame": "^7.20.0", "@babel/core": "^7.20.0", "@babel/generator": "^7.20.5", "@expo/config": "~57.0.8", "@expo/env": "~2.4.2", "@expo/json-file": "~11.0.1", "@expo/metro": "~56.0.0", "@expo/require-utils": "^57.0.4", "@expo/spawn-async": "^1.8.0", "@jridgewell/gen-mapping": "^0.3.13", "@jridgewell/remapping": "^2.3.5", "@jridgewell/sourcemap-codec": "^1.5.5", "browserslist": "^4.25.0", "chalk": "^4.1.0", "debug": "^4.3.2", "getenv": "^2.0.0", "glob": "^13.0.0", "hermes-parser": "^0.36.0", "jsc-safe-url": "^0.2.4", "lightningcss": "^1.30.1", "picomatch": "^4.0.4", "postcss": "^8.5.14", "resolve-from": "^5.0.0" }, "peerDependencies": { "expo": "*" }, "optionalPeers": ["expo"] }, "sha512-+lalXZdoMaKTG1uKXsi2KWO0f7H3KiWrhZzAla4EmNSkcUMRx6K1rhZuBYoaJaKIp9BHZ333KbqRPron7slKQA=="], "@expo/metro-file-map": ["@expo/metro-file-map@57.0.1", "", { "dependencies": { "debug": "^4.3.4", "fb-watchman": "^2.0.2", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "micromatch": "^4.0.4", "walker": "^1.0.8" } }, "sha512-8JXfVstZN7QnP4NianZZnlTVboOWR0sG8trUDNajOjnbGlPln29vponXM84tY+3tAHapz5/TxE53L0ixUwqPtA=="], @@ -317,11 +319,11 @@ "@expo/plist": ["@expo/plist@0.8.1", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-3gTReGIUm0oRaMClsAJYxBnVPCl6fVpsl8HS+DTVxDhW4GyVyxg9E/Znm3BvcHtUJ51RJJI14pC1wvrNilCRHw=="], - "@expo/prebuild-config": ["@expo/prebuild-config@57.0.12", "", { "dependencies": { "@expo/config": "~57.0.7", "@expo/config-plugins": "~57.0.8", "@expo/config-types": "^57.0.2", "@expo/image-utils": "^0.11.4", "@expo/json-file": "^11.0.1", "@react-native/normalize-colors": "0.86.2", "debug": "^4.3.1", "expo-modules-autolinking": "~57.0.10", "resolve-from": "^5.0.0", "semver": "^7.6.0" } }, "sha512-3vwrQ2DSGijJUa8K/j3xUfOdhYgygKdWAjJ7o3r143BGnKD1SwPIMEN7dSDhkmDWR4FAXTQwgaD8dHh5VZd/jA=="], + "@expo/prebuild-config": ["@expo/prebuild-config@57.0.13", "", { "dependencies": { "@expo/config": "~57.0.8", "@expo/config-plugins": "~57.0.8", "@expo/config-types": "^57.0.2", "@expo/image-utils": "^0.11.4", "@expo/json-file": "^11.0.1", "@react-native/normalize-colors": "0.86.2", "debug": "^4.3.1", "expo-modules-autolinking": "~57.0.10", "resolve-from": "^5.0.0", "semver": "^7.6.0" } }, "sha512-VhSySuXqOwK4fIc+9rgms7zN+c1Khj2xpuIgpVLPNyWRtpS8wB+eyV5CSohjSUBa3h+NsFdPk/VG6p0ZwlMDrg=="], "@expo/require-utils": ["@expo/require-utils@57.0.4", "", { "dependencies": { "@babel/code-frame": "^7.20.0", "@babel/core": "^7.25.2", "@babel/plugin-transform-modules-commonjs": "^7.24.8" }, "peerDependencies": { "typescript": "^5.0.0 || ^5.0.0-0 || ^6.0.0 || ^7.0.0" } }, "sha512-e7xbg/9BTQcsZE/oErafZXtI7kh5IgfasLJ97J5sFSzX2cA74pDvdlhW1KHVSaDkQyQv6h1LSLhsY7dEeOk7hw=="], - "@expo/router-server": ["@expo/router-server@57.0.6", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "@expo/metro-runtime": "^57.0.10", "expo": "*", "expo-constants": "^57.0.11", "expo-font": "^57.0.1", "expo-router": "*", "expo-server": "^57.0.3", "react": "*", "react-dom": "*", "react-server-dom-webpack": "~19.0.1 || ~19.1.2 || ~19.2.1" }, "optionalPeers": ["@expo/metro-runtime", "expo-router", "react-dom", "react-server-dom-webpack"] }, "sha512-/0H7OIilU4lmdR3V9UZuKou71cwaJ11sneW8/T6Rtr46LA71lgBWzdRldvVxaWv8dT+cu90f4jl+M3DYXN9MqQ=="], + "@expo/router-server": ["@expo/router-server@57.0.7", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "@expo/metro-runtime": "^57.0.12", "expo": "*", "expo-constants": "^57.0.13", "expo-font": "^57.0.1", "expo-router": "*", "expo-server": "^57.0.3", "react": "*", "react-dom": "*", "react-server-dom-webpack": "~19.0.1 || ~19.1.2 || ~19.2.1" }, "optionalPeers": ["@expo/metro-runtime", "expo-router", "react-dom", "react-server-dom-webpack"] }, "sha512-QFHwt6V7UovmYA7+8BoMeKj3fh6WtkM9zksKjNAlZdcEI/hUhcW4uged6So5yc4tq+eA60kA7gIVZPKgBIZdrQ=="], "@expo/schema-utils": ["@expo/schema-utils@57.0.2", "", {}, "sha512-fMu/jyN0l1Wzv7XkeWR4IYCx1M8ryui3FdBNGrWwbRgJ7EhxXxK8E2jxP2W3pbgUwUY0V3hG8+GyfCZwny+Lxw=="], @@ -331,7 +333,7 @@ "@expo/sudo-prompt": ["@expo/sudo-prompt@9.3.2", "", {}, "sha512-HHQigo3rQWKMDzYDLkubN5WQOYXJJE2eNqIQC2axC2iO3mHdwnIR7FgZVvHWtBwAdzBgAP0ECp8KqS8TiMKvgw=="], - "@expo/ui": ["@expo/ui@57.0.11", "", { "dependencies": { "sf-symbols-typescript": "^2.1.0", "vaul": "^1.1.2" }, "peerDependencies": { "@babel/core": "*", "expo": "*", "react": "*", "react-dom": "*", "react-native": "*", "react-native-worklets": "*" }, "optionalPeers": ["@babel/core", "react-dom", "react-native-worklets"] }, "sha512-m1BSq15sg4sCmoFwOsMxBpETgyFhGlCbVPUyjdJ6Y00Ve0Fb4sueaFLRyeYRbZ8DC1z3Hgp5LNCYzBBBdMhxMg=="], + "@expo/ui": ["@expo/ui@57.0.12", "", { "dependencies": { "sf-symbols-typescript": "^2.1.0", "vaul": "^1.1.2" }, "peerDependencies": { "@babel/core": "*", "expo": "*", "react": "*", "react-dom": "*", "react-native": "*", "react-native-worklets": "*" }, "optionalPeers": ["@babel/core", "react-dom", "react-native-worklets"] }, "sha512-ZkrECV6xZe0+Drq6C0hrBKvz1534/VyARNp9ziKihC6Db69W29+jBDZm8k9cyRyS1Hh23q6LP8J+2wDyUM8eAA=="], "@expo/ws-tunnel": ["@expo/ws-tunnel@2.0.0", "", { "peerDependencies": { "ws": "^8.0.0" } }, "sha512-j+JfTRdCk820J9dU0sA2SqshQIKFOMo7ED84w9MJFcebfbNQgsLztEY/SABDkGnjatrW4xGqnUhVRxSBVyCkXw=="], @@ -457,7 +459,7 @@ "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw=="], - "@react-native-async-storage/async-storage": ["@react-native-async-storage/async-storage@3.1.1", "", { "dependencies": { "idb": "8.0.3" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-z+PnLz1n6ECKhgoHZHkfc+dijXZEyZnNFSajbtE0NEbsJhmX8x9GlOeiMQIKX2E4DUqPSgfIh4FYBv1M49KgPQ=="], + "@react-native-async-storage/async-storage": ["@react-native-async-storage/async-storage@2.2.0", "", { "dependencies": { "merge-options": "^3.0.4" }, "peerDependencies": { "react-native": "^0.0.0-0 || >=0.65 <1.0" } }, "sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw=="], "@react-native-masked-view/masked-view": ["@react-native-masked-view/masked-view@0.3.2", "", { "peerDependencies": { "react": ">=16", "react-native": ">=0.57" } }, "sha512-XwuQoW7/GEgWRMovOQtX3A4PrXhyaZm0lVUiY8qJDvdngjLms9Cpdck6SmGAUNqQwcj2EadHC1HwL0bEyoa/SQ=="], @@ -491,6 +493,12 @@ "@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.86.2", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.2.0", "react": "*", "react-native": "0.86.2" } }, "sha512-uO0J72gh3EvE+1/GHRk18QRyBDTRHRB0AraAfojsRjbT7VMuJwKrZYaKGshavoaEud6aw00ZB9/8mTMIKjjcAw=="], + "@revenuecat/purchases-js": ["@revenuecat/purchases-js@1.52.3", "", {}, "sha512-ZU+mqdW7jsGTqYhtDmvDjcLzplvfh+jTspSKC0eMijxmFik0r/Wwq/CkD3o0QEqVRbVF0HkwEh2zZp6qdGR1Eg=="], + + "@revenuecat/purchases-js-hybrid-mappings": ["@revenuecat/purchases-js-hybrid-mappings@18.31.0", "", { "dependencies": { "@revenuecat/purchases-js": "1.52.3" } }, "sha512-iVnTulEs9tXHAJwogYhUN639mU1vV/2eLv1vKvEV9lxDw6rbL5mj4vDHbK9Yrw4IeI0C8Z8Xy14UDZ74W+y2VQ=="], + + "@revenuecat/purchases-typescript-internal": ["@revenuecat/purchases-typescript-internal@18.31.0", "", {}, "sha512-5AE00P0AX34ou14ayEXFEdlWbNPFSYwAQl+1MWvTMKOd9wup1/T3erM53kp2t+ms4oajJv14qwNjzlCnH4JdnA=="], + "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], "@scure/base": ["@scure/base@2.3.0", "", {}, "sha512-NsG6Y03tY6R5BUis4FdVtHVkur0U6FOzskgs9ZXNl78CUc9fkZ78HmENUle1nSOkCasDmbubmWD9qwB7mm4PZA=="], @@ -519,20 +527,12 @@ "@sinonjs/fake-timers": ["@sinonjs/fake-timers@10.3.0", "", { "dependencies": { "@sinonjs/commons": "^3.0.0" } }, "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA=="], - "@testing-library/dom": ["@testing-library/dom@10.4.1", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "picocolors": "1.1.1", "pretty-format": "^27.0.2" } }, "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg=="], - - "@testing-library/jest-dom": ["@testing-library/jest-dom@6.9.1", "", { "dependencies": { "@adobe/css-tools": "^4.4.0", "aria-query": "^5.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.6.3", "picocolors": "^1.1.1", "redent": "^3.0.0" } }, "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA=="], - "@testing-library/react-native": ["@testing-library/react-native@13.3.3", "", { "dependencies": { "jest-matcher-utils": "^30.0.5", "picocolors": "^1.1.1", "pretty-format": "^30.0.5", "redent": "^3.0.0" }, "peerDependencies": { "jest": ">=29.0.0", "react": ">=18.2.0", "react-native": ">=0.71", "react-test-renderer": ">=18.2.0" } }, "sha512-k6Mjsd9dbZgvY4Bl7P1NIpePQNi+dfYtlJ5voi9KQlynxSyQkfOgJmYGCYmw/aSgH/rUcFvG8u5gd4npzgRDyg=="], - "@testing-library/user-event": ["@testing-library/user-event@14.6.3", "", { "peerDependencies": { "@testing-library/dom": ">=7.21.4" } }, "sha512-6dBq67jT8lE+JTE8Exm02Kt6ze43hz1jdiSpSJwtTZiT1xQQ6b7nZYTTQ9njdArdU8XklOwaDp/AbT/eYSKF4g=="], - "@tootallnate/once": ["@tootallnate/once@2.0.1", "", {}, "sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ=="], "@tybys/wasm-util": ["@tybys/wasm-util@0.10.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg=="], - "@types/aria-query": ["@types/aria-query@5.0.4", "", {}, "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw=="], - "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], @@ -665,7 +665,7 @@ "agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="], - "agent-cli-detector": ["agent-cli-detector@0.1.5", "", { "bin": "dist/cli.js" }, "sha512-6xvLw0EGPuxoYGZeqyMV4AK+WoZ31jsqb7a5pln1BTf6oDFsrgvfCJT7E7y9oAqifJZhJ3fZ0J36H7o6JzrB0Q=="], + "agent-cli-detector": ["agent-cli-detector@0.1.6", "", { "bin": { "agent-cli-detector": "dist/cli.js" } }, "sha512-vKrPeEVN3upDF3GjWxsWBbwQgMtNJ8VB1cduPvK3svmmz4ENpS7yaPxbogsbe3w+xp9xp2Cu+0Ar41rjAR4+lA=="], "ajv": ["ajv@6.15.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="], @@ -685,8 +685,6 @@ "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], - "aria-query": ["aria-query@5.3.0", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A=="], - "array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="], "array-includes": ["array-includes@3.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.0", "es-object-atoms": "^1.1.1", "get-intrinsic": "^1.3.0", "is-string": "^1.1.1", "math-intrinsics": "^1.1.0" } }, "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ=="], @@ -853,8 +851,6 @@ "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], - "css.escape": ["css.escape@1.5.1", "", {}, "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg=="], - "cssom": ["cssom@0.5.0", "", {}, "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw=="], "cssstyle": ["cssstyle@2.3.0", "", { "dependencies": { "cssom": "~0.3.6" } }, "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A=="], @@ -909,8 +905,6 @@ "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], - "dom-accessibility-api": ["dom-accessibility-api@0.6.3", "", {}, "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w=="], - "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], @@ -1011,27 +1005,27 @@ "expect": ["expect@29.7.0", "", { "dependencies": { "@jest/expect-utils": "^29.7.0", "jest-get-type": "^29.6.3", "jest-matcher-utils": "^29.7.0", "jest-message-util": "^29.7.0", "jest-util": "^29.7.0" } }, "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw=="], - "expo": ["expo@57.0.13", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "^57.0.15", "@expo/config": "~57.0.7", "@expo/config-plugins": "~57.0.8", "@expo/devtools": "~57.0.1", "@expo/dom-webview": "~57.0.1", "@expo/fingerprint": "^0.20.7", "@expo/local-build-cache-provider": "^57.0.6", "@expo/log-box": "^57.0.2", "@expo/metro": "~56.0.0", "@expo/metro-config": "~57.0.8", "@ungap/structured-clone": "^1.3.0", "babel-preset-expo": "~57.0.7", "expo-asset": "~57.0.11", "expo-constants": "~57.0.11", "expo-file-system": "~57.0.3", "expo-font": "~57.0.1", "expo-keep-awake": "~57.0.1", "expo-modules-autolinking": "~57.0.10", "expo-modules-core": "~57.0.11", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-minimum": "^0.1.2" }, "peerDependencies": { "@expo/metro-runtime": "*", "react": "*", "react-dom": "*", "react-native": "*", "react-native-web": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/metro-runtime", "react-dom", "react-native-web", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-oJnPSAcQYDIXTJowL9fm6SvAU5CU0P+u1WtWM9a/7uUmeCrkcVKoaGstwF+UY3GoM11S7FO4KKmRl1aU12CTKA=="], + "expo": ["expo@57.0.15", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "^57.0.17", "@expo/config": "~57.0.8", "@expo/config-plugins": "~57.0.8", "@expo/devtools": "~57.0.1", "@expo/dom-webview": "~57.0.1", "@expo/fingerprint": "^0.20.9", "@expo/local-build-cache-provider": "^57.0.7", "@expo/log-box": "^57.0.3", "@expo/metro": "~56.0.0", "@expo/metro-config": "~57.0.9", "@ungap/structured-clone": "^1.3.0", "babel-preset-expo": "~57.0.7", "expo-asset": "~57.0.13", "expo-constants": "~57.0.13", "expo-file-system": "~57.0.5", "expo-font": "~57.0.1", "expo-keep-awake": "~57.0.1", "expo-modules-autolinking": "~57.0.10", "expo-modules-core": "~57.0.12", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-minimum": "^0.1.2" }, "peerDependencies": { "@expo/metro-runtime": "*", "react": "*", "react-dom": "*", "react-native": "*", "react-native-web": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/metro-runtime", "react-dom", "react-native-web", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-9UooISw8S8Gxo9wpsPcGkyRlf2UzNr+F26LSU2+M8iaiZ1WAjPR0I75NKFX8ETbrSgthZ2lQHgy5IU2KE/mpBA=="], - "expo-asset": ["expo-asset@57.0.11", "", { "dependencies": { "@expo/image-utils": "^0.11.4", "expo-constants": "~57.0.11" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-tDaExt9fOKeSc51mmZNqfejyBt9argzo14XP9OmKEdAk2E/mWKJnUNj6rfUzHC5MhG120xuZC/d1ncqq0aC7Pg=="], + "expo-asset": ["expo-asset@57.0.13", "", { "dependencies": { "@expo/image-utils": "^0.11.4", "expo-constants": "~57.0.13" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-RPjMcmPXRMb6UbQdTIkmSDEnQL5LKGTu7ZXatq3U67V6ldlSdQeQ9pQV7zlmk0DrbnaMEh3HYiEh2YxWLNyCzA=="], "expo-clipboard": ["expo-clipboard@57.0.1", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-HWICri4+1ao7S6QEfcorxVumXDiDnx1guGGewjZgGJWLGxFYs0RgH8ujBs+lkTzBkMmlwADaWSlaesR+nDJt5Q=="], - "expo-constants": ["expo-constants@57.0.11", "", { "dependencies": { "@expo/env": "~2.4.2" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-gpSZ13Nfx0BOc9ALjG1SMhks5csb8Z6ncEVdhDgv0NRrmJcHPRvyUlWaKjRjzwW730XrQ6PIXFRcnNmAxOLj5A=="], + "expo-constants": ["expo-constants@57.0.13", "", { "dependencies": { "@expo/env": "~2.4.2" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-eB5AHp7kKxsVIBjTetUgj5WQSw8joI2ekzgTlcUv+Hc0x2t0jZU6IiL4DpyOT2yZQ71n0WJZCkmOKLgxlajIzg=="], "expo-crypto": ["expo-crypto@57.0.1", "", { "peerDependencies": { "expo": "*" } }, "sha512-xwegXQw3ATgeL1ZuqbSNrGzOeG+zNeh6Z6DSJk825Qpa3TEQQ1kG3ioE1p3g/SNF373BAVz2iBKUTSytlIbBRA=="], - "expo-dev-client": ["expo-dev-client@57.0.12", "", { "dependencies": { "expo-dev-launcher": "~57.0.12", "expo-dev-menu": "~57.0.12", "expo-dev-menu-interface": "~57.0.0", "expo-manifests": "~57.0.1", "expo-updates-interface": "~57.0.1" }, "peerDependencies": { "expo": "*" } }, "sha512-KAVV7YyIEQNLB5452nm1BHa7ePthD+HytkEfZha6DILjWowhr0eQ9roUnUKMBMsXnfb4J5cErSzsV8zMTKAUcQ=="], + "expo-dev-client": ["expo-dev-client@57.0.14", "", { "dependencies": { "expo-dev-launcher": "~57.0.14", "expo-dev-menu": "~57.0.14", "expo-dev-menu-interface": "~57.0.0", "expo-manifests": "~57.0.1", "expo-updates-interface": "~57.0.1" }, "peerDependencies": { "expo": "*" } }, "sha512-0WEZJZtUZC0PgkZXm3BHWVYiOBM8hbkMP50Nk24X+K6k5+EWBmwmsSO/K4sojKyO1Pxhb/GHtSYaV8t1YI1x/w=="], - "expo-dev-launcher": ["expo-dev-launcher@57.0.12", "", { "dependencies": { "@expo/schema-utils": "^57.0.2", "expo-dev-menu": "~57.0.12", "expo-manifests": "~57.0.1" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-Au00VBTezkzdlwbwxb6pcWGDmF/QlA0kTAYZZY1JFi8A351FLBEv9kcVdgNU+xasr8qloaD3wWwS429eqA6lWA=="], + "expo-dev-launcher": ["expo-dev-launcher@57.0.14", "", { "dependencies": { "@expo/schema-utils": "^57.0.2", "expo-dev-menu": "~57.0.14", "expo-manifests": "~57.0.1" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-zb1Y6cBIhniBjTpihBHaWx0O81w3aWp5ddAw+ThpfCGrMVlYCdaBb2zlo1dZ1swJna7mn09eIID97U3pPAh83g=="], - "expo-dev-menu": ["expo-dev-menu@57.0.12", "", { "dependencies": { "expo-dev-menu-interface": "~57.0.0" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-ub513/edOV/QIPTxLU86+TynUNCIlOAMAUrhHy7hJAHRLCJWn2qVpOxnfcGZimSGk7lthpRAf67oyAK0VE2egA=="], + "expo-dev-menu": ["expo-dev-menu@57.0.14", "", { "dependencies": { "expo-dev-menu-interface": "~57.0.0" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-lTD5ErQrrH57v1HOM4RY2gA9hmvqXoZ/AArM7LQLCts3fKqaahOGg45ETRUgdvULv3K4wbKwhXwCRoANWMxGTw=="], "expo-dev-menu-interface": ["expo-dev-menu-interface@57.0.0", "", { "peerDependencies": { "expo": "*" } }, "sha512-F47VdzOHYc19FhI/jBgctpO8a5UskTIxG6a1E5t3W5gF8VImuvBQffdXXfLHhsuCl7dS3v3U0R45cleeVXO1Zg=="], "expo-device": ["expo-device@57.0.1", "", { "dependencies": { "ua-parser-js": "^0.7.33" }, "peerDependencies": { "expo": "*" } }, "sha512-jyEMDUticH+dhcL3GHa2aiifOvGXJsmb3oVT2R2q4i8bN7Bddy61+NkpMmuS2VAZrvoLQwf0TJJ/1vi1ukvutA=="], - "expo-file-system": ["expo-file-system@57.0.4", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-h8qDOxSW1SQfnZyvH0+HeOfXCr2X4v3x50+d19JuyQcjDR+JA3tng20TlQxIHazzLPPbwtSKA1Dj3+XIOpnoKg=="], + "expo-file-system": ["expo-file-system@57.0.5", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-XjGrCClF0935y5wLB9qNQQUVptNEy+0OloBstXlCd+IeNXLo3uNOod6cX4N0hofIhNIrN1Al8fwfay7R0Z1a2A=="], "expo-font": ["expo-font@57.0.1", "", { "dependencies": { "fontfaceobserver": "^2.1.0" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-QyS9L1Kh9sKJg4gfU6rdbpxpmH+DyzBX8z6jVvXMUDoqLr1GqmkO/Wu379KCXjL///kWbhpNlbi7AgBuj4VdIQ=="], @@ -1043,7 +1037,7 @@ "expo-image-loader": ["expo-image-loader@57.0.1", "", { "peerDependencies": { "expo": "*" } }, "sha512-uhrZKLT/cTl2mXyR28kPpVkS5O+PK9N1QA/07IFM4f5T4g0lTW1JHT3NEWwEEsGFldPmVX4j7LwUVVZxE+woug=="], - "expo-image-picker": ["expo-image-picker@57.0.10", "", { "dependencies": { "expo-image-loader": "~57.0.1" }, "peerDependencies": { "expo": "*" } }, "sha512-Zr00cd4RuUJlke8yN8/lKdl55UauoacF45j86zJa6oxJoe+wjlt9kkf0aGxQeoPW1JILT5Ikr3Os4+a9ROJYEw=="], + "expo-image-picker": ["expo-image-picker@57.0.12", "", { "dependencies": { "expo-image-loader": "~57.0.1" }, "peerDependencies": { "expo": "*" } }, "sha512-BjZLioItcDNrXwp46XZDZGDEUJ16/bK0QzxPjdNijiPYpLfQLeuFYoX9yH31sosnli0UL++x4ndYQoTMsICdlw=="], "expo-json-utils": ["expo-json-utils@57.0.1", "", {}, "sha512-cgTe1NqzQdYs/WN+3nIY5IZg8s0pb0xaTUbhYvxQDn137GbwRfHoGM2se3m3Vsl4Qu+B9G4RPEK5WJDEU2Do7g=="], @@ -1051,25 +1045,25 @@ "expo-linear-gradient": ["expo-linear-gradient@57.0.1", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-CpS8eMqoIWcHVGKV66zbDvzotCw9qYp3f8CuI9N+h1LaO0tMLUzBpkhAKePUsXlpN3yolYlHFSPkfVZ/uSh+iA=="], - "expo-linking": ["expo-linking@57.0.6", "", { "dependencies": { "expo-constants": "~57.0.11", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-NdKjEGk+ywwGRNvgQCq9KettM1eVHfR1+uLov+0ohb6rmmMEgnstfLcc3f0DKMQ0PnROsY5G5+ZkNeiairYRXA=="], + "expo-linking": ["expo-linking@57.0.7", "", { "dependencies": { "expo-constants": "~57.0.13", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-Ujn4kY0bd1MoJFLYuvIUWamlZH61pkahrUpug3hBtOeS89LDbPyKNjjmWef6+CPTGQfed2PlfuMZuPO1BCrg5w=="], - "expo-location": ["expo-location@57.0.10", "", { "dependencies": { "@expo/image-utils": "^0.11.4" }, "peerDependencies": { "expo": "*" } }, "sha512-E/NdVxmd2+lODFgMc8CC6L0Zl+w20L1VEwPBGdJXblGew6Sv70FA3NlVP73Hi/QWmjECvbYTjkKR7OnrVnmaLA=="], + "expo-location": ["expo-location@57.0.12", "", { "dependencies": { "@expo/image-utils": "^0.11.4" }, "peerDependencies": { "expo": "*" } }, "sha512-Fnh1dzIvZgc2mX7fXuXf6NxbEttZQLEnSXCbFHCLNtxyImUf/sURE93C9Jed+IfS/ozmtl84s/1nfz/cI87e9A=="], "expo-manifests": ["expo-manifests@57.0.1", "", { "dependencies": { "expo-json-utils": "~57.0.1" }, "peerDependencies": { "expo": "*" } }, "sha512-qB/mDG2dYdl+EvUeQuqP8KFYCFgFCQjJYdWIHo8SFBgDzMYmdF286DFY2M1M9Okr99wkb5M4tgA3aCcwv3aEQA=="], "expo-modules-autolinking": ["expo-modules-autolinking@57.0.10", "", { "dependencies": { "@expo/require-utils": "^57.0.4", "@expo/spawn-async": "^1.8.0", "chalk": "^4.1.0", "commander": "^7.2.0" }, "bin": { "expo-modules-autolinking": "bin/expo-modules-autolinking.js" } }, "sha512-jNqLswMx8QHN8VXRgud+xT+9q+J9U63CEGlx+k4V/IE9Qyt9HrKbWp+pIDma0fOquta5HBfSfsShcI+NkEpTiA=="], - "expo-modules-core": ["expo-modules-core@57.0.11", "", { "dependencies": { "@expo/expo-modules-macros-plugin": "0.6.1", "expo-modules-jsi": "~57.0.4", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*", "react-native-worklets": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0" }, "optionalPeers": ["react-native-worklets"] }, "sha512-gzRAI+vs0g9eObyQfGq1kp017flMeqZMzprqquCWxKg/AYdJXKmGXibJqMVFvRbUpluYBsW8U9P0inntKbzJOg=="], + "expo-modules-core": ["expo-modules-core@57.0.12", "", { "dependencies": { "@expo/expo-modules-macros-plugin": "0.6.1", "expo-modules-jsi": "~57.0.5", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*", "react-native-worklets": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0" }, "optionalPeers": ["react-native-worklets"] }, "sha512-hKqCdu8+78oNKWCgM4xSeblfmD/audgNVCn6uUCJuNBS/hc4DyC0Ia1X96SSZF9w9bGTLjNS8j2b7DshiC3WJA=="], - "expo-modules-jsi": ["expo-modules-jsi@57.0.4", "", { "peerDependencies": { "react-native": "*" } }, "sha512-vt7FyqUqqFXiRVnBqYD7y+GSPTgeua5Ocoy0+SYt+RSHkZEA2Fyop7If3g1TYDzQObYybPRo7TG2Rle1XLaWFw=="], + "expo-modules-jsi": ["expo-modules-jsi@57.0.5", "", { "peerDependencies": { "react-native": "*" } }, "sha512-NQF7MUF0j3rQHV8KJqETYA1SrJr3USvQ/AWEhODo+unMRFBDP9BKpn8+aNGGmx6fa2XLnqC2qulVw4DT6Gp13Q=="], - "expo-router": ["expo-router@57.0.13", "", { "dependencies": { "@expo/log-box": "^57.0.2", "@expo/metro-runtime": "^57.0.10", "@expo/schema-utils": "^57.0.2", "@expo/ui": "^57.0.11", "@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-tabs": "^1.1.12", "@react-native-masked-view/masked-view": "^0.3.2", "@testing-library/jest-dom": "^6.9.1", "@testing-library/user-event": "^14.6.1", "client-only": "^0.0.1", "color": "^4.2.3", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", "expo-glass-effect": "^57.0.1", "expo-server": "^57.0.3", "expo-symbols": "^57.0.2", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", "nanoid": "^3.3.8", "query-string": "^7.1.3", "react-fast-compare": "^3.2.2", "react-is": "^19.1.0", "react-native-drawer-layout": "^4.2.2", "react-native-screens": "^4.26.0", "server-only": "^0.0.1", "sf-symbols-typescript": "^2.1.0", "shallowequal": "^1.1.0", "standard-navigation": "^0.0.5", "vaul": "^1.1.2" }, "peerDependencies": { "@testing-library/react-native": ">= 13.2.0", "expo": "*", "expo-constants": "^57.0.11", "expo-linking": "^57.0.6", "react": "*", "react-dom": "*", "react-native": "*", "react-native-gesture-handler": "*", "react-native-reanimated": "*", "react-native-safe-area-context": ">= 5.4.0", "react-native-web": "*", "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4" }, "optionalPeers": ["@testing-library/react-native", "react-dom", "react-native-gesture-handler", "react-native-reanimated", "react-native-web", "react-server-dom-webpack"] }, "sha512-f0dgD1F2q2upYLum7Qo/kNjCJ2P5nqBTAUqWggCPSFLck+mNT72LRUH6R5OMgprjuIL3mc4pAscqTktfZHxa5w=="], + "expo-router": ["expo-router@57.0.15", "", { "dependencies": { "@expo/log-box": "^57.0.3", "@expo/metro-runtime": "^57.0.12", "@expo/schema-utils": "^57.0.2", "@expo/ui": "^57.0.12", "@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-tabs": "^1.1.12", "@react-native-masked-view/masked-view": "^0.3.2", "client-only": "^0.0.1", "color": "^4.2.3", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", "expo-glass-effect": "^57.0.1", "expo-server": "^57.0.3", "expo-symbols": "^57.0.2", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", "nanoid": "^3.3.8", "query-string": "^7.1.3", "react-fast-compare": "^3.2.2", "react-is": "^19.1.0", "react-native-drawer-layout": "^4.2.2", "react-native-screens": "^4.26.0", "server-only": "^0.0.1", "sf-symbols-typescript": "^2.1.0", "shallowequal": "^1.1.0", "standard-navigation": "^0.0.5", "vaul": "^1.1.2" }, "peerDependencies": { "@testing-library/react-native": ">= 13.2.0", "expo": "*", "expo-constants": "^57.0.13", "expo-linking": "^57.0.7", "react": "*", "react-dom": "*", "react-native": "*", "react-native-gesture-handler": "*", "react-native-reanimated": "*", "react-native-safe-area-context": ">= 5.4.0", "react-native-web": "*", "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4" }, "optionalPeers": ["@testing-library/react-native", "react-dom", "react-native-gesture-handler", "react-native-reanimated", "react-native-web", "react-server-dom-webpack"] }, "sha512-vwr2HL2U7hqv3QTkuz0e8hQc5hkgpXztisy30VwhdXJVDPdP0/m8wSiYUm6GKyZAbcXfD4fn44ZYcJsSESY6cA=="], "expo-secure-store": ["expo-secure-store@57.0.1", "", { "peerDependencies": { "expo": "*" } }, "sha512-tLa1VmSadOq19mA/dwkl99RbHyjLE0T1qqBYMY3/OsguZTI+rlrDy/DDJjupqlVtmr95hD7o1pYqx5aL+B4YMA=="], "expo-server": ["expo-server@57.0.3", "", {}, "sha512-aK+LdKzauHSGmsOStZtyxdzv0zWssCkxTw3m4QuOhfDSJsZaMRTd9O41d8ixU/QfELTbaJ0oRNcF7JFV/7O9YQ=="], - "expo-splash-screen": ["expo-splash-screen@57.0.6", "", { "dependencies": { "@expo/config-plugins": "~57.0.7", "@expo/image-utils": "^0.11.4", "xml2js": "0.6.0" }, "peerDependencies": { "expo": "*" } }, "sha512-FY0E7hMyXVAsNh18yGzIjdooPXdjafalEb6mk2EcqNPjXspHuu+pVEhUscEunw4wF8F/w6MOpT7UfOwHVWez9g=="], + "expo-splash-screen": ["expo-splash-screen@57.0.7", "", { "dependencies": { "@expo/config-plugins": "~57.0.8", "@expo/image-utils": "^0.11.4", "xml2js": "0.6.0" }, "peerDependencies": { "expo": "*" } }, "sha512-QxqfjOCTnTGnqK2BxfEtxUJOcnsJbUXO873Q342r3VkgHAG877eozsNzgYWQXcCFj/asMwx2uy9OXxBShxc5rQ=="], "expo-sqlite": ["expo-sqlite@57.0.1", "", { "dependencies": { "await-lock": "^2.2.2" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-I6KoUvfGIiROTKxr5D3H+jRIGA/iEvWEtqHK4XMukAA7tVTinz/YdS8zOz6/DdG6vgrNmvF7gyOcbhLinlfxzQ=="], @@ -1221,8 +1215,6 @@ "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], - "idb": ["idb@8.0.3", "", {}, "sha512-LtwtVyVYO5BqRvcsKuB2iUMnHwPVByPCXFXOpuU96IZPPoPN6xjOGxZQ74pgSVVLQWtUOYgyeL4GE98BY5D3wg=="], - "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], @@ -1291,6 +1283,8 @@ "is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="], + "is-plain-obj": ["is-plain-obj@2.1.0", "", {}, "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA=="], + "is-potential-custom-element-name": ["is-potential-custom-element-name@1.0.1", "", {}, "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="], "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], @@ -1473,8 +1467,6 @@ "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], - "lz-string": ["lz-string@1.5.0", "", { "bin": "bin/bin.js" }, "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ=="], - "make-dir": ["make-dir@4.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw=="], "make-error": ["make-error@1.3.6", "", {}, "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="], @@ -1491,6 +1483,8 @@ "memoize-one": ["memoize-one@5.2.1", "", {}, "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="], + "merge-options": ["merge-options@3.0.4", "", { "dependencies": { "is-plain-obj": "^2.1.0" } }, "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ=="], + "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], "metro": ["metro@0.84.4", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/core": "^7.25.2", "@babel/generator": "^7.29.1", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "accepts": "^2.0.0", "ci-info": "^2.0.0", "connect": "^3.6.5", "debug": "^4.4.0", "error-stack-parser": "^2.0.6", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "hermes-parser": "0.35.0", "image-size": "^1.0.2", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", "metro-babel-transformer": "0.84.4", "metro-cache": "0.84.4", "metro-cache-key": "0.84.4", "metro-config": "0.84.4", "metro-core": "0.84.4", "metro-file-map": "0.84.4", "metro-resolver": "0.84.4", "metro-runtime": "0.84.4", "metro-source-map": "0.84.4", "metro-symbolicate": "0.84.4", "metro-transform-plugins": "0.84.4", "metro-transform-worker": "0.84.4", "mime-types": "^3.0.1", "nullthrows": "^1.1.1", "serialize-error": "^2.1.0", "source-map": "^0.5.6", "throat": "^5.0.0", "ws": "^7.5.10", "yargs": "^17.6.2" }, "bin": "src/cli.js" }, "sha512-8ETTubqfD6ornDy2zYDvRcKnVDOXdFJsjetYDBsY4oAsb6NJkiwFR+FaMESyGppFmQUyBQA4H4sFGxzcQSGtFA=="], @@ -1733,6 +1727,8 @@ "react-native-is-edge-to-edge": ["react-native-is-edge-to-edge@1.3.1", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-NIXU/iT5+ORyCc7p0z2nnlkouYKX425vuU1OEm6bMMtWWR9yvb+Xg5AZmImTKoF9abxCPqrKC3rOZsKzUYgYZA=="], + "react-native-purchases": ["react-native-purchases@10.7.2", "", { "dependencies": { "@revenuecat/purchases-js-hybrid-mappings": "18.31.0", "@revenuecat/purchases-typescript-internal": "18.31.0" }, "peerDependencies": { "react": ">= 16.6.3", "react-native": ">= 0.73.0", "react-native-web": "*" }, "optionalPeers": ["react-native-web"] }, "sha512-pI2Vh1oUtjjggYCd8P6u4Rl8Hck/lNhx6exxeoZYCGEeu7VQgGxzRDYTJ5f+96g057G6FcZ0bfMyD4VBxxQsuA=="], + "react-native-reanimated": ["react-native-reanimated@4.5.1", "", { "dependencies": { "react-native-is-edge-to-edge": "^1.3.1", "semver": "^7.7.3" }, "peerDependencies": { "react": "*", "react-native": "0.83 - 0.86", "react-native-worklets": "0.10.x" } }, "sha512-RnMvtDuR+68ig864gAvZCOdZehqhC5rFmMo0kn+ARfgVSTvFeF6IFLBVgMPUu0KwihaapEyW24WRi6nEyy1kSA=="], "react-native-safe-area-context": ["react-native-safe-area-context@5.7.0", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-/9/MtQz8ODphjsLdZ+GZAIcC/RtoqW9EeShf7Uvnfgm/pzYrJ75y3PV/J1wuAV1T5Dye5ygq4EAW20RoBq0ABQ=="], @@ -2153,8 +2149,6 @@ "@expo/cli/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@expo/config/@expo/config-plugins": ["@expo/config-plugins@57.0.7", "", { "dependencies": { "@expo/config-types": "^57.0.2", "@expo/json-file": "~11.0.1", "@expo/plist": "^0.8.1", "@expo/require-utils": "^57.0.4", "@expo/sdk-runtime-versions": "^1.0.0", "chalk": "^4.1.2", "debug": "^4.3.5", "getenv": "^2.0.0", "glob": "^13.0.0", "semver": "^7.5.4", "slugify": "^1.6.6", "xcode": "^3.0.1", "xml2js": "0.6.0" } }, "sha512-jvXMiNuH8W7fmU9yCk4/jVwDX2G/5rWUg5PZ22mriccEeQVS9HJjQiUHivMaK6MxEG5L9f0RPScxe/nQfnpQvg=="], - "@expo/devcert/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], "@expo/fingerprint/minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="], @@ -2163,6 +2157,8 @@ "@expo/metro-config/picomatch": ["picomatch@4.0.5", "", {}, "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A=="], + "@expo/metro-runtime/@expo/log-box": ["@expo/log-box@57.0.2", "", { "dependencies": { "@expo/dom-webview": "^57.0.1", "anser": "^1.4.9", "stacktrace-parser": "^0.1.10" }, "peerDependencies": { "@expo/dom-webview": "^57.0.1", "expo": "*", "react": "*", "react-native": "*" } }, "sha512-ZsFyfIR7YCbQAdVLzuTUmMHofZC7ZS9ywYCJNPlLc78x59cI8GwXFEIVbRjjC0uJERpNtXx/tsNNnkhexXlzMw=="], + "@expo/metro-runtime/pretty-format": ["pretty-format@29.7.0", "", { "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } }, "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ=="], "@expo/plist/xmlbuilder": ["xmlbuilder@15.1.1", "", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="], @@ -2201,10 +2197,6 @@ "@scure/bip39/@scure/base": ["@scure/base@2.0.0", "", {}, "sha512-3E1kpuZginKkek01ovG8krQ0Z44E3DHPjc5S2rjJw9lZn3KSQOs8S7wqikF/AH7iRanHypj85uGyxk0XAyC37w=="], - "@testing-library/dom/dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="], - - "@testing-library/dom/pretty-format": ["pretty-format@27.5.1", "", { "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" } }, "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ=="], - "@types/jest/pretty-format": ["pretty-format@29.7.0", "", { "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } }, "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ=="], "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.6", "", {}, "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw=="], @@ -2249,7 +2241,7 @@ "expo-modules-autolinking/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], - "expo-splash-screen/@expo/config-plugins": ["@expo/config-plugins@57.0.7", "", { "dependencies": { "@expo/config-types": "^57.0.2", "@expo/json-file": "~11.0.1", "@expo/plist": "^0.8.1", "@expo/require-utils": "^57.0.4", "@expo/sdk-runtime-versions": "^1.0.0", "chalk": "^4.1.2", "debug": "^4.3.5", "getenv": "^2.0.0", "glob": "^13.0.0", "semver": "^7.5.4", "slugify": "^1.6.6", "xcode": "^3.0.1", "xml2js": "0.6.0" } }, "sha512-jvXMiNuH8W7fmU9yCk4/jVwDX2G/5rWUg5PZ22mriccEeQVS9HJjQiUHivMaK6MxEG5L9f0RPScxe/nQfnpQvg=="], + "expo-router/@expo/metro-runtime": ["@expo/metro-runtime@57.0.12", "", { "dependencies": { "@expo/log-box": "^57.0.3", "anser": "^1.4.9", "pretty-format": "^29.7.0", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0" }, "peerDependencies": { "expo": "*", "react": "*", "react-dom": "*", "react-native": "*" }, "optionalPeers": ["react-dom"] }, "sha512-WpgjfRFh88B5tKJrbsypvyxx0MKuXMo+ru9Gbjq4Qwj7OboJmrQ+g555YCgiQD3uk3J1ThzgEU06yZOV43suGA=="], "fbjs/promise": ["promise@7.3.1", "", { "dependencies": { "asap": "~2.0.3" } }, "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg=="], @@ -2427,8 +2419,6 @@ "@react-native/metro-babel-transformer/hermes-parser/hermes-estree": ["hermes-estree@0.36.0", "", {}, "sha512-A1+8zn5oss2CFP7pKsOaxorQG6FNIz1WU1VDqruLPPZl3LVgeE2C5xfFg8Ow6/Ow4mSslLLtYP1J3n38eKyW9w=="], - "@testing-library/dom/pretty-format/react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="], - "@types/jest/pretty-format/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="], "@types/jest/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], @@ -2445,6 +2435,8 @@ "expect/jest-matcher-utils/pretty-format": ["pretty-format@29.7.0", "", { "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } }, "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ=="], + "expo-router/@expo/metro-runtime/pretty-format": ["pretty-format@29.7.0", "", { "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } }, "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ=="], + "expo/pretty-format/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="], "expo/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], @@ -2547,6 +2539,10 @@ "expect/jest-matcher-utils/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + "expo-router/@expo/metro-runtime/pretty-format/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="], + + "expo-router/@expo/metro-runtime/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + "expo/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.12", "", {}, "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g=="], "glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], @@ -2581,6 +2577,8 @@ "expect/jest-matcher-utils/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.12", "", {}, "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g=="], + "expo-router/@expo/metro-runtime/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.12", "", {}, "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g=="], + "log-symbols/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], "ora/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], diff --git a/devpost-submission.md b/devpost-submission.md new file mode 100644 index 0000000..6470e30 --- /dev/null +++ b/devpost-submission.md @@ -0,0 +1,206 @@ +# OpenDating — RevenueCat Shipaton 2026 + +Status: draft only. The public project page is published, but OpenDating has not +been entered into Shipaton judging. + +The live web build is the same Expo application and is the public demo. It does +not replace the native Store URL for a standard Shipaton entry: Shipaton states +that web apps and TestFlight builds are not eligible. The only no-Store path is +the Next Gen Award for an eligible student using a verifiable academic email, +public repository, and demo video. + +## Project details + +- Project: OpenDating +- Tagline: Deliberate private introductions on an open protocol. +- Devpost draft: https://devpost.com/software/opendating +- Live web preview: https://opendating-mobile.expo.app +- Source: https://github.com/jongan69/opendating-mobile +- Platform: iOS (iPhone and iPad) +- Built with: Expo, React Native, TypeScript, RevenueCat, Nostr, Cloudflare Workers, Cloudflare Workers AI + +## Description + +### Inspiration + +Dating apps often ask people to trade privacy for participation: a phone number, +precise location, readable conversations, and an engagement-optimized swipe +feed. OpenDating explores a smaller, calmer model where members own their +identity and understand each disclosure before making a choice. + +### What it does + +OpenDating presents one deliberate introduction at a time. Each introduction +explains the visible compatibility facts behind it and includes a privacy +receipt showing what is shared, withheld, and unlocked only after mutual +interest. Interest is private, and a conversation opens only after both people +choose each other. + +Members create a self-owned account without email, phone number, or social +login. Exact GPS is reduced on-device to an approximate 5 km area before +discovery. Matched conversations use end-to-end encryption. The app also +includes blocking, private reporting, visibility controls, recovery-key backup, +and permanent account deletion. + +OpenDating Plus is an optional $4.99 lifetime purchase powered by RevenueCat. +It unlocks Sage, Ocean, and Plum accent themes. It never changes discovery, +ranking, matching, messaging, recovery, deletion, or safety. + +### How we built it + +The client uses Expo Router, React Native, and strict TypeScript. Nostr provides +the identity and cryptographic building blocks, while the OpenDating protocol +defines profiles, discovery, private choices, matches, moderation, and encrypted +messages. A Cloudflare Worker operates the relay and media services. RevenueCat +validates the lifetime Plus entitlement using an opaque billing identifier; +profile, location, recovery-key, safety, and message content is not sent to +RevenueCat. + +The browser build uses an encrypted local identity vault so the real app can be +tested without a native install. The private recovery key is encrypted with +AES-256-GCM using a PBKDF2-derived browser-lock key and is never persisted in +plaintext. + +### Challenges + +The hardest boundary was making a decentralized identity understandable and +recoverable without turning the recovery key into a normal password. We also +had to keep coarse location, encrypted messaging, moderation, browser storage, +and StoreKit entitlement state explicit across degraded-network and locked +states. + +Apple declined the first iOS candidate under Guideline 4.3(b). We replaced the +swipe-first experience with deliberate private introductions, privacy receipts, +and a Privacy Passport before preparing a fresh release. + +### Accomplishments + +- One explained introduction instead of an endless swipe feed +- A live Privacy Passport for identity, visibility, and disclosure boundaries +- Coarse-location discovery without transmitting raw GPS +- Match-only end-to-end encrypted conversations +- Operational report, block, unmatch, feedback, and deletion paths +- A browser app with an encrypted recovery-key vault +- A non-consumable Plus product that sells customization, not dating outcomes + +### What we learned + +Privacy works better as an interaction than as a policy page. Showing a privacy +receipt at the moment of an introduction makes the boundary understandable. +Likewise, a portable identity needs visible backup, lock, and deletion controls +to feel trustworthy rather than merely decentralized. + +### How we used AI + +Cloudflare Workers AI screens only profile display names and bios for obvious +safety-policy violations before publication. It does not process photos, +location, recovery keys, likes, matches, reports, or encrypted messages. Codex +was used to inspect the repository, implement and review changes, run tests, +and verify deployment and release artifacts. + +### What's next + +Wait for App Review of iOS 0.1.1 (5), complete the App Store metadata for the +lifetime purchase, run purchase and restore on a physical iOS device, and add +the resulting Store URL, promo code, screenshot, and public demo video to the +Shipaton entry. Federation and independent service providers remain +post-hackathon work. + +## Testing instructions + +1. Open https://opendating-mobile.expo.app in a modern HTTPS browser. +2. Create a browser account with a 12-character-or-longer browser-lock + passphrase, or import a disposable Nostr `nsec`/hex recovery key. +3. Complete onboarding, then verify Privacy Passport, introductions, profile, + visibility, blocking/reporting, matches, browser lock, and recovery-key + export/import. +4. Reload the page and verify the encrypted identity locks before reconnecting. +5. On iOS, use App Store build 0.1.1 (5) and verify the lifetime Plus purchase, + restore, and entitlement removal with a disposable StoreKit account. + +Do not use a personal recovery key or include private keys, exact location, or +message content in screenshots or bug reports. + +## Public demo and repository + +- Live app: https://opendating-mobile.expo.app +- Source: https://github.com/jongan69/opendating-mobile +- Demo video: pending a public YouTube or Vimeo upload, two minutes or less + +## Demo video outline + +- 0:00–0:15 — problem and OpenDating's private-introduction model +- 0:15–0:45 — create/import account and coarse-location boundary +- 0:45–1:15 — Privacy Passport, introduction reasons, and privacy receipt +- 1:15–1:35 — mutual match, encrypted messaging, report/block controls +- 1:35–1:50 — $4.99 lifetime Plus themes and RevenueCat restore +- 1:50–2:00 — live web app, open protocol, and closing result + +## Screenshot shot list + +- Published gallery: six live-web screenshots at exactly 1179 × 2556, without + device frames or user data: + - `screenshots/devpost/01-welcome-1179x2556.png` + - `screenshots/devpost/02-browser-lock-1179x2556.png` + - `screenshots/devpost/03-create-account-1179x2556.png` + - `screenshots/devpost/04-import-recovery-key-1179x2556.png` + - `screenshots/devpost/05-privacy-boundaries-1179x2556.png` + - `screenshots/devpost/06-terms-1179x2556.png` +- Pending IAP review capture: Plus lifetime-purchase screen + +## Known limitations + +- The public web app is a functional preview, but standard Shipaton eligibility + requires the fully published native Store listing. +- OpenDating Plus remains unavailable until Apple accepts its missing review + metadata and the purchase is proven on a physical device. +- The relay and protocol are an early public implementation without federation + or a production availability SLA. + +## Shipaton submission fields + +- Includes App Icon (27378): `BrandAssetPack/icons/ios-app-icon-1024.png` is + already the project thumbnail; confirm the checkbox during final review +- Includes screenshot (27379): six exact-size screenshots uploaded and verified + in the public Devpost gallery +- First Version Date Confirmation (27380): answer only after the revised build is published +- Is Staff or Sponsor (27381): false +- App type (27382): iOS (iPhone and/or iPad) +- Published App Store URL (27383): pending +- RevenueCat project ID (28118): `proj3363ecdc` +- Promo code (28135): pending App Store promo-code creation +- HAMM Award (27388): OpenDating uses one transparent lifetime purchase for + cosmetic themes. A non-consumable purchase fits a privacy-first utility better + than recurring access fees or advertising, and core dating and safety features + remain free. +- Peace Prize (27389): OpenDating minimizes sensitive data collection, keeps + choices private until mutual, encrypts matched conversations, and gives members + direct visibility, recovery, reporting, blocking, and deletion controls. +- Design Award (27391): The app replaces swipe mechanics with one deliberate + introduction, visible compatibility reasons, a privacy receipt, and a Privacy + Passport. The interface uses calm platform-aware surfaces and accessible + light, dark, and accent themes. +- Additional notes (27392): The public web preview demonstrates the application + flow, but the standard Shipaton entry will use the published iOS Store URL and + a physical-device demo video. + +## Required completion evidence + +- [x] Description drafted +- [x] 1024 × 1024 icon exists +- [x] Devpost project, write-up, links, and app icon published +- [x] Production web preview deployed +- [x] Cloudflare Worker responds in production +- [x] App Store non-consumable created +- [x] RevenueCat project, entitlement, offering, and product connected +- [x] Fresh iOS 0.1.1 build 5 uploaded and valid in App Store Connect +- [x] Build 5 attached to App Store version 0.1.1 and internal TestFlight QA +- [ ] Purchase, restore, and entitlement verified on a physical iOS device +- [x] Six 1179 × 2556 screenshots captured without device frames or user data +- [x] Six-image gallery uploaded and verified on the public Devpost project +- [ ] Public YouTube or Vimeo demo, two minutes or less +- [x] Revised iOS 0.1.1 build 5 submitted and waiting for App Review +- [ ] Revised app fully published on the App Store +- [ ] App Store promo code created for judges +- [x] Devpost project update confirmed by Jonathan +- [ ] Final Devpost submission explicitly confirmed by Jonathan diff --git a/docs/APP-REVIEW-NOTES.md b/docs/APP-REVIEW-NOTES.md index fb67574..af5166b 100644 --- a/docs/APP-REVIEW-NOTES.md +++ b/docs/APP-REVIEW-NOTES.md @@ -4,7 +4,7 @@ Copy the **Reviewer Notes** block at the bottom into the Notes field of the App Review Information section in App Store Connect. The rest of this document is the working source for that block. -**Last updated:** 2026-08-09 · **App version:** 0.1.1 +**Last updated:** 2026-08-29 · **App version:** 0.1.1 --- @@ -17,8 +17,9 @@ beginning with app launch, showing the typical user flow. Must include account registration, login, and deletion; user-generated content with reporting and blocking; and every permission prompt. -There is no paid content, purchase, or subscription flow in this app, so that -section does not apply. Say so explicitly in the reply rather than omitting it. +Show the optional one-time OpenDating Plus purchase, selecting a custom accent, +and Restore Purchases. The recording must use an Apple sandbox account and must +not show credentials or payment details. ## 2. Devices and operating systems tested @@ -100,12 +101,12 @@ review region. |---|---|---| | OpenDating relay (Cloudflare Workers) | Sole backend. Profile storage, discovery matching, match/like routing, encrypted message transport, reports, blocks, account deletion. | Operated by the developer at `wss://opendating-relay.jonathang132298.workers.dev`. Service endpoints are discovered at runtime from the relay's public service document. | | Cloudflare Workers AI | Automated safety screening for profile display names and bios before publication. | The developer-operated relay sends this profile text to Cloudflare's `@cf/meta/llama-3.2-3b-instruct` model. Photos are not sent, and it does not process encrypted messages. Disclosed in-app on the onboarding privacy screen and at Settings → Privacy. | +| RevenueCat | Optional one-time OpenDating Plus purchase and entitlement status. | Receives an opaque, domain-separated billing identifier and Apple purchase/entitlement data. It does not receive profile text, photos, location, recovery keys, likes, matches, reports, or messages. | | Expo Application Services (EAS) | Build and submission tooling only. | Build-time only. Not contacted by the shipped app at runtime. | -**Not used:** no payment processor, no in-app purchases or subscriptions, no -advertising SDK, no third-party analytics or crash reporting, no third-party -authentication provider, no data broker, and no App Tracking Transparency -prompt (the app does not track). +**Not used:** no subscriptions, advertising SDK, third-party analytics or crash +reporting, third-party authentication provider, data broker, or App Tracking +Transparency prompt (the app does not track). The app's privacy manifest declares `NSPrivacyTracking: false` with no tracking domains. @@ -113,8 +114,8 @@ domains. ## 6. Regional differences **The app functions identically in all regions.** There is no region-locked -content, no country-specific feature gating, no regional pricing (the app is -free everywhere), and no geographic availability restriction in the app itself. +content or country-specific feature gating. The app is free; Apple localizes the +optional one-time Plus price by storefront. A country code derived from the user's coarse location is used only to scope discovery to a sensible area. It does not enable or disable features. @@ -135,7 +136,7 @@ enforced at a minimum of 18, and the App Store age rating is set to 17+. **User-generated content controls,** as required by Guideline 1.2: - Terms of Service and Community Standards are shown during onboarding and at Settings → Terms. Profile creation is disabled until the member explicitly - accepts the August 9, 2026 policy version; version and acceptance time are + accepts the August 29, 2026 policy version; version and acceptance time are recorded locally for the account. - Any profile can be reported from the profile screen or from a chat. - Any user can be blocked; blocks take effect immediately on-device and are @@ -154,8 +155,8 @@ SCREEN RECORDING A physical-device recording on the latest iPadOS is attached to the App Review reply. It begins with app launch and shows account access and registration, policy consent, permission prompts, discovery, reporting, blocking, matching, -encrypted messaging, and account deletion. There are no purchases or -subscriptions to demonstrate. +encrypted messaging, the one-time Plus purchase and restore flow, and account +deletion. DEVICES TESTED - Samsung SM-A166U1, Android 16: physical-device onboarding and discovery. @@ -204,7 +205,10 @@ PERMISSIONS AND PURCHASES for nearby discovery; exact GPS is not transmitted. - Photo library: adds profile photos. - No App Tracking Transparency prompt; the app does not track. -The app is free with no paid content, purchase, or subscription. +- OpenDating Plus is an optional $4.99 one-time purchase that unlocks Sage, + Ocean, and Plum app accents. It does not affect discovery, ranking, matching, + messaging, recovery, deletion, or safety. Restore Purchases is available on + the same screen. There is no subscription. EXTERNAL SERVICES - Developer-operated OpenDating relay on Cloudflare Workers: profile storage, @@ -214,14 +218,17 @@ EXTERNAL SERVICES of profile display names and bios before publication. Photos are not sent to it and it does not process encrypted messages. This is disclosed to the user in-app on the onboarding privacy screen and at Settings -> Privacy. +- RevenueCat: validates the optional lifetime Plus entitlement using an opaque + billing identifier. It does not receive profile, location, key, safety, or + message content. - Expo Application Services: build and submission tooling only; not contacted by the shipped app at runtime. -No payment processor, advertising network, analytics provider, data broker, or -third-party authentication service is used. +No advertising network, analytics provider, data broker, or third-party +authentication service is used. REGIONS The app behaves consistently across all regions. There is no region-locked -content, feature gating, regional pricing, or in-app availability restriction. +content or feature gating. Apple localizes the optional one-time Plus price. REGULATED SERVICES AND THIRD-PARTY MATERIAL OpenDating is a dating/social-networking app, not a financial, medical, legal, diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index d221e0e..bd85004 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -1,10 +1,20 @@ # OpenDating Mobile Handoff -Last reviewed: August 9, 2026. +Last reviewed: August 29, 2026. ## Handoff status -The repository is ready for another engineer to clone, test, and continue. Release 0.1.1 is approved for iOS and Android launch in `release/manifest.json`. The broader technical, operational, legal, and marketplace gates in `ROADMAP-1.0.md` remain the path toward 1.0. +The repository is ready for another engineer to clone, test, and continue. +Release 0.1.1 is **not approved for launch**: `release/manifest.json` is blocked, +Apple rejected the previous submission under Guideline 4.3(b), and the next +candidate still needs external and physical-device evidence. + +`main` remains the production branch. `dev` contains the production web app and +the one-time Plus implementation. EAS production build 0.1.1 (5) enables the +RevenueCat public SDK configuration and is attached to the editable App Store +version. App Review submission `278e4366-f6a6-4f02-a7a7-2fcce7980f42` is +waiting for review, but the repository does not approve release until +`docs/MONETIZATION.md` and the physical-device gates are satisfied. The source of truth for current readiness is: @@ -26,12 +36,12 @@ Historical documents with `COMPLETE` in their filenames describe the v0.1 featur ```bash cp .env.example .env -npm ci -npm run typecheck -npm run lint -npm test -npm run security:audit -npm run release:validate +bun install --frozen-lockfile +bun run typecheck +bun run lint +bun run test +bun run security:audit +bun run release:validate ``` Expo SDK 57 APIs must be checked against the versioned Expo documentation. Protocol calls must be checked against the installed package declarations in `node_modules/opendating-protocol/dist/index.d.ts`. @@ -45,22 +55,29 @@ Do not put credential values in issues, documentation, chat, or Git. | GitHub | Admin or maintainer on both repositories | `main` is protected; staging and reviewer-gated production environments exist | | npm | Publish rights for `opendating-protocol` | Current session is unauthenticated; registry remains `0.1.0` | | Expo/EAS | Project owner or developer | Production builds remain release-manifest gated | -| Apple | App Store Connect access | Ship a fresh 0.1.1 build; 0.1.0 build 4 is superseded | +| Apple | App Store Connect access | 0.1.1 build 5 is waiting for App Review and is in the internal `OpenDating QA` TestFlight group; physical proof and replacement media remain | | Google | Play Console and service account | Ship a fresh 0.1.1 bundle; 0.1.0 version code 3 is superseded | | Cloudflare | Read access for integration diagnosis | Resource ownership and deployments belong to the backend repository | -| Future vendors | Persona, Hive, RevenueCat, Sentry, moderation provider | Not approved or active for production data | +| RevenueCat | Project `proj3363ecdc` | Catalog and public SDK key are active for build 5; Apple credentials and native transaction proof remain | +| Future vendors | Persona, Hive, Sentry, moderation provider | Not approved or active for production data | ## Known dependency state -The mobile lockfile currently contains two high `image-size` advisories without patched releases and one medium `uuid` advisory through Expo/Metro/Xcode build tooling. `security/audit-exceptions.json` binds exceptions to exact advisories, affected ranges, owners, and a September 30, 2026 expiry. They must be removed or explicitly renewed with evidence before expiry. +`security/audit-exceptions.json` is the only allowed dependency exception +source. The audit fails when Bun reports a new high/critical advisory, when the +documented advisory set changes, or when the exception expires. Do not expand +the exception merely to make CI green; first update the Expo-compatible +dependency set and inspect the remaining paths. ## Immediate continuation order -1. Authenticate npm, publish and verify `opendating-protocol@0.1.1`, then pin the exact artifact here. -2. Record App Store withdrawal and Android hold evidence. -3. Begin Phase 1 with the native signer boundary and SQLCipher repositories; these precede public acquisition. -4. Implement deterministic sync/outbox/global blocks, then push and verification. -5. Do not start public beta until the trust-and-safety, legal, vendor, deletion, security, and staffing gates are evidenced. +1. Keep `dev` clean and run the Bun quality gates above before new work. +2. Authenticate npm, publish and verify `opendating-protocol@0.1.1`, then pin the exact artifact here and remove the temporary request-routing mirror. +3. Resolve the dependency audit without broad or permanent exceptions. +4. Install TestFlight build 5 on a physical iOS device and verify purchase, restore, revocation, identity changes, reinstall, offline behavior, and the complete critical walkthrough. +5. Capture fresh Passport/private-introduction screenshots, the Plus review screenshot, and the App Review video from that verified build. +6. Monitor App Review submission `278e4366-f6a6-4f02-a7a7-2fcce7980f42`; respond truthfully with the prepared 4.3(b) evidence if Apple requests clarification. +7. Do not start public beta until the trust-and-safety, legal, vendor, deletion, security, and staffing gates are evidenced. ## Release handoff rule diff --git a/docs/MONETIZATION.md b/docs/MONETIZATION.md new file mode 100644 index 0000000..7c9608d --- /dev/null +++ b/docs/MONETIZATION.md @@ -0,0 +1,47 @@ +# OpenDating monetization contract + +**Status:** implementation and catalogs are connected in production candidate +0.1.1 (5). The feature remains a blocked release candidate until the +purchase/restore flow passes on a physical iOS device. + +OpenDating Plus may sell customization and convenience. It must never sell +ranking, boosts, hidden admirers, safety, verification, recovery, deletion, +matching, reactions, discovery, filters, or messaging. + +## RevenueCat catalog + +- Project: `proj3363ecdc` +- iOS app: `app8aaadf2571` +- Entitlement: `plus` +- Offering: `default` +- Product: `opendating_plus_lifetime` (non-consumable) +- App Store Connect product ID: `6806640623` +- App Store Connect version ID: `c62d972a-949a-4148-822a-6ae49f98dbe9` +- Package: `$rc_lifetime` +- Price: $4.99 in the US, with store-localized pricing elsewhere +- Benefit: Sage, Ocean, and Plum app accent themes +- EAS build: `cf5d4b22-f7aa-430b-980f-f4b191718612` +- App Store Connect build: `12dd3ff2-f9bd-491a-984f-b14aafd02ef8` (0.1.1 build 5, valid) + +Prices are never hardcoded in the app. The paywall renders the localized store +price delivered by RevenueCat. + +## Privacy and release gates + +The SDK derives a stable SHA-256 billing identifier from a domain-separated +value. A raw Nostr public key is never sent to RevenueCat or logged. + +The purchase screen is fail closed and requires both +`EXPO_PUBLIC_REVENUECAT_ENABLED=true` and +`EXPO_PUBLIC_OPENDATING_PLUS_FEATURES_READY=true`. The paid entitlement changes +only local accent colors. It never changes discovery, ranking, matching, +messaging, recovery, deletion, or safety behavior. + +Before enabling, validate the store product, map the entitlement and lifetime +package in RevenueCat, then exercise purchase, refund/revocation, restore, +identity import, identity deletion, offline access, and app-reinstall paths in +a native build. + +The client fails closed unless RevenueCat reports `VERIFIED` or +`VERIFIED_ON_DEVICE` for the entitlement. App Privacy and the public +subprocessor list must be updated before either feature gate becomes true. diff --git a/docs/RELEASE-STATUS.md b/docs/RELEASE-STATUS.md index 8fe7e95..fe0f759 100644 --- a/docs/RELEASE-STATUS.md +++ b/docs/RELEASE-STATUS.md @@ -2,6 +2,20 @@ **Status: proposed launch candidate.** OpenDating Mobile 0.1.1 is a proposed iOS App Store and Google Play release. Launch approval is not effective until Phase 0 release-containment gates pass and `release/manifest.json` records the reviewed source SHA, artifact IDs, build numbers, and checksums. +Apple rejected the previous submission under Guideline 4.3(b). Fresh production +build 0.1.1 (5), built from `c505b83a11b986bb29879c178327460f187ec370`, +is valid in App Store Connect and attached to the editable 0.1.1 version. It is +waiting for App Review in submission +`278e4366-f6a6-4f02-a7a7-2fcce7980f42`, submitted on August 29, 2026. +Replacement screenshots, physical-device recording, purchase/restore proof, +and the evidence in `docs/GUIDELINE-4.3B-RESPONSE.md` remain required before +the repository can record launch approval. + +The stale rejected review submission is canceled. `asc review doctor` reports +no public-API blocking checks; the IAP review image and the initial-version +release-note warning remain, along with website-only Regulations and Permits +declarations. + ## Verified in this release - One-at-a-time private introductions and candidate-profile navigation are implemented. @@ -13,6 +27,8 @@ - Early direct messages are buffered during bootstrap and in-memory replay tracking is bounded. - Typecheck, lint, unit tests, protocol conformance tests, dependency review, production audit exceptions, and release-manifest validation are CI gates. - Both repositories protect `main`; GitHub staging environments are protected-branch-only and production environments require `jongan69` approval. +- The production web app and Cloudflare Worker respond successfully over HTTPS, and the web export includes the restrictive CSP. +- RevenueCat project `proj3363ecdc` contains the App Store product, `plus` entitlement, current `default` offering, and `$rc_lifetime` package used by build 5. ## Tracked for follow-up releases @@ -23,6 +39,7 @@ These are post-launch engineering priorities, not launch gates: 3. Enforce global blocks and active-match authorization before any inbound DM reaches UI state. 4. Add push delivery, liveness/age verification, profile moderation, appeals, and staffed trust-and-safety operations. 5. Resolve or renew the time-limited SDK dependency exceptions in `security/audit-exceptions.json`. +6. Validate RevenueCat purchase, restore, revocation, identity changes, reinstall, and offline behavior on a physical iOS device. ## Release mechanics diff --git a/docs/STORE_LISTING.md b/docs/STORE_LISTING.md index 1779312..e37aa7f 100644 --- a/docs/STORE_LISTING.md +++ b/docs/STORE_LISTING.md @@ -1,11 +1,11 @@ # OpenDating Store Listing -**Last updated:** 2026-08-13 +**Last updated:** 2026-08-29 -> **Submission status: blocked.** Apple rejected iOS 0.1.0 (1) under Guideline -> 4.3(b) on August 13, 2026. This copy belongs to the materially revised 0.1.1 -> candidate and must not be attached to the rejected binary as though it -> described that build. +> **Submission status: waiting for App Review.** Apple rejected iOS 0.1.0 (1) +> under Guideline 4.3(b) on August 13, 2026. The materially revised 0.1.1 (5) +> candidate was submitted on August 29, 2026. Repository launch approval stays +> blocked until its independent release evidence is complete. This is the canonical copy deck for the first App Store Connect and Google Play Console records. @@ -52,6 +52,7 @@ BUILT AROUND DATA MINIMIZATION - Open an end-to-end encrypted conversation only after mutual interest - Block locally and report privately - Use the app without ads, tracking, or a data-broker business model +- Optionally unlock Sage, Ocean, and Plum app accents with one lifetime purchase OpenDating is the first reference client for the open OpenDating protocol. Your recovery key can restore your account on another compatible OpenDating client or @@ -101,6 +102,7 @@ Safety. Confirm the final console answers before submitting for review. | Messages and user-generated content | Messaging and safety | Yes | No | | Public account ID | Account functionality | Yes | No | | Reports and block actions | Safety and moderation | Yes | No | +| Purchase history | Optional Plus entitlement | Yes, through an opaque billing ID | No | The app does not use third-party advertising SDKs and does not sell personal data. iOS export compliance is configured as standard encryption with no France @@ -133,10 +135,11 @@ the release evidence before adding those files back to `store.config.json`. | Platform | Build | Artifact | |---|---|---| -| iOS | `79e9b81e-6f66-4dcc-b46f-4ae53da4ae67` | Superseded App Store IPA, v0.1.0 build 4 — do not ship | +| iOS | `cf5d4b22-f7aa-430b-980f-f4b191718612` | EAS production IPA, v0.1.1 build 5; App Store Connect build `12dd3ff2-f9bd-491a-984f-b14aafd02ef8`, valid and attached but not submitted | | Android | `f5b79c72-91ee-4dd3-96e7-0343911e2ca2` | Superseded Play Store AAB, v0.1.0 version code 3 — do not ship | -Build fresh 0.1.1 artifacts before submitting. +Build a fresh Android 0.1.1 artifact before any Android submission. Do not +replace iOS build 5 unless physical testing finds a release-blocking defect. ## Submission Commands diff --git a/jest.config.js b/jest.config.js index a2edc2a..e901c78 100644 --- a/jest.config.js +++ b/jest.config.js @@ -13,7 +13,7 @@ module.exports = { transform: { '^.+\\.[tj]sx?$': ['ts-jest', { tsconfig: '/tsconfig.jest.json' }], }, - transformIgnorePatterns: ['/node_modules/(?!(opendating-protocol|@noble)/)'], + transformIgnorePatterns: ['/node_modules/(?!(opendating-protocol|@noble|@scure)/)'], testPathIgnorePatterns: ['/node_modules/', '/.expo/'], testMatch: ['**/__tests__/**/*.test.ts'], }; diff --git a/package.json b/package.json index 1be1ca1..1d776a9 100644 --- a/package.json +++ b/package.json @@ -29,28 +29,28 @@ "main": "index.ts", "version": "0.1.1", "dependencies": { - "@expo/ui": "~57.0.11", + "@expo/ui": "~57.0.12", "@noble/curves": "1.9.7", "@nostr-dev-kit/ndk": "^2.18.1", - "@react-native-async-storage/async-storage": "^3.1.1", + "@react-native-async-storage/async-storage": "2.2.0", "@scure/base": "^2.3.0", - "expo": "~57.0.13", + "expo": "~57.0.15", "expo-clipboard": "~57.0.1", - "expo-constants": "~57.0.11", + "expo-constants": "~57.0.13", "expo-crypto": "~57.0.1", - "expo-dev-client": "~57.0.12", + "expo-dev-client": "~57.0.14", "expo-device": "~57.0.1", "expo-font": "~57.0.1", "expo-glass-effect": "~57.0.1", "expo-haptics": "^57.0.1", "expo-image": "~57.0.3", - "expo-image-picker": "^57.0.10", + "expo-image-picker": "~57.0.12", "expo-linear-gradient": "~57.0.1", - "expo-linking": "~57.0.6", - "expo-location": "^57.0.10", - "expo-router": "~57.0.13", + "expo-linking": "~57.0.7", + "expo-location": "~57.0.12", + "expo-router": "~57.0.15", "expo-secure-store": "^57.0.1", - "expo-splash-screen": "~57.0.6", + "expo-splash-screen": "~57.0.7", "expo-sqlite": "~57.0.1", "expo-status-bar": "~57.0.1", "expo-symbols": "~57.0.2", @@ -63,6 +63,7 @@ "react-native": "0.86.2", "react-native-gesture-handler": "~2.32.0", "react-native-get-random-values": "^1.11.0", + "react-native-purchases": "^10.6.0", "react-native-reanimated": "4.5.1", "react-native-safe-area-context": "~5.7.0", "react-native-screens": "~4.26.2", @@ -88,12 +89,15 @@ "android": "expo run:android", "ios": "expo run:ios", "web": "expo start --web", + "export:web": "expo export --platform web && node scripts/secure-web-export.mjs", + "serve:web": "expo serve", "typecheck": "tsc --noEmit", "lint": "expo lint", "test": "jest --runInBand", "test:watch": "jest --watch", "clean": "expo start --clear", - "deploy:web": "echo 'Deploy via GitHub Pages — push to main and the deploy-web workflow handles the rest.'", + "deploy:web": "bun run export:web && eas deploy", + "deploy:web:prod": "bun run export:web && eas deploy --prod", "release:verify": "node scripts/release/assert-release-ready.mjs", "release:validate": "node scripts/release/assert-release-ready.mjs --validate-only", "security:audit": "bun scripts/check-production-audit.mjs", @@ -105,7 +109,7 @@ "build:ios:screenshot": "eas build --profile screenshot --platform ios", "submit:ios": "bun run release:verify && eas submit --profile production --platform ios", "store:ios:lookup-asc-app-id": "node scripts/release/lib/lookup-asc-app-id.mjs", - "store:metadata:lint": "bun x eas-cli@21.7.0 metadata:lint --profile production", + "store:metadata:lint": "ASC_API_KEY_PATH=${ASC_API_KEY_PATH:-/dev/null} ASC_API_KEY_ISSUER_ID=${ASC_API_KEY_ISSUER_ID:-00000000-0000-0000-0000-000000000000} bun x eas-cli@21.7.0 metadata:lint --profile production", "store:metadata:push": "bun run release:verify && bun x eas-cli@21.7.0 metadata:push --profile production", "build:all": "bun run release:verify -- --source-only && eas build --profile production --platform all", "screenshots:capture": "./scripts/capture-screenshots.sh", @@ -114,12 +118,15 @@ "blog:generate": "node scripts/release/lib/generate-articles.mjs", "blog:build": "node scripts/release/lib/build-blog.mjs", "check:duplicates": "node scripts/check-duplicate-runtimes.mjs", - "test:release-tools": "bun test scripts/release/lib/security-utils.test.mjs", + "test:release-tools": "bun test ./scripts/release/lib/security-utils.test.mjs", "postinstall": "node scripts/check-duplicate-runtimes.mjs" }, "private": true, "packageManager": "bun@1.3.14", "overrides": { "uuid": ">=14.0.1" + }, + "patchedDependencies": { + "tseep@1.3.1": "patches/tseep@1.3.1.patch" } } diff --git a/patches/tseep@1.3.1.patch b/patches/tseep@1.3.1.patch new file mode 100644 index 0000000..903cfd2 --- /dev/null +++ b/patches/tseep@1.3.1.patch @@ -0,0 +1,11 @@ +diff --git a/lib/index.js b/lib/index.js +index ee8a7a19fb5fbf409464e467aa7c3a4c0869534c..caae05c2433dea825722fcc5b5d0815486178f45 100644 +--- a/lib/index.js ++++ b/lib/index.js +@@ -15,5 +15,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) { + }; + Object.defineProperty(exports, "__esModule", { value: true }); + __exportStar(require("./types"), exports); +-__exportStar(require("./ee"), exports); ++__exportStar(require("./ee-safe"), exports); + //# sourceMappingURL=index.js.map diff --git a/public/privacy/index.html b/public/privacy/index.html index 07d3a7b..a010430 100644 --- a/public/privacy/index.html +++ b/public/privacy/index.html @@ -30,7 +30,7 @@

Privacy Policy

-
Last updated: August 9, 2026
+
Last updated: August 29, 2026

Our Approach to Privacy

OpenDating is designed to minimize data collection and separate service responsibilities. Privacy depends on both architecture and operating policy; no system can honestly promise that surveillance or compromise is impossible.

@@ -54,7 +54,7 @@

Information we do NOT collect

  • Contact lists or address books
  • Browsing history
  • Device advertising identifiers
  • -
  • Payment information in the current beta
  • +
  • Full payment-card or bank-account details; Apple processes payment
  • Any data from other apps on your device
  • @@ -66,7 +66,7 @@

    How We Use Information

  • Encrypted likes are routed to the matcher service to create matches
  • Encrypted messages are routed between matched users
  • -

    The current beta does not use advertising SDKs or product analytics. Infrastructure security and operational logs may still be processed. Any future allowlisted aggregate analytics or moderation vendors will require an updated notice and production approval.

    +

    The app does not use advertising SDKs or product analytics. RevenueCat processes an opaque billing identifier and Apple purchase-entitlement status only when the optional one-time Plus feature is enabled. Infrastructure security and operational logs may still be processed. Any future allowlisted aggregate analytics or moderation vendors will require an updated notice and production approval.

    Data Storage and Security

    Data Sharing

    -

    We do not sell or rent profile or relationship data and do not have advertising partners. Cloudflare processes service data as the current infrastructure provider; Apple, Google, and Expo may process build or distribution data. See the current subprocessors list.

    +

    We do not sell or rent profile or relationship data and do not have advertising partners. Cloudflare processes service data as the current infrastructure provider. RevenueCat may process an opaque billing identifier and purchase-entitlement status; it does not receive profile text, photos, location, recovery keys, likes, matches, reports, or messages. Apple, Google, and Expo may process purchase, build, or distribution data. See the current subprocessors list.

    Your Control