Skip to content

Services Layer

A service is the only client-side place allowed to call supabase.functions.invoke(). Services wrap edge-function calls for a feature and live at tiers/[tier]/features/[name]/services/{feature}Service.js.

Rules

  • Only services call functions.invoke() — never components, hooks, pages, or JSX.
  • EF names come from an EDGE_FN config map — never inline strings.
  • Throw on error so callers (usually a TanStack useMutation) can handle it.
js
// services/featureService.js
import { supabase } from '@/lib/supabaseClient';
import { EDGE_FN } from '../config/featureConfig';

export const featureService = {
  async save(payload) {
    const { data, error } = await supabase.functions.invoke(EDGE_FN.SAVE, { body: payload });
    if (error) throw error;
    return data;
  },
};

EDGE_FN config maps

Every deployed edge function is registered in a per-feature config constant so names are never inlined:

js
// config/edgeBuilderConfig.js (authoritative for Edge Builder)
export const EDGE_FN = {
  SAVE:      'trade-planner-save',
  UPDATE:    'trade-planner-update',
  LIFECYCLE: 'trade-planner-lifecycle',
  SHARE:     'trade-planner-share',
};

FinFluencify keeps its own map in config/cloudflareConfig.js. The full deployed list is the Edge Function Index.

Mutations

Services are typically consumed through TanStack Query useMutation (the standard for writes), giving loading/error state, optimistic updates, and cache invalidation. Reads, by contrast, use RPC hooks.