@fayz-ai/plugin-banking-br 0.10.41 → 0.10.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/migrations/index.ts"],"names":[],"mappings":";AAIO,IAAM,sBAAA,GAAyB,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;;AAAA;;;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;;AAAA;;AAAA;;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2a/B,IAAM,8CAAA,GAAiD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+KvD,IAAM,UAAA,GAAiD;AAAA,EAC5D,EAAE,EAAA,EAAI,cAAA,EAAgB,GAAA,EAAK,sBAAA,EAAuB;AAAA,EAClD,EAAE,EAAA,EAAI,sCAAA,EAAwC,GAAA,EAAK,8CAAA;AACrD","file":"main.js","sourcesContent":["// AUTO-GENERATED from 000_baseline.sql, 001_the_import_rpc_names_real_tables.sql — regenerate with scripts/embed-migrations.mjs\n// SQL files are the source of truth; this inline copy lets the manifest declare\n// migrations as data. Do not edit by hand — run the embed script instead.\n\nexport const MIGRATION_000_BASELINE = `-- ============================================================================\n-- plugins/plugin-banking-br/src/migrations/000_baseline.sql — what installing this provisions, as one file.\n--\n-- GENERATED by scripts/emit-unit-baselines.mjs (#338). Do not edit by hand:\n-- change the schema, regenerate, and let scripts/check-chain-equivalence.mjs\n-- prove the result still matches.\n--\n-- This replaced 2 migration files. They are kept, unapplied, in\n-- migrations.archive/ — a year of decisions is worth reading even when it is no\n-- longer worth replaying.\n--\n-- Object order is fixed rather than dependency-sorted: schemas, types,\n-- sequences, tables, defaults, functions, constraints, views, indexes, foreign\n-- keys, triggers, row security, policies, grants. Dependencies BETWEEN units\n-- are carried by the order packages/db/chain.json declares.\n-- ============================================================================\n\n-- A LANGUAGE sql function binds its body at CREATE time, and 570 functions\n-- sorted by name are not sorted by who calls whom. This is what lets them load\n-- in any order; every body is still compiled on first call, so a genuinely\n-- broken reference surfaces then rather than never. Session-scoped.\nSET check_function_bodies = false;\n\n\n\n-- ── default privileges: reset ───────────────────────────────────────────\n-- Cleared BEFORE anything is created, so every object below gets the ACL the\n-- dump describes rather than the image's defaults on top of it. Restored at\n-- the end of this file.\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON SEQUENCES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON SEQUENCES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON SEQUENCES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON SEQUENCES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON FUNCTIONS FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON FUNCTIONS FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON FUNCTIONS FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON FUNCTIONS FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON TABLES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON TABLES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON TABLES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON TABLES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\n\n-- ── function ────────────────────────────────────────────────────────────\n\nCREATE FUNCTION public.plg_bank_emit_movement_imported() RETURNS trigger\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO 'public'\n AS $$\nDECLARE\n v_payload jsonb;\nBEGIN\n IF NEW.external_source IS NULL OR NEW.external_id IS NULL THEN\n RETURN NULL;\n END IF;\n\n -- The contract every consumer reads. Not the row: a whole-row payload would\n -- put the ledger's internal bookkeeping inside every webhook by default.\n v_payload := jsonb_build_object(\n 'movement_id', NEW.id::text,\n 'provider', NEW.external_source,\n 'external_id', NEW.external_id,\n 'direction', NEW.direction,\n 'amount', NEW.amount,\n 'payment_date', NEW.payment_date,\n 'description', NEW.notes,\n 'bank_account_id', NEW.bank_account_id);\n\n BEGIN\n PERFORM public.plg_emit_event(\n 'financial.movement.imported', v_payload, 'financial_movement',\n NEW.id::text, NEW.tenant_id, NULL);\n EXCEPTION WHEN OTHERS THEN\n -- Observability must never be able to reject the write that caused it.\n RAISE WARNING '[plg_bank_emit_movement_imported] % on %: %', TG_OP, TG_TABLE_NAME, SQLERRM;\n END;\n\n RETURN NULL;\nEND;\n$$;\n\nCREATE FUNCTION public.plugbank_import_movements(p_payload jsonb) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO 'public'\n AS $$\nDECLARE\n v_tenants uuid[];\n v_tenant uuid;\n v_connection uuid;\n v_instance text;\n v_account uuid;\n v_connector text;\n v_trigger text;\n v_from date;\n v_to date;\n v_started timestamptz := now();\n v_line jsonb;\n v_external text;\n v_amount numeric(14,2);\n v_date date;\n v_fetched int := 0;\n v_imported int := 0;\n v_duplicates int := 0;\n v_inserted uuid;\n v_run uuid;\nBEGIN\n v_connection := nullif(btrim(p_payload->>'integration_id'), '')::uuid;\n IF v_connection IS NULL THEN\n RAISE EXCEPTION 'plugbank_import_movements: integration_id is required'\n USING ERRCODE = 'invalid_parameter_value';\n END IF;\n\n SELECT c.tenant_id, c.instance_key, c.connector_id\n INTO v_tenant, v_instance, v_connector\n FROM public.plg_connections c\n WHERE c.id = v_connection AND c.active;\n\n IF v_tenant IS NULL THEN\n RAISE EXCEPTION 'plugbank_import_movements: no active connection %', v_connection\n USING ERRCODE = 'no_data_found';\n END IF;\n\n -- The account this connection is for. \\`instance_key\\` is text because it also\n -- carries things that are not uuids for other connectors (a Bling company, a\n -- gateway instance); here it is the bank account, and '' is the account-less\n -- default that \\`bank_account_id IS NULL\\` used to mean.\n v_account := nullif(btrim(v_instance), '')::uuid;\n\n -- SECURITY DEFINER bypasses RLS, so the membership check the policy would\n -- have made has to happen here.\n SELECT array_agg(t) INTO v_tenants FROM public.user_tenant_ids() AS t;\n IF auth.uid() IS NOT NULL AND NOT (v_tenant = ANY (COALESCE(v_tenants, '{}'::uuid[]))) THEN\n RAISE EXCEPTION 'plugbank_import_movements: caller is not a member of tenant %', v_tenant\n USING ERRCODE = 'insufficient_privilege';\n END IF;\n\n -- Refusing beats ignoring: a caller that believes it is importing into\n -- another tenant must be told, not silently redirected into this one.\n IF nullif(btrim(p_payload->>'tenant_id'), '') IS NOT NULL\n AND (p_payload->>'tenant_id')::uuid IS DISTINCT FROM v_tenant THEN\n RAISE EXCEPTION 'plugbank_import_movements: payload names another tenant; the tenant comes from the connection'\n USING ERRCODE = 'insufficient_privilege';\n END IF;\n\n -- Same rule as the tenant, one level down: the account is the connection's,\n -- and a payload naming a different one is a caller importing into the wrong\n -- ledger account. 002 let the payload override it silently — with one\n -- connection per account that override is how two accounts get mixed.\n IF nullif(btrim(p_payload->>'bank_account_id'), '') IS NOT NULL\n AND (p_payload->>'bank_account_id')::uuid IS DISTINCT FROM v_account THEN\n RAISE EXCEPTION 'plugbank_import_movements: payload names another bank account; the account comes from the connection'\n USING ERRCODE = 'insufficient_privilege';\n END IF;\n\n v_from := nullif(btrim(p_payload->>'period_from'), '')::date;\n v_to := nullif(btrim(p_payload->>'period_to'), '')::date;\n v_trigger := lower(coalesce(nullif(btrim(p_payload->>'trigger'), ''), 'manual'));\n IF v_trigger NOT IN ('on-write', 'scheduled', 'manual', 'webhook') THEN\n RAISE EXCEPTION 'plugbank_import_movements: unknown trigger %', v_trigger\n USING ERRCODE = 'invalid_parameter_value';\n END IF;\n\n FOR v_line IN SELECT * FROM jsonb_array_elements(coalesce(p_payload->'lines', '[]'::jsonb))\n LOOP\n v_fetched := v_fetched + 1;\n v_external := nullif(btrim(v_line->>'external_id'), '');\n v_date := nullif(btrim(v_line->>'date'), '')::date;\n v_amount := abs(coalesce((v_line->>'amount')::numeric, 0));\n\n -- A line with no provider id cannot be recognised on re-delivery, so it\n -- would import again on every run. Skipping it is the lesser wrong.\n IF v_external IS NULL OR v_date IS NULL OR v_amount = 0 THEN\n CONTINUE;\n END IF;\n\n INSERT INTO public.plg_financial_movements (\n tenant_id, direction, movement_kind, amount, paid_amount, status,\n due_date, payment_date, bank_account_id, notes, external_id, external_source)\n VALUES (\n v_tenant,\n CASE WHEN upper(coalesce(v_line->>'type', 'C')) LIKE 'C%' THEN 'credit' ELSE 'debit' END,\n 'payment', v_amount, v_amount, 'paid',\n v_date, v_date, v_account,\n nullif(btrim(v_line->>'description'), ''),\n v_external, coalesce(v_connector, 'plugbank'))\n ON CONFLICT (tenant_id, external_source, external_id)\n WHERE external_id IS NOT NULL AND external_source IS NOT NULL\n DO NOTHING\n RETURNING id INTO v_inserted;\n\n IF v_inserted IS NULL THEN\n v_duplicates := v_duplicates + 1;\n ELSE\n v_imported := v_imported + 1;\n END IF;\n v_inserted := NULL;\n END LOOP;\n\n UPDATE public.plg_connections\n SET last_sync_at = now(), status = 'connected', status_detail = NULL, updated_at = now()\n WHERE id = v_connection;\n\n -- \\`stats\\` is where the three facts a manual statement import has and a generic\n -- run does not go: the operator picked a period, a re-import of that period is\n -- mostly duplicates by design, and someone pressed the button. The panel reads\n -- all three back from here.\n INSERT INTO public.plg_sync_runs (\n tenant_id, connection_id, connector_id, direction, trigger_kind, status,\n stream, fetched, written, stats, started_at, finished_at)\n VALUES (\n v_tenant, v_connection, coalesce(v_connector, 'plugbank'), 'inbound', v_trigger, 'success',\n 'statement', v_fetched, v_imported,\n jsonb_strip_nulls(jsonb_build_object(\n 'duplicates', v_duplicates,\n 'period_from', v_from,\n 'period_to', v_to,\n 'triggered_by_user_id', auth.uid())),\n v_started, now())\n RETURNING id INTO v_run;\n\n RETURN jsonb_build_object(\n 'ok', true,\n 'sync_run_id', v_run,\n 'fetched', v_fetched,\n 'imported', v_imported,\n 'duplicates', v_duplicates);\nEND;\n$$;\n\n\n-- ── trigger ─────────────────────────────────────────────────────────────\n\nCREATE TRIGGER plg_financial_movements_emit_imported AFTER INSERT ON public.plg_financial_movements FOR EACH ROW EXECUTE FUNCTION public.plg_bank_emit_movement_imported();\n\n\n-- ── acl ─────────────────────────────────────────────────────────────────\n\nREVOKE ALL ON FUNCTION public.plg_bank_emit_movement_imported() FROM PUBLIC;\nGRANT ALL ON FUNCTION public.plg_bank_emit_movement_imported() TO authenticated;\nGRANT ALL ON FUNCTION public.plg_bank_emit_movement_imported() TO service_role;\n\nREVOKE ALL ON FUNCTION public.plugbank_import_movements(p_payload jsonb) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.plugbank_import_movements(p_payload jsonb) TO authenticated;\nGRANT ALL ON FUNCTION public.plugbank_import_movements(p_payload jsonb) TO service_role;\n\n\n-- ── comment ─────────────────────────────────────────────────────────────\n\nCOMMENT ON FUNCTION public.plugbank_import_movements(p_payload jsonb) IS 'Import bank-statement lines into the financial ledger and file the run in plg_sync_runs. The tenant AND the bank account come from the plg_connections row named by integration_id, never from the payload.';\n\n\n-- ── default privileges: restore ─────────────────────────────────────────\n-- Put back, so the NEXT thing installed inherits what the chain had.\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO anon$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO anon$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO anon$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO anon$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO anon$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO anon$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT MAINTAIN ON TABLES TO anon$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT MAINTAIN ON TABLES TO anon$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO anon$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO anon$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$--\n-- PostgreSQL database dump complete\n--$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$--\n-- PostgreSQL database dump complete\n--$stmt$;\nEND $dp$;\n`\n\nexport const MIGRATION_001_THE_IMPORT_RPC_NAMES_REAL_TABLES = `-- ==========================================================================\n-- 001_the_import_rpc_names_real_tables — plugbank_import_movements\n-- stops reaching through 141's bridge (#352).\n--\n-- 107 renamed the connector spine out of the \\`plg_\\` prefix — the prefix means\n-- \"a plugin owns this\", and the connector framework's tables are the BASE's.\n-- 141 left \\`plg_connections\\` and \\`plg_sync_runs\\` answering as views so callers\n-- could move without a synchronised deploy. This function never moved, and it\n-- is not alone: \\`plg_connections\\` had 13 callers and \\`connections\\` had none.\n-- The bridge became the road.\n--\n-- The body is 000_baseline's, unchanged except for the three names. It is not\n-- an edit of that file — an applied migration is immutable and the ledger\n-- treats drift as a hard stop — it is a CREATE OR REPLACE that lands after it.\n--\n-- Why this plugin has to carry its own: the function is banking-br's, and the\n-- views it stops using are the spine's. The spine runs FIRST, so a spine file\n-- cannot drop a view that a plugin applied later still reads. Each package\n-- moves its own callers; the aliases go once nobody is left.\n--\n-- Replay-safe: CREATE OR REPLACE, same signature, same grants (which 000 set\n-- and this does not touch).\n-- ==========================================================================\n\nCREATE OR REPLACE FUNCTION public.plugbank_import_movements(p_payload jsonb) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO 'public'\n AS $$\nDECLARE\n v_tenants uuid[];\n v_tenant uuid;\n v_connection uuid;\n v_instance text;\n v_account uuid;\n v_connector text;\n v_trigger text;\n v_from date;\n v_to date;\n v_started timestamptz := now();\n v_line jsonb;\n v_external text;\n v_amount numeric(14,2);\n v_date date;\n v_fetched int := 0;\n v_imported int := 0;\n v_duplicates int := 0;\n v_inserted uuid;\n v_run uuid;\nBEGIN\n v_connection := nullif(btrim(p_payload->>'integration_id'), '')::uuid;\n IF v_connection IS NULL THEN\n RAISE EXCEPTION 'plugbank_import_movements: integration_id is required'\n USING ERRCODE = 'invalid_parameter_value';\n END IF;\n\n SELECT c.tenant_id, c.instance_key, c.connector_id\n INTO v_tenant, v_instance, v_connector\n FROM public.connections c\n WHERE c.id = v_connection AND c.active;\n\n IF v_tenant IS NULL THEN\n RAISE EXCEPTION 'plugbank_import_movements: no active connection %', v_connection\n USING ERRCODE = 'no_data_found';\n END IF;\n\n -- The account this connection is for. \\`instance_key\\` is text because it also\n -- carries things that are not uuids for other connectors (a Bling company, a\n -- gateway instance); here it is the bank account, and '' is the account-less\n -- default that \\`bank_account_id IS NULL\\` used to mean.\n v_account := nullif(btrim(v_instance), '')::uuid;\n\n -- SECURITY DEFINER bypasses RLS, so the membership check the policy would\n -- have made has to happen here.\n SELECT array_agg(t) INTO v_tenants FROM public.user_tenant_ids() AS t;\n IF auth.uid() IS NOT NULL AND NOT (v_tenant = ANY (COALESCE(v_tenants, '{}'::uuid[]))) THEN\n RAISE EXCEPTION 'plugbank_import_movements: caller is not a member of tenant %', v_tenant\n USING ERRCODE = 'insufficient_privilege';\n END IF;\n\n -- Refusing beats ignoring: a caller that believes it is importing into\n -- another tenant must be told, not silently redirected into this one.\n IF nullif(btrim(p_payload->>'tenant_id'), '') IS NOT NULL\n AND (p_payload->>'tenant_id')::uuid IS DISTINCT FROM v_tenant THEN\n RAISE EXCEPTION 'plugbank_import_movements: payload names another tenant; the tenant comes from the connection'\n USING ERRCODE = 'insufficient_privilege';\n END IF;\n\n -- Same rule as the tenant, one level down: the account is the connection's,\n -- and a payload naming a different one is a caller importing into the wrong\n -- ledger account. 002 let the payload override it silently — with one\n -- connection per account that override is how two accounts get mixed.\n IF nullif(btrim(p_payload->>'bank_account_id'), '') IS NOT NULL\n AND (p_payload->>'bank_account_id')::uuid IS DISTINCT FROM v_account THEN\n RAISE EXCEPTION 'plugbank_import_movements: payload names another bank account; the account comes from the connection'\n USING ERRCODE = 'insufficient_privilege';\n END IF;\n\n v_from := nullif(btrim(p_payload->>'period_from'), '')::date;\n v_to := nullif(btrim(p_payload->>'period_to'), '')::date;\n v_trigger := lower(coalesce(nullif(btrim(p_payload->>'trigger'), ''), 'manual'));\n IF v_trigger NOT IN ('on-write', 'scheduled', 'manual', 'webhook') THEN\n RAISE EXCEPTION 'plugbank_import_movements: unknown trigger %', v_trigger\n USING ERRCODE = 'invalid_parameter_value';\n END IF;\n\n FOR v_line IN SELECT * FROM jsonb_array_elements(coalesce(p_payload->'lines', '[]'::jsonb))\n LOOP\n v_fetched := v_fetched + 1;\n v_external := nullif(btrim(v_line->>'external_id'), '');\n v_date := nullif(btrim(v_line->>'date'), '')::date;\n v_amount := abs(coalesce((v_line->>'amount')::numeric, 0));\n\n -- A line with no provider id cannot be recognised on re-delivery, so it\n -- would import again on every run. Skipping it is the lesser wrong.\n IF v_external IS NULL OR v_date IS NULL OR v_amount = 0 THEN\n CONTINUE;\n END IF;\n\n INSERT INTO public.plg_financial_movements (\n tenant_id, direction, movement_kind, amount, paid_amount, status,\n due_date, payment_date, bank_account_id, notes, external_id, external_source)\n VALUES (\n v_tenant,\n CASE WHEN upper(coalesce(v_line->>'type', 'C')) LIKE 'C%' THEN 'credit' ELSE 'debit' END,\n 'payment', v_amount, v_amount, 'paid',\n v_date, v_date, v_account,\n nullif(btrim(v_line->>'description'), ''),\n v_external, coalesce(v_connector, 'plugbank'))\n ON CONFLICT (tenant_id, external_source, external_id)\n WHERE external_id IS NOT NULL AND external_source IS NOT NULL\n DO NOTHING\n RETURNING id INTO v_inserted;\n\n IF v_inserted IS NULL THEN\n v_duplicates := v_duplicates + 1;\n ELSE\n v_imported := v_imported + 1;\n END IF;\n v_inserted := NULL;\n END LOOP;\n\n UPDATE public.connections\n SET last_sync_at = now(), status = 'connected', status_detail = NULL, updated_at = now()\n WHERE id = v_connection;\n\n -- \\`stats\\` is where the three facts a manual statement import has and a generic\n -- run does not go: the operator picked a period, a re-import of that period is\n -- mostly duplicates by design, and someone pressed the button. The panel reads\n -- all three back from here.\n INSERT INTO public.sync_runs (\n tenant_id, connection_id, connector_id, direction, trigger_kind, status,\n stream, fetched, written, stats, started_at, finished_at)\n VALUES (\n v_tenant, v_connection, coalesce(v_connector, 'plugbank'), 'inbound', v_trigger, 'success',\n 'statement', v_fetched, v_imported,\n jsonb_strip_nulls(jsonb_build_object(\n 'duplicates', v_duplicates,\n 'period_from', v_from,\n 'period_to', v_to,\n 'triggered_by_user_id', auth.uid())),\n v_started, now())\n RETURNING id INTO v_run;\n\n RETURN jsonb_build_object(\n 'ok', true,\n 'sync_run_id', v_run,\n 'fetched', v_fetched,\n 'imported', v_imported,\n 'duplicates', v_duplicates);\nEND;\n$$;\nCOMMENT ON FUNCTION public.plugbank_import_movements(p_payload jsonb) IS\n 'Import bank-statement lines into the financial ledger and file the run in public.sync_runs. The tenant AND the bank account come from the public.connections row named by integration_id, never from the payload.';\n`\n\nexport const MIGRATIONS: Array<{ id: string; sql: string }> = [\n { id: \"000_baseline\", sql: MIGRATION_000_BASELINE },\n { id: \"001_the_import_rpc_names_real_tables\", sql: MIGRATION_001_THE_IMPORT_RPC_NAMES_REAL_TABLES },\n]\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fayz-ai/plugin-banking-br",
3
- "version": "0.10.41",
3
+ "version": "0.10.43",
4
4
  "description": "[experimental] Fayz SDK — Brazilian open-banking connector (Tecnospeed PlugBank) feeding the financial ledger",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -17,6 +17,12 @@
17
17
  "require": "./dist/schema.cjs"
18
18
  }
19
19
  },
20
+ "imports": {
21
+ "#migrations/*": {
22
+ "browser": "./dist/migrations/*.browser.js",
23
+ "default": "./dist/migrations/*.js"
24
+ }
25
+ },
20
26
  "files": [
21
27
  "dist"
22
28
  ],
@@ -25,9 +31,9 @@
25
31
  "react-dom": "^18.0.0 || ^19.0.0"
26
32
  },
27
33
  "dependencies": {
28
- "@fayz-ai/core": "^0.59.0",
34
+ "@fayz-ai/core": "^0.63.0",
29
35
  "@fayz-ai/db": "^0.24.3",
30
- "@fayz-ai/ui": "^0.60.0"
36
+ "@fayz-ai/ui": "^0.63.0"
31
37
  },
32
38
  "devDependencies": {
33
39
  "@types/react": "^18.3.0",