functionsOutOfSyncProvider top-level property

FutureProvider<bool> functionsOutOfSyncProvider
final

Whether the Edge Function bundle deployed to the user's Supabase project is out of sync with the one the app currently ships.

Reads both _schema_meta.version and _schema_meta.functions_hash in two sequential PostgREST calls (the second of which is guarded by the version check, so we never hit the column-missing error on legacy instances). Invalidate this provider after a successful redeploy in the Settings banner so the banner disappears without a sign-out/sign-in.

Implementation

final functionsOutOfSyncProvider = FutureProvider<bool>((ref) async {
  // Re-run when the Supabase auth state changes.
  ref.watch(authStateProvider);

  final client = Supabase.instance.client;
  if (client.auth.currentUser == null) return false;

  try {
    final versionRow = await client
        .from('_schema_meta')
        .select('version')
        .maybeSingle();
    if (versionRow == null) return false;
    final version = versionRow['version'];
    final schemaVersion = version is int ? version : null;

    if (schemaVersion == null || schemaVersion < _functionsHashMinVersion) {
      // Pre-migration-059 schema. Wait for the incremental migration to
      // add the column before we start nagging; otherwise the banner would
      // open a dialog that hits 42703 on the hash write.
      return false;
    }

    final hashRow = await client
        .from('_schema_meta')
        .select('functions_hash')
        .maybeSingle();
    final deployedHash = hashRow?['functions_hash'] as String?;

    return functionsOutOfSyncFromMeta(
      schemaVersion: schemaVersion,
      deployedHash: deployedHash,
      bundledHash: functionsBundleHash,
    );
  } on PostgrestException catch (e) {
    // Table missing (42P01), column missing (42703), or schema cache miss
    // (PGRST205): fall through to "no banner". Incremental migration will
    // eventually catch them up, at which point the provider will re-run
    // and the banner will appear.
    if (e.code == '42P01' || e.code == '42703' || e.code == 'PGRST205') {
      return false;
    }
    // Fail quiet on anything else — the banner is a nice-to-have, not a
    // blocker for Settings rendering.
    return false;
  } catch (_) {
    return false;
  }
});