@fidacy/mcp 0.1.5 → 0.1.6

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/dist/lib.js CHANGED
@@ -1,5 +1,527 @@
1
- export * from "./types.js";
2
- export * from "./core.js";
3
- export * from "./executor.js";
4
- export * from "./signing.js";
5
- //# sourceMappingURL=lib.js.map
1
+ // ../firewall/dist/util.js
2
+ function stableStringify(obj) {
3
+ if (obj === null || typeof obj !== "object")
4
+ return JSON.stringify(obj);
5
+ if (Array.isArray(obj))
6
+ return "[" + obj.map(stableStringify).join(",") + "]";
7
+ const keys = Object.keys(obj).sort();
8
+ return "{" + keys.map((k) => JSON.stringify(k) + ":" + stableStringify(obj[k])).join(",") + "}";
9
+ }
10
+
11
+ // ../firewall/dist/signing.js
12
+ import crypto from "node:crypto";
13
+ function loadOrGenerateKeyPair() {
14
+ const b64 = process.env.FIDACY_SIGNING_KEY_B64;
15
+ if (b64) {
16
+ const pem = Buffer.from(b64, "base64").toString("utf8");
17
+ const privateKey2 = crypto.createPrivateKey(pem);
18
+ const publicKey2 = crypto.createPublicKey(privateKey2);
19
+ return { privateKey: privateKey2, publicKey: publicKey2, ephemeral: false };
20
+ }
21
+ const { privateKey, publicKey } = crypto.generateKeyPairSync("ed25519");
22
+ return { privateKey, publicKey, ephemeral: true };
23
+ }
24
+ function publicKeyPem(publicKey) {
25
+ return publicKey.export({ type: "spki", format: "pem" }).toString();
26
+ }
27
+ function sign(privateKey, message) {
28
+ return crypto.sign(null, Buffer.from(message, "utf8"), privateKey).toString("base64url");
29
+ }
30
+ function verify(publicKey, message, signatureB64url) {
31
+ try {
32
+ return crypto.verify(null, Buffer.from(message, "utf8"), publicKey, Buffer.from(signatureB64url, "base64url"));
33
+ } catch {
34
+ return false;
35
+ }
36
+ }
37
+ function sha256(input) {
38
+ return crypto.createHash("sha256").update(input).digest("hex");
39
+ }
40
+
41
+ // ../firewall/dist/grant.js
42
+ import crypto2 from "node:crypto";
43
+ function verifyGrant(publicKeyPem2, grant, expected) {
44
+ const parts = grant.split(".");
45
+ if (parts.length !== 2 || !parts[0] || !parts[1])
46
+ return { valid: false, reason: "malformed_grant" };
47
+ const [body, sig] = parts;
48
+ let pub;
49
+ try {
50
+ pub = crypto2.createPublicKey(publicKeyPem2);
51
+ } catch {
52
+ return { valid: false, reason: "bad_public_key" };
53
+ }
54
+ if (!verify(pub, body, sig))
55
+ return { valid: false, reason: "invalid_signature" };
56
+ let payload;
57
+ try {
58
+ payload = JSON.parse(Buffer.from(body, "base64url").toString("utf8"));
59
+ } catch {
60
+ return { valid: false, reason: "undecodable_payload" };
61
+ }
62
+ if (Date.now() > payload.exp)
63
+ return { valid: false, reason: "grant_expired" };
64
+ if (payload.payee !== expected.payee)
65
+ return { valid: false, reason: `payee_mismatch:${payload.payee}!=${expected.payee}` };
66
+ if (payload.amount !== expected.amount)
67
+ return { valid: false, reason: `amount_mismatch:${payload.amount}!=${expected.amount}` };
68
+ if (payload.currency !== expected.currency)
69
+ return { valid: false, reason: `currency_mismatch` };
70
+ if ((payload.invoiceRef ?? null) !== (expected.invoiceRef ?? null))
71
+ return { valid: false, reason: `invoice_mismatch:${payload.invoiceRef ?? "none"}!=${expected.invoiceRef ?? "none"}` };
72
+ return { valid: true, payload };
73
+ }
74
+
75
+ // ../firewall/dist/audit-store.js
76
+ import fs from "node:fs";
77
+ var FileAuditStore = class {
78
+ path;
79
+ chain = [];
80
+ constructor(path) {
81
+ this.path = path;
82
+ this.load();
83
+ }
84
+ load() {
85
+ if (!fs.existsSync(this.path))
86
+ return;
87
+ try {
88
+ const raw = fs.readFileSync(this.path, "utf8");
89
+ const parsed = [];
90
+ for (const line of raw.split("\n")) {
91
+ if (!line.trim())
92
+ continue;
93
+ parsed.push(JSON.parse(line));
94
+ }
95
+ this.chain = parsed;
96
+ if (!this.intact())
97
+ throw new Error("audit chain integrity broken");
98
+ } catch (err) {
99
+ this.chain = [];
100
+ try {
101
+ const quarantine = `${this.path}.corrupt-${Date.now()}`;
102
+ fs.renameSync(this.path, quarantine);
103
+ console.error(`[fidacy] audit log at ${this.path} is unreadable/tampered (${err.message}); quarantined to ${quarantine}, starting a fresh chain.`);
104
+ } catch {
105
+ console.error(`[fidacy] audit log at ${this.path} is unreadable/tampered and could not be quarantined; starting a fresh in-memory chain.`);
106
+ }
107
+ }
108
+ }
109
+ head() {
110
+ return this.chain.length ? this.chain[this.chain.length - 1].hash : "GENESIS";
111
+ }
112
+ append(decision) {
113
+ const prevHash = this.head();
114
+ const seq = this.chain.length;
115
+ const ts = decision.ts;
116
+ const digest = sha256(stableStringify({ decisionId: decision.decisionId, status: decision.status, request: decision.request, violatedRule: decision.violatedRule ?? null }));
117
+ const hash = sha256(`${prevHash}|${digest}|${seq}|${ts}`);
118
+ const record2 = { seq, decisionId: decision.decisionId, status: decision.status, subject: decision.subject, digest, prevHash, hash, ts };
119
+ fs.appendFileSync(this.path, JSON.stringify(record2) + "\n");
120
+ this.chain.push(record2);
121
+ return record2;
122
+ }
123
+ find(decisionId) {
124
+ return this.chain.find((r) => r.decisionId === decisionId);
125
+ }
126
+ intact() {
127
+ let prev = "GENESIS";
128
+ for (const r of this.chain) {
129
+ const expected = sha256(`${prev}|${r.digest}|${r.seq}|${r.ts}`);
130
+ if (expected !== r.hash || r.prevHash !== prev)
131
+ return false;
132
+ prev = r.hash;
133
+ }
134
+ return true;
135
+ }
136
+ };
137
+
138
+ // ../firewall/dist/executor.js
139
+ import { createPublicKey } from "node:crypto";
140
+ import { randomUUID } from "node:crypto";
141
+ var ReferenceRail = class {
142
+ settlements = [];
143
+ async execute(req) {
144
+ const railRef = "ref_" + randomUUID();
145
+ this.settlements.push({ ...req, railRef, at: (/* @__PURE__ */ new Date()).toISOString() });
146
+ return { railRef };
147
+ }
148
+ };
149
+ var GrantEnforcingExecutor = class {
150
+ rail;
151
+ used = /* @__PURE__ */ new Set();
152
+ pub;
153
+ constructor(publicKeyPem2, rail) {
154
+ this.rail = rail;
155
+ this.pub = createPublicKey(publicKeyPem2);
156
+ }
157
+ async execute(req, grant) {
158
+ if (!grant)
159
+ return { status: "REFUSED", reason: "missing_grant" };
160
+ const dot = grant.indexOf(".");
161
+ if (dot < 0)
162
+ return { status: "REFUSED", reason: "malformed_grant" };
163
+ const body = grant.slice(0, dot);
164
+ const sig = grant.slice(dot + 1);
165
+ if (!verify(this.pub, body, sig))
166
+ return { status: "REFUSED", reason: "invalid_signature" };
167
+ let p;
168
+ try {
169
+ p = JSON.parse(Buffer.from(body, "base64url").toString("utf8"));
170
+ } catch {
171
+ return { status: "REFUSED", reason: "undecodable_grant" };
172
+ }
173
+ if (Date.now() > p.exp)
174
+ return { status: "REFUSED", reason: "grant_expired" };
175
+ if (this.used.has(p.decisionId))
176
+ return { status: "REFUSED", reason: "grant_replayed" };
177
+ if (p.payee !== req.payee)
178
+ return { status: "REFUSED", reason: "payee_mismatch" };
179
+ if (p.amount !== req.amount)
180
+ return { status: "REFUSED", reason: "amount_mismatch" };
181
+ if (p.currency !== req.currency)
182
+ return { status: "REFUSED", reason: "currency_mismatch" };
183
+ if (req.invoiceRef != null && req.invoiceRef !== (p.invoiceRef ?? null)) {
184
+ return { status: "REFUSED", reason: "invoice_mismatch" };
185
+ }
186
+ this.used.add(p.decisionId);
187
+ const { railRef } = await this.rail.execute(req);
188
+ return { status: "EXECUTED", railRef, decisionId: p.decisionId };
189
+ }
190
+ };
191
+
192
+ // ../firewall/dist/evaluate.js
193
+ function evaluate(mandate, req, spentSoFar) {
194
+ const now = Date.now();
195
+ if (mandate.revoked)
196
+ return "mandate_revoked";
197
+ if (now < Date.parse(mandate.window.notBefore))
198
+ return "before_mandate_window";
199
+ if (now > Date.parse(mandate.window.notAfter))
200
+ return "after_mandate_window";
201
+ if (req.currency !== mandate.allow.currency)
202
+ return `currency_not_allowed:${req.currency}`;
203
+ if (req.amount <= 0)
204
+ return "non_positive_amount";
205
+ if (req.amount > mandate.allow.perTxMax)
206
+ return `per_tx_cap_exceeded:${req.amount}>${mandate.allow.perTxMax}`;
207
+ if (spentSoFar + req.amount > mandate.allow.maxTotal)
208
+ return `total_cap_exceeded:${spentSoFar + req.amount}>${mandate.allow.maxTotal}`;
209
+ const payeeOk = mandate.allow.payees.includes("*") || mandate.allow.payees.includes(req.payee);
210
+ if (!payeeOk)
211
+ return `payee_not_in_allowlist:${req.payee}`;
212
+ const catOk = mandate.allow.categories.includes("*") || mandate.allow.categories.includes(req.category);
213
+ if (!catOk)
214
+ return `category_not_allowed:${req.category}`;
215
+ return null;
216
+ }
217
+
218
+ // ../firewall/dist/core.js
219
+ import { randomUUID as randomUUID2 } from "node:crypto";
220
+ function canonInvoice(ref) {
221
+ if (typeof ref !== "string")
222
+ return "";
223
+ return ref.normalize("NFC").replace(/[\s\u200B\u200C\u200D\uFEFF]+/g, "").toLowerCase();
224
+ }
225
+ function validateRequest(req) {
226
+ if (!req || typeof req !== "object")
227
+ return "invalid_request";
228
+ if (typeof req.amount !== "number" || !Number.isFinite(req.amount) || req.amount <= 0)
229
+ return "invalid_amount";
230
+ if (typeof req.payee !== "string" || req.payee.length === 0)
231
+ return "invalid_payee";
232
+ if (typeof req.currency !== "string" || req.currency.length === 0)
233
+ return "invalid_currency";
234
+ return null;
235
+ }
236
+ function requireHttpsBase(raw) {
237
+ const trimmed = String(raw ?? "").replace(/\/+$/, "");
238
+ let u;
239
+ try {
240
+ u = new URL(trimmed);
241
+ } catch {
242
+ throw new Error("FIDACY_API_URL is not a valid URL");
243
+ }
244
+ const localHttp = u.protocol === "http:" && (u.hostname === "localhost" || u.hostname === "127.0.0.1" || u.hostname === "[::1]");
245
+ if (u.protocol !== "https:" && !localHttp) {
246
+ throw new Error("FIDACY_API_URL must be https:// (the API key is sent to it)");
247
+ }
248
+ return trimmed;
249
+ }
250
+ var DevFidacyCore = class {
251
+ priv;
252
+ pubPem;
253
+ mandate;
254
+ store;
255
+ spent = 0;
256
+ claimedInvoices = /* @__PURE__ */ new Set();
257
+ onDecision;
258
+ constructor(opts) {
259
+ const kp = loadOrGenerateKeyPair();
260
+ this.priv = kp.privateKey;
261
+ this.pubPem = publicKeyPem(kp.publicKey);
262
+ if (kp.ephemeral)
263
+ console.error("[fidacy] dev mode: ephemeral signing key. Production: set FIDACY_SIGNING_KEY_B64, or FIDACY_MODE=http + FIDACY_API_URL + FIDACY_API_KEY to use the live core.");
264
+ this.mandate = opts.mandate;
265
+ this.store = new FileAuditStore(opts.auditLogPath ?? "./fidacy-audit.log");
266
+ this.onDecision = opts.onDecision;
267
+ }
268
+ async getMandate() {
269
+ return this.mandate;
270
+ }
271
+ async decide(req, subject) {
272
+ const decisionId = randomUUID2();
273
+ const ts = (/* @__PURE__ */ new Date()).toISOString();
274
+ const invalid = validateRequest(req);
275
+ if (invalid) {
276
+ const decision2 = { decisionId, status: "DENY", subject, mandateId: this.mandate.id, request: req, violatedRule: invalid, ts };
277
+ this.store.append(decision2);
278
+ this.onDecision?.(decision2);
279
+ return decision2;
280
+ }
281
+ const violated = evaluate(this.mandate, req, this.spent);
282
+ if (violated) {
283
+ const decision2 = { decisionId, status: "DENY", subject, mandateId: this.mandate.id, request: req, violatedRule: violated, ts };
284
+ this.store.append(decision2);
285
+ this.onDecision?.(decision2);
286
+ return decision2;
287
+ }
288
+ const invoice = canonInvoice(req.invoiceRef);
289
+ if (invoice) {
290
+ const k = `${subject}|${invoice}`;
291
+ if (this.claimedInvoices.has(k)) {
292
+ const decision2 = { decisionId, status: "DENY", subject, mandateId: this.mandate.id, request: req, violatedRule: `duplicate_invoice:${invoice}`, ts };
293
+ this.store.append(decision2);
294
+ this.onDecision?.(decision2);
295
+ return decision2;
296
+ }
297
+ this.claimedInvoices.add(k);
298
+ }
299
+ const grantPayload = { decisionId, subject, payee: req.payee, amount: req.amount, currency: req.currency, exp: Date.now() + 12e4, ...req.invoiceRef ? { invoiceRef: req.invoiceRef } : {} };
300
+ const grantBody = Buffer.from(stableStringify(grantPayload), "utf8").toString("base64url");
301
+ const grant = `${grantBody}.${sign(this.priv, grantBody)}`;
302
+ const decision = { decisionId, status: "ALLOW", subject, mandateId: this.mandate.id, request: req, grant, ts };
303
+ this.spent += req.amount;
304
+ this.store.append(decision);
305
+ this.onDecision?.(decision);
306
+ return decision;
307
+ }
308
+ async getProof(decisionId) {
309
+ const record2 = this.store.find(decisionId);
310
+ if (!record2)
311
+ return null;
312
+ return { record: record2, chainIntact: this.store.intact(), verifiedAgainstPublicKey: this.pubPem };
313
+ }
314
+ publicKey() {
315
+ return this.pubPem;
316
+ }
317
+ };
318
+ var HttpFidacyCore = class {
319
+ apiKey;
320
+ subjectPub;
321
+ baseUrl;
322
+ // Enforce https before any key-bearing request — a hostile FIDACY_API_URL would
323
+ // otherwise exfiltrate the API key in the Authorization header.
324
+ constructor(baseUrl, apiKey, subjectPub = "") {
325
+ this.apiKey = apiKey;
326
+ this.subjectPub = subjectPub;
327
+ this.baseUrl = requireHttpsBase(baseUrl);
328
+ }
329
+ async call(path, body) {
330
+ const res = await fetch(`${this.baseUrl}${path}`, {
331
+ method: "POST",
332
+ headers: { "content-type": "application/json", authorization: `Bearer ${this.apiKey}` },
333
+ body: JSON.stringify(body)
334
+ });
335
+ if (!res.ok)
336
+ throw new Error(`fidacy core ${path} -> ${res.status}`);
337
+ return await res.json();
338
+ }
339
+ async getMandate(subject) {
340
+ return this.call("/v1/mandate/get", { subject });
341
+ }
342
+ async decide(req, subject) {
343
+ return this.call("/v1/decide", { req, subject });
344
+ }
345
+ async getProof(decisionId) {
346
+ return this.call("/v1/audit/proof", { decisionId });
347
+ }
348
+ publicKey() {
349
+ return this.subjectPub;
350
+ }
351
+ };
352
+
353
+ // src/config.ts
354
+ import { homedir } from "node:os";
355
+ import { join } from "node:path";
356
+ import {
357
+ existsSync,
358
+ mkdirSync,
359
+ readFileSync,
360
+ writeFileSync
361
+ } from "node:fs";
362
+ function configDir() {
363
+ return process.env.FIDACY_CONFIG_DIR ?? join(homedir(), ".fidacy");
364
+ }
365
+ function configPath() {
366
+ return join(configDir(), "config.json");
367
+ }
368
+ function auditLogPath() {
369
+ if (process.env.FIDACY_AUDIT_PATH) return process.env.FIDACY_AUDIT_PATH;
370
+ const dir = join(configDir(), "audit");
371
+ try {
372
+ mkdirSync(dir, { recursive: true, mode: 448 });
373
+ } catch {
374
+ }
375
+ return join(dir, "audit.log");
376
+ }
377
+ function readConfig() {
378
+ const p = configPath();
379
+ if (!existsSync(p)) return null;
380
+ try {
381
+ const raw = JSON.parse(readFileSync(p, "utf8"));
382
+ if (!raw || typeof raw.anon_id !== "string") return null;
383
+ return {
384
+ anon_id: raw.anon_id,
385
+ tier: raw.tier === "paid" ? "paid" : "free",
386
+ api_key: typeof raw.api_key === "string" ? raw.api_key : null,
387
+ mandate: raw.mandate
388
+ };
389
+ } catch {
390
+ return null;
391
+ }
392
+ }
393
+ function resolveMandateRules(cfg) {
394
+ const m = cfg?.mandate ?? {};
395
+ const envList = (v) => v === void 0 ? void 0 : v.split(",").map((s) => s.trim()).filter(Boolean);
396
+ const envNum = (v) => v === void 0 || v === "" ? void 0 : Number(v);
397
+ return {
398
+ payees: envList(process.env.FIDACY_ALLOW_PAYEES) ?? m.payees ?? [],
399
+ categories: envList(process.env.FIDACY_ALLOW_CATEGORIES) ?? m.categories ?? ["*"],
400
+ currency: process.env.FIDACY_CURRENCY ?? m.currency ?? "USD",
401
+ perTxMax: envNum(process.env.FIDACY_PER_TX_MAX) ?? m.perTxMax ?? 2500,
402
+ maxTotal: envNum(process.env.FIDACY_MAX_TOTAL) ?? m.maxTotal ?? 1e4
403
+ };
404
+ }
405
+
406
+ // src/telemetry.ts
407
+ var CLIENT_VERSION = "0.1.5";
408
+ function telemetryEnabled() {
409
+ const v = (process.env.FIDACY_DISABLE_TELEMETRY ?? "").trim().toLowerCase();
410
+ return !(v === "1" || v === "true" || v === "yes");
411
+ }
412
+ function endpoint() {
413
+ const base = (process.env.FIDACY_ENGINE_URL ?? "https://api.fidacy.com").replace(/\/$/, "");
414
+ return `${base}/v1/telemetry`;
415
+ }
416
+ var anonIdCache = null;
417
+ function anonId() {
418
+ if (anonIdCache) return anonIdCache;
419
+ anonIdCache = readConfig()?.anon_id ?? null;
420
+ return anonIdCache;
421
+ }
422
+ var buffer = [];
423
+ var flushTimer = null;
424
+ function resultOf(status, violatedRule) {
425
+ if (status === "ALLOW") return "allow";
426
+ const r = violatedRule ?? "";
427
+ if (r.startsWith("per_tx_cap") || r.startsWith("total_cap")) return "deny_cap";
428
+ if (r.startsWith("payee_not_in_allowlist")) return "deny_payee";
429
+ return "deny_scope";
430
+ }
431
+ function record(type, result) {
432
+ if (!telemetryEnabled()) return;
433
+ buffer.push({ type, ts: (/* @__PURE__ */ new Date()).toISOString(), client_version: CLIENT_VERSION, ...result ? { result } : {} });
434
+ if (!flushTimer) {
435
+ flushTimer = setTimeout(() => {
436
+ void flush();
437
+ }, 2e3);
438
+ if (typeof flushTimer.unref === "function") flushTimer.unref();
439
+ }
440
+ }
441
+ var recordDecision = (status, violatedRule) => record("decision", resultOf(status, violatedRule));
442
+ async function flush() {
443
+ if (flushTimer) {
444
+ clearTimeout(flushTimer);
445
+ flushTimer = null;
446
+ }
447
+ if (!telemetryEnabled() || buffer.length === 0) return;
448
+ const id = anonId();
449
+ if (!id) {
450
+ buffer = [];
451
+ return;
452
+ }
453
+ const events = buffer;
454
+ buffer = [];
455
+ try {
456
+ await fetch(endpoint(), {
457
+ method: "POST",
458
+ headers: { "content-type": "application/json" },
459
+ body: JSON.stringify({ anon_id: id, events })
460
+ });
461
+ } catch {
462
+ }
463
+ }
464
+
465
+ // src/core.ts
466
+ function buildMandate() {
467
+ if (process.env.FIDACY_MANDATE_JSON) {
468
+ try {
469
+ const parsed = JSON.parse(process.env.FIDACY_MANDATE_JSON);
470
+ if (parsed && typeof parsed === "object" && parsed.allow && parsed.window) return parsed;
471
+ console.error("[fidacy] FIDACY_MANDATE_JSON is missing allow/window; ignoring it and using the safe default mandate.");
472
+ } catch (err) {
473
+ console.error(`[fidacy] FIDACY_MANDATE_JSON is not valid JSON (${err.message}); ignoring it and using the safe default mandate.`);
474
+ }
475
+ }
476
+ const subject = process.env.FIDACY_SUBJECT ?? "agent:demo";
477
+ const rules = resolveMandateRules(readConfig());
478
+ return {
479
+ id: "mandate:local",
480
+ subject,
481
+ version: "ap2.v0.2.0",
482
+ allow: {
483
+ payees: rules.payees,
484
+ categories: rules.categories,
485
+ currency: rules.currency,
486
+ maxTotal: rules.maxTotal,
487
+ perTxMax: rules.perTxMax
488
+ },
489
+ window: {
490
+ notBefore: process.env.FIDACY_NOT_BEFORE ?? new Date(Date.now() - 36e5).toISOString(),
491
+ notAfter: process.env.FIDACY_NOT_AFTER ?? new Date(Date.now() + 30 * 864e5).toISOString()
492
+ },
493
+ revoked: false
494
+ };
495
+ }
496
+ function makeCore() {
497
+ if ((process.env.FIDACY_MODE ?? "dev") === "http") {
498
+ const url = process.env.FIDACY_API_URL;
499
+ const key = process.env.FIDACY_API_KEY;
500
+ if (!url || !key) throw new Error("FIDACY_MODE=http requires FIDACY_API_URL and FIDACY_API_KEY");
501
+ return new HttpFidacyCore(url, key, process.env.FIDACY_PUBLIC_KEY_PEM ?? "");
502
+ }
503
+ return new DevFidacyCore({
504
+ mandate: buildMandate(),
505
+ auditLogPath: auditLogPath(),
506
+ onDecision: (d) => recordDecision(d.status, d.violatedRule)
507
+ });
508
+ }
509
+ export {
510
+ DevFidacyCore,
511
+ FileAuditStore,
512
+ GrantEnforcingExecutor,
513
+ HttpFidacyCore,
514
+ ReferenceRail,
515
+ canonInvoice,
516
+ evaluate,
517
+ loadOrGenerateKeyPair,
518
+ makeCore,
519
+ publicKeyPem,
520
+ requireHttpsBase,
521
+ sha256,
522
+ sign,
523
+ stableStringify,
524
+ validateRequest,
525
+ verify,
526
+ verifyGrant
527
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fidacy/mcp",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Fidacy action firewall for AI agents. Mandate-gated payment authorization as an MCP server.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://fidacy.com",
@@ -24,12 +24,8 @@
24
24
  "exports": {
25
25
  ".": "./dist/index.js",
26
26
  "./assess": "./dist/assess.js",
27
- "./grant": "./dist/grant.js",
28
- "./types": "./dist/types.js",
29
27
  "./core": "./dist/core.js",
30
- "./executor": "./dist/executor.js",
31
- "./signing": "./dist/signing.js",
32
- "./util": "./dist/util.js"
28
+ "./lib": "./dist/lib.js"
33
29
  },
34
30
  "files": [
35
31
  "dist",
@@ -41,7 +37,7 @@
41
37
  "access": "public"
42
38
  },
43
39
  "scripts": {
44
- "build": "tsc",
40
+ "build": "node scripts/bundle.mjs",
45
41
  "dev": "tsx watch src/index.ts",
46
42
  "start": "node dist/index.js",
47
43
  "prepublishOnly": "npm run build"
@@ -54,6 +50,7 @@
54
50
  "zod": "^3.25.0"
55
51
  },
56
52
  "devDependencies": {
53
+ "@fidacy/firewall": "workspace:*",
57
54
  "@types/node": "^22.10.0",
58
55
  "tsx": "^4.19.2",
59
56
  "typescript": "^5.7.2"
package/dist/assess.d.ts DELETED
@@ -1,78 +0,0 @@
1
- export type AssessKind = "ap2_payment" | "message_send" | "voice_call" | "custom" | "claim_document";
2
- export interface AssessParams {
3
- /** Action kind. Defaults to `ap2_payment`. */
4
- kind?: AssessKind;
5
- /** The action/mandate object for this kind. */
6
- mandate: unknown;
7
- /** Optional explicit mandate type. The engine derives it otherwise. */
8
- mandateType?: string;
9
- /** Optional A2A correlation block. Adds the `A2A-Version` header when present. */
10
- a2a?: {
11
- task_id: string;
12
- };
13
- /** Optional spending mandate. Sent as snake_case `spending_mandate`. */
14
- spendingMandate?: unknown;
15
- /** Optional idempotency key. Sent as snake_case `idempotency_key`. Enables retry. */
16
- idempotencyKey?: string;
17
- }
18
- export interface AssessResult {
19
- decision: "approve" | "review" | "deny";
20
- score: number;
21
- assessmentId: string;
22
- mandateId: string;
23
- riskPayloadJws: string;
24
- riskPayload: Record<string, unknown>;
25
- signingKeyId: string;
26
- signals: Record<string, unknown>;
27
- mandate: Record<string, unknown>;
28
- outcome: Record<string, unknown>;
29
- billing?: Record<string, unknown>;
30
- spend_guard?: Record<string, unknown>;
31
- a2a?: Record<string, unknown>;
32
- [k: string]: unknown;
33
- }
34
- export interface RejectionReason {
35
- key: string;
36
- category?: string;
37
- message?: string;
38
- description?: string;
39
- }
40
- /**
41
- * Typed error from the engine. `message` is STATIC and never contains the key or
42
- * request body. `type` is the stable engine error code (or a client code), and
43
- * `status` is the HTTP status (0 for network/timeout).
44
- */
45
- export declare class AssessError extends Error {
46
- readonly type: string;
47
- readonly status: number;
48
- readonly details?: unknown;
49
- readonly rejection_reasons?: RejectionReason[];
50
- constructor(opts: {
51
- type: string;
52
- status: number;
53
- details?: unknown;
54
- rejection_reasons?: RejectionReason[];
55
- });
56
- }
57
- export interface AssessConfig {
58
- /** Base URL of the engine, e.g. `https://api.fidacy.com`. Trailing slashes stripped. */
59
- engineUrl: string;
60
- /** API key (`fky_live_…`/`fky_test_…`) with scope `assess:write`. Never logged. */
61
- apiKey: string;
62
- /** Custom fetch (tests, edge runtimes). Default: `globalThis.fetch`. */
63
- fetchImpl?: typeof fetch;
64
- /** Per-request timeout in ms. Default 10000. */
65
- timeoutMs?: number;
66
- /** Max retries on transient failures (only when an idempotency key is set). Default 2. */
67
- maxRetries?: number;
68
- /** Backoff (ms) for attempt n. Default exponential base 200ms cap 2000ms. */
69
- backoffMs?: (n: number) => number;
70
- }
71
- /**
72
- * Call the live engine's POST /v1/assess and return the signed trust verdict.
73
- *
74
- * Retries ONLY when an idempotency key was supplied, on 5xx/429/network/timeout,
75
- * with small exponential backoff and a per-request AbortController timeout. This
76
- * mirrors the @fidacy/sdk request() behavior. Self-contained; no sdk import.
77
- */
78
- export declare function assessAction(params: AssessParams, cfg: AssessConfig): Promise<AssessResult>;
@@ -1 +0,0 @@
1
- {"version":3,"file":"assess.js","sourceRoot":"","sources":["../src/assess.ts"],"names":[],"mappings":"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"}
@@ -1,11 +0,0 @@
1
- import { AuditRecord, Decision } from "./types.js";
2
- export declare class FileAuditStore {
3
- private path;
4
- private chain;
5
- constructor(path: string);
6
- private load;
7
- private head;
8
- append(decision: Decision): AuditRecord;
9
- find(decisionId: string): AuditRecord | undefined;
10
- intact(): boolean;
11
- }