@frihet/mcp-server 1.16.6 → 2.0.0
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/README.md +168 -82
- package/dist/agent-onboarding.d.ts +98 -0
- package/dist/agent-onboarding.js +275 -0
- package/dist/api-origin.d.ts +9 -0
- package/dist/api-origin.js +41 -0
- package/dist/canary/mcp-harness.d.ts +77 -0
- package/dist/canary/mcp-harness.js +552 -0
- package/dist/capability-truth.d.ts +29 -0
- package/dist/capability-truth.js +262 -0
- package/dist/claude-candidate-contract.d.ts +482 -0
- package/dist/claude-candidate-contract.js +87 -0
- package/dist/claude-output-privacy.d.ts +17 -0
- package/dist/claude-output-privacy.js +240 -0
- package/dist/claude-profile.d.ts +18 -0
- package/dist/claude-profile.js +260 -0
- package/dist/client-interface.d.ts +47 -33
- package/dist/client.d.ts +172 -40
- package/dist/client.js +708 -165
- package/dist/demo-client.d.ts +41 -32
- package/dist/demo-client.js +202 -31
- package/dist/demo-fixtures.d.ts +3 -3
- package/dist/demo-fixtures.js +7 -7
- package/dist/deposit-contract.d.ts +29 -0
- package/dist/deposit-contract.js +76 -0
- package/dist/fetch-no-redirect.d.ts +3 -0
- package/dist/fetch-no-redirect.js +16 -0
- package/dist/fiscal-aliases.d.ts +44 -0
- package/dist/fiscal-aliases.js +62 -0
- package/dist/fiscal-period.d.ts +26 -0
- package/dist/fiscal-period.js +31 -0
- package/dist/google-profile.d.ts +19 -0
- package/dist/google-profile.js +122 -0
- package/dist/index.js +68 -59
- package/dist/logger.d.ts +2 -2
- package/dist/logger.js +140 -8
- package/dist/muse-profile.d.ts +19 -0
- package/dist/muse-profile.js +122 -0
- package/dist/observability.d.ts +18 -29
- package/dist/observability.js +194 -106
- package/dist/openai-profile.d.ts +26 -22
- package/dist/openai-profile.js +1193 -157
- package/dist/openai-review-contract.d.ts +15 -6
- package/dist/openai-review-contract.js +714 -41
- package/dist/openai-review-oauth.d.ts +149 -2
- package/dist/openai-review-oauth.js +220 -6
- package/dist/prompts/register-all.d.ts +2 -0
- package/dist/prompts/register-all.js +34 -78
- package/dist/public-capability-contract.d.ts +39 -0
- package/dist/public-capability-contract.js +186 -0
- package/dist/redaction.d.ts +15 -0
- package/dist/redaction.js +83 -0
- package/dist/resources/register-all.js +154 -64
- package/dist/retry-after.d.ts +19 -0
- package/dist/retry-after.js +84 -0
- package/dist/server-composition.d.ts +19 -0
- package/dist/server-composition.js +74 -0
- package/dist/tool-exposure.d.ts +31 -27
- package/dist/tool-exposure.js +211 -87
- package/dist/tools/accountingClose.d.ts +14 -5
- package/dist/tools/accountingClose.js +41 -23
- package/dist/tools/audit_gl.js +8 -8
- package/dist/tools/backend-availability.d.ts +8 -29
- package/dist/tools/backend-availability.js +31 -30
- package/dist/tools/bank_rules.js +66 -15
- package/dist/tools/banking.js +5 -13
- package/dist/tools/clients.js +261 -15
- package/dist/tools/crm.js +22 -21
- package/dist/tools/deposits.js +114 -85
- package/dist/tools/einvoice.d.ts +16 -2
- package/dist/tools/einvoice.js +59 -12
- package/dist/tools/expenses.d.ts +16 -0
- package/dist/tools/expenses.js +47 -27
- package/dist/tools/fiscal.d.ts +3 -4
- package/dist/tools/fiscal.js +93 -60
- package/dist/tools/gestoria.js +15 -7
- package/dist/tools/hr.d.ts +2 -3
- package/dist/tools/hr.js +49 -20
- package/dist/tools/igic.d.ts +9 -8
- package/dist/tools/igic.js +34 -64
- package/dist/tools/impuesto_sociedades.d.ts +4 -5
- package/dist/tools/impuesto_sociedades.js +16 -37
- package/dist/tools/intelligence.js +166 -12
- package/dist/tools/invoices.js +224 -54
- package/dist/tools/kitchen.js +19 -9
- package/dist/tools/payroll.d.ts +5 -8
- package/dist/tools/payroll.js +19 -32
- package/dist/tools/permissions.d.ts +4 -7
- package/dist/tools/permissions.js +11 -14
- package/dist/tools/products.js +6 -6
- package/dist/tools/quotes.js +172 -26
- package/dist/tools/recurring.js +26 -25
- package/dist/tools/register-all.d.ts +2 -2
- package/dist/tools/register-all.js +9 -6
- package/dist/tools/search.d.ts +19 -0
- package/dist/tools/search.js +84 -0
- package/dist/tools/shared.d.ts +1445 -109
- package/dist/tools/shared.js +478 -102
- package/dist/tools/team.js +24 -28
- package/dist/tools/time.js +4 -12
- package/dist/tools/vendors.js +249 -15
- package/dist/tools/webhooks.js +35 -30
- package/dist/types.d.ts +31 -5
- package/dist/workflows/daily-operational-brief.d.ts +163 -0
- package/dist/workflows/daily-operational-brief.js +881 -0
- package/docs/agent-onboarding.json +391 -0
- package/package.json +49 -12
- package/dist/tools/onboarding.d.ts +0 -19
- package/dist/tools/onboarding.js +0 -64
package/dist/demo-client.d.ts
CHANGED
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
* stamp; this is the one accepted, documented gap).
|
|
19
19
|
*/
|
|
20
20
|
import type { IFrihetClient } from "./client-interface.js";
|
|
21
|
-
import type { PaginatedResponse } from "./types.js";
|
|
21
|
+
import type { CreateWebhookInput, CreateWebhookResult, PaginatedResponse, UpdateWebhookInput, Webhook } from "./types.js";
|
|
22
|
+
import { type BinaryDocument, type EInvoiceDocument, type EInvoiceExportResult, type McpEInvoiceExportFormat } from "./client.js";
|
|
22
23
|
type Rec = Record<string, unknown>;
|
|
23
24
|
export declare class DemoFrihetClient implements IFrihetClient {
|
|
24
25
|
listInvoices(params?: {
|
|
@@ -75,8 +76,8 @@ export declare class DemoFrihetClient implements IFrihetClient {
|
|
|
75
76
|
deleteVendor(_id: string): Promise<void>;
|
|
76
77
|
sendInvoice(id: string, to?: string): Promise<Rec>;
|
|
77
78
|
markInvoicePaid(id: string, paidDate?: string): Promise<Rec>;
|
|
78
|
-
getInvoicePdf(id: string): Promise<
|
|
79
|
-
getInvoiceEInvoice(invoiceId: string): Promise<
|
|
79
|
+
getInvoicePdf(id: string): Promise<BinaryDocument>;
|
|
80
|
+
getInvoiceEInvoice(invoiceId: string): Promise<EInvoiceDocument>;
|
|
80
81
|
createCreditNote(invoiceId: string, data: {
|
|
81
82
|
reason: string;
|
|
82
83
|
reasonDescription?: string;
|
|
@@ -88,14 +89,31 @@ export declare class DemoFrihetClient implements IFrihetClient {
|
|
|
88
89
|
daysOverdue?: number;
|
|
89
90
|
}): Promise<Rec>;
|
|
90
91
|
sendQuote(id: string, to?: string): Promise<Rec>;
|
|
91
|
-
listWebhooks(
|
|
92
|
+
listWebhooks(): Promise<{
|
|
93
|
+
data: Webhook[];
|
|
94
|
+
total: number;
|
|
95
|
+
_demo?: true;
|
|
96
|
+
_demoNotice?: string;
|
|
97
|
+
}>;
|
|
98
|
+
getWebhook(id: string): Promise<Webhook>;
|
|
99
|
+
createWebhook(data: CreateWebhookInput): Promise<CreateWebhookResult>;
|
|
100
|
+
updateWebhook(id: string, data: UpdateWebhookInput): Promise<Webhook>;
|
|
101
|
+
deleteWebhook(_id: string): Promise<void>;
|
|
102
|
+
globalSearch(params: {
|
|
103
|
+
q: string;
|
|
104
|
+
types?: ReadonlyArray<"invoices" | "expenses" | "vendors" | "clients" | "products">;
|
|
92
105
|
limit?: number;
|
|
93
106
|
offset?: number;
|
|
94
|
-
}): Promise<
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
107
|
+
}): Promise<{
|
|
108
|
+
data: Record<string, unknown>[];
|
|
109
|
+
total: number;
|
|
110
|
+
limit: number;
|
|
111
|
+
offset: number;
|
|
112
|
+
hasMore: boolean;
|
|
113
|
+
query: string;
|
|
114
|
+
types: ReadonlyArray<"invoices" | "expenses" | "vendors" | "clients" | "products">;
|
|
115
|
+
truncated?: boolean;
|
|
116
|
+
}>;
|
|
99
117
|
listClientContacts(_clientId: string, params?: {
|
|
100
118
|
limit?: number;
|
|
101
119
|
offset?: number;
|
|
@@ -106,7 +124,7 @@ export declare class DemoFrihetClient implements IFrihetClient {
|
|
|
106
124
|
limit?: number;
|
|
107
125
|
offset?: number;
|
|
108
126
|
}): Promise<PaginatedResponse<Rec>>;
|
|
109
|
-
logClientActivity(
|
|
127
|
+
logClientActivity(_clientId: string, data: Rec): Promise<Rec>;
|
|
110
128
|
listClientNotes(_clientId: string, params?: {
|
|
111
129
|
limit?: number;
|
|
112
130
|
offset?: number;
|
|
@@ -170,14 +188,9 @@ export declare class DemoFrihetClient implements IFrihetClient {
|
|
|
170
188
|
}>;
|
|
171
189
|
exportEInvoice(params: {
|
|
172
190
|
invoiceId: string;
|
|
173
|
-
format:
|
|
191
|
+
format: McpEInvoiceExportFormat;
|
|
174
192
|
signed?: boolean;
|
|
175
|
-
}): Promise<
|
|
176
|
-
xmlUrl: string;
|
|
177
|
-
filename: string;
|
|
178
|
-
format: string;
|
|
179
|
-
signed: boolean;
|
|
180
|
-
}>;
|
|
193
|
+
}): Promise<EInvoiceExportResult>;
|
|
181
194
|
faceSubmit(params: {
|
|
182
195
|
invoiceId: string;
|
|
183
196
|
mode: "mock" | "sandbox" | "production";
|
|
@@ -311,7 +324,7 @@ export declare class DemoFrihetClient implements IFrihetClient {
|
|
|
311
324
|
updateTeamMemberRole(memberId: string, role: string): Promise<Rec>;
|
|
312
325
|
removeTeamMember(_memberId: string): Promise<void>;
|
|
313
326
|
approveGLEntry(entryId: string, notes?: string): Promise<Rec>;
|
|
314
|
-
rejectGLEntry(entryId: string,
|
|
327
|
+
rejectGLEntry(entryId: string, note: string): Promise<Rec>;
|
|
315
328
|
getGLEntryAuditLog(entryId: string): Promise<Rec>;
|
|
316
329
|
addCustomPortalDomain(data: {
|
|
317
330
|
domain: string;
|
|
@@ -352,15 +365,13 @@ export declare class DemoFrihetClient implements IFrihetClient {
|
|
|
352
365
|
}): Promise<PaginatedResponse<Rec>>;
|
|
353
366
|
createBankRule(data: {
|
|
354
367
|
name: string;
|
|
355
|
-
|
|
368
|
+
bankConditions: Array<{
|
|
356
369
|
field: string;
|
|
357
370
|
operator: string;
|
|
358
371
|
value: string;
|
|
359
372
|
}>;
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
value: string;
|
|
363
|
-
}>;
|
|
373
|
+
action: string;
|
|
374
|
+
actionConfig: Record<string, unknown>;
|
|
364
375
|
isActive?: boolean;
|
|
365
376
|
}): Promise<Rec>;
|
|
366
377
|
sendGestoriaMessage(data: {
|
|
@@ -403,7 +414,9 @@ export declare class DemoFrihetClient implements IFrihetClient {
|
|
|
403
414
|
};
|
|
404
415
|
}): Promise<Rec>;
|
|
405
416
|
getGestoriaAgingConsolidated(_params?: {
|
|
406
|
-
|
|
417
|
+
workspaceIds?: string[];
|
|
418
|
+
asOf?: string;
|
|
419
|
+
bustCache?: boolean;
|
|
407
420
|
}): Promise<Rec>;
|
|
408
421
|
listLeaves(params?: {
|
|
409
422
|
limit?: number;
|
|
@@ -427,8 +440,8 @@ export declare class DemoFrihetClient implements IFrihetClient {
|
|
|
427
440
|
employeeId: string;
|
|
428
441
|
mood?: string;
|
|
429
442
|
location?: string;
|
|
430
|
-
}): Promise<Rec>;
|
|
431
|
-
attendanceClockOut(entryId: string): Promise<Rec>;
|
|
443
|
+
}, _idempotencyKey?: string): Promise<Rec>;
|
|
444
|
+
attendanceClockOut(entryId: string, _idempotencyKey?: string): Promise<Rec>;
|
|
432
445
|
getOvertimeReport(params: {
|
|
433
446
|
period: string;
|
|
434
447
|
employeeId?: string;
|
|
@@ -441,20 +454,16 @@ export declare class DemoFrihetClient implements IFrihetClient {
|
|
|
441
454
|
eventType?: string;
|
|
442
455
|
}): Promise<Rec>;
|
|
443
456
|
exportPayroll(params: {
|
|
444
|
-
format: "a3" | "contasol" | "sage" | "
|
|
457
|
+
format: "a3" | "contasol" | "sage" | "siltra";
|
|
445
458
|
month: string;
|
|
446
459
|
}): Promise<Rec>;
|
|
447
460
|
getPayrollChecklist(params: {
|
|
448
461
|
month: string;
|
|
449
462
|
}): Promise<Rec>;
|
|
450
|
-
getOnboardingStatus(): Promise<Rec>;
|
|
451
|
-
setOnboardingPersona(data: {
|
|
452
|
-
persona: "autonomo" | "empresa" | "agencia" | "gestoria";
|
|
453
|
-
}): Promise<Rec>;
|
|
454
463
|
getPermissionsMatrix(): Promise<Rec>;
|
|
455
464
|
getMyPermissions(): Promise<Rec>;
|
|
456
465
|
getCurrentPeriod(params?: {
|
|
457
|
-
|
|
466
|
+
fiscalYear?: string;
|
|
458
467
|
}): Promise<Rec>;
|
|
459
468
|
closePeriod(data: {
|
|
460
469
|
type: "monthly" | "quarterly";
|
package/dist/demo-client.js
CHANGED
|
@@ -17,7 +17,63 @@
|
|
|
17
17
|
* - delete / remove methods → resolve void (interface return type forbids a
|
|
18
18
|
* stamp; this is the one accepted, documented gap).
|
|
19
19
|
*/
|
|
20
|
+
import { toApiEInvoiceExportFormat, } from "./client.js";
|
|
21
|
+
import { Buffer } from "node:buffer";
|
|
20
22
|
import { READ_STAMP, FISCAL_STAMP, DEMO_NOW, demoPage, demoEmptyPage, findOrStub, demoId, simulateWrite, simulateAction, demoClients, demoProducts, demoInvoices, demoExpenses, demoQuotes, demoVendors, demoBankAccounts, demoTransactions, } from "./demo-fixtures.js";
|
|
23
|
+
const DEMO_RBAC_ROLES = ["owner", "admin", "manager", "sales", "accountant", "employee", "viewer"];
|
|
24
|
+
const DEMO_RBAC_RESOURCES = [
|
|
25
|
+
"workspace", "invoices", "quotes", "expenses", "clients", "products", "accounting",
|
|
26
|
+
"people", "payroll", "integrations", "banking", "settings", "audit_log", "billing",
|
|
27
|
+
];
|
|
28
|
+
const DEMO_RBAC_ACTIONS = ["read", "create", "update", "delete", "bulk_delete", "export"];
|
|
29
|
+
const DEMO_FULL_ACTIONS = [...DEMO_RBAC_ACTIONS];
|
|
30
|
+
const DEMO_PERMISSION_MATRIX = {
|
|
31
|
+
owner: {
|
|
32
|
+
workspace: ["read", "update", "export"],
|
|
33
|
+
invoices: DEMO_FULL_ACTIONS, quotes: DEMO_FULL_ACTIONS, expenses: DEMO_FULL_ACTIONS,
|
|
34
|
+
clients: DEMO_FULL_ACTIONS, products: DEMO_FULL_ACTIONS, accounting: DEMO_FULL_ACTIONS,
|
|
35
|
+
people: DEMO_FULL_ACTIONS, payroll: DEMO_FULL_ACTIONS, integrations: DEMO_FULL_ACTIONS,
|
|
36
|
+
banking: ["read", "create", "update", "delete", "export"],
|
|
37
|
+
settings: ["read", "update"], audit_log: ["read", "export"],
|
|
38
|
+
billing: ["read", "create", "update", "delete", "export"],
|
|
39
|
+
},
|
|
40
|
+
admin: {
|
|
41
|
+
workspace: ["read", "update", "export"],
|
|
42
|
+
invoices: DEMO_FULL_ACTIONS, quotes: DEMO_FULL_ACTIONS, expenses: DEMO_FULL_ACTIONS,
|
|
43
|
+
clients: DEMO_FULL_ACTIONS, products: DEMO_FULL_ACTIONS, accounting: DEMO_FULL_ACTIONS,
|
|
44
|
+
people: DEMO_FULL_ACTIONS, payroll: DEMO_FULL_ACTIONS, integrations: DEMO_FULL_ACTIONS,
|
|
45
|
+
banking: ["read", "create", "update", "delete", "export"],
|
|
46
|
+
settings: ["read", "update"], audit_log: ["read", "export"],
|
|
47
|
+
},
|
|
48
|
+
manager: {
|
|
49
|
+
workspace: ["read"], invoices: ["read", "export"], quotes: ["read", "export"],
|
|
50
|
+
clients: ["read", "export"], products: ["read", "export"], expenses: ["read", "export"],
|
|
51
|
+
banking: ["read"], people: DEMO_FULL_ACTIONS, payroll: ["read", "export"],
|
|
52
|
+
settings: ["read"], integrations: ["read"], audit_log: ["read"],
|
|
53
|
+
},
|
|
54
|
+
sales: {
|
|
55
|
+
workspace: ["read"], invoices: ["read", "create", "update", "export"],
|
|
56
|
+
quotes: ["read", "create", "update", "export"], clients: ["read", "create", "update", "export"],
|
|
57
|
+
products: ["read", "export"], expenses: ["read", "export"],
|
|
58
|
+
},
|
|
59
|
+
accountant: {
|
|
60
|
+
workspace: ["read"], invoices: ["read", "create", "update", "export"],
|
|
61
|
+
quotes: ["read", "export"], expenses: ["read", "create", "update", "export"],
|
|
62
|
+
clients: ["read", "export"], products: ["read", "export"],
|
|
63
|
+
banking: ["read", "create", "update", "export"], accounting: ["read", "create", "update", "export"],
|
|
64
|
+
people: ["read"], audit_log: ["read", "export"],
|
|
65
|
+
},
|
|
66
|
+
employee: { workspace: ["read"] },
|
|
67
|
+
viewer: {
|
|
68
|
+
workspace: ["read", "export"], invoices: ["read", "export"], quotes: ["read", "export"],
|
|
69
|
+
expenses: ["read", "export"], clients: ["read", "export"], products: ["read", "export"],
|
|
70
|
+
banking: ["read"], accounting: ["read", "export"], people: ["read"], payroll: ["read"],
|
|
71
|
+
settings: ["read"], integrations: ["read"], audit_log: ["read"],
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
const DEMO_OWNER_CAPABILITIES = Object.entries(DEMO_PERMISSION_MATRIX.owner)
|
|
75
|
+
.flatMap(([resource, actions]) => actions.map((action) => `${resource}:${action}`))
|
|
76
|
+
.sort();
|
|
21
77
|
export class DemoFrihetClient {
|
|
22
78
|
// ---------------------------------------------------------------- Invoices
|
|
23
79
|
async listInvoices(params) {
|
|
@@ -139,13 +195,27 @@ export class DemoFrihetClient {
|
|
|
139
195
|
return simulateAction(id, { status: "paid", paidAt: paidDate ?? DEMO_NOW });
|
|
140
196
|
}
|
|
141
197
|
async getInvoicePdf(id) {
|
|
142
|
-
|
|
198
|
+
// #1393: shape mirrors the live BinaryDocument contract (id,
|
|
199
|
+
// contentType, sizeBytes, base64) so demo-mode outputSchema validation
|
|
200
|
+
// runs against the same fields as the live path.
|
|
201
|
+
const demoPdfBytes = Buffer.from("%PDF-1.4\n%%DEMO e-invoice for " + id + "\n%%EOF\n", "utf8");
|
|
202
|
+
return {
|
|
203
|
+
id,
|
|
204
|
+
contentType: "application/pdf",
|
|
205
|
+
sizeBytes: demoPdfBytes.byteLength,
|
|
206
|
+
base64: demoPdfBytes.toString("base64"),
|
|
207
|
+
...READ_STAMP,
|
|
208
|
+
};
|
|
143
209
|
}
|
|
144
210
|
async getInvoiceEInvoice(invoiceId) {
|
|
211
|
+
// #1393: mirrors the live XML arm of the MIME-discriminated contract.
|
|
212
|
+
const xml = `<?xml version="1.0" encoding="UTF-8"?>\n<Invoice><!-- DEMO example e-invoice for ${invoiceId} --></Invoice>`;
|
|
145
213
|
return {
|
|
146
|
-
|
|
214
|
+
id: invoiceId,
|
|
215
|
+
xml,
|
|
216
|
+
contentType: "application/xml; charset=utf-8",
|
|
217
|
+
sizeBytes: Buffer.byteLength(xml, "utf8"),
|
|
147
218
|
filename: `${invoiceId}.xml`,
|
|
148
|
-
format: "facturae",
|
|
149
219
|
...FISCAL_STAMP,
|
|
150
220
|
};
|
|
151
221
|
}
|
|
@@ -190,21 +260,60 @@ export class DemoFrihetClient {
|
|
|
190
260
|
return { id, status: "sent", sentAt: DEMO_NOW, ...(to ? { to } : {}), ...FISCAL_STAMP };
|
|
191
261
|
}
|
|
192
262
|
// ---------------------------------------------------------------- Webhooks
|
|
193
|
-
async listWebhooks(
|
|
194
|
-
|
|
263
|
+
async listWebhooks() {
|
|
264
|
+
const { data, total } = demoEmptyPage();
|
|
265
|
+
return { data: data, total };
|
|
195
266
|
}
|
|
196
267
|
async getWebhook(id) {
|
|
197
|
-
return {
|
|
268
|
+
return {
|
|
269
|
+
id,
|
|
270
|
+
name: "Demo webhook",
|
|
271
|
+
url: "https://example.com/webhooks/frihet",
|
|
272
|
+
events: ["invoice.paid"],
|
|
273
|
+
status: "active",
|
|
274
|
+
metadata: { demo: true },
|
|
275
|
+
hasSecret: false,
|
|
276
|
+
createdAt: DEMO_NOW,
|
|
277
|
+
updatedAt: DEMO_NOW,
|
|
278
|
+
...READ_STAMP,
|
|
279
|
+
};
|
|
198
280
|
}
|
|
199
281
|
async createWebhook(data) {
|
|
200
|
-
return simulateWrite("demo_wh",
|
|
282
|
+
return simulateWrite("demo_wh", { ...data }, {
|
|
283
|
+
status: data.status ?? "active",
|
|
284
|
+
hasSecret: typeof data.secret === "string" && data.secret.length > 0,
|
|
285
|
+
});
|
|
201
286
|
}
|
|
202
287
|
async updateWebhook(id, data) {
|
|
203
|
-
|
|
288
|
+
const { secret, ...fields } = data;
|
|
289
|
+
const { success: _success, ...result } = simulateAction(id, {
|
|
290
|
+
name: "Demo webhook",
|
|
291
|
+
url: "https://example.com/webhooks/frihet",
|
|
292
|
+
events: ["invoice.paid"],
|
|
293
|
+
status: "active",
|
|
294
|
+
metadata: { demo: true },
|
|
295
|
+
hasSecret: typeof secret === "string" && secret.length > 0,
|
|
296
|
+
...fields,
|
|
297
|
+
});
|
|
298
|
+
return result;
|
|
204
299
|
}
|
|
205
300
|
async deleteWebhook(_id) {
|
|
206
301
|
return;
|
|
207
302
|
}
|
|
303
|
+
// ---------------------------------------------------------------- Cross-resource search
|
|
304
|
+
// ----------------------------------------------------------------
|
|
305
|
+
async globalSearch(params) {
|
|
306
|
+
return {
|
|
307
|
+
data: [],
|
|
308
|
+
total: 0,
|
|
309
|
+
limit: params.limit ?? 25,
|
|
310
|
+
offset: params.offset ?? 0,
|
|
311
|
+
hasMore: false,
|
|
312
|
+
query: params.q,
|
|
313
|
+
types: params.types ?? ["invoices", "expenses", "vendors", "clients", "products"],
|
|
314
|
+
truncated: false,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
208
317
|
// ---------------------------------------------------------------- CRM: Contacts
|
|
209
318
|
async listClientContacts(_clientId, params) {
|
|
210
319
|
return demoEmptyPage(params);
|
|
@@ -219,8 +328,13 @@ export class DemoFrihetClient {
|
|
|
219
328
|
async listClientActivities(_clientId, params) {
|
|
220
329
|
return demoEmptyPage(params);
|
|
221
330
|
}
|
|
222
|
-
async logClientActivity(
|
|
223
|
-
return simulateWrite("demo_act", data, {
|
|
331
|
+
async logClientActivity(_clientId, data) {
|
|
332
|
+
return simulateWrite("demo_act", data, {
|
|
333
|
+
type: data.type === "email" ? "email_sent" : data.type,
|
|
334
|
+
timestamp: DEMO_NOW,
|
|
335
|
+
createdBy: "user",
|
|
336
|
+
metadata: {},
|
|
337
|
+
});
|
|
224
338
|
}
|
|
225
339
|
// ---------------------------------------------------------------- CRM: Notes
|
|
226
340
|
async listClientNotes(_clientId, params) {
|
|
@@ -327,7 +441,15 @@ export class DemoFrihetClient {
|
|
|
327
441
|
return { fileUrl: "https://app.frihet.io/demo/datev.csv", filename: "demo-datev.csv", rowCount: 24, fiscalPeriod: `${params.periodStart}..${params.periodEnd}`, encoding: "cp1252", ...FISCAL_STAMP };
|
|
328
442
|
}
|
|
329
443
|
async exportEInvoice(params) {
|
|
330
|
-
|
|
444
|
+
const format = toApiEInvoiceExportFormat(params.format);
|
|
445
|
+
return {
|
|
446
|
+
xml: `<?xml version="1.0" encoding="UTF-8"?><DemoEInvoice format="${format}"/>`,
|
|
447
|
+
contentType: "application/xml",
|
|
448
|
+
filename: `${params.invoiceId}.xml`,
|
|
449
|
+
format,
|
|
450
|
+
signed: params.signed ?? false,
|
|
451
|
+
...FISCAL_STAMP,
|
|
452
|
+
};
|
|
331
453
|
}
|
|
332
454
|
async faceSubmit(params) {
|
|
333
455
|
return { registroFACe: "DEMO-FACE-0001", status: "submitted", submittedAt: DEMO_NOW, mode: params.mode, ...FISCAL_STAMP };
|
|
@@ -404,7 +526,8 @@ export class DemoFrihetClient {
|
|
|
404
526
|
}
|
|
405
527
|
// ---------------------------------------------------------------- Fiscal (simulated / read summaries)
|
|
406
528
|
async getFiscalModeloSummary(modeloCode, period) {
|
|
407
|
-
|
|
529
|
+
const defaultPeriod = modeloCode === "390" || modeloCode === "347" ? "2026" : "2026-Q2";
|
|
530
|
+
return { model: modeloCode, period: period ?? defaultPeriod, readonly: true, summary: { totalRevenue: 3960.4, totalExpenses: 405.6 }, ...FISCAL_STAMP };
|
|
408
531
|
}
|
|
409
532
|
async getVerifactuStatus(invoiceId) {
|
|
410
533
|
return { invoiceId, status: "accepted", accepted: true, submittedAt: DEMO_NOW, ...FISCAL_STAMP };
|
|
@@ -476,8 +599,8 @@ export class DemoFrihetClient {
|
|
|
476
599
|
async approveGLEntry(entryId, notes) {
|
|
477
600
|
return simulateAction(entryId, { status: "approved", ...(notes ? { notes } : {}) });
|
|
478
601
|
}
|
|
479
|
-
async rejectGLEntry(entryId,
|
|
480
|
-
return simulateAction(entryId, { status: "rejected",
|
|
602
|
+
async rejectGLEntry(entryId, note) {
|
|
603
|
+
return simulateAction(entryId, { status: "rejected", note });
|
|
481
604
|
}
|
|
482
605
|
async getGLEntryAuditLog(entryId) {
|
|
483
606
|
return { entryId, log: [], ...READ_STAMP };
|
|
@@ -515,7 +638,7 @@ export class DemoFrihetClient {
|
|
|
515
638
|
return demoEmptyPage(params);
|
|
516
639
|
}
|
|
517
640
|
async createBankRule(data) {
|
|
518
|
-
return simulateWrite("demo_rule", { name: data.name,
|
|
641
|
+
return simulateWrite("demo_rule", { name: data.name, bankConditions: data.bankConditions, action: data.action, actionConfig: data.actionConfig }, { isActive: data.isActive ?? true });
|
|
519
642
|
}
|
|
520
643
|
// ---------------------------------------------------------------- Gestoria
|
|
521
644
|
async sendGestoriaMessage(data) {
|
|
@@ -549,14 +672,24 @@ export class DemoFrihetClient {
|
|
|
549
672
|
async cancelLeave(leaveId) {
|
|
550
673
|
return simulateAction(leaveId, { status: "cancelled" });
|
|
551
674
|
}
|
|
552
|
-
async attendanceClockIn(data) {
|
|
675
|
+
async attendanceClockIn(data, _idempotencyKey) {
|
|
553
676
|
return simulateWrite("demo_att", { employeeId: data.employeeId, ...(data.mood ? { mood: data.mood } : {}), ...(data.location ? { location: data.location } : {}) }, { status: "open", clockInAt: DEMO_NOW });
|
|
554
677
|
}
|
|
555
|
-
async attendanceClockOut(entryId) {
|
|
678
|
+
async attendanceClockOut(entryId, _idempotencyKey) {
|
|
556
679
|
return simulateAction(entryId, { status: "closed", clockOutAt: DEMO_NOW });
|
|
557
680
|
}
|
|
558
681
|
async getOvertimeReport(params) {
|
|
559
|
-
return {
|
|
682
|
+
return {
|
|
683
|
+
period: params.period,
|
|
684
|
+
employeeId: params.employeeId ?? null,
|
|
685
|
+
recordCount: 0,
|
|
686
|
+
dailyOvertime: [],
|
|
687
|
+
weeklyOvertime: [],
|
|
688
|
+
monthlyTotal: { workedMinutes: 0, overtimeMinutes: 0, regularMinutes: 0 },
|
|
689
|
+
annualOvertimeHours: 0,
|
|
690
|
+
alerts: [],
|
|
691
|
+
...READ_STAMP,
|
|
692
|
+
};
|
|
560
693
|
}
|
|
561
694
|
async listAnomalies(params) {
|
|
562
695
|
return demoEmptyPage(params);
|
|
@@ -565,30 +698,68 @@ export class DemoFrihetClient {
|
|
|
565
698
|
async testWebhook(id, data) {
|
|
566
699
|
return { webhookId: id, delivered: true, statusCode: 200, responseTimeMs: 42, eventType: data?.eventType ?? "ping", attemptedAt: DEMO_NOW, ...FISCAL_STAMP };
|
|
567
700
|
}
|
|
568
|
-
// ---------------------------------------------------------------- Payroll (
|
|
701
|
+
// ---------------------------------------------------------------- Payroll (read-only demo)
|
|
569
702
|
async exportPayroll(params) {
|
|
570
|
-
return {
|
|
703
|
+
return {
|
|
704
|
+
month: params.month,
|
|
705
|
+
format: params.format,
|
|
706
|
+
employees: [],
|
|
707
|
+
summary: { exportedCount: 0, skippedNotReady: 0, totalGrossAnnual: 0 },
|
|
708
|
+
...READ_STAMP,
|
|
709
|
+
};
|
|
571
710
|
}
|
|
572
711
|
async getPayrollChecklist(params) {
|
|
573
|
-
return {
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
async setOnboardingPersona(data) {
|
|
580
|
-
return { workspaceId: "demo_ws_001", persona: data.persona, updatedAt: DEMO_NOW, ...READ_STAMP };
|
|
712
|
+
return {
|
|
713
|
+
month: params.month,
|
|
714
|
+
employees: [],
|
|
715
|
+
summary: { total: 0, ready: 0, notReady: 0, reviewedThisMonth: 0 },
|
|
716
|
+
...READ_STAMP,
|
|
717
|
+
};
|
|
581
718
|
}
|
|
582
719
|
// ---------------------------------------------------------------- Permissions
|
|
583
720
|
async getPermissionsMatrix() {
|
|
584
|
-
return {
|
|
721
|
+
return {
|
|
722
|
+
roles: DEMO_RBAC_ROLES,
|
|
723
|
+
resources: DEMO_RBAC_RESOURCES,
|
|
724
|
+
actions: DEMO_RBAC_ACTIONS,
|
|
725
|
+
legacyAliases: { editor: "sales" },
|
|
726
|
+
matrix: DEMO_PERMISSION_MATRIX,
|
|
727
|
+
source: "hand-maintained demo snapshot of the Frihet RBAC model; not derived from firestore.rules and not verified against it",
|
|
728
|
+
...READ_STAMP,
|
|
729
|
+
};
|
|
585
730
|
}
|
|
586
731
|
async getMyPermissions() {
|
|
587
|
-
return {
|
|
732
|
+
return {
|
|
733
|
+
role: "owner",
|
|
734
|
+
isOwner: true,
|
|
735
|
+
resources: DEMO_PERMISSION_MATRIX.owner,
|
|
736
|
+
scopes: DEMO_OWNER_CAPABILITIES,
|
|
737
|
+
legacyFieldSemantics: { resources: "rbacResources", scopes: "rbacCapabilities" },
|
|
738
|
+
rbac: {
|
|
739
|
+
role: "owner",
|
|
740
|
+
isOwner: true,
|
|
741
|
+
resources: DEMO_PERMISSION_MATRIX.owner,
|
|
742
|
+
capabilities: DEMO_OWNER_CAPABILITIES,
|
|
743
|
+
},
|
|
744
|
+
apiKeyScopes: [],
|
|
745
|
+
apiKeyUnrestricted: true,
|
|
746
|
+
denied: { einvoice: false },
|
|
747
|
+
deniedSemantics: "Known API-key scope denials only; not an exhaustive effective-authorization report.",
|
|
748
|
+
notIncluded: ["featureFlags", "deployedEndpoints"],
|
|
749
|
+
...READ_STAMP,
|
|
750
|
+
};
|
|
588
751
|
}
|
|
589
752
|
// ---------------------------------------------------------------- Period close
|
|
590
753
|
async getCurrentPeriod(params) {
|
|
591
|
-
|
|
754
|
+
const fiscalYear = params?.fiscalYear ?? "2026";
|
|
755
|
+
return {
|
|
756
|
+
fiscalYear,
|
|
757
|
+
fiscalYearStart: "01-01",
|
|
758
|
+
status: "open",
|
|
759
|
+
dateRange: { from: `${fiscalYear}-01-01`, to: `${fiscalYear}-12-31` },
|
|
760
|
+
closing: null,
|
|
761
|
+
...READ_STAMP,
|
|
762
|
+
};
|
|
592
763
|
}
|
|
593
764
|
async closePeriod(data) {
|
|
594
765
|
return simulateWrite("demo_period", { type: data.type }, { status: "closed", closedAt: DEMO_NOW });
|
package/dist/demo-fixtures.d.ts
CHANGED
|
@@ -30,13 +30,13 @@ export declare const EMPTY_STAMP: DemoStamp;
|
|
|
30
30
|
export declare const DEMO_NOW = "2026-07-15T10:00:00.000Z";
|
|
31
31
|
/** Test IBAN (ECBS/AEAT example — never a real account). */
|
|
32
32
|
export declare const DEMO_TEST_IBAN = "ES9121000418450200051332";
|
|
33
|
-
export type DemoPaginated = PaginatedResponse<Record<string, unknown
|
|
34
|
-
/** Wrap a fixture array in a
|
|
33
|
+
export type DemoPaginated = PaginatedResponse<Record<string, unknown>>;
|
|
34
|
+
/** Wrap a fixture array in a PaginatedResponse. */
|
|
35
35
|
export declare function demoPage(data: Record<string, unknown>[], params?: {
|
|
36
36
|
limit?: number;
|
|
37
37
|
offset?: number;
|
|
38
38
|
}): DemoPaginated;
|
|
39
|
-
/** Empty
|
|
39
|
+
/** Empty PaginatedResponse for surfaces without dedicated fixtures. */
|
|
40
40
|
export declare function demoEmptyPage(params?: {
|
|
41
41
|
limit?: number;
|
|
42
42
|
offset?: number;
|
package/dist/demo-fixtures.js
CHANGED
|
@@ -36,24 +36,24 @@ export const EMPTY_STAMP = {
|
|
|
36
36
|
export const DEMO_NOW = "2026-07-15T10:00:00.000Z";
|
|
37
37
|
/** Test IBAN (ECBS/AEAT example — never a real account). */
|
|
38
38
|
export const DEMO_TEST_IBAN = "ES9121000418450200051332";
|
|
39
|
-
/** Wrap a fixture array in a
|
|
39
|
+
/** Wrap a fixture array in a PaginatedResponse. */
|
|
40
40
|
export function demoPage(data, params) {
|
|
41
|
+
const limit = params?.limit ?? 50;
|
|
42
|
+
const offset = params?.offset ?? 0;
|
|
41
43
|
return {
|
|
42
|
-
data,
|
|
44
|
+
data: data.slice(offset, offset + limit),
|
|
43
45
|
total: data.length,
|
|
44
|
-
limit
|
|
45
|
-
offset
|
|
46
|
-
...READ_STAMP,
|
|
46
|
+
limit,
|
|
47
|
+
offset,
|
|
47
48
|
};
|
|
48
49
|
}
|
|
49
|
-
/** Empty
|
|
50
|
+
/** Empty PaginatedResponse for surfaces without dedicated fixtures. */
|
|
50
51
|
export function demoEmptyPage(params) {
|
|
51
52
|
return {
|
|
52
53
|
data: [],
|
|
53
54
|
total: 0,
|
|
54
55
|
limit: params?.limit ?? 50,
|
|
55
56
|
offset: params?.offset ?? 0,
|
|
56
|
-
...EMPTY_STAMP,
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
/* ------------------------------------------------------------------ */
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
/** Locally generated guidance only: never includes input values or provider text. */
|
|
3
|
+
export declare class DepositInputError extends Error {
|
|
4
|
+
readonly statusCode = 400;
|
|
5
|
+
readonly errorCode = "invalid_deposit_input";
|
|
6
|
+
constructor(message: string);
|
|
7
|
+
}
|
|
8
|
+
/** Writable fields accepted by publicApi v132's strict deposits schema. */
|
|
9
|
+
export declare const depositFields: {
|
|
10
|
+
clientId: z.ZodString;
|
|
11
|
+
clientName: z.ZodString;
|
|
12
|
+
amount: z.ZodNumber;
|
|
13
|
+
currency: z.ZodString;
|
|
14
|
+
description: z.ZodString;
|
|
15
|
+
receivedDate: z.ZodString;
|
|
16
|
+
paymentMethod: z.ZodOptional<z.ZodString>;
|
|
17
|
+
paymentReference: z.ZodOptional<z.ZodString>;
|
|
18
|
+
};
|
|
19
|
+
/** Writable fields accepted by publicApi v132's strict /deposits/:id/apply schema. */
|
|
20
|
+
export declare const applyDepositFields: {
|
|
21
|
+
invoiceId: z.ZodString;
|
|
22
|
+
invoiceNumber: z.ZodString;
|
|
23
|
+
amount: z.ZodNumber;
|
|
24
|
+
};
|
|
25
|
+
/** Validate deposit application payload against the strict backend contract before request I/O. */
|
|
26
|
+
export declare function normalizeApplyDepositBody(input?: Record<string, unknown>): Record<string, unknown>;
|
|
27
|
+
/** Preserve the established MCP date/reference names on the canonical API wire. */
|
|
28
|
+
export declare function normalizeDepositBody(input: Record<string, unknown>, partial: boolean): Record<string, unknown>;
|
|
29
|
+
//# sourceMappingURL=deposit-contract.d.ts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
/** Locally generated guidance only: never includes input values or provider text. */
|
|
3
|
+
export class DepositInputError extends Error {
|
|
4
|
+
statusCode = 400;
|
|
5
|
+
errorCode = "invalid_deposit_input";
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "DepositInputError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/** Writable fields accepted by publicApi v132's strict deposits schema. */
|
|
12
|
+
export const depositFields = {
|
|
13
|
+
clientId: z.string().min(1).max(128),
|
|
14
|
+
clientName: z.string().min(1).max(500),
|
|
15
|
+
amount: z.number().positive(),
|
|
16
|
+
currency: z.string().length(3),
|
|
17
|
+
description: z.string().min(1).max(2000),
|
|
18
|
+
receivedDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
|
|
19
|
+
paymentMethod: z.string().max(200).optional(),
|
|
20
|
+
paymentReference: z.string().max(200).optional(),
|
|
21
|
+
};
|
|
22
|
+
/** Writable fields accepted by publicApi v132's strict /deposits/:id/apply schema. */
|
|
23
|
+
export const applyDepositFields = {
|
|
24
|
+
invoiceId: z.string().min(1).max(128),
|
|
25
|
+
invoiceNumber: z.string().min(1).max(200),
|
|
26
|
+
amount: z.number().positive(),
|
|
27
|
+
};
|
|
28
|
+
const applyDepositBody = z.object(applyDepositFields).strict();
|
|
29
|
+
/** Validate deposit application payload against the strict backend contract before request I/O. */
|
|
30
|
+
export function normalizeApplyDepositBody(input = {}) {
|
|
31
|
+
if (Object.prototype.hasOwnProperty.call(input, "notes")) {
|
|
32
|
+
throw new DepositInputError("Deposit application field 'notes' is not writable; the API does not accept it. / El campo 'notes' no se puede guardar al aplicar el depósito.");
|
|
33
|
+
}
|
|
34
|
+
const parsed = applyDepositBody.safeParse(input);
|
|
35
|
+
if (!parsed.success) {
|
|
36
|
+
const known = new Set(Object.keys(applyDepositFields));
|
|
37
|
+
const fields = [...new Set(parsed.error.issues.map((issue) => issue.path[0]).filter((field) => typeof field === "string" && known.has(field)))];
|
|
38
|
+
throw new DepositInputError(`Invalid deposit application input${fields.length ? ` (${fields.join(", ")})` : ""}. Provide invoiceId, invoiceNumber and a positive amount. / Indica invoiceId, invoiceNumber y un importe positivo.`);
|
|
39
|
+
}
|
|
40
|
+
return parsed.data;
|
|
41
|
+
}
|
|
42
|
+
const createDepositBody = z.object({
|
|
43
|
+
...depositFields,
|
|
44
|
+
currency: depositFields.currency.default("EUR"),
|
|
45
|
+
}).strict();
|
|
46
|
+
// PATCH must not inject the create default or turn an empty update into a write.
|
|
47
|
+
const updateDepositBody = z.object(depositFields).partial().strict().refine((fields) => Object.values(fields).some((value) => value !== undefined), { message: "Provide at least one writable deposit field / Indica al menos un campo del depósito" });
|
|
48
|
+
/** Preserve the established MCP date/reference names on the canonical API wire. */
|
|
49
|
+
export function normalizeDepositBody(input, partial) {
|
|
50
|
+
const body = { ...input };
|
|
51
|
+
for (const unsupported of ["status", "notes"]) {
|
|
52
|
+
if (Object.prototype.hasOwnProperty.call(body, unsupported)) {
|
|
53
|
+
throw new DepositInputError(`Deposit field '${unsupported}' is not writable; the API does not accept it. / El campo '${unsupported}' no se puede guardar en el depósito.`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
for (const [alias, canonical] of [["date", "receivedDate"], ["reference", "paymentReference"]]) {
|
|
57
|
+
if (body[alias] !== undefined) {
|
|
58
|
+
if (body[canonical] !== undefined && body[canonical] !== body[alias]) {
|
|
59
|
+
throw new DepositInputError(`Conflicting deposit fields '${alias}' and '${canonical}'. / Los campos '${alias}' y '${canonical}' no coinciden.`);
|
|
60
|
+
}
|
|
61
|
+
body[canonical] = body[alias];
|
|
62
|
+
}
|
|
63
|
+
delete body[alias];
|
|
64
|
+
}
|
|
65
|
+
const parsed = (partial ? updateDepositBody : createDepositBody).safeParse(body);
|
|
66
|
+
if (!parsed.success) {
|
|
67
|
+
const known = new Set(Object.keys(depositFields));
|
|
68
|
+
const fields = [...new Set(parsed.error.issues.map((issue) => issue.path[0]).filter((field) => typeof field === "string" && known.has(field)))];
|
|
69
|
+
const guidance = partial
|
|
70
|
+
? "Provide at least one valid writable deposit field; date uses YYYY-MM-DD. / Indica al menos un campo editable válido; date usa YYYY-MM-DD."
|
|
71
|
+
: "Provide clientId, clientName, a positive amount, description and receivedDate (date) in YYYY-MM-DD format. / Indica clientId, clientName, un importe positivo, description y receivedDate (date) con formato YYYY-MM-DD.";
|
|
72
|
+
throw new DepositInputError(`Invalid deposit input${fields.length ? ` (${fields.join(", ")})` : ""}. ${guidance}`);
|
|
73
|
+
}
|
|
74
|
+
return parsed.data;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=deposit-contract.js.map
|