mirror of
https://github.com/jjbrunton/Sauci.git
synced 2026-11-01 18:19:43 +00:00
Fix EAS local builds and resolve require cycles
- Add dotenv-cli for EAS local builds to load env vars - Break circular dependencies in store/hooks imports - Add env var validation with clear error messages - Remove hardcoded Sentry auth token from sentry.properties - Add .ipa files to .gitignore 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bb2ce5a6a6
commit
58209b94ef
19 files changed
+458
-114
No files matched your search
@@ -14,6 +14,8 @@ import { useEncryptionKeys } from './useEncryptionKeys';
|
||||
import { getCachedSignedUrl, getStoragePath } from '../lib/imageCache';
|
||||
import { supabase } from '../lib/supabase';
|
||||
import { reencryptPendingMessages } from '../lib/encryption/reencryptPendingMessages';
|
||||
// Import shared cache from mediaCache to avoid circular dependency
|
||||
import { decryptedMediaCache, clearDecryptedMediaCache } from '../lib/mediaCache';
|
||||
|
||||
export type DecryptedMediaErrorCode =
|
||||
| 'E2EE_NOT_SUPPORTED'
|
||||
@@ -22,8 +24,8 @@ export type DecryptedMediaErrorCode =
|
||||
| 'E2EE_PENDING_RECIPIENT_KEY'
|
||||
| 'E2EE_DECRYPT_FAILED';
|
||||
|
||||
// In-memory cache to avoid re-decrypting the same media
|
||||
const decryptedMediaCache = new Map<string, string>();
|
||||
// Re-export clearDecryptedMediaCache for backwards compatibility
|
||||
export { clearDecryptedMediaCache };
|
||||
|
||||
interface DecryptedMediaState {
|
||||
/** Local file URI to the decrypted media (or null if not ready) */
|
||||
@@ -396,13 +398,3 @@ export function useDecryptedMedia({
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the decrypted media cache
|
||||
* Call this when logging out or when memory is low
|
||||
*/
|
||||
export async function clearDecryptedMediaCache(): Promise<void> {
|
||||
for (const uri of decryptedMediaCache.values()) {
|
||||
await cleanupDecryptedMedia(uri);
|
||||
}
|
||||
decryptedMediaCache.clear();
|
||||
}
|
||||
@@ -22,7 +22,8 @@ import {
|
||||
} from '../lib/encryption';
|
||||
import type { RSAPublicKeyJWK } from '../lib/encryption';
|
||||
import { supabase } from '../lib/supabase';
|
||||
import { useAuthStore } from '../store';
|
||||
// Import directly from authStore to avoid circular dependency with store/index.ts
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
|
||||
interface UseEncryptionKeysReturn {
|
||||
/** RSA private key in JWK format */
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { router } from "expo-router";
|
||||
import { supabase } from "./supabase";
|
||||
import { useAuthStore } from "../store";
|
||||
// Import directly from authStore to avoid circular dependency with store/index.ts
|
||||
import { useAuthStore } from "../store/authStore";
|
||||
|
||||
/**
|
||||
* Handles authentication errors from edge function calls.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Media Cache Utilities
|
||||
*
|
||||
* Extracted from useDecryptedMedia to avoid circular dependencies.
|
||||
* This module handles caching of decrypted media files.
|
||||
*/
|
||||
|
||||
import { cleanupDecryptedMedia } from './encryption';
|
||||
|
||||
// In-memory cache to avoid re-decrypting the same media
|
||||
export const decryptedMediaCache = new Map<string, string>();
|
||||
|
||||
/**
|
||||
* Clears all cached decrypted media files from disk and memory.
|
||||
* Call this on sign out to free up storage.
|
||||
*/
|
||||
export async function clearDecryptedMediaCache(): Promise<void> {
|
||||
for (const uri of decryptedMediaCache.values()) {
|
||||
await cleanupDecryptedMedia(uri);
|
||||
}
|
||||
decryptedMediaCache.clear();
|
||||
}
|
||||
@@ -47,10 +47,26 @@ const ExpoStorageAdapter = {
|
||||
},
|
||||
};
|
||||
|
||||
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL!;
|
||||
const supabaseAnonKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY!;
|
||||
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL;
|
||||
const supabaseAnonKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY;
|
||||
|
||||
export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
|
||||
// Validate environment variables at startup (skip in test environment where mocks handle this)
|
||||
const isTestEnv = process.env.NODE_ENV === 'test' || process.env.JEST_WORKER_ID !== undefined;
|
||||
if (!isTestEnv && (!supabaseUrl || !supabaseAnonKey)) {
|
||||
const missing = [];
|
||||
if (!supabaseUrl) missing.push('EXPO_PUBLIC_SUPABASE_URL');
|
||||
if (!supabaseAnonKey) missing.push('EXPO_PUBLIC_SUPABASE_ANON_KEY');
|
||||
const errorMsg = `Missing required environment variables: ${missing.join(', ')}. App cannot start.`;
|
||||
console.error('[Supabase]', errorMsg);
|
||||
// In production, this will be caught by Sentry before crashing
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
||||
// Use dummy values in test environment (supabase-js is mocked anyway)
|
||||
const finalUrl = supabaseUrl || (isTestEnv ? 'https://test.supabase.co' : '');
|
||||
const finalKey = supabaseAnonKey || (isTestEnv ? 'test-key' : '');
|
||||
|
||||
export const supabase = createClient(finalUrl, finalKey, {
|
||||
auth: {
|
||||
storage: ExpoStorageAdapter,
|
||||
autoRefreshToken: true,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* Crypto polyfill for React Native
|
||||
*
|
||||
*
|
||||
* This file must be imported BEFORE any code that uses crypto.
|
||||
* It installs react-native-quick-crypto as the global crypto implementation.
|
||||
*
|
||||
*
|
||||
* On web, we skip this since the native Web Crypto API is available.
|
||||
*/
|
||||
|
||||
@@ -13,17 +13,17 @@ if (Platform.OS !== 'web') {
|
||||
try {
|
||||
// Import react-native-quick-crypto to install its polyfill
|
||||
const QuickCrypto = require('react-native-quick-crypto');
|
||||
|
||||
|
||||
// Install the polyfill globally if not already present
|
||||
if (typeof global.crypto === 'undefined') {
|
||||
(global as any).crypto = QuickCrypto;
|
||||
}
|
||||
|
||||
|
||||
// Also ensure subtle is available
|
||||
if (global.crypto && !global.crypto.subtle) {
|
||||
(global.crypto as any).subtle = QuickCrypto.subtle;
|
||||
}
|
||||
|
||||
|
||||
console.log('[Crypto] react-native-quick-crypto polyfill installed');
|
||||
} catch (error) {
|
||||
console.error('[Crypto] Failed to install crypto polyfill:', error);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { create } from "zustand";
|
||||
import { supabase } from "../lib/supabase";
|
||||
import { Events } from "../lib/analytics";
|
||||
import { clearKeys } from "../lib/encryption";
|
||||
import { clearDecryptedMediaCache } from "../hooks/useDecryptedMedia";
|
||||
import { clearDecryptedMediaCache } from "../lib/mediaCache";
|
||||
import type { Profile, Couple } from "@/types";
|
||||
import type { RSAPublicKeyJWK, RSAPrivateKeyJWK } from "../lib/encryption/types";
|
||||
|
||||
|
||||
@@ -1,20 +1,10 @@
|
||||
/// <reference types="jest" />
|
||||
|
||||
// Environment variables are set in setupEnv.js (runs before modules load)
|
||||
|
||||
// Some modules rely on this global existing in RN.
|
||||
(global as any).__DEV__ = true;
|
||||
|
||||
if (!process.env.EXPO_PUBLIC_SUPABASE_URL) {
|
||||
process.env.EXPO_PUBLIC_SUPABASE_URL = 'https://example.supabase.co';
|
||||
}
|
||||
|
||||
if (!process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY) {
|
||||
process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY = 'test-anon-key';
|
||||
}
|
||||
|
||||
if (!process.env.EXPO_PUBLIC_REVENUECAT_ENTITLEMENT_ID) {
|
||||
process.env.EXPO_PUBLIC_REVENUECAT_ENTITLEMENT_ID = 'pro';
|
||||
}
|
||||
|
||||
jest.mock('@supabase/supabase-js', () => {
|
||||
const makeChannel = () => {
|
||||
const channel: any = {
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// Set test environment variables BEFORE modules are loaded
|
||||
// This must run in setupFiles (not setupFilesAfterEnv) to ensure
|
||||
// env vars are available when supabase.ts is imported
|
||||
|
||||
process.env.EXPO_PUBLIC_SUPABASE_URL = 'https://example.supabase.co';
|
||||
process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY = 'test-anon-key';
|
||||
process.env.EXPO_PUBLIC_REVENUECAT_ENTITLEMENT_ID = 'pro';
|
||||
Reference in new issue
Block a user