@fayz-ai/plugin-banking-br 0.9.1

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Faya Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # @fayz-ai/plugin-banking-br
2
+
3
+ Brazilian open-banking connector. Syncs a bank statement into the SDK financial
4
+ ledger and drives **reconciliation (conciliação)**. Provider: **Tecnospeed PlugBank**.
5
+
6
+ Graduated from the app-local incubator, where it lived duplicated byte for byte
7
+ in `beauty-saas` and `agency-os`. Further provider drivers (Inter, Belvo, Pluggy)
8
+ go behind the same connector shape.
9
+
10
+ ## Install
11
+
12
+ ```ts
13
+ import { createFinancialPlugin } from '@fayz-ai/plugin-financial'
14
+ import { createOpenBankingPlugin } from '@fayz-ai/plugin-banking-br'
15
+
16
+ plugins: [
17
+ createFinancialPlugin({ modules: { reconciliation: true } }),
18
+ createOpenBankingPlugin(),
19
+ ]
20
+ ```
21
+
22
+ Addon scope: it contributes a connector into its host (`plugin-financial`) and
23
+ surfaces under **Financial → settings → Integrations**. No left-nav entry of its own.
24
+
25
+ ## What it owns
26
+ - **DB**: `public.bank_integrations` (connection + credentials) and
27
+ `public.bank_integration_sync_log` (run audit). See `src/schema/` + `src/migrations/`.
28
+ - **Edge function** (deployed by the app): `supabase/functions/plugbank-sync` — calls
29
+ the PlugBank API, normalizes lines, imports into `public.plg_financial_movements`
30
+ tagged `external_source='plugbank'` (idempotent via the financial
31
+ `uq_financial_movements_external` index).
32
+ - **UI**: connect/test/save, fetch a statement, import selected lines, view history.
33
+
34
+ ## How it composes with the SDK
35
+ - Depends on `@fayz-ai/plugin-financial`. Imported lines are reconciled in
36
+ **Financial → Conciliação**, which is the SDK `ReconciliationView` enabled via
37
+ `createFinancialPlugin({ modules: { reconciliation: true } })`.
38
+ - The matching model + columns (`external_id`, `external_source`, `reconciled_at`,
39
+ `matched_movement_id`) live in the SDK financial migration `007_reconciliation.sql`.
40
+
41
+ ## Deploy
42
+ 1. Apply the SDK financial migration `007_reconciliation.sql` and this plugin's
43
+ `src/migrations/001_openbanking.sql`.
44
+ 2. `supabase functions deploy plugbank-sync` with secrets
45
+ `PLUGBANK_BASE_URL`, plus the standard `SUPABASE_URL` / `SUPABASE_SERVICE_ROLE_KEY`.
46
+ 3. Register `createOpenBankingPlugin()` in the app config and enable the
47
+ financial `reconciliation` module.
48
+ 4. (Optional, "runs in backend") schedule a daily `import_transactions` via
49
+ `pg_cron` + `pg_net` to the function for hands-off sync.
@@ -0,0 +1,3 @@
1
+ import type { ConnectorDefinition } from '@fayz-ai/core';
2
+ export declare const openBankingConnector: ConnectorDefinition;
3
+ //# sourceMappingURL=connectorDef.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connectorDef.d.ts","sourceRoot":"","sources":["../../src/connectors/connectorDef.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAoHxD,eAAO,MAAM,oBAAoB,EAAE,mBAkBlC,CAAA"}
@@ -0,0 +1,25 @@
1
+ import type { BankIntegration, SaveIntegrationInput, SyncLogEntry, TestConnectionResult, FetchStatementResult, ImportResult, BankLine } from '../types';
2
+ export interface OpenBankingProvider {
3
+ getIntegration(bankAccountId?: string): Promise<BankIntegration | null>;
4
+ saveIntegration(input: SaveIntegrationInput): Promise<BankIntegration>;
5
+ testConnection(input: {
6
+ apiToken: string;
7
+ cnpj: string;
8
+ environment?: string;
9
+ }): Promise<TestConnectionResult>;
10
+ fetchStatement(input: {
11
+ integrationId: string;
12
+ from: string;
13
+ to: string;
14
+ }): Promise<FetchStatementResult>;
15
+ importTransactions(input: {
16
+ integrationId: string;
17
+ bankAccountId?: string;
18
+ from: string;
19
+ to: string;
20
+ lines: BankLine[];
21
+ }): Promise<ImportResult>;
22
+ getSyncLog(integrationId: string): Promise<SyncLogEntry[]>;
23
+ }
24
+ export declare function createOpenBankingProvider(): OpenBankingProvider;
25
+ //# sourceMappingURL=supabase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supabase.d.ts","sourceRoot":"","sources":["../../src/data/supabase.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,eAAe,EAAE,oBAAoB,EAAE,YAAY,EACnD,oBAAoB,EAAE,oBAAoB,EAAE,YAAY,EAAE,QAAQ,EACnE,MAAM,UAAU,CAAA;AAuBjB,MAAM,WAAW,mBAAmB;IAClC,cAAc,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAA;IACvE,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IACtE,cAAc,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAA;IAC9G,cAAc,CAAC,KAAK,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAA;IACzG,kBAAkB,CAAC,KAAK,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,QAAQ,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IAChJ,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAA;CAC3D;AAED,wBAAgB,yBAAyB,IAAI,mBAAmB,CAwF/D"}
@@ -0,0 +1,7 @@
1
+ import type { PluginManifest } from '@fayz-ai/core';
2
+ export { createOpenBankingProvider } from './data/supabase';
3
+ export { openBankingConnector } from './connectors/connectorDef';
4
+ export * from './schema';
5
+ export * from './types';
6
+ export declare function createOpenBankingPlugin(): PluginManifest;
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAGnD,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAA;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAChE,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AAKvB,wBAAgB,uBAAuB,IAAI,cAAc,CAaxD"}
package/dist/index.js ADDED
@@ -0,0 +1,309 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { Download, Loader2, History, CheckCircle2, AlertCircle } from 'lucide-react';
3
+ import { DatePicker, Button, toast } from '@fayz-ai/ui';
4
+ import { getActiveTenantId, getSupabaseClientOptional } from '@fayz-ai/core';
5
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
+ import { pgTable, timestamps, timestamp, boolean, text, uuid, tenantId, createdAt, integer, date } from '@fayz-ai/db';
7
+
8
+ // src/connectors/connectorDef.tsx
9
+ var FUNCTION = "plugbank-sync";
10
+ function sb() {
11
+ const supabase = getSupabaseClientOptional();
12
+ if (!supabase) throw new Error("Supabase not initialized");
13
+ return supabase;
14
+ }
15
+ function rowToIntegration(r) {
16
+ return {
17
+ id: r.id,
18
+ provider: r.provider,
19
+ bankAccountId: r.bank_account_id ?? void 0,
20
+ apiToken: r.api_token ?? void 0,
21
+ cnpj: r.cnpj ?? void 0,
22
+ environment: r.environment ?? "production",
23
+ active: r.active ?? true,
24
+ lastSyncAt: r.last_sync_at ?? void 0
25
+ };
26
+ }
27
+ function createOpenBankingProvider() {
28
+ return {
29
+ async getIntegration(bankAccountId) {
30
+ const supabase = sb();
31
+ let qb = supabase.from("bank_integrations").select("*").eq("provider", "plugbank");
32
+ qb = bankAccountId ? qb.eq("bank_account_id", bankAccountId) : qb.is("bank_account_id", null);
33
+ const { data } = await qb.limit(1).maybeSingle();
34
+ return data ? rowToIntegration(data) : null;
35
+ },
36
+ async saveIntegration(input) {
37
+ const supabase = sb();
38
+ const tenantId2 = getActiveTenantId();
39
+ const row = {
40
+ tenant_id: tenantId2,
41
+ provider: "plugbank",
42
+ bank_account_id: input.bankAccountId ?? null,
43
+ api_token: input.apiToken,
44
+ cnpj: input.cnpj,
45
+ environment: input.environment ?? "production",
46
+ active: true,
47
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
48
+ };
49
+ const { data, error } = await supabase.from("bank_integrations").upsert(input.id ? { id: input.id, ...row } : row, { onConflict: "tenant_id,bank_account_id,provider" }).select().single();
50
+ if (error) throw error;
51
+ return rowToIntegration(data);
52
+ },
53
+ async testConnection(input) {
54
+ const supabase = sb();
55
+ const { data, error } = await supabase.functions.invoke(FUNCTION, {
56
+ body: { action: "test_connection", apiToken: input.apiToken, cnpj: input.cnpj, environment: input.environment ?? "production" }
57
+ });
58
+ if (error) return { ok: false, message: error.message };
59
+ return data;
60
+ },
61
+ async fetchStatement(input) {
62
+ const supabase = sb();
63
+ const { data, error } = await supabase.functions.invoke(FUNCTION, {
64
+ body: { action: "fetch_statement", integrationId: input.integrationId, from: input.from, to: input.to }
65
+ });
66
+ if (error) throw new Error(error.message);
67
+ return data;
68
+ },
69
+ async importTransactions(input) {
70
+ const supabase = sb();
71
+ const { data, error } = await supabase.functions.invoke(FUNCTION, {
72
+ body: {
73
+ action: "import_transactions",
74
+ integrationId: input.integrationId,
75
+ bankAccountId: input.bankAccountId,
76
+ from: input.from,
77
+ to: input.to,
78
+ lines: input.lines
79
+ }
80
+ });
81
+ if (error) throw new Error(error.message);
82
+ return data;
83
+ },
84
+ async getSyncLog(integrationId) {
85
+ const supabase = sb();
86
+ const { data } = await supabase.from("bank_integration_sync_log").select("*").eq("bank_integration_id", integrationId).order("created_at", { ascending: false }).limit(20);
87
+ return (data ?? []).map((r) => ({
88
+ id: r.id,
89
+ periodFrom: r.period_from ?? void 0,
90
+ periodTo: r.period_to ?? void 0,
91
+ transactionsFetched: r.transactions_fetched ?? 0,
92
+ transactionsImported: r.transactions_imported ?? 0,
93
+ duplicates: r.duplicates ?? 0,
94
+ status: r.status,
95
+ errorMessage: r.error_message ?? void 0,
96
+ createdAt: r.created_at
97
+ }));
98
+ }
99
+ };
100
+ }
101
+ var provider = createOpenBankingProvider();
102
+ function brl(n) {
103
+ try {
104
+ return new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(n);
105
+ } catch {
106
+ return `R$ ${n.toFixed(2)}`;
107
+ }
108
+ }
109
+ function OpenBankingExtraPanel() {
110
+ const [integration, setIntegration] = useState(null);
111
+ const [loaded, setLoaded] = useState(false);
112
+ const [from, setFrom] = useState(() => {
113
+ const d = /* @__PURE__ */ new Date();
114
+ d.setDate(d.getDate() - 30);
115
+ return d.toISOString().slice(0, 10);
116
+ });
117
+ const [to, setTo] = useState(() => (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
118
+ const [lines, setLines] = useState([]);
119
+ const [selected, setSelected] = useState(/* @__PURE__ */ new Set());
120
+ const [fetching, setFetching] = useState(false);
121
+ const [importing, setImporting] = useState(false);
122
+ const [log, setLog] = useState([]);
123
+ async function load() {
124
+ const found = await provider.getIntegration();
125
+ setIntegration(found);
126
+ if (found) void provider.getSyncLog(found.id).then(setLog);
127
+ setLoaded(true);
128
+ }
129
+ useEffect(() => {
130
+ void load();
131
+ }, []);
132
+ if (!loaded || !integration) return null;
133
+ async function handleFetch() {
134
+ if (!integration) return;
135
+ setFetching(true);
136
+ try {
137
+ const res = await provider.fetchStatement({ integrationId: integration.id, from, to });
138
+ setLines(res.lines);
139
+ setSelected(new Set(res.lines.map((l) => l.externalId)));
140
+ } catch (e) {
141
+ toast.error(e?.message ?? "Erro ao buscar extrato");
142
+ } finally {
143
+ setFetching(false);
144
+ }
145
+ }
146
+ async function handleImport() {
147
+ if (!integration) return;
148
+ const toImport = lines.filter((l) => selected.has(l.externalId));
149
+ if (toImport.length === 0) {
150
+ toast.error("Selecione ao menos uma linha");
151
+ return;
152
+ }
153
+ setImporting(true);
154
+ try {
155
+ const res = await provider.importTransactions({ integrationId: integration.id, from, to, lines: toImport });
156
+ toast.success(`${res.imported} importadas${res.duplicates ? ` \xB7 ${res.duplicates} duplicadas` : ""}`);
157
+ setLines([]);
158
+ setSelected(/* @__PURE__ */ new Set());
159
+ void provider.getSyncLog(integration.id).then(setLog);
160
+ } catch (e) {
161
+ toast.error(e?.message ?? "Erro ao importar");
162
+ } finally {
163
+ setImporting(false);
164
+ }
165
+ }
166
+ function toggle(id) {
167
+ setSelected((prev) => {
168
+ const next = new Set(prev);
169
+ next.has(id) ? next.delete(id) : next.add(id);
170
+ return next;
171
+ });
172
+ }
173
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4 border-t pt-4", children: [
174
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
175
+ /* @__PURE__ */ jsx(Download, { className: "h-4 w-4 text-muted-foreground" }),
176
+ /* @__PURE__ */ jsx("h4", { className: "text-sm font-semibold", children: "Importar extrato" })
177
+ ] }),
178
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-end gap-3", children: [
179
+ /* @__PURE__ */ jsxs("div", { children: [
180
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "De" }),
181
+ /* @__PURE__ */ jsx(DatePicker, { value: from, onChange: setFrom, className: "mt-1" })
182
+ ] }),
183
+ /* @__PURE__ */ jsxs("div", { children: [
184
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "At\xE9" }),
185
+ /* @__PURE__ */ jsx(DatePicker, { value: to, onChange: setTo, className: "mt-1" })
186
+ ] }),
187
+ /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: handleFetch, disabled: fetching, children: [
188
+ fetching ? /* @__PURE__ */ jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx(Download, { className: "h-3.5 w-3.5" }),
189
+ " Buscar extrato"
190
+ ] })
191
+ ] }),
192
+ lines.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
193
+ /* @__PURE__ */ jsx("div", { className: "rounded-md border divide-y max-h-72 overflow-auto", children: lines.map((l) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-3 px-3 py-2 text-sm cursor-pointer hover:bg-muted/30", children: [
194
+ /* @__PURE__ */ jsx("input", { type: "checkbox", checked: selected.has(l.externalId), onChange: () => toggle(l.externalId) }),
195
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs w-20 shrink-0", children: l.date }),
196
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: l.description }),
197
+ /* @__PURE__ */ jsxs("span", { className: `font-semibold shrink-0 ${l.type === "C" ? "text-success" : "text-destructive"}`, children: [
198
+ l.type === "C" ? "+" : "-",
199
+ brl(l.amount)
200
+ ] })
201
+ ] }, l.externalId)) }),
202
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
203
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
204
+ selected.size,
205
+ " de ",
206
+ lines.length,
207
+ " selecionadas"
208
+ ] }),
209
+ /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: handleImport, disabled: importing || selected.size === 0, children: [
210
+ importing ? /* @__PURE__ */ jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx(Download, { className: "h-3.5 w-3.5" }),
211
+ " Importar selecionadas"
212
+ ] })
213
+ ] })
214
+ ] }),
215
+ log.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
216
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
217
+ /* @__PURE__ */ jsx(History, { className: "h-4 w-4 text-muted-foreground" }),
218
+ /* @__PURE__ */ jsx("h4", { className: "text-sm font-semibold", children: "Hist\xF3rico" })
219
+ ] }),
220
+ /* @__PURE__ */ jsx("div", { className: "rounded-md border divide-y text-sm", children: log.map((r) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-3 py-2", children: [
221
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: new Date(r.createdAt).toLocaleString("pt-BR") }),
222
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
223
+ r.periodFrom,
224
+ " \u2192 ",
225
+ r.periodTo
226
+ ] }),
227
+ /* @__PURE__ */ jsxs("span", { className: "ml-auto text-xs", children: [
228
+ r.transactionsImported,
229
+ "/",
230
+ r.transactionsFetched,
231
+ " importadas",
232
+ r.duplicates ? ` \xB7 ${r.duplicates} dup` : ""
233
+ ] }),
234
+ r.status === "success" ? /* @__PURE__ */ jsx(CheckCircle2, { className: "h-3.5 w-3.5 text-success" }) : /* @__PURE__ */ jsx(AlertCircle, { className: "h-3.5 w-3.5 text-warning" })
235
+ ] }, r.id)) })
236
+ ] })
237
+ ] });
238
+ }
239
+ var openBankingConnector = {
240
+ id: "plugbank",
241
+ hostPluginId: "financial",
242
+ name: "Open Banking \xB7 Tecnospeed PlugBank",
243
+ description: "Importe o extrato banc\xE1rio e concilie em Financeiro \u2192 Concilia\xE7\xE3o.",
244
+ icon: "Landmark",
245
+ authKind: "api-key",
246
+ fields: [
247
+ { key: "cnpj", label: "CNPJ", type: "text", placeholder: "00.000.000/0001-00" },
248
+ { key: "apiToken", label: "Token API PlugBank", type: "password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" }
249
+ ],
250
+ async getStatus() {
251
+ const found = await provider.getIntegration();
252
+ return { connected: !!found?.apiToken };
253
+ },
254
+ testConnection: (values) => provider.testConnection({ apiToken: values.apiToken, cnpj: values.cnpj }),
255
+ saveConnection: async (values) => {
256
+ await provider.saveIntegration({ apiToken: values.apiToken, cnpj: values.cnpj });
257
+ },
258
+ ExtraPanel: OpenBankingExtraPanel
259
+ };
260
+ var bankIntegrations = pgTable("bank_integrations", {
261
+ id: uuid("id").primaryKey().defaultRandom(),
262
+ tenantId: tenantId(),
263
+ provider: text("provider").notNull().default("plugbank"),
264
+ bankAccountId: uuid("bank_account_id"),
265
+ // Tecnospeed PlugBank credentials
266
+ apiToken: text("api_token"),
267
+ cnpj: text("cnpj"),
268
+ environment: text("environment").notNull().default("production"),
269
+ // production | sandbox
270
+ active: boolean("active").notNull().default(true),
271
+ lastSyncAt: timestamp("last_sync_at", { withTimezone: true }),
272
+ ...timestamps
273
+ });
274
+ var bankIntegrationSyncLog = pgTable("bank_integration_sync_log", {
275
+ id: uuid("id").primaryKey().defaultRandom(),
276
+ tenantId: tenantId(),
277
+ bankIntegrationId: uuid("bank_integration_id").notNull().references(() => bankIntegrations.id, { onDelete: "cascade" }),
278
+ bankAccountId: uuid("bank_account_id"),
279
+ periodFrom: date("period_from"),
280
+ periodTo: date("period_to"),
281
+ transactionsFetched: integer("transactions_fetched").notNull().default(0),
282
+ transactionsImported: integer("transactions_imported").notNull().default(0),
283
+ duplicates: integer("duplicates").notNull().default(0),
284
+ status: text("status").notNull().default("success"),
285
+ // success | partial | error
286
+ errorMessage: text("error_message"),
287
+ triggeredByUserId: uuid("triggered_by_user_id"),
288
+ ...createdAt
289
+ });
290
+
291
+ // src/index.ts
292
+ function createOpenBankingPlugin() {
293
+ return {
294
+ id: "openbanking",
295
+ name: "Open Banking",
296
+ icon: "Landmark",
297
+ version: "0.1.0",
298
+ scope: "addon",
299
+ defaultEnabled: true,
300
+ dependencies: ["financial"],
301
+ navigation: [],
302
+ routes: [],
303
+ connectors: [openBankingConnector]
304
+ };
305
+ }
306
+
307
+ export { bankIntegrationSyncLog, bankIntegrations, createOpenBankingPlugin, createOpenBankingProvider, openBankingConnector };
308
+ //# sourceMappingURL=index.js.map
309
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/data/supabase.ts","../src/connectors/connectorDef.tsx","../src/schema/index.ts","../src/index.ts"],"names":["tenantId"],"mappings":"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","file":"index.js","sourcesContent":["// Open Banking plugin (app-local) — Supabase data provider.\n//\n// Thin control-plane client. The heavy lifting (calling the Tecnospeed PlugBank\n// API, normalizing lines, importing into plg_financial_movements with idempotency)\n// runs in the `plugbank-sync` Edge Function. This provider reads/writes the\n// connection row, invokes the function, and reads the sync log.\n//\n// On graduation this file moves to the SDK banking plugin largely unchanged.\nimport { getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core'\nimport type {\n BankIntegration, SaveIntegrationInput, SyncLogEntry,\n TestConnectionResult, FetchStatementResult, ImportResult, BankLine,\n} from '../types'\n\nconst FUNCTION = 'plugbank-sync'\n\nfunction sb() {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) throw new Error('Supabase not initialized')\n return supabase\n}\n\nfunction rowToIntegration(r: any): BankIntegration {\n return {\n id: r.id,\n provider: r.provider,\n bankAccountId: r.bank_account_id ?? undefined,\n apiToken: r.api_token ?? undefined,\n cnpj: r.cnpj ?? undefined,\n environment: r.environment ?? 'production',\n active: r.active ?? true,\n lastSyncAt: r.last_sync_at ?? undefined,\n }\n}\n\nexport interface OpenBankingProvider {\n getIntegration(bankAccountId?: string): Promise<BankIntegration | null>\n saveIntegration(input: SaveIntegrationInput): Promise<BankIntegration>\n testConnection(input: { apiToken: string; cnpj: string; environment?: string }): Promise<TestConnectionResult>\n fetchStatement(input: { integrationId: string; from: string; to: string }): Promise<FetchStatementResult>\n importTransactions(input: { integrationId: string; bankAccountId?: string; from: string; to: string; lines: BankLine[] }): Promise<ImportResult>\n getSyncLog(integrationId: string): Promise<SyncLogEntry[]>\n}\n\nexport function createOpenBankingProvider(): OpenBankingProvider {\n return {\n async getIntegration(bankAccountId) {\n const supabase = sb()\n let qb = supabase.from('bank_integrations').select('*').eq('provider', 'plugbank')\n qb = bankAccountId ? qb.eq('bank_account_id', bankAccountId) : qb.is('bank_account_id', null)\n const { data } = await qb.limit(1).maybeSingle()\n return data ? rowToIntegration(data) : null\n },\n\n async saveIntegration(input) {\n const supabase = sb()\n const tenantId = getActiveTenantId()\n const row = {\n tenant_id: tenantId,\n provider: 'plugbank',\n bank_account_id: input.bankAccountId ?? null,\n api_token: input.apiToken,\n cnpj: input.cnpj,\n environment: input.environment ?? 'production',\n active: true,\n updated_at: new Date().toISOString(),\n }\n // Upsert on the unique (tenant_id, bank_account_id, provider) key.\n const { data, error } = await supabase\n .from('bank_integrations')\n .upsert(input.id ? { id: input.id, ...row } : row, { onConflict: 'tenant_id,bank_account_id,provider' })\n .select()\n .single()\n if (error) throw error\n return rowToIntegration(data)\n },\n\n async testConnection(input) {\n const supabase = sb()\n const { data, error } = await supabase.functions.invoke(FUNCTION, {\n body: { action: 'test_connection', apiToken: input.apiToken, cnpj: input.cnpj, environment: input.environment ?? 'production' },\n })\n if (error) return { ok: false, message: error.message }\n return data as TestConnectionResult\n },\n\n async fetchStatement(input) {\n const supabase = sb()\n const { data, error } = await supabase.functions.invoke(FUNCTION, {\n body: { action: 'fetch_statement', integrationId: input.integrationId, from: input.from, to: input.to },\n })\n if (error) throw new Error(error.message)\n return data as FetchStatementResult\n },\n\n async importTransactions(input) {\n const supabase = sb()\n const { data, error } = await supabase.functions.invoke(FUNCTION, {\n body: {\n action: 'import_transactions',\n integrationId: input.integrationId,\n bankAccountId: input.bankAccountId,\n from: input.from,\n to: input.to,\n lines: input.lines,\n },\n })\n if (error) throw new Error(error.message)\n return data as ImportResult\n },\n\n async getSyncLog(integrationId) {\n const supabase = sb()\n const { data } = await supabase\n .from('bank_integration_sync_log')\n .select('*')\n .eq('bank_integration_id', integrationId)\n .order('created_at', { ascending: false })\n .limit(20)\n return (data ?? []).map((r: any) => ({\n id: r.id,\n periodFrom: r.period_from ?? undefined,\n periodTo: r.period_to ?? undefined,\n transactionsFetched: r.transactions_fetched ?? 0,\n transactionsImported: r.transactions_imported ?? 0,\n duplicates: r.duplicates ?? 0,\n status: r.status,\n errorMessage: r.error_message ?? undefined,\n createdAt: r.created_at,\n }))\n },\n }\n}\n","// Open Banking (Tecnospeed PlugBank) as a unified ConnectorDefinition.\n//\n// Surfaces inside plugin-financial's settings → Integrations tab (the host),\n// rendered by the shared ConnectorsHub. The hub handles the credentials form\n// (CNPJ / Token) + Test / Save; the ExtraPanel below adds the statement import\n// + sync history (only meaningful once the connection is saved).\nimport React, { useEffect, useState } from 'react'\nimport { Download, History, CheckCircle2, AlertCircle, Loader2 } from 'lucide-react'\nimport { Button, DatePicker, toast } from '@fayz-ai/ui'\nimport type { ConnectorDefinition } from '@fayz-ai/core'\nimport { createOpenBankingProvider } from '../data/supabase'\nimport type { BankIntegration, BankLine, SyncLogEntry } from '../types'\n\nconst provider = createOpenBankingProvider()\n\nfunction brl(n: number): string {\n try { return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(n) }\n catch { return `R$ ${n.toFixed(2)}` }\n}\n\nfunction OpenBankingExtraPanel() {\n const [integration, setIntegration] = useState<BankIntegration | null>(null)\n const [loaded, setLoaded] = useState(false)\n const [from, setFrom] = useState(() => { const d = new Date(); d.setDate(d.getDate() - 30); return d.toISOString().slice(0, 10) })\n const [to, setTo] = useState(() => new Date().toISOString().slice(0, 10))\n const [lines, setLines] = useState<BankLine[]>([])\n const [selected, setSelected] = useState<Set<string>>(new Set())\n const [fetching, setFetching] = useState(false)\n const [importing, setImporting] = useState(false)\n const [log, setLog] = useState<SyncLogEntry[]>([])\n\n async function load() {\n const found = await provider.getIntegration()\n setIntegration(found)\n if (found) void provider.getSyncLog(found.id).then(setLog)\n setLoaded(true)\n }\n useEffect(() => { void load() }, [])\n\n if (!loaded || !integration) return null // nothing to import until the connection is saved\n\n async function handleFetch() {\n if (!integration) return\n setFetching(true)\n try {\n const res = await provider.fetchStatement({ integrationId: integration.id, from, to })\n setLines(res.lines)\n setSelected(new Set(res.lines.map((l) => l.externalId)))\n } catch (e: any) { toast.error(e?.message ?? 'Erro ao buscar extrato') }\n finally { setFetching(false) }\n }\n\n async function handleImport() {\n if (!integration) return\n const toImport = lines.filter((l) => selected.has(l.externalId))\n if (toImport.length === 0) { toast.error('Selecione ao menos uma linha'); return }\n setImporting(true)\n try {\n const res = await provider.importTransactions({ integrationId: integration.id, from, to, lines: toImport })\n toast.success(`${res.imported} importadas${res.duplicates ? ` · ${res.duplicates} duplicadas` : ''}`)\n setLines([]); setSelected(new Set())\n void provider.getSyncLog(integration.id).then(setLog)\n } catch (e: any) { toast.error(e?.message ?? 'Erro ao importar') }\n finally { setImporting(false) }\n }\n\n function toggle(id: string) {\n setSelected((prev) => { const next = new Set(prev); next.has(id) ? next.delete(id) : next.add(id); return next })\n }\n\n return (\n <div className=\"space-y-4 border-t pt-4\">\n <div className=\"flex items-center gap-2\"><Download className=\"h-4 w-4 text-muted-foreground\" /><h4 className=\"text-sm font-semibold\">Importar extrato</h4></div>\n <div className=\"flex flex-wrap items-end gap-3\">\n <div><span className=\"text-xs font-medium text-muted-foreground\">De</span><DatePicker value={from} onChange={setFrom} className=\"mt-1\" /></div>\n <div><span className=\"text-xs font-medium text-muted-foreground\">Até</span><DatePicker value={to} onChange={setTo} className=\"mt-1\" /></div>\n <Button variant=\"outline\" size=\"sm\" onClick={handleFetch} disabled={fetching}>\n {fetching ? <Loader2 className=\"h-3.5 w-3.5 animate-spin\" /> : <Download className=\"h-3.5 w-3.5\" />} Buscar extrato\n </Button>\n </div>\n\n {lines.length > 0 && (\n <>\n <div className=\"rounded-md border divide-y max-h-72 overflow-auto\">\n {lines.map((l) => (\n <label key={l.externalId} className=\"flex items-center gap-3 px-3 py-2 text-sm cursor-pointer hover:bg-muted/30\">\n <input type=\"checkbox\" checked={selected.has(l.externalId)} onChange={() => toggle(l.externalId)} />\n <span className=\"text-muted-foreground text-xs w-20 shrink-0\">{l.date}</span>\n <span className=\"flex-1 truncate\">{l.description}</span>\n <span className={`font-semibold shrink-0 ${l.type === 'C' ? 'text-success' : 'text-destructive'}`}>\n {l.type === 'C' ? '+' : '-'}{brl(l.amount)}\n </span>\n </label>\n ))}\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-muted-foreground\">{selected.size} de {lines.length} selecionadas</span>\n <Button size=\"sm\" onClick={handleImport} disabled={importing || selected.size === 0}>\n {importing ? <Loader2 className=\"h-3.5 w-3.5 animate-spin\" /> : <Download className=\"h-3.5 w-3.5\" />} Importar selecionadas\n </Button>\n </div>\n </>\n )}\n\n {log.length > 0 && (\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-2\"><History className=\"h-4 w-4 text-muted-foreground\" /><h4 className=\"text-sm font-semibold\">Histórico</h4></div>\n <div className=\"rounded-md border divide-y text-sm\">\n {log.map((r) => (\n <div key={r.id} className=\"flex items-center gap-3 px-3 py-2\">\n <span className=\"text-muted-foreground text-xs\">{new Date(r.createdAt).toLocaleString('pt-BR')}</span>\n <span className=\"text-xs text-muted-foreground\">{r.periodFrom} → {r.periodTo}</span>\n <span className=\"ml-auto text-xs\">{r.transactionsImported}/{r.transactionsFetched} importadas{r.duplicates ? ` · ${r.duplicates} dup` : ''}</span>\n {r.status === 'success'\n ? <CheckCircle2 className=\"h-3.5 w-3.5 text-success\" />\n : <AlertCircle className=\"h-3.5 w-3.5 text-warning\" />}\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport const openBankingConnector: ConnectorDefinition = {\n id: 'plugbank',\n hostPluginId: 'financial',\n name: 'Open Banking · Tecnospeed PlugBank',\n description: 'Importe o extrato bancário e concilie em Financeiro → Conciliação.',\n icon: 'Landmark',\n authKind: 'api-key',\n fields: [\n { key: 'cnpj', label: 'CNPJ', type: 'text', placeholder: '00.000.000/0001-00' },\n { key: 'apiToken', label: 'Token API PlugBank', type: 'password', placeholder: '••••••••' },\n ],\n async getStatus() {\n const found = await provider.getIntegration()\n return { connected: !!found?.apiToken }\n },\n testConnection: (values) => provider.testConnection({ apiToken: values.apiToken, cnpj: values.cnpj }),\n saveConnection: async (values) => { await provider.saveIntegration({ apiToken: values.apiToken, cnpj: values.cnpj }) },\n ExtraPanel: OpenBankingExtraPanel,\n}\n","// Open Banking plugin (app-local incubator) — Ring-1 Drizzle schema.\n//\n// CLIENT-OWNED connector that follows the SDK plugin contract. It owns the bank\n// connection + sync-audit tables and a Supabase Edge Function (plugbank-sync)\n// that imports bank-statement lines into the SDK financial ledger\n// (public.plg_financial_movements, tagged external_source='plugbank'). The matching\n// happens in the SDK financial plugin's Reconciliation view.\n//\n// Graduation path (see PLUGIN.md): move this folder to\n// `fayz-sdk/plugins/plugin-banking-br/src/` largely unchanged.\n//\n// Builders come from @fayz-ai/admin/db (front-door re-export of @fayz-ai/db —\n// single drizzle-orm instance). NEVER import pgTable/uuid from drizzle-orm/pg-core directly.\nimport { pgTable, uuid, text, integer, boolean, timestamp, date, tenantId, timestamps, createdAt } from '@fayz-ai/db'\n\n// bank_integrations — one connection per (tenant, bank account, provider).\n// Holds the provider credentials (Tecnospeed PlugBank: api_token + cnpj). Server\n// secrets that must never reach the browser live in Supabase function env; this\n// row stores the per-tenant config + token that the edge function reads with the\n// service role.\nexport const bankIntegrations = pgTable('bank_integrations', {\n id: uuid('id').primaryKey().defaultRandom(),\n tenantId: tenantId(),\n provider: text('provider').notNull().default('plugbank'),\n bankAccountId: uuid('bank_account_id'),\n // Tecnospeed PlugBank credentials\n apiToken: text('api_token'),\n cnpj: text('cnpj'),\n environment: text('environment').notNull().default('production'), // production | sandbox\n active: boolean('active').notNull().default(true),\n lastSyncAt: timestamp('last_sync_at', { withTimezone: true }),\n ...timestamps,\n})\n\n// bank_integration_sync_log — one row per sync run (audit trail).\nexport const bankIntegrationSyncLog = pgTable('bank_integration_sync_log', {\n id: uuid('id').primaryKey().defaultRandom(),\n tenantId: tenantId(),\n bankIntegrationId: uuid('bank_integration_id').notNull().references(() => bankIntegrations.id, { onDelete: 'cascade' }),\n bankAccountId: uuid('bank_account_id'),\n periodFrom: date('period_from'),\n periodTo: date('period_to'),\n transactionsFetched: integer('transactions_fetched').notNull().default(0),\n transactionsImported: integer('transactions_imported').notNull().default(0),\n duplicates: integer('duplicates').notNull().default(0),\n status: text('status').notNull().default('success'), // success | partial | error\n errorMessage: text('error_message'),\n triggeredByUserId: uuid('triggered_by_user_id'),\n ...createdAt,\n})\n","// Open Banking plugin (app-local incubator) — public surface + manifest.\n//\n// CLIENT-OWNED connector following the SDK plugin contract. Settings-only\n// (no left-nav page): contributes an \"Open Banking\" tab to /settings for\n// connecting Tecnospeed PlugBank and importing the bank statement. Imported\n// lines land in the SDK financial ledger and are reconciled in\n// Financial → Conciliação (enable the financial `reconciliation` module).\n//\n// Graduation path (PLUGIN.md): move to fayz-sdk/plugins/plugin-banking-br.\nimport type { PluginManifest } from '@fayz-ai/core'\nimport { openBankingConnector } from './connectors/connectorDef'\n\nexport { createOpenBankingProvider } from './data/supabase'\nexport { openBankingConnector } from './connectors/connectorDef'\nexport * from './schema'\nexport * from './types'\n\n// Addon plugin: contributes the PlugBank connector into its host\n// (plugin-financial). It appears in Financial settings → Integrations — no\n// top-level settings tab of its own.\nexport function createOpenBankingPlugin(): PluginManifest {\n return {\n id: 'openbanking',\n name: 'Open Banking',\n icon: 'Landmark',\n version: '0.1.0',\n scope: 'addon',\n defaultEnabled: true,\n dependencies: ['financial'],\n navigation: [],\n routes: [],\n connectors: [openBankingConnector],\n }\n}\n"]}
@@ -0,0 +1,6 @@
1
+ export declare const MIGRATION_001_OPENBANKING = "-- Open Banking plugin (app-local) \u2014 companion SQL: tables + RLS + grants.\n-- Idempotent (safe to re-run). Mirrors the Drizzle schema in ../schema/index.ts.\n-- The bank-statement reconciliation columns on public.plg_financial_movements come\n-- from the SDK financial plugin migration 007_reconciliation.sql \u2014 apply that too.\n\nCREATE TABLE IF NOT EXISTS public.bank_integrations (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n provider text NOT NULL DEFAULT 'plugbank',\n bank_account_id uuid,\n api_token text,\n cnpj text,\n environment text NOT NULL DEFAULT 'production',\n active boolean NOT NULL DEFAULT true,\n last_sync_at timestamptz,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (tenant_id, bank_account_id, provider)\n);\nCREATE INDEX IF NOT EXISTS idx_bank_integrations_tenant ON public.bank_integrations(tenant_id);\n\nCREATE TABLE IF NOT EXISTS public.bank_integration_sync_log (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n bank_integration_id uuid NOT NULL REFERENCES public.bank_integrations(id) ON DELETE CASCADE,\n bank_account_id uuid,\n period_from date,\n period_to date,\n transactions_fetched integer NOT NULL DEFAULT 0,\n transactions_imported integer NOT NULL DEFAULT 0,\n duplicates integer NOT NULL DEFAULT 0,\n status text NOT NULL DEFAULT 'success',\n error_message text,\n triggered_by_user_id uuid,\n created_at timestamptz NOT NULL DEFAULT now()\n);\nCREATE INDEX IF NOT EXISTS idx_bank_sync_log_integration ON public.bank_integration_sync_log(bank_integration_id);\n\n-- RLS: tenant isolation (canonical form: tenant_id IN (SELECT public.user_tenant_ids())).\nDO $$\nDECLARE t text;\nBEGIN\n FOR t IN SELECT unnest(ARRAY['bank_integrations','bank_integration_sync_log'])\n LOOP\n EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', t);\n EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON public.%I TO authenticated', t);\n IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_select') THEN\n EXECUTE format('CREATE POLICY %I ON public.%I FOR SELECT TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()))', t||'_select', t);\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_insert') THEN\n EXECUTE format('CREATE POLICY %I ON public.%I FOR INSERT TO authenticated WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()))', t||'_insert', t);\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_update') THEN\n EXECUTE format('CREATE POLICY %I ON public.%I FOR UPDATE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()))', t||'_update', t);\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_delete') THEN\n EXECUTE format('CREATE POLICY %I ON public.%I FOR DELETE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()))', t||'_delete', t);\n END IF;\n END LOOP;\nEND $$;\n";
2
+ export declare const MIGRATIONS: Array<{
3
+ id: string;
4
+ sql: string;
5
+ }>;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,yBAAyB,6wGA4DrC,CAAA;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAEzD,CAAA"}
@@ -0,0 +1,423 @@
1
+ export declare const bankIntegrations: import("drizzle-orm/pg-core").PgTableWithColumns<{
2
+ name: "bank_integrations";
3
+ schema: undefined;
4
+ columns: {
5
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
6
+ name: "created_at";
7
+ tableName: "bank_integrations";
8
+ dataType: "date";
9
+ columnType: "PgTimestamp";
10
+ data: Date;
11
+ driverParam: string;
12
+ notNull: true;
13
+ hasDefault: true;
14
+ isPrimaryKey: false;
15
+ isAutoincrement: false;
16
+ hasRuntimeDefault: false;
17
+ enumValues: undefined;
18
+ baseColumn: never;
19
+ identity: undefined;
20
+ generated: undefined;
21
+ }, {}, {}>;
22
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
23
+ name: "updated_at";
24
+ tableName: "bank_integrations";
25
+ dataType: "date";
26
+ columnType: "PgTimestamp";
27
+ data: Date;
28
+ driverParam: string;
29
+ notNull: true;
30
+ hasDefault: true;
31
+ isPrimaryKey: false;
32
+ isAutoincrement: false;
33
+ hasRuntimeDefault: false;
34
+ enumValues: undefined;
35
+ baseColumn: never;
36
+ identity: undefined;
37
+ generated: undefined;
38
+ }, {}, {}>;
39
+ id: import("drizzle-orm/pg-core").PgColumn<{
40
+ name: "id";
41
+ tableName: "bank_integrations";
42
+ dataType: "string";
43
+ columnType: "PgUUID";
44
+ data: string;
45
+ driverParam: string;
46
+ notNull: true;
47
+ hasDefault: true;
48
+ isPrimaryKey: true;
49
+ isAutoincrement: false;
50
+ hasRuntimeDefault: false;
51
+ enumValues: undefined;
52
+ baseColumn: never;
53
+ identity: undefined;
54
+ generated: undefined;
55
+ }, {}, {}>;
56
+ tenantId: import("drizzle-orm/pg-core").PgColumn<{
57
+ name: "tenant_id";
58
+ tableName: "bank_integrations";
59
+ dataType: "string";
60
+ columnType: "PgUUID";
61
+ data: string;
62
+ driverParam: string;
63
+ notNull: true;
64
+ hasDefault: false;
65
+ isPrimaryKey: false;
66
+ isAutoincrement: false;
67
+ hasRuntimeDefault: false;
68
+ enumValues: undefined;
69
+ baseColumn: never;
70
+ identity: undefined;
71
+ generated: undefined;
72
+ }, {}, {}>;
73
+ provider: import("drizzle-orm/pg-core").PgColumn<{
74
+ name: "provider";
75
+ tableName: "bank_integrations";
76
+ dataType: "string";
77
+ columnType: "PgText";
78
+ data: string;
79
+ driverParam: string;
80
+ notNull: true;
81
+ hasDefault: true;
82
+ isPrimaryKey: false;
83
+ isAutoincrement: false;
84
+ hasRuntimeDefault: false;
85
+ enumValues: [string, ...string[]];
86
+ baseColumn: never;
87
+ identity: undefined;
88
+ generated: undefined;
89
+ }, {}, {}>;
90
+ bankAccountId: import("drizzle-orm/pg-core").PgColumn<{
91
+ name: "bank_account_id";
92
+ tableName: "bank_integrations";
93
+ dataType: "string";
94
+ columnType: "PgUUID";
95
+ data: string;
96
+ driverParam: string;
97
+ notNull: false;
98
+ hasDefault: false;
99
+ isPrimaryKey: false;
100
+ isAutoincrement: false;
101
+ hasRuntimeDefault: false;
102
+ enumValues: undefined;
103
+ baseColumn: never;
104
+ identity: undefined;
105
+ generated: undefined;
106
+ }, {}, {}>;
107
+ apiToken: import("drizzle-orm/pg-core").PgColumn<{
108
+ name: "api_token";
109
+ tableName: "bank_integrations";
110
+ dataType: "string";
111
+ columnType: "PgText";
112
+ data: string;
113
+ driverParam: string;
114
+ notNull: false;
115
+ hasDefault: false;
116
+ isPrimaryKey: false;
117
+ isAutoincrement: false;
118
+ hasRuntimeDefault: false;
119
+ enumValues: [string, ...string[]];
120
+ baseColumn: never;
121
+ identity: undefined;
122
+ generated: undefined;
123
+ }, {}, {}>;
124
+ cnpj: import("drizzle-orm/pg-core").PgColumn<{
125
+ name: "cnpj";
126
+ tableName: "bank_integrations";
127
+ dataType: "string";
128
+ columnType: "PgText";
129
+ data: string;
130
+ driverParam: string;
131
+ notNull: false;
132
+ hasDefault: false;
133
+ isPrimaryKey: false;
134
+ isAutoincrement: false;
135
+ hasRuntimeDefault: false;
136
+ enumValues: [string, ...string[]];
137
+ baseColumn: never;
138
+ identity: undefined;
139
+ generated: undefined;
140
+ }, {}, {}>;
141
+ environment: import("drizzle-orm/pg-core").PgColumn<{
142
+ name: "environment";
143
+ tableName: "bank_integrations";
144
+ dataType: "string";
145
+ columnType: "PgText";
146
+ data: string;
147
+ driverParam: string;
148
+ notNull: true;
149
+ hasDefault: true;
150
+ isPrimaryKey: false;
151
+ isAutoincrement: false;
152
+ hasRuntimeDefault: false;
153
+ enumValues: [string, ...string[]];
154
+ baseColumn: never;
155
+ identity: undefined;
156
+ generated: undefined;
157
+ }, {}, {}>;
158
+ active: import("drizzle-orm/pg-core").PgColumn<{
159
+ name: "active";
160
+ tableName: "bank_integrations";
161
+ dataType: "boolean";
162
+ columnType: "PgBoolean";
163
+ data: boolean;
164
+ driverParam: boolean;
165
+ notNull: true;
166
+ hasDefault: true;
167
+ isPrimaryKey: false;
168
+ isAutoincrement: false;
169
+ hasRuntimeDefault: false;
170
+ enumValues: undefined;
171
+ baseColumn: never;
172
+ identity: undefined;
173
+ generated: undefined;
174
+ }, {}, {}>;
175
+ lastSyncAt: import("drizzle-orm/pg-core").PgColumn<{
176
+ name: "last_sync_at";
177
+ tableName: "bank_integrations";
178
+ dataType: "date";
179
+ columnType: "PgTimestamp";
180
+ data: Date;
181
+ driverParam: string;
182
+ notNull: false;
183
+ hasDefault: false;
184
+ isPrimaryKey: false;
185
+ isAutoincrement: false;
186
+ hasRuntimeDefault: false;
187
+ enumValues: undefined;
188
+ baseColumn: never;
189
+ identity: undefined;
190
+ generated: undefined;
191
+ }, {}, {}>;
192
+ };
193
+ dialect: "pg";
194
+ }>;
195
+ export declare const bankIntegrationSyncLog: import("drizzle-orm/pg-core").PgTableWithColumns<{
196
+ name: "bank_integration_sync_log";
197
+ schema: undefined;
198
+ columns: {
199
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
200
+ name: "created_at";
201
+ tableName: "bank_integration_sync_log";
202
+ dataType: "date";
203
+ columnType: "PgTimestamp";
204
+ data: Date;
205
+ driverParam: string;
206
+ notNull: true;
207
+ hasDefault: true;
208
+ isPrimaryKey: false;
209
+ isAutoincrement: false;
210
+ hasRuntimeDefault: false;
211
+ enumValues: undefined;
212
+ baseColumn: never;
213
+ identity: undefined;
214
+ generated: undefined;
215
+ }, {}, {}>;
216
+ id: import("drizzle-orm/pg-core").PgColumn<{
217
+ name: "id";
218
+ tableName: "bank_integration_sync_log";
219
+ dataType: "string";
220
+ columnType: "PgUUID";
221
+ data: string;
222
+ driverParam: string;
223
+ notNull: true;
224
+ hasDefault: true;
225
+ isPrimaryKey: true;
226
+ isAutoincrement: false;
227
+ hasRuntimeDefault: false;
228
+ enumValues: undefined;
229
+ baseColumn: never;
230
+ identity: undefined;
231
+ generated: undefined;
232
+ }, {}, {}>;
233
+ tenantId: import("drizzle-orm/pg-core").PgColumn<{
234
+ name: "tenant_id";
235
+ tableName: "bank_integration_sync_log";
236
+ dataType: "string";
237
+ columnType: "PgUUID";
238
+ data: string;
239
+ driverParam: string;
240
+ notNull: true;
241
+ hasDefault: false;
242
+ isPrimaryKey: false;
243
+ isAutoincrement: false;
244
+ hasRuntimeDefault: false;
245
+ enumValues: undefined;
246
+ baseColumn: never;
247
+ identity: undefined;
248
+ generated: undefined;
249
+ }, {}, {}>;
250
+ bankIntegrationId: import("drizzle-orm/pg-core").PgColumn<{
251
+ name: "bank_integration_id";
252
+ tableName: "bank_integration_sync_log";
253
+ dataType: "string";
254
+ columnType: "PgUUID";
255
+ data: string;
256
+ driverParam: string;
257
+ notNull: true;
258
+ hasDefault: false;
259
+ isPrimaryKey: false;
260
+ isAutoincrement: false;
261
+ hasRuntimeDefault: false;
262
+ enumValues: undefined;
263
+ baseColumn: never;
264
+ identity: undefined;
265
+ generated: undefined;
266
+ }, {}, {}>;
267
+ bankAccountId: import("drizzle-orm/pg-core").PgColumn<{
268
+ name: "bank_account_id";
269
+ tableName: "bank_integration_sync_log";
270
+ dataType: "string";
271
+ columnType: "PgUUID";
272
+ data: string;
273
+ driverParam: string;
274
+ notNull: false;
275
+ hasDefault: false;
276
+ isPrimaryKey: false;
277
+ isAutoincrement: false;
278
+ hasRuntimeDefault: false;
279
+ enumValues: undefined;
280
+ baseColumn: never;
281
+ identity: undefined;
282
+ generated: undefined;
283
+ }, {}, {}>;
284
+ periodFrom: import("drizzle-orm/pg-core").PgColumn<{
285
+ name: "period_from";
286
+ tableName: "bank_integration_sync_log";
287
+ dataType: "string";
288
+ columnType: "PgDateString";
289
+ data: string;
290
+ driverParam: string;
291
+ notNull: false;
292
+ hasDefault: false;
293
+ isPrimaryKey: false;
294
+ isAutoincrement: false;
295
+ hasRuntimeDefault: false;
296
+ enumValues: undefined;
297
+ baseColumn: never;
298
+ identity: undefined;
299
+ generated: undefined;
300
+ }, {}, {}>;
301
+ periodTo: import("drizzle-orm/pg-core").PgColumn<{
302
+ name: "period_to";
303
+ tableName: "bank_integration_sync_log";
304
+ dataType: "string";
305
+ columnType: "PgDateString";
306
+ data: string;
307
+ driverParam: string;
308
+ notNull: false;
309
+ hasDefault: false;
310
+ isPrimaryKey: false;
311
+ isAutoincrement: false;
312
+ hasRuntimeDefault: false;
313
+ enumValues: undefined;
314
+ baseColumn: never;
315
+ identity: undefined;
316
+ generated: undefined;
317
+ }, {}, {}>;
318
+ transactionsFetched: import("drizzle-orm/pg-core").PgColumn<{
319
+ name: "transactions_fetched";
320
+ tableName: "bank_integration_sync_log";
321
+ dataType: "number";
322
+ columnType: "PgInteger";
323
+ data: number;
324
+ driverParam: string | number;
325
+ notNull: true;
326
+ hasDefault: true;
327
+ isPrimaryKey: false;
328
+ isAutoincrement: false;
329
+ hasRuntimeDefault: false;
330
+ enumValues: undefined;
331
+ baseColumn: never;
332
+ identity: undefined;
333
+ generated: undefined;
334
+ }, {}, {}>;
335
+ transactionsImported: import("drizzle-orm/pg-core").PgColumn<{
336
+ name: "transactions_imported";
337
+ tableName: "bank_integration_sync_log";
338
+ dataType: "number";
339
+ columnType: "PgInteger";
340
+ data: number;
341
+ driverParam: string | number;
342
+ notNull: true;
343
+ hasDefault: true;
344
+ isPrimaryKey: false;
345
+ isAutoincrement: false;
346
+ hasRuntimeDefault: false;
347
+ enumValues: undefined;
348
+ baseColumn: never;
349
+ identity: undefined;
350
+ generated: undefined;
351
+ }, {}, {}>;
352
+ duplicates: import("drizzle-orm/pg-core").PgColumn<{
353
+ name: "duplicates";
354
+ tableName: "bank_integration_sync_log";
355
+ dataType: "number";
356
+ columnType: "PgInteger";
357
+ data: number;
358
+ driverParam: string | number;
359
+ notNull: true;
360
+ hasDefault: true;
361
+ isPrimaryKey: false;
362
+ isAutoincrement: false;
363
+ hasRuntimeDefault: false;
364
+ enumValues: undefined;
365
+ baseColumn: never;
366
+ identity: undefined;
367
+ generated: undefined;
368
+ }, {}, {}>;
369
+ status: import("drizzle-orm/pg-core").PgColumn<{
370
+ name: "status";
371
+ tableName: "bank_integration_sync_log";
372
+ dataType: "string";
373
+ columnType: "PgText";
374
+ data: string;
375
+ driverParam: string;
376
+ notNull: true;
377
+ hasDefault: true;
378
+ isPrimaryKey: false;
379
+ isAutoincrement: false;
380
+ hasRuntimeDefault: false;
381
+ enumValues: [string, ...string[]];
382
+ baseColumn: never;
383
+ identity: undefined;
384
+ generated: undefined;
385
+ }, {}, {}>;
386
+ errorMessage: import("drizzle-orm/pg-core").PgColumn<{
387
+ name: "error_message";
388
+ tableName: "bank_integration_sync_log";
389
+ dataType: "string";
390
+ columnType: "PgText";
391
+ data: string;
392
+ driverParam: string;
393
+ notNull: false;
394
+ hasDefault: false;
395
+ isPrimaryKey: false;
396
+ isAutoincrement: false;
397
+ hasRuntimeDefault: false;
398
+ enumValues: [string, ...string[]];
399
+ baseColumn: never;
400
+ identity: undefined;
401
+ generated: undefined;
402
+ }, {}, {}>;
403
+ triggeredByUserId: import("drizzle-orm/pg-core").PgColumn<{
404
+ name: "triggered_by_user_id";
405
+ tableName: "bank_integration_sync_log";
406
+ dataType: "string";
407
+ columnType: "PgUUID";
408
+ data: string;
409
+ driverParam: string;
410
+ notNull: false;
411
+ hasDefault: false;
412
+ isPrimaryKey: false;
413
+ isAutoincrement: false;
414
+ hasRuntimeDefault: false;
415
+ enumValues: undefined;
416
+ baseColumn: never;
417
+ identity: undefined;
418
+ generated: undefined;
419
+ }, {}, {}>;
420
+ };
421
+ dialect: "pg";
422
+ }>;
423
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAY3B,CAAA;AAGF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcjC,CAAA"}
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ var db = require('@fayz-ai/db');
4
+
5
+ // src/schema/index.ts
6
+ var bankIntegrations = db.pgTable("bank_integrations", {
7
+ id: db.uuid("id").primaryKey().defaultRandom(),
8
+ tenantId: db.tenantId(),
9
+ provider: db.text("provider").notNull().default("plugbank"),
10
+ bankAccountId: db.uuid("bank_account_id"),
11
+ // Tecnospeed PlugBank credentials
12
+ apiToken: db.text("api_token"),
13
+ cnpj: db.text("cnpj"),
14
+ environment: db.text("environment").notNull().default("production"),
15
+ // production | sandbox
16
+ active: db.boolean("active").notNull().default(true),
17
+ lastSyncAt: db.timestamp("last_sync_at", { withTimezone: true }),
18
+ ...db.timestamps
19
+ });
20
+ var bankIntegrationSyncLog = db.pgTable("bank_integration_sync_log", {
21
+ id: db.uuid("id").primaryKey().defaultRandom(),
22
+ tenantId: db.tenantId(),
23
+ bankIntegrationId: db.uuid("bank_integration_id").notNull().references(() => bankIntegrations.id, { onDelete: "cascade" }),
24
+ bankAccountId: db.uuid("bank_account_id"),
25
+ periodFrom: db.date("period_from"),
26
+ periodTo: db.date("period_to"),
27
+ transactionsFetched: db.integer("transactions_fetched").notNull().default(0),
28
+ transactionsImported: db.integer("transactions_imported").notNull().default(0),
29
+ duplicates: db.integer("duplicates").notNull().default(0),
30
+ status: db.text("status").notNull().default("success"),
31
+ // success | partial | error
32
+ errorMessage: db.text("error_message"),
33
+ triggeredByUserId: db.uuid("triggered_by_user_id"),
34
+ ...db.createdAt
35
+ });
36
+
37
+ exports.bankIntegrationSyncLog = bankIntegrationSyncLog;
38
+ exports.bankIntegrations = bankIntegrations;
39
+ //# sourceMappingURL=schema.cjs.map
40
+ //# sourceMappingURL=schema.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/schema/index.ts"],"names":["pgTable","uuid","tenantId","text","boolean","timestamp","timestamps","date","integer","createdAt"],"mappings":";;;;;AAoBO,IAAM,gBAAA,GAAmBA,WAAQ,mBAAA,EAAqB;AAAA,EAC3D,IAAIC,OAAA,CAAK,IAAI,CAAA,CAAE,UAAA,GAAa,aAAA,EAAc;AAAA,EAC1C,UAAUC,WAAA,EAAS;AAAA,EACnB,UAAUC,OAAA,CAAK,UAAU,EAAE,OAAA,EAAQ,CAAE,QAAQ,UAAU,CAAA;AAAA,EACvD,aAAA,EAAeF,QAAK,iBAAiB,CAAA;AAAA;AAAA,EAErC,QAAA,EAAUE,QAAK,WAAW,CAAA;AAAA,EAC1B,IAAA,EAAMA,QAAK,MAAM,CAAA;AAAA,EACjB,aAAaA,OAAA,CAAK,aAAa,EAAE,OAAA,EAAQ,CAAE,QAAQ,YAAY,CAAA;AAAA;AAAA,EAC/D,QAAQC,UAAA,CAAQ,QAAQ,EAAE,OAAA,EAAQ,CAAE,QAAQ,IAAI,CAAA;AAAA,EAChD,YAAYC,YAAA,CAAU,cAAA,EAAgB,EAAE,YAAA,EAAc,MAAM,CAAA;AAAA,EAC5D,GAAGC;AACL,CAAC;AAGM,IAAM,sBAAA,GAAyBN,WAAQ,2BAAA,EAA6B;AAAA,EACzE,IAAIC,OAAA,CAAK,IAAI,CAAA,CAAE,UAAA,GAAa,aAAA,EAAc;AAAA,EAC1C,UAAUC,WAAA,EAAS;AAAA,EACnB,iBAAA,EAAmBD,OAAA,CAAK,qBAAqB,CAAA,CAAE,OAAA,EAAQ,CAAE,UAAA,CAAW,MAAM,gBAAA,CAAiB,EAAA,EAAI,EAAE,QAAA,EAAU,WAAW,CAAA;AAAA,EACtH,aAAA,EAAeA,QAAK,iBAAiB,CAAA;AAAA,EACrC,UAAA,EAAYM,QAAK,aAAa,CAAA;AAAA,EAC9B,QAAA,EAAUA,QAAK,WAAW,CAAA;AAAA,EAC1B,qBAAqBC,UAAA,CAAQ,sBAAsB,EAAE,OAAA,EAAQ,CAAE,QAAQ,CAAC,CAAA;AAAA,EACxE,sBAAsBA,UAAA,CAAQ,uBAAuB,EAAE,OAAA,EAAQ,CAAE,QAAQ,CAAC,CAAA;AAAA,EAC1E,YAAYA,UAAA,CAAQ,YAAY,EAAE,OAAA,EAAQ,CAAE,QAAQ,CAAC,CAAA;AAAA,EACrD,QAAQL,OAAA,CAAK,QAAQ,EAAE,OAAA,EAAQ,CAAE,QAAQ,SAAS,CAAA;AAAA;AAAA,EAClD,YAAA,EAAcA,QAAK,eAAe,CAAA;AAAA,EAClC,iBAAA,EAAmBF,QAAK,sBAAsB,CAAA;AAAA,EAC9C,GAAGQ;AACL,CAAC","file":"schema.cjs","sourcesContent":["// Open Banking plugin (app-local incubator) — Ring-1 Drizzle schema.\n//\n// CLIENT-OWNED connector that follows the SDK plugin contract. It owns the bank\n// connection + sync-audit tables and a Supabase Edge Function (plugbank-sync)\n// that imports bank-statement lines into the SDK financial ledger\n// (public.plg_financial_movements, tagged external_source='plugbank'). The matching\n// happens in the SDK financial plugin's Reconciliation view.\n//\n// Graduation path (see PLUGIN.md): move this folder to\n// `fayz-sdk/plugins/plugin-banking-br/src/` largely unchanged.\n//\n// Builders come from @fayz-ai/admin/db (front-door re-export of @fayz-ai/db —\n// single drizzle-orm instance). NEVER import pgTable/uuid from drizzle-orm/pg-core directly.\nimport { pgTable, uuid, text, integer, boolean, timestamp, date, tenantId, timestamps, createdAt } from '@fayz-ai/db'\n\n// bank_integrations — one connection per (tenant, bank account, provider).\n// Holds the provider credentials (Tecnospeed PlugBank: api_token + cnpj). Server\n// secrets that must never reach the browser live in Supabase function env; this\n// row stores the per-tenant config + token that the edge function reads with the\n// service role.\nexport const bankIntegrations = pgTable('bank_integrations', {\n id: uuid('id').primaryKey().defaultRandom(),\n tenantId: tenantId(),\n provider: text('provider').notNull().default('plugbank'),\n bankAccountId: uuid('bank_account_id'),\n // Tecnospeed PlugBank credentials\n apiToken: text('api_token'),\n cnpj: text('cnpj'),\n environment: text('environment').notNull().default('production'), // production | sandbox\n active: boolean('active').notNull().default(true),\n lastSyncAt: timestamp('last_sync_at', { withTimezone: true }),\n ...timestamps,\n})\n\n// bank_integration_sync_log — one row per sync run (audit trail).\nexport const bankIntegrationSyncLog = pgTable('bank_integration_sync_log', {\n id: uuid('id').primaryKey().defaultRandom(),\n tenantId: tenantId(),\n bankIntegrationId: uuid('bank_integration_id').notNull().references(() => bankIntegrations.id, { onDelete: 'cascade' }),\n bankAccountId: uuid('bank_account_id'),\n periodFrom: date('period_from'),\n periodTo: date('period_to'),\n transactionsFetched: integer('transactions_fetched').notNull().default(0),\n transactionsImported: integer('transactions_imported').notNull().default(0),\n duplicates: integer('duplicates').notNull().default(0),\n status: text('status').notNull().default('success'), // success | partial | error\n errorMessage: text('error_message'),\n triggeredByUserId: uuid('triggered_by_user_id'),\n ...createdAt,\n})\n"]}
package/dist/schema.js ADDED
@@ -0,0 +1,37 @@
1
+ import { pgTable, timestamps, timestamp, boolean, text, uuid, tenantId, createdAt, integer, date } from '@fayz-ai/db';
2
+
3
+ // src/schema/index.ts
4
+ var bankIntegrations = pgTable("bank_integrations", {
5
+ id: uuid("id").primaryKey().defaultRandom(),
6
+ tenantId: tenantId(),
7
+ provider: text("provider").notNull().default("plugbank"),
8
+ bankAccountId: uuid("bank_account_id"),
9
+ // Tecnospeed PlugBank credentials
10
+ apiToken: text("api_token"),
11
+ cnpj: text("cnpj"),
12
+ environment: text("environment").notNull().default("production"),
13
+ // production | sandbox
14
+ active: boolean("active").notNull().default(true),
15
+ lastSyncAt: timestamp("last_sync_at", { withTimezone: true }),
16
+ ...timestamps
17
+ });
18
+ var bankIntegrationSyncLog = pgTable("bank_integration_sync_log", {
19
+ id: uuid("id").primaryKey().defaultRandom(),
20
+ tenantId: tenantId(),
21
+ bankIntegrationId: uuid("bank_integration_id").notNull().references(() => bankIntegrations.id, { onDelete: "cascade" }),
22
+ bankAccountId: uuid("bank_account_id"),
23
+ periodFrom: date("period_from"),
24
+ periodTo: date("period_to"),
25
+ transactionsFetched: integer("transactions_fetched").notNull().default(0),
26
+ transactionsImported: integer("transactions_imported").notNull().default(0),
27
+ duplicates: integer("duplicates").notNull().default(0),
28
+ status: text("status").notNull().default("success"),
29
+ // success | partial | error
30
+ errorMessage: text("error_message"),
31
+ triggeredByUserId: uuid("triggered_by_user_id"),
32
+ ...createdAt
33
+ });
34
+
35
+ export { bankIntegrationSyncLog, bankIntegrations };
36
+ //# sourceMappingURL=schema.js.map
37
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/schema/index.ts"],"names":[],"mappings":";;;AAoBO,IAAM,gBAAA,GAAmB,QAAQ,mBAAA,EAAqB;AAAA,EAC3D,IAAI,IAAA,CAAK,IAAI,CAAA,CAAE,UAAA,GAAa,aAAA,EAAc;AAAA,EAC1C,UAAU,QAAA,EAAS;AAAA,EACnB,UAAU,IAAA,CAAK,UAAU,EAAE,OAAA,EAAQ,CAAE,QAAQ,UAAU,CAAA;AAAA,EACvD,aAAA,EAAe,KAAK,iBAAiB,CAAA;AAAA;AAAA,EAErC,QAAA,EAAU,KAAK,WAAW,CAAA;AAAA,EAC1B,IAAA,EAAM,KAAK,MAAM,CAAA;AAAA,EACjB,aAAa,IAAA,CAAK,aAAa,EAAE,OAAA,EAAQ,CAAE,QAAQ,YAAY,CAAA;AAAA;AAAA,EAC/D,QAAQ,OAAA,CAAQ,QAAQ,EAAE,OAAA,EAAQ,CAAE,QAAQ,IAAI,CAAA;AAAA,EAChD,YAAY,SAAA,CAAU,cAAA,EAAgB,EAAE,YAAA,EAAc,MAAM,CAAA;AAAA,EAC5D,GAAG;AACL,CAAC;AAGM,IAAM,sBAAA,GAAyB,QAAQ,2BAAA,EAA6B;AAAA,EACzE,IAAI,IAAA,CAAK,IAAI,CAAA,CAAE,UAAA,GAAa,aAAA,EAAc;AAAA,EAC1C,UAAU,QAAA,EAAS;AAAA,EACnB,iBAAA,EAAmB,IAAA,CAAK,qBAAqB,CAAA,CAAE,OAAA,EAAQ,CAAE,UAAA,CAAW,MAAM,gBAAA,CAAiB,EAAA,EAAI,EAAE,QAAA,EAAU,WAAW,CAAA;AAAA,EACtH,aAAA,EAAe,KAAK,iBAAiB,CAAA;AAAA,EACrC,UAAA,EAAY,KAAK,aAAa,CAAA;AAAA,EAC9B,QAAA,EAAU,KAAK,WAAW,CAAA;AAAA,EAC1B,qBAAqB,OAAA,CAAQ,sBAAsB,EAAE,OAAA,EAAQ,CAAE,QAAQ,CAAC,CAAA;AAAA,EACxE,sBAAsB,OAAA,CAAQ,uBAAuB,EAAE,OAAA,EAAQ,CAAE,QAAQ,CAAC,CAAA;AAAA,EAC1E,YAAY,OAAA,CAAQ,YAAY,EAAE,OAAA,EAAQ,CAAE,QAAQ,CAAC,CAAA;AAAA,EACrD,QAAQ,IAAA,CAAK,QAAQ,EAAE,OAAA,EAAQ,CAAE,QAAQ,SAAS,CAAA;AAAA;AAAA,EAClD,YAAA,EAAc,KAAK,eAAe,CAAA;AAAA,EAClC,iBAAA,EAAmB,KAAK,sBAAsB,CAAA;AAAA,EAC9C,GAAG;AACL,CAAC","file":"schema.js","sourcesContent":["// Open Banking plugin (app-local incubator) — Ring-1 Drizzle schema.\n//\n// CLIENT-OWNED connector that follows the SDK plugin contract. It owns the bank\n// connection + sync-audit tables and a Supabase Edge Function (plugbank-sync)\n// that imports bank-statement lines into the SDK financial ledger\n// (public.plg_financial_movements, tagged external_source='plugbank'). The matching\n// happens in the SDK financial plugin's Reconciliation view.\n//\n// Graduation path (see PLUGIN.md): move this folder to\n// `fayz-sdk/plugins/plugin-banking-br/src/` largely unchanged.\n//\n// Builders come from @fayz-ai/admin/db (front-door re-export of @fayz-ai/db —\n// single drizzle-orm instance). NEVER import pgTable/uuid from drizzle-orm/pg-core directly.\nimport { pgTable, uuid, text, integer, boolean, timestamp, date, tenantId, timestamps, createdAt } from '@fayz-ai/db'\n\n// bank_integrations — one connection per (tenant, bank account, provider).\n// Holds the provider credentials (Tecnospeed PlugBank: api_token + cnpj). Server\n// secrets that must never reach the browser live in Supabase function env; this\n// row stores the per-tenant config + token that the edge function reads with the\n// service role.\nexport const bankIntegrations = pgTable('bank_integrations', {\n id: uuid('id').primaryKey().defaultRandom(),\n tenantId: tenantId(),\n provider: text('provider').notNull().default('plugbank'),\n bankAccountId: uuid('bank_account_id'),\n // Tecnospeed PlugBank credentials\n apiToken: text('api_token'),\n cnpj: text('cnpj'),\n environment: text('environment').notNull().default('production'), // production | sandbox\n active: boolean('active').notNull().default(true),\n lastSyncAt: timestamp('last_sync_at', { withTimezone: true }),\n ...timestamps,\n})\n\n// bank_integration_sync_log — one row per sync run (audit trail).\nexport const bankIntegrationSyncLog = pgTable('bank_integration_sync_log', {\n id: uuid('id').primaryKey().defaultRandom(),\n tenantId: tenantId(),\n bankIntegrationId: uuid('bank_integration_id').notNull().references(() => bankIntegrations.id, { onDelete: 'cascade' }),\n bankAccountId: uuid('bank_account_id'),\n periodFrom: date('period_from'),\n periodTo: date('period_to'),\n transactionsFetched: integer('transactions_fetched').notNull().default(0),\n transactionsImported: integer('transactions_imported').notNull().default(0),\n duplicates: integer('duplicates').notNull().default(0),\n status: text('status').notNull().default('success'), // success | partial | error\n errorMessage: text('error_message'),\n triggeredByUserId: uuid('triggered_by_user_id'),\n ...createdAt,\n})\n"]}
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ export declare function BankIntegrationSettings(): React.JSX.Element;
3
+ //# sourceMappingURL=BankIntegrationSettings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BankIntegrationSettings.d.ts","sourceRoot":"","sources":["../../src/settings/BankIntegrationSettings.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAuC,MAAM,OAAO,CAAA;AAa3D,wBAAgB,uBAAuB,sBAyLtC"}
@@ -0,0 +1,48 @@
1
+ export interface BankIntegration {
2
+ id: string;
3
+ provider: string;
4
+ bankAccountId?: string;
5
+ apiToken?: string;
6
+ cnpj?: string;
7
+ environment: string;
8
+ active: boolean;
9
+ lastSyncAt?: string;
10
+ }
11
+ export interface SaveIntegrationInput {
12
+ id?: string;
13
+ bankAccountId?: string;
14
+ apiToken: string;
15
+ cnpj: string;
16
+ environment?: string;
17
+ }
18
+ export interface SyncLogEntry {
19
+ id: string;
20
+ periodFrom?: string;
21
+ periodTo?: string;
22
+ transactionsFetched: number;
23
+ transactionsImported: number;
24
+ duplicates: number;
25
+ status: string;
26
+ errorMessage?: string;
27
+ createdAt: string;
28
+ }
29
+ /** A normalized bank-statement line returned by the edge function. */
30
+ export interface BankLine {
31
+ externalId: string;
32
+ date: string;
33
+ type: 'C' | 'D';
34
+ amount: number;
35
+ description: string;
36
+ }
37
+ export interface TestConnectionResult {
38
+ ok: boolean;
39
+ message?: string;
40
+ }
41
+ export interface FetchStatementResult {
42
+ lines: BankLine[];
43
+ }
44
+ export interface ImportResult {
45
+ imported: number;
46
+ duplicates: number;
47
+ }
48
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,oBAAoB,EAAE,MAAM,CAAA;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,sEAAsE;AACtE,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,GAAG,GAAG,GAAG,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,OAAO,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,QAAQ,EAAE,CAAA;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;CACnB"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@fayz-ai/plugin-banking-br",
3
+ "version": "0.9.1",
4
+ "description": "[experimental] Fayz SDK — Brazilian open-banking connector (Tecnospeed PlugBank) feeding the financial ledger",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ },
14
+ "./schema": {
15
+ "types": "./dist/schema/index.d.ts",
16
+ "import": "./dist/schema.js",
17
+ "require": "./dist/schema.cjs"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "peerDependencies": {
24
+ "react": "^18.0.0 || ^19.0.0",
25
+ "react-dom": "^18.0.0 || ^19.0.0"
26
+ },
27
+ "dependencies": {
28
+ "@fayz-ai/core": "^0.10.0",
29
+ "@fayz-ai/db": "^0.10.0",
30
+ "@fayz-ai/ui": "^0.10.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/react": "^18.3.0",
34
+ "@types/react-dom": "^18.3.0",
35
+ "lucide-react": "^0.400.0",
36
+ "react": "^18.3.0",
37
+ "react-dom": "^18.3.0",
38
+ "tsup": "^8.2.0",
39
+ "typescript": "^5.5.0"
40
+ },
41
+ "license": "MIT",
42
+ "keywords": [
43
+ "fayz",
44
+ "fayz-plugin",
45
+ "fayz-sdk"
46
+ ],
47
+ "scripts": {
48
+ "build": "tsup && tsc --emitDeclarationOnly --declaration --declarationMap --noEmit false",
49
+ "dev": "tsup --watch",
50
+ "typecheck": "tsc --noEmit",
51
+ "clean": "rm -rf dist"
52
+ }
53
+ }