@lerianstudio/matcher-mcp 1.0.0-beta.5

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.
Files changed (220) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +281 -0
  3. package/dist/auth/request-token.js +117 -0
  4. package/dist/auth/request-token.js.map +1 -0
  5. package/dist/config.js +95 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/matcher/client.js +168 -0
  8. package/dist/matcher/client.js.map +1 -0
  9. package/dist/observability/otel.js +223 -0
  10. package/dist/observability/otel.js.map +1 -0
  11. package/dist/server.js +245 -0
  12. package/dist/server.js.map +1 -0
  13. package/dist/spec/curated-operations.js +145 -0
  14. package/dist/spec/curated-operations.js.map +1 -0
  15. package/dist/spec/index.js +155 -0
  16. package/dist/spec/index.js.map +1 -0
  17. package/dist/spec/load.js +76 -0
  18. package/dist/spec/load.js.map +1 -0
  19. package/dist/spec/openapi.yaml +15217 -0
  20. package/dist/tools/context/create.js +100 -0
  21. package/dist/tools/context/create.js.map +1 -0
  22. package/dist/tools/context/get.js +31 -0
  23. package/dist/tools/context/get.js.map +1 -0
  24. package/dist/tools/context/index.js +21 -0
  25. package/dist/tools/context/index.js.map +1 -0
  26. package/dist/tools/context/list.js +78 -0
  27. package/dist/tools/context/list.js.map +1 -0
  28. package/dist/tools/context/shared.js +61 -0
  29. package/dist/tools/context/shared.js.map +1 -0
  30. package/dist/tools/context/update.js +105 -0
  31. package/dist/tools/context/update.js.map +1 -0
  32. package/dist/tools/dashboard/aggregates.js +34 -0
  33. package/dist/tools/dashboard/aggregates.js.map +1 -0
  34. package/dist/tools/dashboard/cash-impact.js +36 -0
  35. package/dist/tools/dashboard/cash-impact.js.map +1 -0
  36. package/dist/tools/dashboard/index.js +27 -0
  37. package/dist/tools/dashboard/index.js.map +1 -0
  38. package/dist/tools/dashboard/match-rate.js +35 -0
  39. package/dist/tools/dashboard/match-rate.js.map +1 -0
  40. package/dist/tools/dashboard/metrics.js +36 -0
  41. package/dist/tools/dashboard/metrics.js.map +1 -0
  42. package/dist/tools/dashboard/shared.js +122 -0
  43. package/dist/tools/dashboard/shared.js.map +1 -0
  44. package/dist/tools/dashboard/sla.js +33 -0
  45. package/dist/tools/dashboard/sla.js.map +1 -0
  46. package/dist/tools/dashboard/source-breakdown.js +36 -0
  47. package/dist/tools/dashboard/source-breakdown.js.map +1 -0
  48. package/dist/tools/dashboard/volume.js +35 -0
  49. package/dist/tools/dashboard/volume.js.map +1 -0
  50. package/dist/tools/dispute/close.js +49 -0
  51. package/dist/tools/dispute/close.js.map +1 -0
  52. package/dist/tools/dispute/get.js +27 -0
  53. package/dist/tools/dispute/get.js.map +1 -0
  54. package/dist/tools/dispute/index.js +17 -0
  55. package/dist/tools/dispute/index.js.map +1 -0
  56. package/dist/tools/dispute/list.js +137 -0
  57. package/dist/tools/dispute/list.js.map +1 -0
  58. package/dist/tools/dispute/shared.js +66 -0
  59. package/dist/tools/dispute/shared.js.map +1 -0
  60. package/dist/tools/dispute/submit-evidence.js +58 -0
  61. package/dist/tools/dispute/submit-evidence.js.map +1 -0
  62. package/dist/tools/exception/add-comment.js +50 -0
  63. package/dist/tools/exception/add-comment.js.map +1 -0
  64. package/dist/tools/exception/adjust-entry.js +71 -0
  65. package/dist/tools/exception/adjust-entry.js.map +1 -0
  66. package/dist/tools/exception/bulk-assign.js +47 -0
  67. package/dist/tools/exception/bulk-assign.js.map +1 -0
  68. package/dist/tools/exception/bulk-dispatch.js +69 -0
  69. package/dist/tools/exception/bulk-dispatch.js.map +1 -0
  70. package/dist/tools/exception/bulk-resolve.js +64 -0
  71. package/dist/tools/exception/bulk-resolve.js.map +1 -0
  72. package/dist/tools/exception/delete-comment.js +40 -0
  73. package/dist/tools/exception/delete-comment.js.map +1 -0
  74. package/dist/tools/exception/dispatch.js +64 -0
  75. package/dist/tools/exception/dispatch.js.map +1 -0
  76. package/dist/tools/exception/force-match.js +55 -0
  77. package/dist/tools/exception/force-match.js.map +1 -0
  78. package/dist/tools/exception/get.js +34 -0
  79. package/dist/tools/exception/get.js.map +1 -0
  80. package/dist/tools/exception/history.js +61 -0
  81. package/dist/tools/exception/history.js.map +1 -0
  82. package/dist/tools/exception/index.js +39 -0
  83. package/dist/tools/exception/index.js.map +1 -0
  84. package/dist/tools/exception/list-comments.js +35 -0
  85. package/dist/tools/exception/list-comments.js.map +1 -0
  86. package/dist/tools/exception/list.js +169 -0
  87. package/dist/tools/exception/list.js.map +1 -0
  88. package/dist/tools/exception/open-dispute.js +53 -0
  89. package/dist/tools/exception/open-dispute.js.map +1 -0
  90. package/dist/tools/exception/shared.js +98 -0
  91. package/dist/tools/exception/shared.js.map +1 -0
  92. package/dist/tools/fee-rule/create.js +106 -0
  93. package/dist/tools/fee-rule/create.js.map +1 -0
  94. package/dist/tools/fee-rule/delete.js +27 -0
  95. package/dist/tools/fee-rule/delete.js.map +1 -0
  96. package/dist/tools/fee-rule/get.js +27 -0
  97. package/dist/tools/fee-rule/get.js.map +1 -0
  98. package/dist/tools/fee-rule/index.js +21 -0
  99. package/dist/tools/fee-rule/index.js.map +1 -0
  100. package/dist/tools/fee-rule/list.js +64 -0
  101. package/dist/tools/fee-rule/list.js.map +1 -0
  102. package/dist/tools/fee-rule/shared.js +67 -0
  103. package/dist/tools/fee-rule/shared.js.map +1 -0
  104. package/dist/tools/fee-rule/update.js +70 -0
  105. package/dist/tools/fee-rule/update.js.map +1 -0
  106. package/dist/tools/fee-schedule/create.js +105 -0
  107. package/dist/tools/fee-schedule/create.js.map +1 -0
  108. package/dist/tools/fee-schedule/delete.js +32 -0
  109. package/dist/tools/fee-schedule/delete.js.map +1 -0
  110. package/dist/tools/fee-schedule/get.js +30 -0
  111. package/dist/tools/fee-schedule/get.js.map +1 -0
  112. package/dist/tools/fee-schedule/index.js +22 -0
  113. package/dist/tools/fee-schedule/index.js.map +1 -0
  114. package/dist/tools/fee-schedule/list.js +56 -0
  115. package/dist/tools/fee-schedule/list.js.map +1 -0
  116. package/dist/tools/fee-schedule/shared.js +58 -0
  117. package/dist/tools/fee-schedule/shared.js.map +1 -0
  118. package/dist/tools/fee-schedule/simulate.js +54 -0
  119. package/dist/tools/fee-schedule/simulate.js.map +1 -0
  120. package/dist/tools/fee-schedule/update.js +69 -0
  121. package/dist/tools/fee-schedule/update.js.map +1 -0
  122. package/dist/tools/generic/describe-operation.js +157 -0
  123. package/dist/tools/generic/describe-operation.js.map +1 -0
  124. package/dist/tools/generic/invoke.js +343 -0
  125. package/dist/tools/generic/invoke.js.map +1 -0
  126. package/dist/tools/generic/list-operations.js +73 -0
  127. package/dist/tools/generic/list-operations.js.map +1 -0
  128. package/dist/tools/ingestion/index.js +29 -0
  129. package/dist/tools/ingestion/index.js.map +1 -0
  130. package/dist/tools/ingestion/job-errors-list.js +45 -0
  131. package/dist/tools/ingestion/job-errors-list.js.map +1 -0
  132. package/dist/tools/ingestion/job-get.js +42 -0
  133. package/dist/tools/ingestion/job-get.js.map +1 -0
  134. package/dist/tools/ingestion/job-transactions-list.js +93 -0
  135. package/dist/tools/ingestion/job-transactions-list.js.map +1 -0
  136. package/dist/tools/ingestion/jobs-list.js +89 -0
  137. package/dist/tools/ingestion/jobs-list.js.map +1 -0
  138. package/dist/tools/ingestion/shared.js +84 -0
  139. package/dist/tools/ingestion/shared.js.map +1 -0
  140. package/dist/tools/ingestion/transaction-ignore.js +51 -0
  141. package/dist/tools/ingestion/transaction-ignore.js.map +1 -0
  142. package/dist/tools/ingestion/transactions-search.js +143 -0
  143. package/dist/tools/ingestion/transactions-search.js.map +1 -0
  144. package/dist/tools/match-rule/create.js +64 -0
  145. package/dist/tools/match-rule/create.js.map +1 -0
  146. package/dist/tools/match-rule/delete.js +35 -0
  147. package/dist/tools/match-rule/delete.js.map +1 -0
  148. package/dist/tools/match-rule/get.js +32 -0
  149. package/dist/tools/match-rule/get.js.map +1 -0
  150. package/dist/tools/match-rule/index.js +22 -0
  151. package/dist/tools/match-rule/index.js.map +1 -0
  152. package/dist/tools/match-rule/list.js +72 -0
  153. package/dist/tools/match-rule/list.js.map +1 -0
  154. package/dist/tools/match-rule/reorder.js +45 -0
  155. package/dist/tools/match-rule/reorder.js.map +1 -0
  156. package/dist/tools/match-rule/shared.js +71 -0
  157. package/dist/tools/match-rule/shared.js.map +1 -0
  158. package/dist/tools/match-rule/update.js +68 -0
  159. package/dist/tools/match-rule/update.js.map +1 -0
  160. package/dist/tools/matching/get.js +48 -0
  161. package/dist/tools/matching/get.js.map +1 -0
  162. package/dist/tools/matching/groups.js +98 -0
  163. package/dist/tools/matching/groups.js.map +1 -0
  164. package/dist/tools/matching/index.js +19 -0
  165. package/dist/tools/matching/index.js.map +1 -0
  166. package/dist/tools/matching/list.js +76 -0
  167. package/dist/tools/matching/list.js.map +1 -0
  168. package/dist/tools/matching/shared.js +77 -0
  169. package/dist/tools/matching/shared.js.map +1 -0
  170. package/dist/tools/matching/start.js +55 -0
  171. package/dist/tools/matching/start.js.map +1 -0
  172. package/dist/tools/report/count-exceptions.js +45 -0
  173. package/dist/tools/report/count-exceptions.js.map +1 -0
  174. package/dist/tools/report/count-matched.js +46 -0
  175. package/dist/tools/report/count-matched.js.map +1 -0
  176. package/dist/tools/report/count-transactions.js +44 -0
  177. package/dist/tools/report/count-transactions.js.map +1 -0
  178. package/dist/tools/report/count-unmatched.js +44 -0
  179. package/dist/tools/report/count-unmatched.js.map +1 -0
  180. package/dist/tools/report/export-exceptions.js +46 -0
  181. package/dist/tools/report/export-exceptions.js.map +1 -0
  182. package/dist/tools/report/export-matched.js +47 -0
  183. package/dist/tools/report/export-matched.js.map +1 -0
  184. package/dist/tools/report/export-summary.js +47 -0
  185. package/dist/tools/report/export-summary.js.map +1 -0
  186. package/dist/tools/report/export-unmatched.js +47 -0
  187. package/dist/tools/report/export-unmatched.js.map +1 -0
  188. package/dist/tools/report/export-variance.js +46 -0
  189. package/dist/tools/report/export-variance.js.map +1 -0
  190. package/dist/tools/report/index.js +40 -0
  191. package/dist/tools/report/index.js.map +1 -0
  192. package/dist/tools/report/matched.js +44 -0
  193. package/dist/tools/report/matched.js.map +1 -0
  194. package/dist/tools/report/shared.js +176 -0
  195. package/dist/tools/report/shared.js.map +1 -0
  196. package/dist/tools/report/summary.js +41 -0
  197. package/dist/tools/report/summary.js.map +1 -0
  198. package/dist/tools/report/unmatched.js +44 -0
  199. package/dist/tools/report/unmatched.js.map +1 -0
  200. package/dist/tools/report/variance.js +44 -0
  201. package/dist/tools/report/variance.js.map +1 -0
  202. package/dist/tools/source/create.js +84 -0
  203. package/dist/tools/source/create.js.map +1 -0
  204. package/dist/tools/source/get.js +41 -0
  205. package/dist/tools/source/get.js.map +1 -0
  206. package/dist/tools/source/index.js +22 -0
  207. package/dist/tools/source/index.js.map +1 -0
  208. package/dist/tools/source/list.js +72 -0
  209. package/dist/tools/source/list.js.map +1 -0
  210. package/dist/tools/source/shared.js +63 -0
  211. package/dist/tools/source/shared.js.map +1 -0
  212. package/dist/tools/source/update.js +73 -0
  213. package/dist/tools/source/update.js.map +1 -0
  214. package/dist/tools/tool-error.js +74 -0
  215. package/dist/tools/tool-error.js.map +1 -0
  216. package/dist/transport/body-limit.js +82 -0
  217. package/dist/transport/body-limit.js.map +1 -0
  218. package/dist/transport/http.js +154 -0
  219. package/dist/transport/http.js.map +1 -0
  220. package/package.json +68 -0
@@ -0,0 +1,122 @@
1
+ // Shared plumbing for the curated dashboard tools.
2
+ //
3
+ // The dashboard family is a set of seven PURE READS over a context's reporting
4
+ // surface — combined aggregates plus six focused slices (cash-impact, match-rate,
5
+ // metrics, sla, source-breakdown, volume). They are NOT CRUD: every op is a GET
6
+ // hanging off /v1/reports/contexts/{contextId}/dashboard[/<slice>] and every op
7
+ // shares the IDENTICAL inputs — a contextId path param plus an optional
8
+ // date_from/date_to/source_id query. This module factors all of that exactly
9
+ // once (the base path + slice builder, the shared input shape, the query
10
+ // builder, and the relay boilerplate) so the seven tools stay thin (just "name
11
+ // the slice") and so curated + generic surfaces map matcher errors through the
12
+ // identical path (toToolError).
13
+ //
14
+ // Security: the bearer token is never read here directly — requireMatcherClient
15
+ // owns the request-scoped relay and fails closed when no usable credential was
16
+ // provided. The contextId path param is a routing identifier (matcher validates
17
+ // the context belongs to the relayed token's tenant); no tenant identifier is
18
+ // ever read or injected, and no dashboard tool input carries one. source_id is a
19
+ // data filter, never a tenant field.
20
+ import { z } from 'zod';
21
+ import { requireMatcherClient, UnauthenticatedError, } from '../../auth/request-token.js';
22
+ import { isMatcherApiError, toToolError } from '../tool-error.js';
23
+ /** Build the context-scoped dashboard base path (the combined-aggregates op). */
24
+ export function contextDashboardPath(contextId) {
25
+ return `/v1/reports/contexts/${encodeURIComponent(contextId)}/dashboard`;
26
+ }
27
+ /**
28
+ * Build a focused dashboard slice path (cash-impact, match-rate, metrics, sla,
29
+ * source-breakdown, volume) under the context's dashboard base. The slice is a
30
+ * fixed literal owned by each tool, never caller input, so it is appended raw.
31
+ */
32
+ export function contextDashboardSlicePath(contextId, slice) {
33
+ return `${contextDashboardPath(contextId)}/${slice}`;
34
+ }
35
+ /**
36
+ * Zod raw shape shared by all seven dashboard reads: the contextId path param
37
+ * plus the optional date_from/date_to/source_id query. Spread into each tool's
38
+ * inputSchema so the seven stay byte-identical and a single edit covers them all.
39
+ *
40
+ * Dates are YYYY-MM-DD strings; matcher defaults the window (last 30 days ending
41
+ * tomorrow UTC) when omitted and enforces a <=90-day span — we relay the bounds
42
+ * verbatim and let matcher own that validation (a 90-day breach surfaces as a
43
+ * structured RFC 9457 error). contextId and source_id are routing/data params,
44
+ * NOT tenant fields.
45
+ */
46
+ export const dashboardQueryInputShape = {
47
+ contextId: z
48
+ .string()
49
+ .min(1)
50
+ .describe('The reconciliation context id (UUID) to report on. Routing path param, ' +
51
+ 'not a tenant field.'),
52
+ date_from: z
53
+ .string()
54
+ .optional()
55
+ .describe('Start date (YYYY-MM-DD), inclusive. Optional — matcher defaults to 30 ' +
56
+ 'days before date_to. The window may not exceed 90 days.'),
57
+ date_to: z
58
+ .string()
59
+ .optional()
60
+ .describe('End date (YYYY-MM-DD), inclusive. Optional — matcher defaults to ' +
61
+ 'tomorrow (UTC). The window may not exceed 90 days.'),
62
+ source_id: z
63
+ .string()
64
+ .optional()
65
+ .describe('Optional source id (UUID) to scope the report to a single source. A ' +
66
+ 'data filter, not a tenant field.'),
67
+ };
68
+ /**
69
+ * Build the shared dashboard query, omitting unset knobs so the request stays
70
+ * minimal (and matcher applies its own window defaults). contextId is a path
71
+ * param and is intentionally excluded here.
72
+ */
73
+ export function buildDashboardQuery(args) {
74
+ const query = {};
75
+ if (args.date_from !== undefined) {
76
+ query.date_from = args.date_from;
77
+ }
78
+ if (args.date_to !== undefined) {
79
+ query.date_to = args.date_to;
80
+ }
81
+ if (args.source_id !== undefined) {
82
+ query.source_id = args.source_id;
83
+ }
84
+ return Object.keys(query).length > 0 ? query : undefined;
85
+ }
86
+ /**
87
+ * Run one assembled request through the relay: fail-closed auth, dispatch, and
88
+ * RFC 9457 → tool-error mapping — identical to the generic invoke's dispatch so
89
+ * both surfaces produce the same structured error shape.
90
+ *
91
+ * `clientFor` is injectable for tests; production callers pass nothing and get
92
+ * the request-scoped, fail-closed `requireMatcherClient`.
93
+ */
94
+ export async function dispatchDashboard(request, extra, clientFor = requireMatcherClient) {
95
+ let client;
96
+ try {
97
+ // Fail-closed on a missing / empty / non-Bearer credential.
98
+ client = clientFor(extra);
99
+ }
100
+ catch (err) {
101
+ if (err instanceof UnauthenticatedError) {
102
+ return { isError: true, content: [{ type: 'text', text: err.message }] };
103
+ }
104
+ throw err;
105
+ }
106
+ try {
107
+ const result = await client.request(request);
108
+ // Success → matcher's JSON returned as-is (an empty/204 body → null, though
109
+ // these reads always return a body).
110
+ return { content: [{ type: 'text', text: JSON.stringify(result ?? null) }] };
111
+ }
112
+ catch (err) {
113
+ // RFC 9457 problem → the SHARED structured tool error (status/title/detail/
114
+ // code preserved). A non-matcher error is a bug, not a matcher failure, and
115
+ // is re-thrown rather than masqueraded as one.
116
+ if (isMatcherApiError(err)) {
117
+ return toToolError(err);
118
+ }
119
+ throw err;
120
+ }
121
+ }
122
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/tools/dashboard/shared.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ // `dashboard_sla` — curated GET /v1/reports/contexts/{contextId}/dashboard/sla.
2
+ //
3
+ // SLA compliance statistics over the window (spec operationId getSLAStats).
4
+ // Shares the family input shape (contextId path + optional date_from/date_to/
5
+ // source_id query) and the fail-closed relay. contextId is a routing path param
6
+ // and source_id a data filter — neither is a tenant field, and no tenant field
7
+ // is accepted.
8
+ import { buildDashboardQuery, contextDashboardSlicePath, dashboardQueryInputShape, dispatchDashboard, } from './shared.js';
9
+ /** Zod raw shape for `dashboard_sla` input — the shared dashboard shape. */
10
+ export const dashboardSlaInputShape = dashboardQueryInputShape;
11
+ /**
12
+ * Register `dashboard_sla`. Dispatches a GET to the context's /dashboard/sla
13
+ * slice with the optional date/source query and returns matcher's SLA stats
14
+ * verbatim; a matcher error surfaces via the shared toToolError.
15
+ */
16
+ export function registerDashboardSlaTool(server) {
17
+ server.registerTool('dashboard_sla', {
18
+ description: 'Get the SLA compliance statistics for a reconciliation context. Pass ' +
19
+ 'contextId (UUID path param — not a tenant field), and optionally ' +
20
+ 'date_from/date_to (YYYY-MM-DD; matcher defaults to the last 30 days and ' +
21
+ 'caps the window at 90 days) and/or source_id (UUID data filter). No ' +
22
+ 'tenant field is accepted.',
23
+ inputSchema: dashboardSlaInputShape,
24
+ }, async (args, extra) => {
25
+ const query = buildDashboardQuery(args);
26
+ return dispatchDashboard({
27
+ method: 'GET',
28
+ path: contextDashboardSlicePath(args.contextId, 'sla'),
29
+ ...(query !== undefined ? { query } : {}),
30
+ }, extra);
31
+ });
32
+ }
33
+ //# sourceMappingURL=sla.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sla.js","sourceRoot":"","sources":["../../../src/tools/dashboard/sla.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,gFAAgF;AAChF,+EAA+E;AAC/E,eAAe;AAIf,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,wBAAwB,EACxB,iBAAiB,GAClB,MAAM,aAAa,CAAA;AAEpB,4EAA4E;AAC5E,MAAM,CAAC,MAAM,sBAAsB,GAAG,wBAAwB,CAAA;AAE9D;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,MAAiB;IACxD,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,WAAW,EACT,uEAAuE;YACvE,mEAAmE;YACnE,0EAA0E;YAC1E,sEAAsE;YACtE,2BAA2B;QAC7B,WAAW,EAAE,sBAAsB;KACpC,EACD,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;QACpB,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAA;QACvC,OAAO,iBAAiB,CACtB;YACE,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,yBAAyB,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC;YACtD,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1C,EACD,KAAK,CACN,CAAA;IACH,CAAC,CACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,36 @@
1
+ // `dashboard_source_breakdown` — curated GET
2
+ // /v1/reports/contexts/{contextId}/dashboard/source-breakdown.
3
+ //
4
+ // Per-source reconciliation statistics for the context over the window (spec
5
+ // operationId getSourceBreakdown). Shares the family input shape (contextId path
6
+ // + optional date_from/date_to/source_id query) and the fail-closed relay.
7
+ // contextId is a routing path param and source_id a data filter — neither is a
8
+ // tenant field, and no tenant field is accepted.
9
+ import { buildDashboardQuery, contextDashboardSlicePath, dashboardQueryInputShape, dispatchDashboard, } from './shared.js';
10
+ /** Zod raw shape for `dashboard_source_breakdown` input — the shared dashboard shape. */
11
+ export const dashboardSourceBreakdownInputShape = dashboardQueryInputShape;
12
+ /**
13
+ * Register `dashboard_source_breakdown`. Dispatches a GET to the context's
14
+ * /dashboard/source-breakdown slice with the optional date/source query and
15
+ * returns matcher's per-source breakdown verbatim; a matcher error surfaces via
16
+ * the shared toToolError.
17
+ */
18
+ export function registerDashboardSourceBreakdownTool(server) {
19
+ server.registerTool('dashboard_source_breakdown', {
20
+ description: 'Get the per-source reconciliation breakdown for a context (statistics ' +
21
+ 'grouped by source). Pass contextId (UUID path param — not a tenant ' +
22
+ 'field), and optionally date_from/date_to (YYYY-MM-DD; matcher defaults ' +
23
+ 'to the last 30 days and caps the window at 90 days) and/or source_id ' +
24
+ '(UUID data filter, to narrow to a single source). No tenant field is ' +
25
+ 'accepted.',
26
+ inputSchema: dashboardSourceBreakdownInputShape,
27
+ }, async (args, extra) => {
28
+ const query = buildDashboardQuery(args);
29
+ return dispatchDashboard({
30
+ method: 'GET',
31
+ path: contextDashboardSlicePath(args.contextId, 'source-breakdown'),
32
+ ...(query !== undefined ? { query } : {}),
33
+ }, extra);
34
+ });
35
+ }
36
+ //# sourceMappingURL=source-breakdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-breakdown.js","sourceRoot":"","sources":["../../../src/tools/dashboard/source-breakdown.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,+DAA+D;AAC/D,EAAE;AACF,6EAA6E;AAC7E,iFAAiF;AACjF,2EAA2E;AAC3E,+EAA+E;AAC/E,iDAAiD;AAIjD,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,wBAAwB,EACxB,iBAAiB,GAClB,MAAM,aAAa,CAAA;AAEpB,yFAAyF;AACzF,MAAM,CAAC,MAAM,kCAAkC,GAAG,wBAAwB,CAAA;AAE1E;;;;;GAKG;AACH,MAAM,UAAU,oCAAoC,CAAC,MAAiB;IACpE,MAAM,CAAC,YAAY,CACjB,4BAA4B,EAC5B;QACE,WAAW,EACT,wEAAwE;YACxE,qEAAqE;YACrE,yEAAyE;YACzE,uEAAuE;YACvE,uEAAuE;YACvE,WAAW;QACb,WAAW,EAAE,kCAAkC;KAChD,EACD,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;QACpB,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAA;QACvC,OAAO,iBAAiB,CACtB;YACE,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,yBAAyB,CAAC,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC;YACnE,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1C,EACD,KAAK,CACN,CAAA;IACH,CAAC,CACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,35 @@
1
+ // `dashboard_volume` — curated GET
2
+ // /v1/reports/contexts/{contextId}/dashboard/volume.
3
+ //
4
+ // Transaction volume statistics over the window (spec operationId
5
+ // getVolumeStats). Shares the family input shape (contextId path + optional
6
+ // date_from/date_to/source_id query) and the fail-closed relay. contextId is a
7
+ // routing path param and source_id a data filter — neither is a tenant field,
8
+ // and no tenant field is accepted.
9
+ import { buildDashboardQuery, contextDashboardSlicePath, dashboardQueryInputShape, dispatchDashboard, } from './shared.js';
10
+ /** Zod raw shape for `dashboard_volume` input — the shared dashboard shape. */
11
+ export const dashboardVolumeInputShape = dashboardQueryInputShape;
12
+ /**
13
+ * Register `dashboard_volume`. Dispatches a GET to the context's
14
+ * /dashboard/volume slice with the optional date/source query and returns
15
+ * matcher's volume stats verbatim; a matcher error surfaces via the shared
16
+ * toToolError.
17
+ */
18
+ export function registerDashboardVolumeTool(server) {
19
+ server.registerTool('dashboard_volume', {
20
+ description: 'Get the transaction volume statistics for a reconciliation context. ' +
21
+ 'Pass contextId (UUID path param — not a tenant field), and optionally ' +
22
+ 'date_from/date_to (YYYY-MM-DD; matcher defaults to the last 30 days and ' +
23
+ 'caps the window at 90 days) and/or source_id (UUID data filter). No ' +
24
+ 'tenant field is accepted.',
25
+ inputSchema: dashboardVolumeInputShape,
26
+ }, async (args, extra) => {
27
+ const query = buildDashboardQuery(args);
28
+ return dispatchDashboard({
29
+ method: 'GET',
30
+ path: contextDashboardSlicePath(args.contextId, 'volume'),
31
+ ...(query !== undefined ? { query } : {}),
32
+ }, extra);
33
+ });
34
+ }
35
+ //# sourceMappingURL=volume.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"volume.js","sourceRoot":"","sources":["../../../src/tools/dashboard/volume.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,qDAAqD;AACrD,EAAE;AACF,kEAAkE;AAClE,4EAA4E;AAC5E,+EAA+E;AAC/E,8EAA8E;AAC9E,mCAAmC;AAInC,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,wBAAwB,EACxB,iBAAiB,GAClB,MAAM,aAAa,CAAA;AAEpB,+EAA+E;AAC/E,MAAM,CAAC,MAAM,yBAAyB,GAAG,wBAAwB,CAAA;AAEjE;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CAAC,MAAiB;IAC3D,MAAM,CAAC,YAAY,CACjB,kBAAkB,EAClB;QACE,WAAW,EACT,sEAAsE;YACtE,wEAAwE;YACxE,0EAA0E;YAC1E,sEAAsE;YACtE,2BAA2B;QAC7B,WAAW,EAAE,yBAAyB;KACvC,EACD,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;QACpB,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAA;QACvC,OAAO,iBAAiB,CACtB;YACE,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,yBAAyB,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC;YACzD,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1C,EACD,KAAK,CACN,CAAA;IACH,CAAC,CACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,49 @@
1
+ // `dispute_close` — curated POST /v1/disputes/{disputeId}/close.
2
+ //
3
+ // A custom action (not CRUD): closes a dispute with a final resolution, marking
4
+ // it won or lost. Mirrors the spec's CloseDisputeRequest — `won` (boolean) and
5
+ // `resolution` (1–5000 chars) are both required. disputeId is a UUID path param
6
+ // and is stripped from the POST body; no tenant field is accepted.
7
+ import { z } from 'zod';
8
+ import { disputeClosePath, dispatchDispute } from './shared.js';
9
+ /** Zod raw shape for `dispute_close` input — id (path) + the resolution body. */
10
+ export const closeDisputeInputShape = {
11
+ disputeId: z.string().min(1).describe('The dispute id (UUID) to close.'),
12
+ won: z
13
+ .boolean()
14
+ .describe('Whether the dispute was won (true) or lost (false).'),
15
+ resolution: z
16
+ .string()
17
+ .min(1)
18
+ .max(5000)
19
+ .describe('Resolution description recorded against the dispute (1–5000 chars), e.g. ' +
20
+ '"Counterparty acknowledged the error and issued correction".'),
21
+ };
22
+ /** Build the close POST body from the input minus the path-only `disputeId`. */
23
+ export function buildCloseBody(args) {
24
+ const { disputeId: _disputeId, ...body } = args;
25
+ void _disputeId;
26
+ return body;
27
+ }
28
+ /**
29
+ * Register `dispute_close`. Splits the id (path) from the body, dispatches a POST
30
+ * to the dispute's /close sub-path through the shared fail-closed relay, and
31
+ * returns the updated dispute; a matcher error surfaces via the shared
32
+ * toToolError.
33
+ */
34
+ export function registerDisputeCloseTool(server) {
35
+ server.registerTool('dispute_close', {
36
+ description: 'Close a dispute with a final resolution (by id, UUID). Provide won ' +
37
+ '(boolean: true if the dispute was won) and resolution (1–5000 chars ' +
38
+ 'describing the outcome) — both required. Returns the updated dispute, ' +
39
+ 'or a structured RFC 9457 error. No tenant field is accepted.',
40
+ inputSchema: closeDisputeInputShape,
41
+ }, async (args, extra) => {
42
+ return dispatchDispute({
43
+ method: 'POST',
44
+ path: disputeClosePath(args.disputeId),
45
+ body: buildCloseBody(args),
46
+ }, extra);
47
+ });
48
+ }
49
+ //# sourceMappingURL=close.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"close.js","sourceRoot":"","sources":["../../../src/tools/dispute/close.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,gFAAgF;AAChF,+EAA+E;AAC/E,gFAAgF;AAChF,mEAAmE;AAEnE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE/D,iFAAiF;AACjF,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,iCAAiC,CAAC;IACxE,GAAG,EAAE,CAAC;SACH,OAAO,EAAE;SACT,QAAQ,CAAC,qDAAqD,CAAC;IAClE,UAAU,EAAE,CAAC;SACV,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,IAAI,CAAC;SACT,QAAQ,CACP,2EAA2E;QACzE,8DAA8D,CACjE;CACJ,CAAA;AAOD,gFAAgF;AAChF,MAAM,UAAU,cAAc,CAC5B,IAAuB;IAEvB,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAA;IAC/C,KAAK,UAAU,CAAA;IACf,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,MAAiB;IACxD,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,WAAW,EACT,qEAAqE;YACrE,sEAAsE;YACtE,wEAAwE;YACxE,8DAA8D;QAChE,WAAW,EAAE,sBAAsB;KACpC,EACD,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;QACpB,OAAO,eAAe,CACpB;YACE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC;YACtC,IAAI,EAAE,cAAc,CAAC,IAAI,CAAC;SAC3B,EACD,KAAK,CACN,CAAA;IACH,CAAC,CACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,27 @@
1
+ // `dispute_get` — curated GET /v1/disputes/{disputeId}.
2
+ //
3
+ // Reads one dispute by id. disputeId is the only input (a UUID path param). The
4
+ // dispute must belong to the relayed token's tenant — matcher enforces that; no
5
+ // tenant field is accepted.
6
+ import { z } from 'zod';
7
+ import { disputePath, dispatchDispute } from './shared.js';
8
+ /** Zod raw shape for `dispute_get` input — just the dispute id. */
9
+ export const getDisputeInputShape = {
10
+ disputeId: z.string().min(1).describe('The dispute id (UUID) to fetch.'),
11
+ };
12
+ /**
13
+ * Register `dispute_get`. Substitutes the id into the path and dispatches a GET
14
+ * through the shared fail-closed relay; a matcher error (e.g. 404) surfaces via
15
+ * the shared toToolError.
16
+ */
17
+ export function registerDisputeGetTool(server) {
18
+ server.registerTool('dispute_get', {
19
+ description: 'Fetch a single dispute by id (UUID). The dispute must belong to your ' +
20
+ "token's tenant. Returns the dispute, or a structured RFC 9457 error " +
21
+ '(e.g. 404 if it does not exist or is not yours).',
22
+ inputSchema: getDisputeInputShape,
23
+ }, async (args, extra) => {
24
+ return dispatchDispute({ method: 'GET', path: disputePath(args.disputeId) }, extra);
25
+ });
26
+ }
27
+ //# sourceMappingURL=get.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get.js","sourceRoot":"","sources":["../../../src/tools/dispute/get.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAChF,4BAA4B;AAE5B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE1D,mEAAmE;AACnE,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,iCAAiC,CAAC;CACzE,CAAA;AAKD;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAiB;IACtD,MAAM,CAAC,YAAY,CACjB,aAAa,EACb;QACE,WAAW,EACT,uEAAuE;YACvE,sEAAsE;YACtE,kDAAkD;QACpD,WAAW,EAAE,oBAAoB;KAClC,EACD,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;QACpB,OAAO,eAAe,CACpB,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EACpD,KAAK,CACN,CAAA;IACH,CAAC,CACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ // Curated dispute vertical: four typed tools over the matcher dispute resource —
2
+ // list, get, close, submit-evidence — covering the dispute lifecycle surface.
3
+ // Each tool shares the fail-closed relay (shared.ts) and the RFC 9457 →
4
+ // tool-error mapping (toToolError) with the generic surface, so curated and
5
+ // generic map matcher errors identically. No tool carries a tenant field.
6
+ import { registerDisputeCloseTool } from './close.js';
7
+ import { registerDisputeGetTool } from './get.js';
8
+ import { registerDisputeListTool } from './list.js';
9
+ import { registerDisputeSubmitEvidenceTool } from './submit-evidence.js';
10
+ /** Register all four curated dispute tools on the given server. */
11
+ export function registerDisputeTools(server) {
12
+ registerDisputeListTool(server);
13
+ registerDisputeGetTool(server);
14
+ registerDisputeCloseTool(server);
15
+ registerDisputeSubmitEvidenceTool(server);
16
+ }
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/dispute/index.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,8EAA8E;AAC9E,wEAAwE;AACxE,4EAA4E;AAC5E,0EAA0E;AAI1E,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAA;AACnD,OAAO,EAAE,iCAAiC,EAAE,MAAM,sBAAsB,CAAA;AAExE,mEAAmE;AACnE,MAAM,UAAU,oBAAoB,CAAC,MAAiB;IACpD,uBAAuB,CAAC,MAAM,CAAC,CAAA;IAC/B,sBAAsB,CAAC,MAAM,CAAC,CAAA;IAC9B,wBAAwB,CAAC,MAAM,CAAC,CAAA;IAChC,iCAAiC,CAAC,MAAM,CAAC,CAAA;AAC3C,CAAC"}
@@ -0,0 +1,137 @@
1
+ // `dispute_list` — curated GET /v1/disputes.
2
+ //
3
+ // Cursor-paginated list of the tenant's disputes, with optional state/category
4
+ // filters, a date-range window, and sort knobs. Filters/pagination pass through
5
+ // to matcher and its { items, nextCursor, ... } envelope is returned as-is — no
6
+ // auto-pagination (the model re-calls with the returned cursor). The list is
7
+ // implicitly tenant-scoped by the relayed token; no tenant field is accepted.
8
+ //
9
+ // Input field names are idiomatic camelCase; they map to matcher's snake_case
10
+ // wire query params (date_from/date_to/sort_by/sort_order) in buildListQuery.
11
+ import { z } from 'zod';
12
+ import { dispatchDispute, DISPUTES_PATH } from './shared.js';
13
+ /** Lifecycle states a dispute can be filtered by. */
14
+ export const DISPUTE_STATES = [
15
+ 'DRAFT',
16
+ 'OPEN',
17
+ 'PENDING_EVIDENCE',
18
+ 'WON',
19
+ 'LOST',
20
+ ];
21
+ /** Categories a dispute can be filtered by. */
22
+ export const DISPUTE_CATEGORIES = [
23
+ 'BANK_FEE_ERROR',
24
+ 'UNRECOGNIZED_CHARGE',
25
+ 'DUPLICATE_TRANSACTION',
26
+ 'OTHER',
27
+ ];
28
+ /** Fields the dispute list can be sorted by. */
29
+ export const DISPUTE_SORT_FIELDS = [
30
+ 'id',
31
+ 'created_at',
32
+ 'updated_at',
33
+ 'state',
34
+ 'category',
35
+ ];
36
+ /** Sort directions matcher supports. */
37
+ export const DISPUTE_SORT_ORDERS = ['asc', 'desc'];
38
+ /** Zod raw shape for `dispute_list` input — filters, date window, pagination, sort. */
39
+ export const listDisputesInputShape = {
40
+ state: z
41
+ .enum(DISPUTE_STATES)
42
+ .optional()
43
+ .describe('Filter by lifecycle state (DRAFT|OPEN|PENDING_EVIDENCE|WON|LOST). Omit ' +
44
+ 'to list all.'),
45
+ category: z
46
+ .enum(DISPUTE_CATEGORIES)
47
+ .optional()
48
+ .describe('Filter by category (BANK_FEE_ERROR|UNRECOGNIZED_CHARGE|' +
49
+ 'DUPLICATE_TRANSACTION|OTHER). Omit to list all.'),
50
+ dateFrom: z
51
+ .string()
52
+ .optional()
53
+ .describe('Inclusive lower bound on the filter date, as an RFC 3339 timestamp, e.g. ' +
54
+ '"2025-01-01T00:00:00Z". Sent as the date_from query param.'),
55
+ dateTo: z
56
+ .string()
57
+ .optional()
58
+ .describe('Inclusive upper bound on the filter date, as an RFC 3339 timestamp, e.g. ' +
59
+ '"2025-01-31T23:59:59Z". Sent as the date_to query param.'),
60
+ limit: z
61
+ .number()
62
+ .int()
63
+ .min(1)
64
+ .max(200)
65
+ .optional()
66
+ .describe('Maximum number of records to return (1–200, default 20).'),
67
+ cursor: z
68
+ .string()
69
+ .optional()
70
+ .describe('Opaque pagination cursor from a prior response. Re-call with the ' +
71
+ 'returned nextCursor to page forward (there is no auto-pagination).'),
72
+ sortBy: z
73
+ .enum(DISPUTE_SORT_FIELDS)
74
+ .optional()
75
+ .describe('Field to sort by (id|created_at|updated_at|state|category). Sent as the ' +
76
+ 'sort_by query param.'),
77
+ sortOrder: z
78
+ .enum(DISPUTE_SORT_ORDERS)
79
+ .optional()
80
+ .describe('Sort direction (asc|desc). Sent as the sort_order query param.'),
81
+ };
82
+ /**
83
+ * Build the list query, omitting unset knobs so the request stays minimal. The
84
+ * camelCase input fields map to matcher's snake_case wire query params.
85
+ */
86
+ export function buildListQuery(args) {
87
+ const query = {};
88
+ if (args.state !== undefined) {
89
+ query.state = args.state;
90
+ }
91
+ if (args.category !== undefined) {
92
+ query.category = args.category;
93
+ }
94
+ if (args.dateFrom !== undefined) {
95
+ query.date_from = args.dateFrom;
96
+ }
97
+ if (args.dateTo !== undefined) {
98
+ query.date_to = args.dateTo;
99
+ }
100
+ if (args.limit !== undefined) {
101
+ query.limit = args.limit;
102
+ }
103
+ if (args.cursor !== undefined) {
104
+ query.cursor = args.cursor;
105
+ }
106
+ if (args.sortBy !== undefined) {
107
+ query.sort_by = args.sortBy;
108
+ }
109
+ if (args.sortOrder !== undefined) {
110
+ query.sort_order = args.sortOrder;
111
+ }
112
+ return Object.keys(query).length > 0 ? query : undefined;
113
+ }
114
+ /**
115
+ * Register `dispute_list`. Passes the filters/pagination/sort through and returns
116
+ * matcher's pagination envelope verbatim; a matcher error surfaces via the shared
117
+ * toToolError.
118
+ */
119
+ export function registerDisputeListTool(server) {
120
+ server.registerTool('dispute_list', {
121
+ description: "List the disputes for your token's tenant (cursor-paginated). Filter by " +
122
+ 'state (DRAFT|OPEN|PENDING_EVIDENCE|WON|LOST), category, and/or an RFC ' +
123
+ '3339 dateFrom/dateTo window; sort by sortBy/sortOrder; page with limit ' +
124
+ '(1–200) and cursor. The response carries { items, nextCursor } — ' +
125
+ 'paginate by re-calling with the returned nextCursor. No tenant field is ' +
126
+ 'accepted; the tenant is derived from your bearer token.',
127
+ inputSchema: listDisputesInputShape,
128
+ }, async (args, extra) => {
129
+ const query = buildListQuery(args);
130
+ return dispatchDispute({
131
+ method: 'GET',
132
+ path: DISPUTES_PATH,
133
+ ...(query !== undefined ? { query } : {}),
134
+ }, extra);
135
+ });
136
+ }
137
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/tools/dispute/list.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ // Shared plumbing for the curated dispute tools.
2
+ //
3
+ // Every dispute tool follows the same relay shape: fail-closed auth via
4
+ // requireMatcherClient, dispatch one assembled MatcherRequest, then return
5
+ // matcher's JSON on success or the SHARED toToolError on a MatcherApiError. This
6
+ // module factors that boilerplate exactly once so the four tools stay thin (just
7
+ // "build the request") and so curated + generic surfaces map matcher errors
8
+ // through the identical path (toToolError).
9
+ //
10
+ // Security: the bearer token is never read here directly — requireMatcherClient
11
+ // owns the request-scoped relay and fails closed when no usable credential was
12
+ // provided. No tenant identifier is ever read or injected (matcher derives
13
+ // tenant from the relayed JWT); no dispute tool input carries one.
14
+ import { requireMatcherClient, UnauthenticatedError, } from '../../auth/request-token.js';
15
+ import { isMatcherApiError, toToolError } from '../tool-error.js';
16
+ /** Base path for the dispute resource (tenant-scoped; tenant from the token). */
17
+ export const DISPUTES_PATH = '/v1/disputes';
18
+ /** Build the single-dispute sub-path, URL-encoding the id so reserved chars are safe. */
19
+ export function disputePath(disputeId) {
20
+ return `${DISPUTES_PATH}/${encodeURIComponent(disputeId)}`;
21
+ }
22
+ /** Build the `/close` action sub-path for a single dispute. */
23
+ export function disputeClosePath(disputeId) {
24
+ return `${disputePath(disputeId)}/close`;
25
+ }
26
+ /** Build the `/evidence` action sub-path for a single dispute. */
27
+ export function disputeEvidencePath(disputeId) {
28
+ return `${disputePath(disputeId)}/evidence`;
29
+ }
30
+ /**
31
+ * Run one assembled request through the relay: fail-closed auth, dispatch, and
32
+ * RFC 9457 → tool-error mapping — identical to the generic invoke's dispatch so
33
+ * both surfaces produce the same structured error shape.
34
+ *
35
+ * `clientFor` is injectable for tests; production callers pass nothing and get
36
+ * the request-scoped, fail-closed `requireMatcherClient`.
37
+ */
38
+ export async function dispatchDispute(request, extra, clientFor = requireMatcherClient) {
39
+ let client;
40
+ try {
41
+ // Fail-closed on a missing / empty / non-Bearer credential.
42
+ client = clientFor(extra);
43
+ }
44
+ catch (err) {
45
+ if (err instanceof UnauthenticatedError) {
46
+ return { isError: true, content: [{ type: 'text', text: err.message }] };
47
+ }
48
+ throw err;
49
+ }
50
+ try {
51
+ const result = await client.request(request);
52
+ // Success → matcher's JSON returned as-is (incl. pagination envelopes and
53
+ // 204 → null for an empty body).
54
+ return { content: [{ type: 'text', text: JSON.stringify(result ?? null) }] };
55
+ }
56
+ catch (err) {
57
+ // RFC 9457 problem → the SHARED structured tool error (status/title/detail/
58
+ // code preserved). A non-matcher error is a bug, not a matcher failure, and
59
+ // is re-thrown rather than masqueraded as one.
60
+ if (isMatcherApiError(err)) {
61
+ return toToolError(err);
62
+ }
63
+ throw err;
64
+ }
65
+ }
66
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/tools/dispute/shared.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,EAAE;AACF,wEAAwE;AACxE,2EAA2E;AAC3E,iFAAiF;AACjF,iFAAiF;AACjF,4EAA4E;AAC5E,4CAA4C;AAC5C,EAAE;AACF,gFAAgF;AAChF,+EAA+E;AAC/E,2EAA2E;AAC3E,mEAAmE;AAInE,OAAO,EACL,oBAAoB,EACpB,oBAAoB,GAErB,MAAM,6BAA6B,CAAA;AAEpC,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAEjE,iFAAiF;AACjF,MAAM,CAAC,MAAM,aAAa,GAAG,cAAc,CAAA;AAE3C,yFAAyF;AACzF,MAAM,UAAU,WAAW,CAAC,SAAiB;IAC3C,OAAO,GAAG,aAAa,IAAI,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAA;AAC5D,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,gBAAgB,CAAC,SAAiB;IAChD,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAA;AAC1C,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,mBAAmB,CAAC,SAAiB;IACnD,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,WAAW,CAAA;AAC7C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAuB,EACvB,KAAmC,EACnC,YAAyD,oBAAoB;IAE7E,IAAI,MAAqB,CAAA;IACzB,IAAI,CAAC;QACH,4DAA4D;QAC5D,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,CAAA;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,oBAAoB,EAAE,CAAC;YACxC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAA;QAC1E,CAAC;QACD,MAAM,GAAG,CAAA;IACX,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QAC5C,0EAA0E;QAC1E,iCAAiC;QACjC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,CAAC,EAAE,CAAA;IAC9E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,4EAA4E;QAC5E,4EAA4E;QAC5E,+CAA+C;QAC/C,IAAI,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,OAAO,WAAW,CAAC,GAAG,CAAC,CAAA;QACzB,CAAC;QACD,MAAM,GAAG,CAAA;IACX,CAAC;AACH,CAAC"}
@@ -0,0 +1,58 @@
1
+ // `dispute_submit_evidence` — curated POST /v1/disputes/{disputeId}/evidence.
2
+ //
3
+ // A custom action (not CRUD): attaches evidence to a dispute. Mirrors the spec's
4
+ // SubmitEvidenceRequest — `comment` (1–1000 chars) is required and `fileUrl`
5
+ // (≤2048 chars) is an optional link to a supporting file. The body is plain JSON
6
+ // (a URL to an already-uploaded file), NOT a multipart upload. disputeId is a
7
+ // UUID path param and is stripped from the POST body; no tenant field is accepted.
8
+ import { z } from 'zod';
9
+ import { disputeEvidencePath, dispatchDispute } from './shared.js';
10
+ /** Zod raw shape for `dispute_submit_evidence` input — id (path) + evidence body. */
11
+ export const submitEvidenceInputShape = {
12
+ disputeId: z
13
+ .string()
14
+ .min(1)
15
+ .describe('The dispute id (UUID) to attach evidence to.'),
16
+ comment: z
17
+ .string()
18
+ .min(1)
19
+ .max(1000)
20
+ .describe('Comment describing the evidence (1–1000 chars), e.g. "Attached bank ' +
21
+ 'statement showing correct amount".'),
22
+ fileUrl: z
23
+ .string()
24
+ .max(2048)
25
+ .optional()
26
+ .describe('Optional URL to an already-uploaded evidence file (≤2048 chars), e.g. ' +
27
+ '"https://storage.example.com/evidence/doc123.pdf". A link, not a file ' +
28
+ 'upload.'),
29
+ };
30
+ /** Build the evidence POST body from the input minus the path-only `disputeId`. */
31
+ export function buildEvidenceBody(args) {
32
+ const { disputeId: _disputeId, ...body } = args;
33
+ void _disputeId;
34
+ return body;
35
+ }
36
+ /**
37
+ * Register `dispute_submit_evidence`. Splits the id (path) from the body,
38
+ * dispatches a POST to the dispute's /evidence sub-path through the shared
39
+ * fail-closed relay, and returns the updated dispute; a matcher error surfaces
40
+ * via the shared toToolError.
41
+ */
42
+ export function registerDisputeSubmitEvidenceTool(server) {
43
+ server.registerTool('dispute_submit_evidence', {
44
+ description: 'Submit evidence to a dispute (by id, UUID). Provide comment (1–1000 ' +
45
+ 'chars describing the evidence; required) and optionally fileUrl, a link ' +
46
+ 'to an already-uploaded file (≤2048 chars; this is a URL, not a file ' +
47
+ 'upload). Returns the updated dispute, or a structured RFC 9457 error. ' +
48
+ 'No tenant field is accepted.',
49
+ inputSchema: submitEvidenceInputShape,
50
+ }, async (args, extra) => {
51
+ return dispatchDispute({
52
+ method: 'POST',
53
+ path: disputeEvidencePath(args.disputeId),
54
+ body: buildEvidenceBody(args),
55
+ }, extra);
56
+ });
57
+ }
58
+ //# sourceMappingURL=submit-evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"submit-evidence.js","sourceRoot":"","sources":["../../../src/tools/dispute/submit-evidence.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,EAAE;AACF,iFAAiF;AACjF,6EAA6E;AAC7E,iFAAiF;AACjF,8EAA8E;AAC9E,mFAAmF;AAEnF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElE,qFAAqF;AACrF,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CAAC,8CAA8C,CAAC;IAC3D,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,IAAI,CAAC;SACT,QAAQ,CACP,sEAAsE;QACpE,oCAAoC,CACvC;IACH,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,GAAG,CAAC,IAAI,CAAC;SACT,QAAQ,EAAE;SACV,QAAQ,CACP,wEAAwE;QACtE,wEAAwE;QACxE,SAAS,CACZ;CACJ,CAAA;AAOD,mFAAmF;AACnF,MAAM,UAAU,iBAAiB,CAC/B,IAAyB;IAEzB,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAA;IAC/C,KAAK,UAAU,CAAA;IACf,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iCAAiC,CAAC,MAAiB;IACjE,MAAM,CAAC,YAAY,CACjB,yBAAyB,EACzB;QACE,WAAW,EACT,sEAAsE;YACtE,0EAA0E;YAC1E,sEAAsE;YACtE,wEAAwE;YACxE,8BAA8B;QAChC,WAAW,EAAE,wBAAwB;KACtC,EACD,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;QACpB,OAAO,eAAe,CACpB;YACE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC;YACzC,IAAI,EAAE,iBAAiB,CAAC,IAAI,CAAC;SAC9B,EACD,KAAK,CACN,CAAA;IACH,CAAC,CACF,CAAA;AACH,CAAC"}