@mupag/mcp-server 0.1.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 +57 -0
- package/dist/chunk-ZGVY3GVY.js +1100 -0
- package/dist/chunk-ZGVY3GVY.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +60 -0
- package/dist/server.js +13 -0
- package/dist/server.js.map +1 -0
- package/package.json +63 -0
- package/server.json +37 -0
|
@@ -0,0 +1,1100 @@
|
|
|
1
|
+
// src/server.ts
|
|
2
|
+
import { createHash } from "crypto";
|
|
3
|
+
import { isIP } from "net";
|
|
4
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
|
+
import {
|
|
6
|
+
CallToolRequestSchema,
|
|
7
|
+
ListToolsRequestSchema
|
|
8
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
9
|
+
import { MuPag, MuPagError } from "mupag-sdk";
|
|
10
|
+
var MAX_API_KEY_LENGTH = 512;
|
|
11
|
+
var MAX_IDEMPOTENCY_KEY_LENGTH = 128;
|
|
12
|
+
var MAX_IDENTIFIER_LENGTH = 128;
|
|
13
|
+
var MAX_CURSOR_LENGTH = 256;
|
|
14
|
+
var MAX_TEXT_LENGTH = 500;
|
|
15
|
+
var MAX_INPUT_BYTES = 64 * 1024;
|
|
16
|
+
var MAX_OUTPUT_BYTES = 64 * 1024;
|
|
17
|
+
var MAX_RESPONSE_BYTES = 2 * 1024 * 1024;
|
|
18
|
+
var MAX_MONEY_CENTS = 9e15;
|
|
19
|
+
var MAX_IN_FLIGHT_MUTATIONS = 1e3;
|
|
20
|
+
var IDENTIFIER_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
|
|
21
|
+
var APPROVAL_REFERENCE_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/;
|
|
22
|
+
var SAFE_ERROR_CODE_PATTERN = /^[a-z0-9][a-z0-9_.-]{0,63}$/;
|
|
23
|
+
var MUTATION_GUARD_PROPERTIES = {
|
|
24
|
+
idempotency_key: {
|
|
25
|
+
type: "string",
|
|
26
|
+
minLength: 1,
|
|
27
|
+
maxLength: MAX_IDEMPOTENCY_KEY_LENGTH,
|
|
28
|
+
pattern: "^[\\x21-\\x7E]+$",
|
|
29
|
+
description: "Chave expl\xEDcita e est\xE1vel para repeti\xE7\xE3o segura da mesma inten\xE7\xE3o."
|
|
30
|
+
},
|
|
31
|
+
approval_reference: {
|
|
32
|
+
type: "string",
|
|
33
|
+
minLength: 1,
|
|
34
|
+
maxLength: MAX_IDENTIFIER_LENGTH,
|
|
35
|
+
pattern: "^[A-Za-z0-9][A-Za-z0-9._:/-]*$",
|
|
36
|
+
description: "Refer\xEAncia n\xE3o sens\xEDvel da aprova\xE7\xE3o humana ou do workflow autorizado."
|
|
37
|
+
},
|
|
38
|
+
confirm_financial_effect: {
|
|
39
|
+
type: "boolean",
|
|
40
|
+
const: true,
|
|
41
|
+
description: "Deve ser true para confirmar conscientemente a muta\xE7\xE3o."
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
var MUTATION_REQUIRED = [
|
|
45
|
+
"idempotency_key",
|
|
46
|
+
"approval_reference",
|
|
47
|
+
"confirm_financial_effect"
|
|
48
|
+
];
|
|
49
|
+
var TOOL_DEFINITIONS = [
|
|
50
|
+
{
|
|
51
|
+
name: "create_charge",
|
|
52
|
+
description: "Cria uma cobran\xE7a PIX ou cart\xE3o B2B direto no ambiente sandbox MuPag.",
|
|
53
|
+
inputSchema: {
|
|
54
|
+
type: "object",
|
|
55
|
+
additionalProperties: false,
|
|
56
|
+
properties: {
|
|
57
|
+
amount_cents: {
|
|
58
|
+
type: "integer",
|
|
59
|
+
minimum: 100,
|
|
60
|
+
maximum: MAX_MONEY_CENTS,
|
|
61
|
+
description: "Valor inteiro em centavos; m\xEDnimo de R$ 1,00."
|
|
62
|
+
},
|
|
63
|
+
payment_method: { type: "string", enum: ["pix", "credit_card"] },
|
|
64
|
+
customer: {
|
|
65
|
+
type: "object",
|
|
66
|
+
additionalProperties: false,
|
|
67
|
+
properties: {
|
|
68
|
+
id: { type: "string", minLength: 1, maxLength: MAX_IDENTIFIER_LENGTH },
|
|
69
|
+
name: { type: "string", minLength: 1, maxLength: 200 },
|
|
70
|
+
email: { type: "string", minLength: 3, maxLength: 254 },
|
|
71
|
+
tax_id: { type: "string", pattern: "^(?:[0-9]{11}|[0-9]{14})$" }
|
|
72
|
+
},
|
|
73
|
+
required: ["name", "email", "tax_id"]
|
|
74
|
+
},
|
|
75
|
+
payer_ip: {
|
|
76
|
+
type: "string",
|
|
77
|
+
minLength: 2,
|
|
78
|
+
maxLength: 45,
|
|
79
|
+
description: "IP literal do pagador, atestado pelo merchant; obrigat\xF3rio para cart\xE3o."
|
|
80
|
+
},
|
|
81
|
+
card_token_id: {
|
|
82
|
+
type: "string",
|
|
83
|
+
minLength: 1,
|
|
84
|
+
maxLength: MAX_IDENTIFIER_LENGTH,
|
|
85
|
+
description: "Somente token opaco do PSP; PAN e CVV n\xE3o s\xE3o aceitos."
|
|
86
|
+
},
|
|
87
|
+
installments: { type: "integer", minimum: 1, maximum: 1 },
|
|
88
|
+
description: { type: "string", minLength: 1, maxLength: MAX_TEXT_LENGTH },
|
|
89
|
+
...MUTATION_GUARD_PROPERTIES
|
|
90
|
+
},
|
|
91
|
+
required: [
|
|
92
|
+
"amount_cents",
|
|
93
|
+
"payment_method",
|
|
94
|
+
"customer",
|
|
95
|
+
...MUTATION_REQUIRED
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
annotations: {
|
|
99
|
+
title: "Criar cobran\xE7a",
|
|
100
|
+
destructiveHint: true,
|
|
101
|
+
idempotentHint: true,
|
|
102
|
+
openWorldHint: true
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: "create_checkout_session",
|
|
107
|
+
description: "Cria uma sess\xE3o real de checkout hospedado PIX-only no sandbox MuPag.",
|
|
108
|
+
inputSchema: {
|
|
109
|
+
type: "object",
|
|
110
|
+
additionalProperties: false,
|
|
111
|
+
properties: {
|
|
112
|
+
items: {
|
|
113
|
+
type: "array",
|
|
114
|
+
minItems: 1,
|
|
115
|
+
maxItems: 100,
|
|
116
|
+
items: {
|
|
117
|
+
type: "object",
|
|
118
|
+
additionalProperties: false,
|
|
119
|
+
properties: {
|
|
120
|
+
name: { type: "string", minLength: 1, maxLength: 200 },
|
|
121
|
+
quantity: { type: "integer", minimum: 1, maximum: 1e5 },
|
|
122
|
+
unit_amount_cents: {
|
|
123
|
+
type: "integer",
|
|
124
|
+
minimum: 100,
|
|
125
|
+
maximum: MAX_MONEY_CENTS
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
required: ["name", "quantity", "unit_amount_cents"]
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
success_url: { type: "string", minLength: 1, maxLength: 2048 },
|
|
132
|
+
cancel_url: { type: "string", minLength: 1, maxLength: 2048 },
|
|
133
|
+
customer_id: { type: "string", minLength: 1, maxLength: MAX_IDENTIFIER_LENGTH },
|
|
134
|
+
customer_data: {
|
|
135
|
+
type: "object",
|
|
136
|
+
additionalProperties: false,
|
|
137
|
+
properties: {
|
|
138
|
+
name: { type: "string", minLength: 1, maxLength: 200 },
|
|
139
|
+
email: { type: "string", minLength: 3, maxLength: 254 },
|
|
140
|
+
document: { type: "string", pattern: "^(?:[0-9]{11}|[0-9]{14})$" },
|
|
141
|
+
phone: { type: "string", minLength: 8, maxLength: 20 }
|
|
142
|
+
},
|
|
143
|
+
minProperties: 1
|
|
144
|
+
},
|
|
145
|
+
allowed_payment_methods: {
|
|
146
|
+
type: "array",
|
|
147
|
+
minItems: 1,
|
|
148
|
+
maxItems: 1,
|
|
149
|
+
uniqueItems: true,
|
|
150
|
+
items: { type: "string", enum: ["pix"] }
|
|
151
|
+
},
|
|
152
|
+
expires_in_minutes: { type: "integer", minimum: 1, maximum: 1440 },
|
|
153
|
+
...MUTATION_GUARD_PROPERTIES
|
|
154
|
+
},
|
|
155
|
+
required: ["items", "success_url", "cancel_url", ...MUTATION_REQUIRED]
|
|
156
|
+
},
|
|
157
|
+
annotations: {
|
|
158
|
+
title: "Criar sess\xE3o de checkout",
|
|
159
|
+
destructiveHint: true,
|
|
160
|
+
idempotentHint: true,
|
|
161
|
+
openWorldHint: true
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
name: "create_subscription",
|
|
166
|
+
description: "Cria uma assinatura recorrente no ambiente sandbox MuPag.",
|
|
167
|
+
inputSchema: {
|
|
168
|
+
type: "object",
|
|
169
|
+
additionalProperties: false,
|
|
170
|
+
properties: {
|
|
171
|
+
customer_id: { type: "string", minLength: 1, maxLength: MAX_IDENTIFIER_LENGTH },
|
|
172
|
+
plan_id: { type: "string", minLength: 1, maxLength: MAX_IDENTIFIER_LENGTH },
|
|
173
|
+
payment_method: { type: "string", enum: ["pix", "credit_card"] },
|
|
174
|
+
card_token_id: {
|
|
175
|
+
type: "string",
|
|
176
|
+
minLength: 1,
|
|
177
|
+
maxLength: MAX_IDENTIFIER_LENGTH,
|
|
178
|
+
description: "Somente token opaco do PSP; PAN e CVV n\xE3o s\xE3o aceitos."
|
|
179
|
+
},
|
|
180
|
+
trial_days: { type: "integer", minimum: 0, maximum: 365 },
|
|
181
|
+
external_reference: {
|
|
182
|
+
type: "string",
|
|
183
|
+
minLength: 1,
|
|
184
|
+
maxLength: MAX_IDENTIFIER_LENGTH
|
|
185
|
+
},
|
|
186
|
+
...MUTATION_GUARD_PROPERTIES
|
|
187
|
+
},
|
|
188
|
+
required: ["customer_id", "plan_id", "payment_method", ...MUTATION_REQUIRED]
|
|
189
|
+
},
|
|
190
|
+
annotations: {
|
|
191
|
+
title: "Criar assinatura",
|
|
192
|
+
destructiveHint: true,
|
|
193
|
+
idempotentHint: true,
|
|
194
|
+
openWorldHint: true
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
name: "cancel_subscription",
|
|
199
|
+
description: "Cancela uma assinatura no sandbox, imediatamente ou ao fim do per\xEDodo.",
|
|
200
|
+
inputSchema: {
|
|
201
|
+
type: "object",
|
|
202
|
+
additionalProperties: false,
|
|
203
|
+
properties: {
|
|
204
|
+
subscription_id: {
|
|
205
|
+
type: "string",
|
|
206
|
+
minLength: 1,
|
|
207
|
+
maxLength: MAX_IDENTIFIER_LENGTH
|
|
208
|
+
},
|
|
209
|
+
mode: { type: "string", enum: ["immediate", "end_of_period"] },
|
|
210
|
+
reason: { type: "string", minLength: 1, maxLength: MAX_TEXT_LENGTH },
|
|
211
|
+
...MUTATION_GUARD_PROPERTIES
|
|
212
|
+
},
|
|
213
|
+
required: ["subscription_id", "mode", ...MUTATION_REQUIRED]
|
|
214
|
+
},
|
|
215
|
+
annotations: {
|
|
216
|
+
title: "Cancelar assinatura",
|
|
217
|
+
destructiveHint: true,
|
|
218
|
+
idempotentHint: true,
|
|
219
|
+
openWorldHint: true
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
name: "refund_charge",
|
|
224
|
+
description: "Solicita estorno total expl\xEDcito ou parcial de uma cobran\xE7a no sandbox.",
|
|
225
|
+
inputSchema: {
|
|
226
|
+
type: "object",
|
|
227
|
+
additionalProperties: false,
|
|
228
|
+
properties: {
|
|
229
|
+
charge_id: { type: "string", minLength: 1, maxLength: MAX_IDENTIFIER_LENGTH },
|
|
230
|
+
amount_cents: {
|
|
231
|
+
type: "integer",
|
|
232
|
+
minimum: 1,
|
|
233
|
+
maximum: MAX_MONEY_CENTS
|
|
234
|
+
},
|
|
235
|
+
full: {
|
|
236
|
+
type: "boolean",
|
|
237
|
+
const: true,
|
|
238
|
+
description: "Use true para estorno total; n\xE3o combine com amount_cents."
|
|
239
|
+
},
|
|
240
|
+
reason: { type: "string", minLength: 1, maxLength: MAX_TEXT_LENGTH },
|
|
241
|
+
...MUTATION_GUARD_PROPERTIES
|
|
242
|
+
},
|
|
243
|
+
required: ["charge_id", ...MUTATION_REQUIRED],
|
|
244
|
+
oneOf: [{ required: ["amount_cents"] }, { required: ["full"] }]
|
|
245
|
+
},
|
|
246
|
+
annotations: {
|
|
247
|
+
title: "Estornar cobran\xE7a",
|
|
248
|
+
destructiveHint: true,
|
|
249
|
+
idempotentHint: true,
|
|
250
|
+
openWorldHint: true
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
name: "list_charges",
|
|
255
|
+
description: "Lista cobran\xE7as do merchant autenticado com filtros e pagina\xE7\xE3o limitada.",
|
|
256
|
+
inputSchema: {
|
|
257
|
+
type: "object",
|
|
258
|
+
additionalProperties: false,
|
|
259
|
+
properties: {
|
|
260
|
+
status: { type: "string", minLength: 1, maxLength: 64 },
|
|
261
|
+
customer_id: { type: "string", minLength: 1, maxLength: MAX_IDENTIFIER_LENGTH },
|
|
262
|
+
payment_method: { type: "string", enum: ["pix", "credit_card"] },
|
|
263
|
+
created_at_from: { type: "string", minLength: 1, maxLength: 64 },
|
|
264
|
+
created_at_to: { type: "string", minLength: 1, maxLength: 64 },
|
|
265
|
+
limit: { type: "integer", minimum: 1, maximum: 100 },
|
|
266
|
+
cursor: { type: "string", minLength: 1, maxLength: MAX_CURSOR_LENGTH }
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
annotations: {
|
|
270
|
+
title: "Listar cobran\xE7as",
|
|
271
|
+
readOnlyHint: true,
|
|
272
|
+
destructiveHint: false,
|
|
273
|
+
idempotentHint: true,
|
|
274
|
+
openWorldHint: true
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
name: "get_refund",
|
|
279
|
+
description: "Consulta um estorno pelo ID no escopo do merchant autenticado.",
|
|
280
|
+
inputSchema: {
|
|
281
|
+
type: "object",
|
|
282
|
+
additionalProperties: false,
|
|
283
|
+
properties: {
|
|
284
|
+
refund_id: { type: "string", minLength: 1, maxLength: MAX_IDENTIFIER_LENGTH }
|
|
285
|
+
},
|
|
286
|
+
required: ["refund_id"]
|
|
287
|
+
},
|
|
288
|
+
annotations: {
|
|
289
|
+
title: "Consultar estorno",
|
|
290
|
+
readOnlyHint: true,
|
|
291
|
+
destructiveHint: false,
|
|
292
|
+
idempotentHint: true,
|
|
293
|
+
openWorldHint: true
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
name: "list_charge_refunds",
|
|
298
|
+
description: "Lista os estornos existentes de uma cobran\xE7a no merchant autenticado.",
|
|
299
|
+
inputSchema: {
|
|
300
|
+
type: "object",
|
|
301
|
+
additionalProperties: false,
|
|
302
|
+
properties: {
|
|
303
|
+
charge_id: { type: "string", minLength: 1, maxLength: MAX_IDENTIFIER_LENGTH },
|
|
304
|
+
limit: { type: "integer", minimum: 1, maximum: 100 },
|
|
305
|
+
cursor: { type: "string", minLength: 1, maxLength: MAX_CURSOR_LENGTH }
|
|
306
|
+
},
|
|
307
|
+
required: ["charge_id"]
|
|
308
|
+
},
|
|
309
|
+
annotations: {
|
|
310
|
+
title: "Listar estornos da cobran\xE7a",
|
|
311
|
+
readOnlyHint: true,
|
|
312
|
+
destructiveHint: false,
|
|
313
|
+
idempotentHint: true,
|
|
314
|
+
openWorldHint: true
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
];
|
|
318
|
+
function readConfig(environment) {
|
|
319
|
+
const apiKey = environment.MUPAG_API_KEY;
|
|
320
|
+
if (apiKey === void 0 || apiKey.length === 0) {
|
|
321
|
+
throw new Error("MUPAG_API_KEY \xE9 obrigat\xF3ria.");
|
|
322
|
+
}
|
|
323
|
+
if (apiKey.length > MAX_API_KEY_LENGTH || apiKey.trim() !== apiKey || hasControlCharacter(apiKey)) {
|
|
324
|
+
throw new Error("MUPAG_API_KEY inv\xE1lida.");
|
|
325
|
+
}
|
|
326
|
+
const configuredEnvironment = environment.MUPAG_ENV;
|
|
327
|
+
if (configuredEnvironment === void 0 || configuredEnvironment.length === 0) {
|
|
328
|
+
throw new Error("MUPAG_ENV \xE9 obrigat\xF3ria.");
|
|
329
|
+
}
|
|
330
|
+
if (configuredEnvironment === "prd") {
|
|
331
|
+
throw new Error("O MCP est\xE1 habilitado somente para sandbox; prd n\xE3o est\xE1 dispon\xEDvel.");
|
|
332
|
+
}
|
|
333
|
+
if (configuredEnvironment !== "test") {
|
|
334
|
+
throw new Error("MUPAG_ENV deve selecionar explicitamente o ambiente test.");
|
|
335
|
+
}
|
|
336
|
+
if (!apiKey.startsWith("sk_test_")) {
|
|
337
|
+
throw new Error("MUPAG_API_KEY n\xE3o corresponde ao ambiente test.");
|
|
338
|
+
}
|
|
339
|
+
const rawBaseUrl = environment.MUPAG_API_URL;
|
|
340
|
+
const baseUrl = rawBaseUrl === void 0 ? void 0 : validateBaseUrl(rawBaseUrl);
|
|
341
|
+
return { apiKey, env: "test", baseUrl };
|
|
342
|
+
}
|
|
343
|
+
function createMuPagServer(config, options = {}) {
|
|
344
|
+
const sdk = options.sdk ?? new MuPag({
|
|
345
|
+
apiKey: config.apiKey,
|
|
346
|
+
env: config.env,
|
|
347
|
+
baseUrl: config.baseUrl,
|
|
348
|
+
timeoutMs: 15e3,
|
|
349
|
+
maxResponseBytes: MAX_RESPONSE_BYTES,
|
|
350
|
+
retry: {
|
|
351
|
+
maxRetries: 2,
|
|
352
|
+
initialDelayMs: 250,
|
|
353
|
+
maxDelayMs: 2e3
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
const executor = createToolExecutor(sdk, options.auditSink ?? writeAuditEntry);
|
|
357
|
+
const server = new Server(
|
|
358
|
+
{ name: "mupag-mcp-server", version: "0.1.0" },
|
|
359
|
+
{
|
|
360
|
+
capabilities: { tools: {} },
|
|
361
|
+
instructions: "Servidor MuPag exclusivo de sandbox. Muta\xE7\xF5es exigem aprova\xE7\xE3o expl\xEDcita e Idempotency-Key est\xE1vel."
|
|
362
|
+
}
|
|
363
|
+
);
|
|
364
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
365
|
+
tools: TOOL_DEFINITIONS
|
|
366
|
+
}));
|
|
367
|
+
server.setRequestHandler(
|
|
368
|
+
CallToolRequestSchema,
|
|
369
|
+
async (request) => executor(request.params.name, request.params.arguments)
|
|
370
|
+
);
|
|
371
|
+
return server;
|
|
372
|
+
}
|
|
373
|
+
function createToolExecutor(sdk, auditSink = () => void 0) {
|
|
374
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
375
|
+
return async (name, args) => {
|
|
376
|
+
let prepared;
|
|
377
|
+
try {
|
|
378
|
+
assertInputBudget(args);
|
|
379
|
+
prepared = prepareCall(name, args, sdk);
|
|
380
|
+
} catch (error) {
|
|
381
|
+
return toolError(error instanceof UnknownToolError ? "tool_not_found" : "entrada_invalida");
|
|
382
|
+
}
|
|
383
|
+
if (prepared.kind === "read") {
|
|
384
|
+
return invokeAndSerialize(prepared.invoke);
|
|
385
|
+
}
|
|
386
|
+
const mapKey = `${name}:${prepared.idempotencyKey}`;
|
|
387
|
+
const fingerprint = sha256(stableStringify(prepared.fingerprintPayload));
|
|
388
|
+
const existing = inFlight.get(mapKey);
|
|
389
|
+
if (existing !== void 0) {
|
|
390
|
+
if (existing.fingerprint !== fingerprint) {
|
|
391
|
+
return toolError("idempotency_conflict");
|
|
392
|
+
}
|
|
393
|
+
return existing.result;
|
|
394
|
+
}
|
|
395
|
+
if (inFlight.size >= MAX_IN_FLIGHT_MUTATIONS) {
|
|
396
|
+
return toolError("server_busy");
|
|
397
|
+
}
|
|
398
|
+
let result;
|
|
399
|
+
result = runMutation(
|
|
400
|
+
name,
|
|
401
|
+
prepared,
|
|
402
|
+
fingerprint,
|
|
403
|
+
auditSink
|
|
404
|
+
).finally(() => {
|
|
405
|
+
if (inFlight.get(mapKey)?.result === result) {
|
|
406
|
+
inFlight.delete(mapKey);
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
inFlight.set(mapKey, { fingerprint, result });
|
|
410
|
+
return result;
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
async function runMutation(name, prepared, fingerprint, auditSink) {
|
|
414
|
+
try {
|
|
415
|
+
await auditSink({
|
|
416
|
+
tool: name,
|
|
417
|
+
approvalReference: prepared.approvalReference,
|
|
418
|
+
idempotencyKeyHash: sha256(prepared.idempotencyKey),
|
|
419
|
+
payloadHash: fingerprint,
|
|
420
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
421
|
+
});
|
|
422
|
+
} catch {
|
|
423
|
+
return toolError("audit_unavailable");
|
|
424
|
+
}
|
|
425
|
+
return invokeAndSerialize(prepared.invoke);
|
|
426
|
+
}
|
|
427
|
+
async function invokeAndSerialize(invoke) {
|
|
428
|
+
try {
|
|
429
|
+
return serializeResult(await invoke());
|
|
430
|
+
} catch (error) {
|
|
431
|
+
return safeSdkError(error);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
function prepareCall(name, args, sdk) {
|
|
435
|
+
switch (name) {
|
|
436
|
+
case "create_charge":
|
|
437
|
+
return prepareCreateCharge(args, sdk);
|
|
438
|
+
case "create_checkout_session":
|
|
439
|
+
return prepareCheckoutSession(args, sdk);
|
|
440
|
+
case "create_subscription":
|
|
441
|
+
return prepareCreateSubscription(args, sdk);
|
|
442
|
+
case "cancel_subscription":
|
|
443
|
+
return prepareCancelSubscription(args, sdk);
|
|
444
|
+
case "refund_charge":
|
|
445
|
+
return prepareRefund(args, sdk);
|
|
446
|
+
case "list_charges":
|
|
447
|
+
return prepareListCharges(args, sdk);
|
|
448
|
+
case "get_refund":
|
|
449
|
+
return prepareGetRefund(args, sdk);
|
|
450
|
+
case "list_charge_refunds":
|
|
451
|
+
return prepareListChargeRefunds(args, sdk);
|
|
452
|
+
default:
|
|
453
|
+
throw new UnknownToolError();
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
function prepareCreateCharge(args, sdk) {
|
|
457
|
+
const input = strictObject(args, [
|
|
458
|
+
"amount_cents",
|
|
459
|
+
"payment_method",
|
|
460
|
+
"customer",
|
|
461
|
+
"payer_ip",
|
|
462
|
+
"card_token_id",
|
|
463
|
+
"installments",
|
|
464
|
+
"description",
|
|
465
|
+
...MUTATION_REQUIRED
|
|
466
|
+
]);
|
|
467
|
+
const guards = mutationGuards(input);
|
|
468
|
+
const amount = integer(input.amount_cents, 100, MAX_MONEY_CENTS);
|
|
469
|
+
const paymentMethod = enumValue(input.payment_method, ["pix", "credit_card"]);
|
|
470
|
+
const customer = chargeCustomer(input.customer);
|
|
471
|
+
const payerIp = optionalIpLiteral(input.payer_ip);
|
|
472
|
+
const description = optionalPanSafeText(input.description, MAX_TEXT_LENGTH);
|
|
473
|
+
const cardTokenId = optionalCardTokenIdentifier(input.card_token_id);
|
|
474
|
+
const installments = optionalInteger(input.installments, 1, 1);
|
|
475
|
+
if (paymentMethod === "credit_card" && (cardTokenId === void 0 || payerIp === void 0)) {
|
|
476
|
+
throw new ValidationFailure();
|
|
477
|
+
}
|
|
478
|
+
if (paymentMethod === "pix" && (cardTokenId !== void 0 || installments !== void 0)) {
|
|
479
|
+
throw new ValidationFailure();
|
|
480
|
+
}
|
|
481
|
+
const params = {
|
|
482
|
+
amount_cents: amount,
|
|
483
|
+
payment_method: paymentMethod,
|
|
484
|
+
customer
|
|
485
|
+
};
|
|
486
|
+
addDefined(params, "payer_ip", payerIp);
|
|
487
|
+
addDefined(params, "card_token_id", cardTokenId);
|
|
488
|
+
addDefined(params, "installments", installments);
|
|
489
|
+
addDefined(params, "description", description);
|
|
490
|
+
return mutation(
|
|
491
|
+
guards,
|
|
492
|
+
{ params },
|
|
493
|
+
() => sdk.charges.create(params, { idempotencyKey: guards.idempotencyKey })
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
function prepareCheckoutSession(args, sdk) {
|
|
497
|
+
const input = strictObject(args, [
|
|
498
|
+
"items",
|
|
499
|
+
"success_url",
|
|
500
|
+
"cancel_url",
|
|
501
|
+
"customer_id",
|
|
502
|
+
"customer_data",
|
|
503
|
+
"allowed_payment_methods",
|
|
504
|
+
"expires_in_minutes",
|
|
505
|
+
...MUTATION_REQUIRED
|
|
506
|
+
]);
|
|
507
|
+
const guards = mutationGuards(input);
|
|
508
|
+
if (!Array.isArray(input.items) || input.items.length < 1 || input.items.length > 100) {
|
|
509
|
+
throw new ValidationFailure();
|
|
510
|
+
}
|
|
511
|
+
let total = 0;
|
|
512
|
+
const items = input.items.map((rawItem) => {
|
|
513
|
+
const item = strictObject(rawItem, ["name", "quantity", "unit_amount_cents"]);
|
|
514
|
+
requireOwn(item, ["name", "quantity", "unit_amount_cents"]);
|
|
515
|
+
const name = panSafeText(requiredText(item.name, 200));
|
|
516
|
+
const quantity = integer(item.quantity, 1, 1e5);
|
|
517
|
+
const unitAmount = integer(item.unit_amount_cents, 100, MAX_MONEY_CENTS);
|
|
518
|
+
const lineTotal = quantity * unitAmount;
|
|
519
|
+
if (!Number.isSafeInteger(lineTotal) || lineTotal > MAX_MONEY_CENTS - total) {
|
|
520
|
+
throw new ValidationFailure();
|
|
521
|
+
}
|
|
522
|
+
total += lineTotal;
|
|
523
|
+
return { name, quantity, unit_amount_cents: unitAmount };
|
|
524
|
+
});
|
|
525
|
+
const successUrl = redirectUrl(input.success_url);
|
|
526
|
+
const cancelUrl = redirectUrl(input.cancel_url);
|
|
527
|
+
const customerId = optionalPanSafeIdentifier(input.customer_id);
|
|
528
|
+
const customerData = optionalCheckoutCustomer(input.customer_data);
|
|
529
|
+
if (customerId !== void 0 && customerData !== void 0) {
|
|
530
|
+
throw new ValidationFailure();
|
|
531
|
+
}
|
|
532
|
+
const allowedPaymentMethods = optionalPaymentMethods(input.allowed_payment_methods);
|
|
533
|
+
const expiresInMinutes = optionalInteger(input.expires_in_minutes, 1, 1440);
|
|
534
|
+
const params = {
|
|
535
|
+
items,
|
|
536
|
+
success_url: successUrl,
|
|
537
|
+
cancel_url: cancelUrl
|
|
538
|
+
};
|
|
539
|
+
addDefined(params, "customer_id", customerId);
|
|
540
|
+
addDefined(params, "customer_data", customerData);
|
|
541
|
+
addDefined(params, "allowed_payment_methods", allowedPaymentMethods);
|
|
542
|
+
addDefined(params, "expires_in_minutes", expiresInMinutes);
|
|
543
|
+
return mutation(
|
|
544
|
+
guards,
|
|
545
|
+
{ params },
|
|
546
|
+
() => sdk.checkoutSessions.create(params, { idempotencyKey: guards.idempotencyKey })
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
function prepareCreateSubscription(args, sdk) {
|
|
550
|
+
const input = strictObject(args, [
|
|
551
|
+
"customer_id",
|
|
552
|
+
"plan_id",
|
|
553
|
+
"payment_method",
|
|
554
|
+
"card_token_id",
|
|
555
|
+
"trial_days",
|
|
556
|
+
"external_reference",
|
|
557
|
+
...MUTATION_REQUIRED
|
|
558
|
+
]);
|
|
559
|
+
const guards = mutationGuards(input);
|
|
560
|
+
const customerId = panSafeText(identifier(input.customer_id));
|
|
561
|
+
const planId = identifier(input.plan_id);
|
|
562
|
+
const paymentMethod = enumValue(input.payment_method, ["pix", "credit_card"]);
|
|
563
|
+
const cardTokenId = optionalCardTokenIdentifier(input.card_token_id);
|
|
564
|
+
const trialDays = optionalInteger(input.trial_days, 0, 365);
|
|
565
|
+
const externalReference = optionalPanSafeIdentifier(input.external_reference);
|
|
566
|
+
if (paymentMethod === "credit_card" && cardTokenId === void 0) {
|
|
567
|
+
throw new ValidationFailure();
|
|
568
|
+
}
|
|
569
|
+
if (paymentMethod === "pix" && cardTokenId !== void 0) {
|
|
570
|
+
throw new ValidationFailure();
|
|
571
|
+
}
|
|
572
|
+
const params = {
|
|
573
|
+
customer_id: customerId,
|
|
574
|
+
plan_id: planId,
|
|
575
|
+
payment_method: paymentMethod
|
|
576
|
+
};
|
|
577
|
+
addDefined(params, "card_token_id", cardTokenId);
|
|
578
|
+
addDefined(params, "trial_days", trialDays);
|
|
579
|
+
addDefined(params, "external_reference", externalReference);
|
|
580
|
+
return mutation(
|
|
581
|
+
guards,
|
|
582
|
+
{ params },
|
|
583
|
+
() => sdk.subscriptions.create(params, { idempotencyKey: guards.idempotencyKey })
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
function prepareCancelSubscription(args, sdk) {
|
|
587
|
+
const input = strictObject(args, [
|
|
588
|
+
"subscription_id",
|
|
589
|
+
"mode",
|
|
590
|
+
"reason",
|
|
591
|
+
...MUTATION_REQUIRED
|
|
592
|
+
]);
|
|
593
|
+
const guards = mutationGuards(input);
|
|
594
|
+
const subscriptionId = panSafeText(identifier(input.subscription_id));
|
|
595
|
+
const mode = enumValue(input.mode, ["immediate", "end_of_period"]);
|
|
596
|
+
const reason = optionalPanSafeText(input.reason, MAX_TEXT_LENGTH);
|
|
597
|
+
const params = { mode };
|
|
598
|
+
addDefined(params, "reason", reason);
|
|
599
|
+
return mutation(
|
|
600
|
+
guards,
|
|
601
|
+
{ subscription_id: subscriptionId, params },
|
|
602
|
+
() => sdk.subscriptions.cancel(subscriptionId, params, {
|
|
603
|
+
idempotencyKey: guards.idempotencyKey
|
|
604
|
+
})
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
function prepareRefund(args, sdk) {
|
|
608
|
+
const input = strictObject(args, [
|
|
609
|
+
"charge_id",
|
|
610
|
+
"amount_cents",
|
|
611
|
+
"full",
|
|
612
|
+
"reason",
|
|
613
|
+
...MUTATION_REQUIRED
|
|
614
|
+
]);
|
|
615
|
+
const guards = mutationGuards(input);
|
|
616
|
+
const chargeId = panSafeText(identifier(input.charge_id));
|
|
617
|
+
const amount = optionalInteger(input.amount_cents, 1, MAX_MONEY_CENTS);
|
|
618
|
+
const full = input.full;
|
|
619
|
+
if (amount === void 0 && full !== true || amount !== void 0 && full !== void 0) {
|
|
620
|
+
throw new ValidationFailure();
|
|
621
|
+
}
|
|
622
|
+
const reason = optionalPanSafeText(input.reason, MAX_TEXT_LENGTH);
|
|
623
|
+
const params = {};
|
|
624
|
+
if (amount === void 0) {
|
|
625
|
+
params.full = true;
|
|
626
|
+
} else {
|
|
627
|
+
params.amount_cents = amount;
|
|
628
|
+
}
|
|
629
|
+
addDefined(params, "reason", reason);
|
|
630
|
+
return mutation(
|
|
631
|
+
guards,
|
|
632
|
+
{ charge_id: chargeId, params },
|
|
633
|
+
() => sdk.refunds.create(chargeId, params, { idempotencyKey: guards.idempotencyKey })
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
function prepareListCharges(args, sdk) {
|
|
637
|
+
const input = strictObject(args ?? {}, [
|
|
638
|
+
"status",
|
|
639
|
+
"customer_id",
|
|
640
|
+
"payment_method",
|
|
641
|
+
"created_at_from",
|
|
642
|
+
"created_at_to",
|
|
643
|
+
"limit",
|
|
644
|
+
"cursor"
|
|
645
|
+
]);
|
|
646
|
+
const params = {};
|
|
647
|
+
addDefined(params, "status", optionalSlug(input.status, 64));
|
|
648
|
+
addDefined(params, "customer_id", optionalPanSafeIdentifier(input.customer_id));
|
|
649
|
+
addDefined(
|
|
650
|
+
params,
|
|
651
|
+
"payment_method",
|
|
652
|
+
optionalEnumValue(input.payment_method, ["pix", "credit_card"])
|
|
653
|
+
);
|
|
654
|
+
const createdAtFrom = optionalTimestamp(input.created_at_from);
|
|
655
|
+
const createdAtTo = optionalTimestamp(input.created_at_to);
|
|
656
|
+
if (createdAtFrom !== void 0 && createdAtTo !== void 0 && Date.parse(createdAtFrom) > Date.parse(createdAtTo)) {
|
|
657
|
+
throw new ValidationFailure();
|
|
658
|
+
}
|
|
659
|
+
addDefined(params, "created_at_from", createdAtFrom);
|
|
660
|
+
addDefined(params, "created_at_to", createdAtTo);
|
|
661
|
+
addDefined(params, "limit", optionalInteger(input.limit, 1, 100));
|
|
662
|
+
addDefined(params, "cursor", optionalVisibleAscii(input.cursor, MAX_CURSOR_LENGTH));
|
|
663
|
+
return { kind: "read", invoke: () => sdk.charges.list(params) };
|
|
664
|
+
}
|
|
665
|
+
function prepareGetRefund(args, sdk) {
|
|
666
|
+
const input = strictObject(args, ["refund_id"]);
|
|
667
|
+
requireOwn(input, ["refund_id"]);
|
|
668
|
+
const refundId = panSafeText(identifier(input.refund_id));
|
|
669
|
+
return { kind: "read", invoke: () => sdk.refunds.get(refundId) };
|
|
670
|
+
}
|
|
671
|
+
function prepareListChargeRefunds(args, sdk) {
|
|
672
|
+
const input = strictObject(args, ["charge_id", "limit", "cursor"]);
|
|
673
|
+
requireOwn(input, ["charge_id"]);
|
|
674
|
+
const chargeId = panSafeText(identifier(input.charge_id));
|
|
675
|
+
const params = {};
|
|
676
|
+
addDefined(params, "limit", optionalInteger(input.limit, 1, 100));
|
|
677
|
+
addDefined(params, "cursor", optionalVisibleAscii(input.cursor, MAX_CURSOR_LENGTH));
|
|
678
|
+
return { kind: "read", invoke: () => sdk.refunds.listByCharge(chargeId, params) };
|
|
679
|
+
}
|
|
680
|
+
function mutation(guards, fingerprintPayload, invoke) {
|
|
681
|
+
return {
|
|
682
|
+
kind: "mutation",
|
|
683
|
+
...guards,
|
|
684
|
+
fingerprintPayload,
|
|
685
|
+
invoke
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
function mutationGuards(input) {
|
|
689
|
+
requireOwn(input, MUTATION_REQUIRED);
|
|
690
|
+
if (input.confirm_financial_effect !== true) {
|
|
691
|
+
throw new ValidationFailure();
|
|
692
|
+
}
|
|
693
|
+
const idempotencyKey = panSafeVisibleAscii(
|
|
694
|
+
input.idempotency_key,
|
|
695
|
+
MAX_IDEMPOTENCY_KEY_LENGTH
|
|
696
|
+
);
|
|
697
|
+
if (typeof input.approval_reference !== "string") {
|
|
698
|
+
throw new ValidationFailure();
|
|
699
|
+
}
|
|
700
|
+
const approvalReference = stringMatching(
|
|
701
|
+
panSafeText(input.approval_reference),
|
|
702
|
+
APPROVAL_REFERENCE_PATTERN,
|
|
703
|
+
MAX_IDENTIFIER_LENGTH
|
|
704
|
+
);
|
|
705
|
+
return { idempotencyKey, approvalReference };
|
|
706
|
+
}
|
|
707
|
+
function chargeCustomer(value) {
|
|
708
|
+
const customer = strictObject(value, ["id", "name", "email", "tax_id"]);
|
|
709
|
+
const id = optionalPanSafeIdentifier(customer.id);
|
|
710
|
+
const name = optionalPanSafeText(customer.name, 200);
|
|
711
|
+
const email = optionalPanSafeEmail(customer.email);
|
|
712
|
+
const taxId = optionalTaxId(customer.tax_id);
|
|
713
|
+
if (name === void 0 || email === void 0 || taxId === void 0) {
|
|
714
|
+
throw new ValidationFailure();
|
|
715
|
+
}
|
|
716
|
+
const result = { name, email, tax_id: taxId };
|
|
717
|
+
addDefined(result, "id", id);
|
|
718
|
+
return result;
|
|
719
|
+
}
|
|
720
|
+
function optionalIpLiteral(value) {
|
|
721
|
+
if (value === void 0) {
|
|
722
|
+
return void 0;
|
|
723
|
+
}
|
|
724
|
+
if (typeof value !== "string" || value.length > 45 || isIP(value) === 0) {
|
|
725
|
+
throw new ValidationFailure();
|
|
726
|
+
}
|
|
727
|
+
return value;
|
|
728
|
+
}
|
|
729
|
+
function optionalCheckoutCustomer(value) {
|
|
730
|
+
if (value === void 0) {
|
|
731
|
+
return void 0;
|
|
732
|
+
}
|
|
733
|
+
const customer = strictObject(value, ["name", "email", "document", "phone"]);
|
|
734
|
+
const result = {};
|
|
735
|
+
addDefined(result, "name", optionalPanSafeText(customer.name, 200));
|
|
736
|
+
addDefined(result, "email", optionalPanSafeEmail(customer.email));
|
|
737
|
+
addDefined(result, "document", optionalTaxId(customer.document));
|
|
738
|
+
addDefined(result, "phone", optionalPhone(customer.phone));
|
|
739
|
+
if (Object.keys(result).length === 0) {
|
|
740
|
+
throw new ValidationFailure();
|
|
741
|
+
}
|
|
742
|
+
return result;
|
|
743
|
+
}
|
|
744
|
+
function optionalPaymentMethods(value) {
|
|
745
|
+
if (value === void 0) {
|
|
746
|
+
return void 0;
|
|
747
|
+
}
|
|
748
|
+
if (!Array.isArray(value) || value.length !== 1) {
|
|
749
|
+
throw new ValidationFailure();
|
|
750
|
+
}
|
|
751
|
+
const methods = value.map((item) => enumValue(item, ["pix"]));
|
|
752
|
+
if (new Set(methods).size !== methods.length) {
|
|
753
|
+
throw new ValidationFailure();
|
|
754
|
+
}
|
|
755
|
+
return methods;
|
|
756
|
+
}
|
|
757
|
+
function strictObject(value, allowedKeys) {
|
|
758
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
759
|
+
throw new ValidationFailure();
|
|
760
|
+
}
|
|
761
|
+
const prototype = Object.getPrototypeOf(value);
|
|
762
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
763
|
+
throw new ValidationFailure();
|
|
764
|
+
}
|
|
765
|
+
const record = value;
|
|
766
|
+
const allowed = new Set(allowedKeys);
|
|
767
|
+
for (const key of Object.keys(record)) {
|
|
768
|
+
if (!allowed.has(key)) {
|
|
769
|
+
throw new ValidationFailure();
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
return record;
|
|
773
|
+
}
|
|
774
|
+
function requireOwn(value, keys) {
|
|
775
|
+
for (const key of keys) {
|
|
776
|
+
if (!Object.prototype.hasOwnProperty.call(value, key)) {
|
|
777
|
+
throw new ValidationFailure();
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
function integer(value, minimum, maximum) {
|
|
782
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < minimum || value > maximum) {
|
|
783
|
+
throw new ValidationFailure();
|
|
784
|
+
}
|
|
785
|
+
return value;
|
|
786
|
+
}
|
|
787
|
+
function optionalInteger(value, minimum, maximum) {
|
|
788
|
+
return value === void 0 ? void 0 : integer(value, minimum, maximum);
|
|
789
|
+
}
|
|
790
|
+
function enumValue(value, allowed) {
|
|
791
|
+
if (typeof value !== "string" || !allowed.includes(value)) {
|
|
792
|
+
throw new ValidationFailure();
|
|
793
|
+
}
|
|
794
|
+
return value;
|
|
795
|
+
}
|
|
796
|
+
function optionalEnumValue(value, allowed) {
|
|
797
|
+
return value === void 0 ? void 0 : enumValue(value, allowed);
|
|
798
|
+
}
|
|
799
|
+
function identifier(value) {
|
|
800
|
+
return stringMatching(value, IDENTIFIER_PATTERN, MAX_IDENTIFIER_LENGTH);
|
|
801
|
+
}
|
|
802
|
+
function optionalIdentifier(value) {
|
|
803
|
+
return value === void 0 ? void 0 : identifier(value);
|
|
804
|
+
}
|
|
805
|
+
function optionalCardTokenIdentifier(value) {
|
|
806
|
+
const cardTokenId = optionalIdentifier(value);
|
|
807
|
+
if (cardTokenId !== void 0 && containsPanLikeSequence(cardTokenId)) {
|
|
808
|
+
throw new ValidationFailure();
|
|
809
|
+
}
|
|
810
|
+
return cardTokenId;
|
|
811
|
+
}
|
|
812
|
+
function panSafeText(value) {
|
|
813
|
+
if (containsPanLikeSequence(value)) {
|
|
814
|
+
throw new ValidationFailure();
|
|
815
|
+
}
|
|
816
|
+
return value;
|
|
817
|
+
}
|
|
818
|
+
function optionalPanSafeText(value, maximumLength) {
|
|
819
|
+
const parsed = optionalText(value, maximumLength);
|
|
820
|
+
return parsed === void 0 ? void 0 : panSafeText(parsed);
|
|
821
|
+
}
|
|
822
|
+
function optionalPanSafeEmail(value) {
|
|
823
|
+
const parsed = optionalEmail(value);
|
|
824
|
+
return parsed === void 0 ? void 0 : panSafeText(parsed);
|
|
825
|
+
}
|
|
826
|
+
function optionalPanSafeIdentifier(value) {
|
|
827
|
+
const parsed = optionalIdentifier(value);
|
|
828
|
+
return parsed === void 0 ? void 0 : panSafeText(parsed);
|
|
829
|
+
}
|
|
830
|
+
function containsPanLikeSequence(value) {
|
|
831
|
+
let retainedDigits = "";
|
|
832
|
+
for (const character of value) {
|
|
833
|
+
if (character >= "0" && character <= "9") {
|
|
834
|
+
retainedDigits = (retainedDigits + character).slice(-19);
|
|
835
|
+
for (let length = 12; length <= retainedDigits.length; length += 1) {
|
|
836
|
+
if (validPanSequence(retainedDigits.slice(-length))) return true;
|
|
837
|
+
}
|
|
838
|
+
} else if (/^[\s\p{P}\p{S}\p{M}\p{Cc}\p{Cf}]$/u.test(character)) {
|
|
839
|
+
continue;
|
|
840
|
+
} else {
|
|
841
|
+
retainedDigits = "";
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
return false;
|
|
845
|
+
}
|
|
846
|
+
function validPanSequence(digits) {
|
|
847
|
+
if (!/^[0-9]{12,19}$/.test(digits)) return false;
|
|
848
|
+
let total = 0;
|
|
849
|
+
let doubleDigit = false;
|
|
850
|
+
for (let index = digits.length - 1; index >= 0; index -= 1) {
|
|
851
|
+
let digit = digits.charCodeAt(index) - 48;
|
|
852
|
+
if (doubleDigit) {
|
|
853
|
+
digit *= 2;
|
|
854
|
+
if (digit > 9) digit -= 9;
|
|
855
|
+
}
|
|
856
|
+
total += digit;
|
|
857
|
+
doubleDigit = !doubleDigit;
|
|
858
|
+
}
|
|
859
|
+
return total % 10 === 0;
|
|
860
|
+
}
|
|
861
|
+
function visibleAscii(value, maximumLength) {
|
|
862
|
+
if (typeof value !== "string" || value.length < 1 || value.length > maximumLength || !/^[\x21-\x7e]+$/.test(value)) {
|
|
863
|
+
throw new ValidationFailure();
|
|
864
|
+
}
|
|
865
|
+
return value;
|
|
866
|
+
}
|
|
867
|
+
function panSafeVisibleAscii(value, maximumLength) {
|
|
868
|
+
if (typeof value !== "string" || containsPanLikeSequence(value)) {
|
|
869
|
+
throw new ValidationFailure();
|
|
870
|
+
}
|
|
871
|
+
return visibleAscii(value, maximumLength);
|
|
872
|
+
}
|
|
873
|
+
function optionalVisibleAscii(value, maximumLength) {
|
|
874
|
+
return value === void 0 ? void 0 : visibleAscii(value, maximumLength);
|
|
875
|
+
}
|
|
876
|
+
function stringMatching(value, pattern, maximumLength) {
|
|
877
|
+
if (typeof value !== "string" || value.length < 1 || value.length > maximumLength || !pattern.test(value)) {
|
|
878
|
+
throw new ValidationFailure();
|
|
879
|
+
}
|
|
880
|
+
return value;
|
|
881
|
+
}
|
|
882
|
+
function requiredText(value, maximumLength) {
|
|
883
|
+
if (typeof value !== "string" || value.trim().length === 0 || value.length > maximumLength) {
|
|
884
|
+
throw new ValidationFailure();
|
|
885
|
+
}
|
|
886
|
+
if (hasUnsafeTextControl(value)) {
|
|
887
|
+
throw new ValidationFailure();
|
|
888
|
+
}
|
|
889
|
+
return value.trim();
|
|
890
|
+
}
|
|
891
|
+
function optionalText(value, maximumLength) {
|
|
892
|
+
return value === void 0 ? void 0 : requiredText(value, maximumLength);
|
|
893
|
+
}
|
|
894
|
+
function optionalSlug(value, maximumLength) {
|
|
895
|
+
if (value === void 0) {
|
|
896
|
+
return void 0;
|
|
897
|
+
}
|
|
898
|
+
return stringMatching(value, /^[a-z][a-z0-9_-]*$/, maximumLength);
|
|
899
|
+
}
|
|
900
|
+
function optionalEmail(value) {
|
|
901
|
+
if (value === void 0) {
|
|
902
|
+
return void 0;
|
|
903
|
+
}
|
|
904
|
+
if (typeof value !== "string" || value.length < 3 || value.length > 254 || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) || hasControlCharacter(value)) {
|
|
905
|
+
throw new ValidationFailure();
|
|
906
|
+
}
|
|
907
|
+
return value;
|
|
908
|
+
}
|
|
909
|
+
function optionalTaxId(value) {
|
|
910
|
+
if (value === void 0) {
|
|
911
|
+
return void 0;
|
|
912
|
+
}
|
|
913
|
+
if (typeof value !== "string" || !/^(?:\d{11}|\d{14})$/.test(value)) {
|
|
914
|
+
throw new ValidationFailure();
|
|
915
|
+
}
|
|
916
|
+
return value;
|
|
917
|
+
}
|
|
918
|
+
function optionalPhone(value) {
|
|
919
|
+
if (value === void 0) {
|
|
920
|
+
return void 0;
|
|
921
|
+
}
|
|
922
|
+
if (typeof value !== "string" || !/^\+?[0-9 ()-]{8,20}$/.test(value)) {
|
|
923
|
+
throw new ValidationFailure();
|
|
924
|
+
}
|
|
925
|
+
return value;
|
|
926
|
+
}
|
|
927
|
+
function optionalTimestamp(value) {
|
|
928
|
+
if (value === void 0) {
|
|
929
|
+
return void 0;
|
|
930
|
+
}
|
|
931
|
+
if (typeof value !== "string" || value.length < 1 || value.length > 64 || !Number.isFinite(Date.parse(value))) {
|
|
932
|
+
throw new ValidationFailure();
|
|
933
|
+
}
|
|
934
|
+
return value;
|
|
935
|
+
}
|
|
936
|
+
function redirectUrl(value) {
|
|
937
|
+
if (typeof value !== "string" || value.length < 1 || value.length > 2048) {
|
|
938
|
+
throw new ValidationFailure();
|
|
939
|
+
}
|
|
940
|
+
let parsed;
|
|
941
|
+
try {
|
|
942
|
+
parsed = new URL(value);
|
|
943
|
+
} catch {
|
|
944
|
+
throw new ValidationFailure();
|
|
945
|
+
}
|
|
946
|
+
if (parsed.username !== "" || parsed.password !== "" || parsed.hash !== "" || !isAllowedHttpUrl(parsed)) {
|
|
947
|
+
throw new ValidationFailure();
|
|
948
|
+
}
|
|
949
|
+
return parsed.toString();
|
|
950
|
+
}
|
|
951
|
+
function validateBaseUrl(value) {
|
|
952
|
+
if (value.length < 1 || value.length > 2048 || value.trim() !== value) {
|
|
953
|
+
throw new Error("MUPAG_API_URL inv\xE1lida.");
|
|
954
|
+
}
|
|
955
|
+
let parsed;
|
|
956
|
+
try {
|
|
957
|
+
parsed = new URL(value);
|
|
958
|
+
} catch {
|
|
959
|
+
throw new Error("MUPAG_API_URL inv\xE1lida.");
|
|
960
|
+
}
|
|
961
|
+
if (parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "" || parsed.pathname !== "" && parsed.pathname !== "/" || !isAllowedHttpUrl(parsed)) {
|
|
962
|
+
throw new Error("MUPAG_API_URL inv\xE1lida.");
|
|
963
|
+
}
|
|
964
|
+
return `${parsed.protocol}//${parsed.host}`;
|
|
965
|
+
}
|
|
966
|
+
function isAllowedHttpUrl(value) {
|
|
967
|
+
if (value.protocol === "https:") {
|
|
968
|
+
return value.hostname.length > 0;
|
|
969
|
+
}
|
|
970
|
+
return value.protocol === "http:" && isLoopbackHost(value.hostname);
|
|
971
|
+
}
|
|
972
|
+
function isLoopbackHost(hostname) {
|
|
973
|
+
const normalized = hostname.toLowerCase().replace(/^\[|\]$/g, "");
|
|
974
|
+
return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1";
|
|
975
|
+
}
|
|
976
|
+
function assertInputBudget(value) {
|
|
977
|
+
const stack = [{ value, depth: 0 }];
|
|
978
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
979
|
+
let bytes = 0;
|
|
980
|
+
let nodes = 0;
|
|
981
|
+
while (stack.length > 0) {
|
|
982
|
+
const current = stack.pop();
|
|
983
|
+
if (current === void 0) {
|
|
984
|
+
break;
|
|
985
|
+
}
|
|
986
|
+
nodes++;
|
|
987
|
+
if (nodes > 1e4 || current.depth > 10) {
|
|
988
|
+
throw new ValidationFailure();
|
|
989
|
+
}
|
|
990
|
+
const item = current.value;
|
|
991
|
+
if (typeof item === "string") {
|
|
992
|
+
bytes += Buffer.byteLength(item, "utf8");
|
|
993
|
+
} else if (typeof item === "number" || typeof item === "boolean" || item === null) {
|
|
994
|
+
bytes += 16;
|
|
995
|
+
} else if (typeof item === "object") {
|
|
996
|
+
if (item === null || seen.has(item)) {
|
|
997
|
+
if (item !== null) {
|
|
998
|
+
throw new ValidationFailure();
|
|
999
|
+
}
|
|
1000
|
+
} else {
|
|
1001
|
+
seen.add(item);
|
|
1002
|
+
if (Array.isArray(item)) {
|
|
1003
|
+
for (const child of item) {
|
|
1004
|
+
stack.push({ value: child, depth: current.depth + 1 });
|
|
1005
|
+
}
|
|
1006
|
+
} else {
|
|
1007
|
+
for (const [key, child] of Object.entries(item)) {
|
|
1008
|
+
bytes += Buffer.byteLength(key, "utf8");
|
|
1009
|
+
stack.push({ value: child, depth: current.depth + 1 });
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
} else if (item !== void 0) {
|
|
1014
|
+
throw new ValidationFailure();
|
|
1015
|
+
}
|
|
1016
|
+
if (bytes > MAX_INPUT_BYTES) {
|
|
1017
|
+
throw new ValidationFailure();
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
function serializeResult(value) {
|
|
1022
|
+
let serialized;
|
|
1023
|
+
try {
|
|
1024
|
+
serialized = JSON.stringify(value);
|
|
1025
|
+
} catch {
|
|
1026
|
+
return toolError("invalid_sdk_response");
|
|
1027
|
+
}
|
|
1028
|
+
if (serialized === void 0) {
|
|
1029
|
+
return toolError("invalid_sdk_response");
|
|
1030
|
+
}
|
|
1031
|
+
if (Buffer.byteLength(serialized, "utf8") > MAX_OUTPUT_BYTES) {
|
|
1032
|
+
return toolError("output_too_large");
|
|
1033
|
+
}
|
|
1034
|
+
return { content: [{ type: "text", text: serialized }] };
|
|
1035
|
+
}
|
|
1036
|
+
function safeSdkError(error) {
|
|
1037
|
+
if (error instanceof MuPagError) {
|
|
1038
|
+
const payload = {
|
|
1039
|
+
code: typeof error.code === "string" && SAFE_ERROR_CODE_PATTERN.test(error.code) ? error.code : "api_error"
|
|
1040
|
+
};
|
|
1041
|
+
if (typeof error.status === "number" && Number.isInteger(error.status) && error.status >= 400 && error.status <= 599) {
|
|
1042
|
+
payload.status = error.status;
|
|
1043
|
+
}
|
|
1044
|
+
if (typeof error.requestId === "string" && IDENTIFIER_PATTERN.test(error.requestId)) {
|
|
1045
|
+
payload.request_id = error.requestId;
|
|
1046
|
+
}
|
|
1047
|
+
return toolErrorPayload(payload);
|
|
1048
|
+
}
|
|
1049
|
+
return toolError("sdk_error");
|
|
1050
|
+
}
|
|
1051
|
+
function toolError(code) {
|
|
1052
|
+
return toolErrorPayload({ code });
|
|
1053
|
+
}
|
|
1054
|
+
function toolErrorPayload(payload) {
|
|
1055
|
+
return {
|
|
1056
|
+
isError: true,
|
|
1057
|
+
content: [{ type: "text", text: JSON.stringify({ error: payload }) }]
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
function stableStringify(value) {
|
|
1061
|
+
if (value === null || typeof value !== "object") {
|
|
1062
|
+
return JSON.stringify(value);
|
|
1063
|
+
}
|
|
1064
|
+
if (Array.isArray(value)) {
|
|
1065
|
+
return `[${value.map(stableStringify).join(",")}]`;
|
|
1066
|
+
}
|
|
1067
|
+
const record = value;
|
|
1068
|
+
const pairs = Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`);
|
|
1069
|
+
return `{${pairs.join(",")}}`;
|
|
1070
|
+
}
|
|
1071
|
+
function sha256(value) {
|
|
1072
|
+
return createHash("sha256").update(value, "utf8").digest("hex");
|
|
1073
|
+
}
|
|
1074
|
+
function addDefined(target, key, value) {
|
|
1075
|
+
if (value !== void 0) {
|
|
1076
|
+
target[key] = value;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
function hasControlCharacter(value) {
|
|
1080
|
+
return /[\u0000-\u001f\u007f]/.test(value);
|
|
1081
|
+
}
|
|
1082
|
+
function hasUnsafeTextControl(value) {
|
|
1083
|
+
return /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/.test(value);
|
|
1084
|
+
}
|
|
1085
|
+
function writeAuditEntry(entry) {
|
|
1086
|
+
process.stderr.write(`${JSON.stringify({ event: "mupag_mcp_financial_command", ...entry })}
|
|
1087
|
+
`);
|
|
1088
|
+
}
|
|
1089
|
+
var ValidationFailure = class extends Error {
|
|
1090
|
+
};
|
|
1091
|
+
var UnknownToolError = class extends Error {
|
|
1092
|
+
};
|
|
1093
|
+
|
|
1094
|
+
export {
|
|
1095
|
+
TOOL_DEFINITIONS,
|
|
1096
|
+
readConfig,
|
|
1097
|
+
createMuPagServer,
|
|
1098
|
+
createToolExecutor
|
|
1099
|
+
};
|
|
1100
|
+
//# sourceMappingURL=chunk-ZGVY3GVY.js.map
|