@casys/mcp-erpnext 3.0.2 → 3.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/mcp-erpnext.mjs CHANGED
@@ -3117,7 +3117,25 @@ var require_utils2 = __commonJS({
3117
3117
  var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
3118
3118
  var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
3119
3119
  var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
3120
- var isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu);
3120
+ var isPathCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/]$/u);
3121
+ var isQueryFragmentCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/?]$/u);
3122
+ var isUserinfoCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:]$/u);
3123
+ var BYTE_HEX = new Array(256);
3124
+ {
3125
+ const HEX_DIGITS = "0123456789ABCDEF";
3126
+ for (let i = 0; i < 256; i++) {
3127
+ BYTE_HEX[i] = "%" + HEX_DIGITS[i >> 4] + HEX_DIGITS[i & 15];
3128
+ }
3129
+ }
3130
+ function percentEncodeNonAscii(cp) {
3131
+ if (cp < 2048) {
3132
+ return BYTE_HEX[192 | cp >> 6] + BYTE_HEX[128 | cp & 63];
3133
+ }
3134
+ if (cp < 65536) {
3135
+ return BYTE_HEX[224 | cp >> 12] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
3136
+ }
3137
+ return BYTE_HEX[240 | cp >> 18] + BYTE_HEX[128 | cp >> 12 & 63] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
3138
+ }
3121
3139
  function stringArrayToHexStripped(input) {
3122
3140
  let acc = "";
3123
3141
  let code = 0;
@@ -3142,91 +3160,105 @@ var require_utils2 = __commonJS({
3142
3160
  }
3143
3161
  return acc;
3144
3162
  }
3163
+ var isHextet = RegExp.prototype.test.bind(/^[\dA-Fa-f]{1,4}$/);
3164
+ var isIPvFuture = RegExp.prototype.test.bind(/^[vV][\dA-Fa-f]+\.[A-Za-z\d\-._~!$&'()*+,;=:]+$/);
3165
+ var isZoneCharacter = RegExp.prototype.test.bind(/^[A-Za-z\d\-._~]$/);
3145
3166
  var nonSimpleDomain = RegExp.prototype.test.bind(/[^!"$&'()*+,\-.;=_`a-z{}~]/u);
3146
- function consumeIsZone(buffer) {
3147
- buffer.length = 0;
3148
- return true;
3149
- }
3150
- function consumeHextets(buffer, address, output) {
3151
- if (buffer.length) {
3152
- const hex = stringArrayToHexStripped(buffer);
3153
- if (hex !== "") {
3154
- address.push(hex);
3155
- } else {
3156
- output.error = true;
3157
- return false;
3167
+ function isZoneIdentifier(zone) {
3168
+ if (zone.length === 0) return false;
3169
+ for (let i = 0; i < zone.length; i++) {
3170
+ if (isZoneCharacter(zone[i])) continue;
3171
+ if (zone[i] === "%" && i + 2 < zone.length && isHexPair(zone.slice(i + 1, i + 3))) {
3172
+ i += 2;
3173
+ continue;
3158
3174
  }
3159
- buffer.length = 0;
3175
+ return false;
3160
3176
  }
3161
3177
  return true;
3162
3178
  }
3163
- function getIPV6(input) {
3164
- let tokenCount = 0;
3165
- const output = { error: false, address: "", zone: "" };
3166
- const address = [];
3167
- const buffer = [];
3168
- let endipv6Encountered = false;
3169
- let endIpv6 = false;
3170
- let consume = consumeHextets;
3171
- for (let i = 0; i < input.length; i++) {
3172
- const cursor = input[i];
3173
- if (cursor === "[" || cursor === "]") {
3174
- continue;
3175
- }
3176
- if (cursor === ":") {
3177
- if (endipv6Encountered === true) {
3178
- endIpv6 = true;
3179
+ function compressIPv6ZeroRun(hextets) {
3180
+ let bestStart = -1;
3181
+ let bestLength = 0;
3182
+ let runStart = -1;
3183
+ let runLength = 0;
3184
+ for (let i = 0; i < hextets.length; i++) {
3185
+ if (hextets[i] === "0") {
3186
+ if (runStart === -1) runStart = i;
3187
+ runLength++;
3188
+ if (runLength > bestLength) {
3189
+ bestLength = runLength;
3190
+ bestStart = runStart;
3179
3191
  }
3180
- if (!consume(buffer, address, output)) {
3181
- break;
3182
- }
3183
- if (++tokenCount > 7) {
3184
- output.error = true;
3185
- break;
3186
- }
3187
- if (i > 0 && input[i - 1] === ":") {
3188
- endipv6Encountered = true;
3189
- }
3190
- address.push(":");
3191
- continue;
3192
- } else if (cursor === "%") {
3193
- if (!consume(buffer, address, output)) {
3194
- break;
3195
- }
3196
- consume = consumeIsZone;
3197
3192
  } else {
3198
- buffer.push(cursor);
3193
+ runStart = -1;
3194
+ runLength = 0;
3195
+ }
3196
+ }
3197
+ if (bestLength < 2) return hextets.join(":");
3198
+ const head = hextets.slice(0, bestStart).join(":");
3199
+ const tail = hextets.slice(bestStart + bestLength).join(":");
3200
+ return head + "::" + tail;
3201
+ }
3202
+ function normalizeIPv6Address(input) {
3203
+ const compression = input.indexOf("::");
3204
+ if (compression !== -1 && input.indexOf("::", compression + 1) !== -1) return void 0;
3205
+ const left = compression === -1 ? input.split(":") : input.slice(0, compression).split(":");
3206
+ const right = compression === -1 ? [] : input.slice(compression + 2).split(":");
3207
+ if (compression !== -1) {
3208
+ if (left.length === 1 && left[0] === "") left.length = 0;
3209
+ if (right.length === 1 && right[0] === "") right.length = 0;
3210
+ }
3211
+ const parts = left.concat(right);
3212
+ let hextetCount = 0;
3213
+ for (let i = 0; i < parts.length; i++) {
3214
+ const part = parts[i];
3215
+ if (part === "") return void 0;
3216
+ if (part.indexOf(".") !== -1) {
3217
+ if (i !== parts.length - 1 || compression !== -1 && right.length === 0 || !isIPv4(part)) return void 0;
3218
+ hextetCount += 2;
3199
3219
  continue;
3200
3220
  }
3221
+ if (!isHextet(part)) return void 0;
3222
+ parts[i] = parseInt(part, 16).toString(16);
3223
+ hextetCount++;
3201
3224
  }
3202
- if (buffer.length) {
3203
- if (consume === consumeIsZone) {
3204
- output.zone = buffer.join("");
3205
- } else if (endIpv6) {
3206
- address.push(buffer.join(""));
3207
- } else {
3208
- address.push(stringArrayToHexStripped(buffer));
3209
- }
3225
+ if (compression === -1) {
3226
+ if (hextetCount !== 8) return void 0;
3227
+ return compressIPv6ZeroRun(parts);
3210
3228
  }
3211
- output.address = address.join("");
3212
- return output;
3229
+ if (hextetCount >= 8) return void 0;
3230
+ const expanded = parts.slice(0, left.length);
3231
+ for (let i = hextetCount; i < 8; i++) expanded.push("0");
3232
+ for (let i = left.length; i < parts.length; i++) expanded.push(parts[i]);
3233
+ return compressIPv6ZeroRun(expanded);
3213
3234
  }
3214
3235
  function normalizeIPv6(host) {
3215
- if (findToken(host, ":") < 2) {
3216
- return { host, isIPV6: false };
3217
- }
3218
- const ipv62 = getIPV6(host);
3219
- if (!ipv62.error) {
3220
- let newHost = ipv62.address;
3221
- let escapedHost = ipv62.address;
3222
- if (ipv62.zone) {
3223
- newHost += "%" + ipv62.zone;
3224
- escapedHost += "%25" + ipv62.zone;
3225
- }
3226
- return { host: newHost, isIPV6: true, escapedHost };
3227
- } else {
3228
- return { host, isIPV6: false };
3229
- }
3236
+ const bracketed = host[0] === "[" && host[host.length - 1] === "]";
3237
+ const hasBracket = host[0] === "[" || host[host.length - 1] === "]";
3238
+ if (hasBracket && !bracketed) return { host, isIPV6: false, error: true };
3239
+ let input = bracketed ? host.slice(1, -1) : host;
3240
+ if (bracketed && isIPvFuture(input)) {
3241
+ input = input.toLowerCase();
3242
+ return { host: `[${input}]`, escapedHost: input, isIPV6: false, isIPVFuture: true };
3243
+ }
3244
+ if (findToken(input, ":") < 2) {
3245
+ return { host, isIPV6: false, error: bracketed };
3246
+ }
3247
+ let zoneIdentifier = "";
3248
+ const zoneSeparator = input.indexOf("%");
3249
+ if (zoneSeparator !== -1) {
3250
+ const separatorLength = input.slice(zoneSeparator, zoneSeparator + 3).toLowerCase() === "%25" ? 3 : 1;
3251
+ zoneIdentifier = input.slice(zoneSeparator + separatorLength);
3252
+ if (!isZoneIdentifier(zoneIdentifier)) return { host, isIPV6: false, error: true };
3253
+ input = input.slice(0, zoneSeparator);
3254
+ }
3255
+ const address = normalizeIPv6Address(input);
3256
+ if (address === void 0) return { host, isIPV6: false, error: true };
3257
+ return {
3258
+ host: address + (zoneIdentifier ? "%" + zoneIdentifier : ""),
3259
+ escapedHost: address + (zoneIdentifier ? "%25" + zoneIdentifier : ""),
3260
+ isIPV6: true
3261
+ };
3230
3262
  }
3231
3263
  function findToken(str, token) {
3232
3264
  let ind = 0;
@@ -3345,7 +3377,8 @@ var require_utils2 = __commonJS({
3345
3377
  function normalizePathEncoding(input) {
3346
3378
  let output = "";
3347
3379
  for (let i = 0; i < input.length; i++) {
3348
- if (input[i] === "%" && i + 2 < input.length) {
3380
+ const ch = input[i];
3381
+ if (ch === "%" && i + 2 < input.length) {
3349
3382
  const hex = input.slice(i + 1, i + 3);
3350
3383
  if (isHexPair(hex)) {
3351
3384
  const normalizedHex = hex.toUpperCase();
@@ -3359,10 +3392,152 @@ var require_utils2 = __commonJS({
3359
3392
  continue;
3360
3393
  }
3361
3394
  }
3362
- if (isPathCharacter(input[i])) {
3363
- output += input[i];
3395
+ if (isPathCharacter(ch)) {
3396
+ output += ch;
3397
+ } else {
3398
+ const code = input.charCodeAt(i);
3399
+ if (code < 128) {
3400
+ output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
3401
+ } else if (code < 55296 || code > 57343) {
3402
+ output += percentEncodeNonAscii(code);
3403
+ } else if (code <= 56319 && i + 1 < input.length) {
3404
+ const low = input.charCodeAt(i + 1);
3405
+ if (low >= 56320 && low <= 57343) {
3406
+ output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
3407
+ i++;
3408
+ } else {
3409
+ output += percentEncodeNonAscii(65533);
3410
+ }
3411
+ } else {
3412
+ output += percentEncodeNonAscii(65533);
3413
+ }
3414
+ }
3415
+ }
3416
+ return output;
3417
+ }
3418
+ function serializePathEncoding(input, pathNoScheme = false) {
3419
+ let output = "";
3420
+ let firstSegment = pathNoScheme && input[0] !== "/";
3421
+ for (let i = 0; i < input.length; i++) {
3422
+ const ch = input[i];
3423
+ if (ch === "%" && i + 2 < input.length) {
3424
+ const hex = input.slice(i + 1, i + 3);
3425
+ if (isHexPair(hex)) {
3426
+ output += "%" + hex.toUpperCase();
3427
+ i += 2;
3428
+ continue;
3429
+ }
3430
+ }
3431
+ if (ch === "/") {
3432
+ firstSegment = false;
3433
+ }
3434
+ if (isPathCharacter(ch) && (ch !== ":" || !firstSegment)) {
3435
+ output += ch;
3364
3436
  } else {
3365
- output += escape(input[i]);
3437
+ const code = input.charCodeAt(i);
3438
+ if (code < 128) {
3439
+ output += BYTE_HEX[code];
3440
+ } else if (code < 55296 || code > 57343) {
3441
+ output += percentEncodeNonAscii(code);
3442
+ } else if (code <= 56319 && i + 1 < input.length) {
3443
+ const low = input.charCodeAt(i + 1);
3444
+ if (low >= 56320 && low <= 57343) {
3445
+ output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
3446
+ i++;
3447
+ } else {
3448
+ output += percentEncodeNonAscii(65533);
3449
+ }
3450
+ } else {
3451
+ output += percentEncodeNonAscii(65533);
3452
+ }
3453
+ }
3454
+ }
3455
+ return output;
3456
+ }
3457
+ function encodeComponent(input, isAllowed) {
3458
+ let output = "";
3459
+ for (let i = 0; i < input.length; i++) {
3460
+ const ch = input[i];
3461
+ if (ch === "%" && i + 2 < input.length) {
3462
+ const hex = input.slice(i + 1, i + 3);
3463
+ if (isHexPair(hex)) {
3464
+ output += "%" + hex.toUpperCase();
3465
+ i += 2;
3466
+ continue;
3467
+ }
3468
+ }
3469
+ if (isAllowed(ch)) {
3470
+ output += ch;
3471
+ } else {
3472
+ const code = input.charCodeAt(i);
3473
+ if (code < 128) {
3474
+ output += BYTE_HEX[code];
3475
+ } else if (code < 55296 || code > 57343) {
3476
+ output += percentEncodeNonAscii(code);
3477
+ } else if (code <= 56319 && i + 1 < input.length) {
3478
+ const low = input.charCodeAt(i + 1);
3479
+ if (low >= 56320 && low <= 57343) {
3480
+ output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
3481
+ i++;
3482
+ } else {
3483
+ output += percentEncodeNonAscii(65533);
3484
+ }
3485
+ } else {
3486
+ output += percentEncodeNonAscii(65533);
3487
+ }
3488
+ }
3489
+ }
3490
+ return output;
3491
+ }
3492
+ function encodeUserinfo(input) {
3493
+ return encodeComponent(input, isUserinfoCharacter);
3494
+ }
3495
+ function encodeQuery(input) {
3496
+ return encodeComponent(input, isQueryFragmentCharacter);
3497
+ }
3498
+ function encodeFragment(input) {
3499
+ return encodeComponent(input, isQueryFragmentCharacter);
3500
+ }
3501
+ function isEscapeSafe(cp) {
3502
+ return cp >= 48 && cp <= 57 || cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 || cp === 42 || cp === 43 || cp === 45 || cp === 46 || cp === 47 || cp === 64 || cp === 95;
3503
+ }
3504
+ function normalizeQueryFragmentEncoding(input) {
3505
+ let output = "";
3506
+ for (let i = 0; i < input.length; i++) {
3507
+ const ch = input[i];
3508
+ if (ch === "%" && i + 2 < input.length) {
3509
+ const hex = input.slice(i + 1, i + 3);
3510
+ if (isHexPair(hex)) {
3511
+ const normalizedHex = hex.toUpperCase();
3512
+ const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
3513
+ if (isUnreserved(decoded)) {
3514
+ output += decoded;
3515
+ } else {
3516
+ output += "%" + normalizedHex;
3517
+ }
3518
+ i += 2;
3519
+ continue;
3520
+ }
3521
+ }
3522
+ if (isQueryFragmentCharacter(ch)) {
3523
+ output += ch;
3524
+ } else {
3525
+ const code = input.charCodeAt(i);
3526
+ if (code < 128) {
3527
+ output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
3528
+ } else if (code < 55296 || code > 57343) {
3529
+ output += percentEncodeNonAscii(code);
3530
+ } else if (code <= 56319 && i + 1 < input.length) {
3531
+ const low = input.charCodeAt(i + 1);
3532
+ if (low >= 56320 && low <= 57343) {
3533
+ output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
3534
+ i++;
3535
+ } else {
3536
+ output += percentEncodeNonAscii(65533);
3537
+ }
3538
+ } else {
3539
+ output += percentEncodeNonAscii(65533);
3540
+ }
3366
3541
  }
3367
3542
  }
3368
3543
  return output;
@@ -3385,14 +3560,18 @@ var require_utils2 = __commonJS({
3385
3560
  function recomposeAuthority(component) {
3386
3561
  const uriTokens = [];
3387
3562
  if (component.userinfo !== void 0) {
3388
- uriTokens.push(component.userinfo);
3563
+ uriTokens.push(encodeUserinfo(component.userinfo));
3389
3564
  uriTokens.push("@");
3390
3565
  }
3391
3566
  if (component.host !== void 0) {
3392
- let host = unescape(component.host);
3567
+ let host = component.host;
3393
3568
  if (!isIPv4(host)) {
3394
- const ipV6res = normalizeIPv6(host);
3395
- if (ipV6res.isIPV6 === true) {
3569
+ let ipV6res = normalizeIPv6(host);
3570
+ if (ipV6res.isIPV6 !== true && ipV6res.isIPVFuture !== true) {
3571
+ host = normalizePercentEncoding(host, true);
3572
+ ipV6res = normalizeIPv6(host);
3573
+ }
3574
+ if (ipV6res.isIPV6 === true || ipV6res.isIPVFuture === true) {
3396
3575
  host = `[${ipV6res.escapedHost}]`;
3397
3576
  } else {
3398
3577
  host = reescapeHostDelimiters(host, false);
@@ -3412,6 +3591,11 @@ var require_utils2 = __commonJS({
3412
3591
  reescapeHostDelimiters,
3413
3592
  normalizePercentEncoding,
3414
3593
  normalizePathEncoding,
3594
+ serializePathEncoding,
3595
+ normalizeQueryFragmentEncoding,
3596
+ encodeUserinfo,
3597
+ encodeQuery,
3598
+ encodeFragment,
3415
3599
  escapePreservingEscapes,
3416
3600
  removeDotSegments,
3417
3601
  isIPv4,
@@ -3427,7 +3611,7 @@ var require_schemes2 = __commonJS({
3427
3611
  "node_modules/fast-uri/lib/schemes.js"(exports, module) {
3428
3612
  "use strict";
3429
3613
  var { isUUID } = require_utils2();
3430
- var URN_REG = /([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-.:;=@]|%[\da-f]{2})+)/iu;
3614
+ var URN_REG = /^([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-./:;=@]|%[\da-f]{2})+)$/iu;
3431
3615
  var supportedSchemeNames = (
3432
3616
  /** @type {const} */
3433
3617
  [
@@ -3488,9 +3672,10 @@ var require_schemes2 = __commonJS({
3488
3672
  wsComponent.secure = void 0;
3489
3673
  }
3490
3674
  if (wsComponent.resourceName) {
3491
- const [path, query] = wsComponent.resourceName.split("?");
3675
+ const queryIndex = wsComponent.resourceName.indexOf("?");
3676
+ const path = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
3492
3677
  wsComponent.path = path && path !== "/" ? path : void 0;
3493
- wsComponent.query = query;
3678
+ wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1);
3494
3679
  wsComponent.resourceName = void 0;
3495
3680
  }
3496
3681
  wsComponent.fragment = void 0;
@@ -3502,7 +3687,7 @@ var require_schemes2 = __commonJS({
3502
3687
  return urnComponent;
3503
3688
  }
3504
3689
  const matches = urnComponent.path.match(URN_REG);
3505
- if (matches) {
3690
+ if (matches && matches[0] === urnComponent.path) {
3506
3691
  const scheme = options.scheme || urnComponent.scheme || "urn";
3507
3692
  urnComponent.nid = matches[1].toLowerCase();
3508
3693
  urnComponent.nss = matches[2];
@@ -3636,8 +3821,17 @@ var require_schemes2 = __commonJS({
3636
3821
  var require_fast_uri2 = __commonJS({
3637
3822
  "node_modules/fast-uri/index.js"(exports, module) {
3638
3823
  "use strict";
3639
- var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils2();
3824
+ var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils2();
3640
3825
  var { SCHEMES, getSchemeHandler } = require_schemes2();
3826
+ var VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u;
3827
+ var MALFORMED_SCHEME_ERROR = "URI scheme is malformed.";
3828
+ function decodeValidScheme(scheme) {
3829
+ const decodedScheme = unescape(String(scheme));
3830
+ if (!VALID_SCHEME.test(decodedScheme)) {
3831
+ throw new TypeError(MALFORMED_SCHEME_ERROR);
3832
+ }
3833
+ return decodedScheme;
3834
+ }
3641
3835
  function normalize2(uri, options) {
3642
3836
  if (typeof uri === "string") {
3643
3837
  uri = /** @type {T} */
@@ -3650,12 +3844,34 @@ var require_fast_uri2 = __commonJS({
3650
3844
  }
3651
3845
  function resolve(baseURI, relativeURI, options) {
3652
3846
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
3653
- const { parsed: baseParsed, malformedAuthorityOrPort: baseMalformed } = parseWithStatus(baseURI, schemelessOptions);
3654
- const { parsed: relativeParsed, malformedAuthorityOrPort: relativeMalformed } = parseWithStatus(relativeURI, schemelessOptions);
3655
- if (baseMalformed || relativeMalformed) {
3847
+ const {
3848
+ parsed: baseParsed,
3849
+ malformedAuthorityOrPort: baseMalformed,
3850
+ malformedPercentEncoding: baseMalformedPercentEncoding,
3851
+ malformedSchemeSpecific: baseMalformedSchemeSpecific,
3852
+ malformedHost: baseMalformedHost,
3853
+ malformedScheme: baseMalformedScheme
3854
+ } = parseWithStatus(baseURI, schemelessOptions);
3855
+ const {
3856
+ parsed: relativeParsed,
3857
+ malformedAuthorityOrPort: relativeMalformed,
3858
+ malformedPercentEncoding: relativeMalformedPercentEncoding,
3859
+ malformedSchemeSpecific: relativeMalformedSchemeSpecific,
3860
+ malformedHost: relativeMalformedHost,
3861
+ malformedScheme: relativeMalformedScheme
3862
+ } = parseWithStatus(relativeURI, schemelessOptions);
3863
+ if (baseMalformed || relativeMalformed || baseMalformedPercentEncoding || relativeMalformedPercentEncoding || baseMalformedSchemeSpecific || relativeMalformedSchemeSpecific || baseMalformedHost || relativeMalformedHost || baseMalformedScheme || relativeMalformedScheme) {
3656
3864
  throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
3657
3865
  }
3658
3866
  const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
3867
+ const resolvedSchemeHandler = getSchemeHandler(options && options.scheme || resolved.scheme);
3868
+ const resolvedHost = resolved.host;
3869
+ const resolvedHostIsIP = resolvedHost !== void 0 && resolvedHost !== "" && (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
3870
+ canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
3871
+ const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !new RegExp("\\P{ASCII}", "u").test(resolvedHost);
3872
+ if (resolved.error && !encodedASCIIHost) {
3873
+ throw new Error(resolved.error);
3874
+ }
3659
3875
  schemelessOptions.skipEscape = true;
3660
3876
  return serialize(resolved, schemelessOptions);
3661
3877
  }
@@ -3715,7 +3931,7 @@ var require_fast_uri2 = __commonJS({
3715
3931
  function equal(uriA, uriB, options) {
3716
3932
  const normalizedA = normalizeComparableURI(uriA, options);
3717
3933
  const normalizedB = normalizeComparableURI(uriB, options);
3718
- return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA.toLowerCase() === normalizedB.toLowerCase();
3934
+ return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA === normalizedB;
3719
3935
  }
3720
3936
  function serialize(cmpts, opts) {
3721
3937
  const component = {
@@ -3736,19 +3952,22 @@ var require_fast_uri2 = __commonJS({
3736
3952
  };
3737
3953
  const options = Object.assign({}, opts);
3738
3954
  const uriTokens = [];
3955
+ if (component.scheme) {
3956
+ component.scheme = decodeValidScheme(component.scheme);
3957
+ }
3739
3958
  const schemeHandler = getSchemeHandler(options.scheme || component.scheme);
3740
3959
  if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
3960
+ const hasAuthority = component.userinfo !== void 0 || component.host !== void 0 || component.port !== void 0;
3961
+ const pathNoScheme = !options.skipEscape && component.scheme === void 0 && !hasAuthority;
3741
3962
  if (component.path !== void 0) {
3742
3963
  if (!options.skipEscape) {
3743
- component.path = escapePreservingEscapes(component.path);
3744
- if (component.scheme !== void 0) {
3745
- component.path = component.path.split("%3A").join(":");
3746
- }
3964
+ component.path = serializePathEncoding(component.path, pathNoScheme);
3747
3965
  } else {
3748
3966
  component.path = normalizePercentEncoding(component.path);
3749
3967
  }
3750
3968
  }
3751
3969
  if (options.reference !== "suffix" && component.scheme) {
3970
+ component.scheme = decodeValidScheme(component.scheme);
3752
3971
  uriTokens.push(component.scheme, ":");
3753
3972
  }
3754
3973
  const authority = recomposeAuthority(component);
@@ -3766,16 +3985,19 @@ var require_fast_uri2 = __commonJS({
3766
3985
  if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
3767
3986
  s = removeDotSegments(s);
3768
3987
  }
3988
+ if (pathNoScheme) {
3989
+ s = serializePathEncoding(s, true);
3990
+ }
3769
3991
  if (authority === void 0 && s[0] === "/" && s[1] === "/") {
3770
3992
  s = "/%2F" + s.slice(2);
3771
3993
  }
3772
3994
  uriTokens.push(s);
3773
3995
  }
3774
3996
  if (component.query !== void 0) {
3775
- uriTokens.push("?", component.query);
3997
+ uriTokens.push("?", encodeQuery(component.query));
3776
3998
  }
3777
3999
  if (component.fragment !== void 0) {
3778
- uriTokens.push("#", component.fragment);
4000
+ uriTokens.push("#", encodeFragment(component.fragment));
3779
4001
  }
3780
4002
  return uriTokens.join("");
3781
4003
  }
@@ -3791,6 +4013,32 @@ var require_fast_uri2 = __commonJS({
3791
4013
  }
3792
4014
  return void 0;
3793
4015
  }
4016
+ function hasMalformedPercentEncoding(component) {
4017
+ if (component === void 0) return false;
4018
+ let percent = component.indexOf("%");
4019
+ while (percent !== -1) {
4020
+ if (percent + 2 >= component.length || !/^[\da-f]{2}$/iu.test(component.slice(percent + 1, percent + 3))) {
4021
+ return true;
4022
+ }
4023
+ percent = component.indexOf("%", percent + 3);
4024
+ }
4025
+ return false;
4026
+ }
4027
+ function hasMalformedComponentPercentEncoding(matches) {
4028
+ const host = matches[4];
4029
+ return hasMalformedPercentEncoding(matches[3]) || host !== void 0 && !(host[0] === "[" && host[host.length - 1] === "]") && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]);
4030
+ }
4031
+ function canonicalizeHost(parsed, options, schemeHandler, isIP) {
4032
+ if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && parsed.host[0] !== "[" && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
4033
+ try {
4034
+ parsed.host = new URL("http://" + parsed.host).hostname;
4035
+ } catch (e) {
4036
+ parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
4037
+ return true;
4038
+ }
4039
+ }
4040
+ return false;
4041
+ }
3794
4042
  function parseWithStatus(uri, opts) {
3795
4043
  const options = Object.assign({}, opts);
3796
4044
  const parsed = {
@@ -3803,6 +4051,11 @@ var require_fast_uri2 = __commonJS({
3803
4051
  fragment: void 0
3804
4052
  };
3805
4053
  let malformedAuthorityOrPort = false;
4054
+ let malformedPercentEncoding = false;
4055
+ let malformedSchemeSpecific = false;
4056
+ let malformedHost = false;
4057
+ let malformedIPLiteral = false;
4058
+ let malformedScheme = false;
3806
4059
  let isIP = false;
3807
4060
  if (options.reference === "suffix") {
3808
4061
  if (options.scheme) {
@@ -3839,6 +4092,19 @@ var require_fast_uri2 = __commonJS({
3839
4092
  parsed.path = matches[6] || "";
3840
4093
  parsed.query = matches[7];
3841
4094
  parsed.fragment = matches[8];
4095
+ if (parsed.scheme !== void 0) {
4096
+ const decodedScheme = unescape(parsed.scheme);
4097
+ if (VALID_SCHEME.test(decodedScheme)) {
4098
+ parsed.scheme = decodedScheme.toLowerCase();
4099
+ } else {
4100
+ parsed.error = parsed.error || MALFORMED_SCHEME_ERROR;
4101
+ malformedScheme = true;
4102
+ }
4103
+ }
4104
+ malformedPercentEncoding = hasMalformedComponentPercentEncoding(matches);
4105
+ if (malformedPercentEncoding) {
4106
+ parsed.error = parsed.error || "URI contains malformed percent-encoding.";
4107
+ }
3842
4108
  if (isNaN(parsed.port)) {
3843
4109
  parsed.port = matches[5];
3844
4110
  }
@@ -3850,9 +4116,15 @@ var require_fast_uri2 = __commonJS({
3850
4116
  if (parsed.host) {
3851
4117
  const ipv4result = isIPv4(parsed.host);
3852
4118
  if (ipv4result === false) {
4119
+ const bracketedIPLiteral = parsed.host[0] === "[" && parsed.host[parsed.host.length - 1] === "]";
3853
4120
  const ipv6result = normalizeIPv6(parsed.host);
3854
- parsed.host = ipv6result.host.toLowerCase();
3855
- isIP = ipv6result.isIPV6;
4121
+ isIP = ipv6result.isIPV6 || ipv6result.isIPVFuture === true;
4122
+ malformedIPLiteral = bracketedIPLiteral && ipv6result.error === true;
4123
+ parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase();
4124
+ if (malformedIPLiteral) {
4125
+ parsed.error = parsed.error || "URI host is malformed.";
4126
+ malformedAuthorityOrPort = true;
4127
+ }
3856
4128
  } else {
3857
4129
  isIP = true;
3858
4130
  }
@@ -3870,42 +4142,34 @@ var require_fast_uri2 = __commonJS({
3870
4142
  parsed.error = parsed.error || "URI is not a " + options.reference + " reference.";
3871
4143
  }
3872
4144
  const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
3873
- if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport)) {
3874
- if (parsed.host && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
3875
- try {
3876
- parsed.host = new URL("http://" + parsed.host).hostname;
3877
- } catch (e) {
3878
- parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
3879
- }
3880
- }
3881
- }
4145
+ malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
3882
4146
  if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
3883
4147
  if (uri.indexOf("%") !== -1) {
3884
- if (parsed.scheme !== void 0) {
3885
- parsed.scheme = unescape(parsed.scheme);
3886
- }
3887
- if (parsed.host !== void 0) {
3888
- parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
4148
+ if (parsed.host !== void 0 && !malformedIPLiteral) {
4149
+ const host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
4150
+ parsed.host = reescapeHostDelimiters(host, isIP);
3889
4151
  }
3890
4152
  }
3891
4153
  if (parsed.path) {
3892
4154
  parsed.path = normalizePathEncoding(parsed.path);
3893
4155
  }
4156
+ if (parsed.query) {
4157
+ parsed.query = normalizeQueryFragmentEncoding(parsed.query);
4158
+ }
3894
4159
  if (parsed.fragment) {
3895
- try {
3896
- parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
3897
- } catch {
3898
- parsed.error = parsed.error || "URI malformed";
3899
- }
4160
+ parsed.fragment = normalizeQueryFragmentEncoding(parsed.fragment);
3900
4161
  }
3901
4162
  }
3902
4163
  if (schemeHandler && schemeHandler.parse) {
3903
4164
  schemeHandler.parse(parsed, options);
4165
+ if (schemeHandler === SCHEMES.urn && parsed.nid === void 0) {
4166
+ malformedSchemeSpecific = true;
4167
+ }
3904
4168
  }
3905
4169
  } else {
3906
4170
  parsed.error = parsed.error || "URI can not be parsed.";
3907
4171
  }
3908
- return { parsed, malformedAuthorityOrPort };
4172
+ return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme };
3909
4173
  }
3910
4174
  function parse3(uri, opts) {
3911
4175
  return parseWithStatus(uri, opts).parsed;
@@ -3914,20 +4178,28 @@ var require_fast_uri2 = __commonJS({
3914
4178
  return normalizeStringWithStatus(uri, opts).normalized;
3915
4179
  }
3916
4180
  function normalizeStringWithStatus(uri, opts) {
3917
- const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
4181
+ const { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = parseWithStatus(uri, opts);
3918
4182
  return {
3919
- normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
3920
- malformedAuthorityOrPort
4183
+ normalized: malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? uri : serialize(parsed, opts),
4184
+ malformedAuthorityOrPort,
4185
+ malformedPercentEncoding,
4186
+ malformedSchemeSpecific,
4187
+ malformedHost,
4188
+ malformedScheme
3921
4189
  };
3922
4190
  }
3923
4191
  function normalizeComparableURI(uri, opts) {
3924
- if (typeof uri === "string") {
3925
- const { normalized, malformedAuthorityOrPort } = normalizeStringWithStatus(uri, opts);
3926
- return malformedAuthorityOrPort ? void 0 : normalized;
4192
+ if (typeof uri !== "string" && typeof uri !== "object") {
4193
+ return void 0;
3927
4194
  }
3928
- if (typeof uri === "object") {
3929
- return serialize(uri, opts);
4195
+ let value;
4196
+ try {
4197
+ value = typeof uri === "string" ? uri : serialize(uri, opts);
4198
+ } catch {
4199
+ return void 0;
3930
4200
  }
4201
+ const { normalized, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = normalizeStringWithStatus(value, opts);
4202
+ return malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? void 0 : normalized;
3931
4203
  }
3932
4204
  var fastUri = {
3933
4205
  SCHEMES,
@@ -37072,13 +37344,13 @@ var HonoRequest = class {
37072
37344
  return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams();
37073
37345
  }
37074
37346
  #getDecodedParam(key) {
37075
- const paramKey = this.#matchResult[0][this.routeIndex][1][key];
37347
+ const paramKey = this.#matchResult[0][this.routeIndex]?.[1][key];
37076
37348
  const param = this.#getParamValue(paramKey);
37077
37349
  return param && tryDecodeURIComponent(param);
37078
37350
  }
37079
37351
  #getAllDecodedParams() {
37080
37352
  const decoded = {};
37081
- const keys = Object.keys(this.#matchResult[0][this.routeIndex][1]);
37353
+ const keys = Object.keys(this.#matchResult[0][this.routeIndex]?.[1] ?? {});
37082
37354
  for (const key of keys) {
37083
37355
  const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]);
37084
37356
  if (value !== void 0) {
@@ -38165,6 +38437,9 @@ var Hono = class _Hono {
38165
38437
  };
38166
38438
  };
38167
38439
 
38440
+ // node_modules/hono/dist/router/utils.js
38441
+ var createNullObject = () => /* @__PURE__ */ Object.create(null);
38442
+
38168
38443
  // node_modules/hono/dist/router/reg-exp-router/matcher.js
38169
38444
  var emptyParam = [];
38170
38445
  function match(method, path) {
@@ -38215,7 +38490,7 @@ var Node = class _Node {
38215
38490
  // handler index of a dynamic path, or -1 for a static path terminal
38216
38491
  #index;
38217
38492
  #varIndex;
38218
- #children = /* @__PURE__ */ Object.create(null);
38493
+ #children = createNullObject();
38219
38494
  insert(tokens, index, paramMap, context2, isStatic) {
38220
38495
  let node = this;
38221
38496
  for (let i = 0, len = tokens.length; i < len; i++) {
@@ -38299,7 +38574,7 @@ var Trie = class {
38299
38574
  #root = new Node();
38300
38575
  #index = 0;
38301
38576
  // dynamic path -> [handler index, param assoc]; static paths are not registered
38302
- paths = /* @__PURE__ */ Object.create(null);
38577
+ paths = createNullObject();
38303
38578
  insert(path, isStatic) {
38304
38579
  if (isStatic) {
38305
38580
  this.#root.insert(path.split(""), 0, [], this.#context, true);
@@ -38358,22 +38633,16 @@ var Trie = class {
38358
38633
  };
38359
38634
 
38360
38635
  // node_modules/hono/dist/router/reg-exp-router/router.js
38361
- var wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
38636
+ var wildcardRegExpCache = createNullObject();
38362
38637
  function buildWildcardRegExp(path) {
38363
38638
  return wildcardRegExpCache[path] ??= new RegExp(
38364
- path === "*" ? "" : `^${path.replace(
38365
- /\/\*$|([.\\+*[^\]$()])/g,
38366
- (_, metaChar) => metaChar ? `\\${metaChar}` : "(?:|/.*)"
38639
+ `^${path.replace(
38640
+ /\/:[^/{}]+(?:\{\[\^\/]\+})?(?=[/{]|$)|\/?\*$|([.\\+*[^\]$()?{}|])/g,
38641
+ (match2, metaChar) => metaChar ? `\\${metaChar}` : match2 === "/*" ? TAIL_WILDCARD_REG_EXP_STR : match2 === "*" ? ONLY_WILDCARD_REG_EXP_STR : `/:${LABEL_REG_EXP_STR}`
38367
38642
  )}$`
38368
38643
  );
38369
38644
  }
38370
- function clearWildcardRegExpCache() {
38371
- wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
38372
- }
38373
38645
  function findMiddleware(middleware, path) {
38374
- if (!middleware) {
38375
- return void 0;
38376
- }
38377
38646
  for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length)) {
38378
38647
  if (buildWildcardRegExp(k).test(path)) {
38379
38648
  return [...middleware[k]];
@@ -38387,8 +38656,8 @@ var RegExpRouter = class {
38387
38656
  #routes;
38388
38657
  #tries;
38389
38658
  constructor() {
38390
- this.#middleware = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
38391
- this.#routes = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
38659
+ this.#middleware = { [METHOD_NAME_ALL]: createNullObject() };
38660
+ this.#routes = { [METHOD_NAME_ALL]: createNullObject() };
38392
38661
  this.#tries = { [METHOD_NAME_ALL]: new Trie() };
38393
38662
  }
38394
38663
  #insertPath(method, path) {
@@ -38401,117 +38670,86 @@ var RegExpRouter = class {
38401
38670
  add(method, path, handler) {
38402
38671
  const middleware = this.#middleware;
38403
38672
  const routes = this.#routes;
38404
- if (!middleware || !routes) {
38673
+ if (!middleware) {
38405
38674
  throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
38406
38675
  }
38407
38676
  if (!middleware[method]) {
38408
38677
  this.#tries[method] = new Trie();
38409
- [middleware, routes].forEach((handlerMap) => {
38410
- handlerMap[method] = /* @__PURE__ */ Object.create(null);
38411
- Object.keys(handlerMap[METHOD_NAME_ALL]).forEach((p) => {
38678
+ for (const handlerMap of [middleware, routes]) {
38679
+ handlerMap[method] = createNullObject();
38680
+ for (const p in handlerMap[METHOD_NAME_ALL]) {
38412
38681
  handlerMap[method][p] = [...handlerMap[METHOD_NAME_ALL][p]];
38413
38682
  this.#insertPath(method, p);
38414
- });
38415
- });
38683
+ }
38684
+ }
38416
38685
  }
38417
38686
  if (path === "/*") {
38418
38687
  path = "*";
38419
38688
  }
38420
- const paramCount = (path.match(/\/:/g) || []).length;
38689
+ const methods = method === METHOD_NAME_ALL ? Object.keys(middleware) : [method];
38421
38690
  if (/\*$/.test(path)) {
38422
38691
  const re2 = buildWildcardRegExp(path);
38423
- Object.keys(middleware).forEach((m) => {
38424
- if ((method === METHOD_NAME_ALL || method === m) && !middleware[m][path]) {
38692
+ for (const m of methods) {
38693
+ if (!middleware[m][path]) {
38425
38694
  this.#insertPath(m, path);
38426
38695
  middleware[m][path] = findMiddleware(middleware[m], path) || findMiddleware(middleware[METHOD_NAME_ALL], path) || [];
38427
38696
  }
38428
- });
38429
- Object.keys(middleware).forEach((m) => {
38430
- if (method === METHOD_NAME_ALL || method === m) {
38431
- Object.keys(middleware[m]).forEach((p) => {
38432
- re2.test(p) && middleware[m][p].push([handler, paramCount]);
38433
- });
38434
- }
38435
- });
38436
- Object.keys(routes).forEach((m) => {
38437
- if (method === METHOD_NAME_ALL || method === m) {
38438
- Object.keys(routes[m]).forEach(
38439
- (p) => re2.test(p) && routes[m][p].push([handler, paramCount])
38440
- );
38697
+ }
38698
+ for (const handlerMap of [middleware, routes]) {
38699
+ for (const m of methods) {
38700
+ for (const p in handlerMap[m]) {
38701
+ re2.test(p) && handlerMap[m][p].push([handler, path]);
38702
+ }
38441
38703
  }
38442
- });
38704
+ }
38443
38705
  return;
38444
38706
  }
38445
38707
  const paths = checkOptionalParameter(path) || [path];
38446
- for (let i = 0, len = paths.length; i < len; i++) {
38447
- const path2 = paths[i];
38448
- Object.keys(routes).forEach((m) => {
38449
- if (method === METHOD_NAME_ALL || method === m) {
38450
- if (!routes[m][path2]) {
38451
- this.#insertPath(m, path2);
38452
- routes[m][path2] = [
38453
- ...findMiddleware(middleware[m], path2) || findMiddleware(middleware[METHOD_NAME_ALL], path2) || []
38454
- ];
38455
- }
38456
- routes[m][path2].push([handler, paramCount - len + i + 1]);
38708
+ for (const path2 of paths) {
38709
+ for (const m of methods) {
38710
+ if (!routes[m][path2]) {
38711
+ this.#insertPath(m, path2);
38712
+ routes[m][path2] = findMiddleware(middleware[m], path2) || findMiddleware(middleware[METHOD_NAME_ALL], path2) || [];
38457
38713
  }
38458
- });
38714
+ routes[m][path2].push([handler, path2]);
38715
+ }
38459
38716
  }
38460
38717
  }
38461
38718
  match = match;
38462
38719
  buildAllMatchers() {
38463
- const matchers = /* @__PURE__ */ Object.create(null);
38464
- Object.keys(this.#routes).concat(Object.keys(this.#middleware)).forEach((method) => {
38465
- matchers[method] ||= this.#buildMatcher(method);
38466
- });
38720
+ const matchers = createNullObject();
38721
+ for (const method of Object.keys(this.#routes)) {
38722
+ matchers[method] = this.#buildMatcher(method);
38723
+ }
38467
38724
  this.#middleware = this.#routes = this.#tries = void 0;
38468
- clearWildcardRegExpCache();
38725
+ wildcardRegExpCache = createNullObject();
38469
38726
  return matchers;
38470
38727
  }
38471
38728
  #buildMatcher(method) {
38472
38729
  const middleware = this.#middleware[method];
38473
38730
  const routes = this.#routes[method];
38474
38731
  const trie = this.#tries[method];
38475
- const staticMap = /* @__PURE__ */ Object.create(null);
38732
+ const staticMap = createNullObject();
38476
38733
  const handlerData = [];
38477
- [middleware, routes].forEach((r) => {
38734
+ const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
38735
+ for (const r of [middleware, routes]) {
38478
38736
  for (const path in r) {
38479
38737
  const handlers = r[path];
38480
38738
  const pathData = trie.paths[path];
38481
38739
  if (!pathData) {
38482
- staticMap[path] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam];
38483
- continue;
38484
- }
38485
- const paramAssoc = pathData[1];
38486
- handlerData[pathData[0]] = handlers.map(([h, paramCount]) => {
38487
- const paramIndexMap = /* @__PURE__ */ Object.create(null);
38488
- paramCount -= 1;
38489
- for (; paramCount >= 0; paramCount--) {
38490
- const [key, value] = paramAssoc[paramCount];
38491
- paramIndexMap[key] = value;
38492
- }
38493
- return [h, paramIndexMap];
38494
- });
38495
- }
38496
- });
38497
- const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
38498
- for (let i = 0, len = handlerData.length; i < len; i++) {
38499
- for (let j = 0, len2 = handlerData[i].length; j < len2; j++) {
38500
- const map = handlerData[i][j]?.[1];
38501
- if (!map) {
38740
+ staticMap[path] = [handlers.map(([h]) => [h, createNullObject()]), emptyParam];
38502
38741
  continue;
38503
38742
  }
38504
- const keys = Object.keys(map);
38505
- for (let k = 0, len3 = keys.length; k < len3; k++) {
38506
- map[keys[k]] = paramReplacementMap[map[keys[k]]];
38507
- }
38743
+ handlerData[pathData[0]] = handlers.map(([h, handlerPath]) => [
38744
+ h,
38745
+ trie.paths[handlerPath][1].reduceRight((map, [key], i) => {
38746
+ map[key] = paramReplacementMap[pathData[1][i][1]];
38747
+ return map;
38748
+ }, createNullObject())
38749
+ ]);
38508
38750
  }
38509
38751
  }
38510
- const handlerMap = [];
38511
- for (const i in indexReplacementMap) {
38512
- handlerMap[i] = handlerData[indexReplacementMap[i]];
38513
- }
38514
- return [regexp, handlerMap, staticMap];
38752
+ return [regexp, indexReplacementMap.map((i) => handlerData[i]), staticMap];
38515
38753
  }
38516
38754
  };
38517
38755
 
@@ -38571,11 +38809,11 @@ var SmartRouter = class {
38571
38809
  };
38572
38810
 
38573
38811
  // node_modules/hono/dist/router/trie-router/node.js
38574
- var emptyParams = /* @__PURE__ */ Object.create(null);
38812
+ var emptyParams = createNullObject();
38575
38813
  var order = 0;
38576
38814
  var Node2 = class _Node2 {
38577
38815
  #methods = [];
38578
- #children = /* @__PURE__ */ Object.create(null);
38816
+ #children = createNullObject();
38579
38817
  #patterns = [];
38580
38818
  #pattern;
38581
38819
  #params = emptyParams;
@@ -38612,7 +38850,7 @@ var Node2 = class _Node2 {
38612
38850
  const m = node.#methods[i];
38613
38851
  const handlerSet = m[method] || m[METHOD_NAME_ALL];
38614
38852
  if (handlerSet) {
38615
- handlerSet.params = /* @__PURE__ */ Object.create(null);
38853
+ handlerSet.params = createNullObject();
38616
38854
  handlerSets.push(handlerSet);
38617
38855
  for (let i2 = 0, len2 = handlerSet.possibleKeys.length; i2 < len2; i2++) {
38618
38856
  const key = handlerSet.possibleKeys[i2];
@@ -40550,33 +40788,11 @@ function isObject2(input) {
40550
40788
  return false;
40551
40789
  }
40552
40790
  const prototype = Object.getPrototypeOf(input);
40553
- if (prototype === null) {
40554
- return true;
40555
- }
40556
- let proto = prototype;
40557
- while (Object.getPrototypeOf(proto) !== null) {
40558
- proto = Object.getPrototypeOf(proto);
40559
- }
40560
- return prototype === proto;
40791
+ return prototype === null || Object.getPrototypeOf(prototype) === null;
40561
40792
  }
40562
- function isDisjoint(...headers) {
40563
- const parameters = /* @__PURE__ */ new Set();
40564
- for (const header of headers) {
40565
- if (!header)
40566
- continue;
40567
- for (const parameter of Object.keys(header)) {
40568
- if (parameters.has(parameter)) {
40569
- return false;
40570
- }
40571
- parameters.add(parameter);
40572
- }
40573
- }
40574
- return true;
40793
+ function isJwkSet(input) {
40794
+ return isObject2(input) && Array.isArray(input.keys) && Array.from(input.keys).every(isObject2);
40575
40795
  }
40576
- var isJWK = (key) => isObject2(key) && typeof key.kty === "string";
40577
- var isPrivateJWK = (key) => key.kty !== "oct" && (key.kty === "AKP" && typeof key.priv === "string" || typeof key.d === "string");
40578
- var isPublicJWK = (key) => key.kty !== "oct" && key.d === void 0 && key.priv === void 0;
40579
- var isSecretJWK = (key) => key.kty === "oct" && typeof key.k === "string";
40580
40796
 
40581
40797
  // node_modules/jose/dist/webapi/lib/helpers.js
40582
40798
  var unprotected = Symbol();
@@ -40625,6 +40841,26 @@ async function jwkToKey(entry, jwk) {
40625
40841
  return crypto.subtle.importKey("jwk", keyData, algorithm, jwk.ext ?? !isPrivate, jwk.key_ops ?? entry.usages[isPrivate ? 1 : 0]);
40626
40842
  }
40627
40843
 
40844
+ // node_modules/jose/dist/webapi/lib/jwk_metadata.js
40845
+ function snapshotJwk(jwk) {
40846
+ return { __proto__: null, ...jwk };
40847
+ }
40848
+ function normalizeJwk(jwk) {
40849
+ const normalized = snapshotJwk(jwk);
40850
+ if (normalized.ext !== void 0 && typeof normalized.ext !== "boolean") {
40851
+ throw new TypeError('"ext" (Extractable) Parameter must be a boolean');
40852
+ }
40853
+ if (normalized.key_ops !== void 0) {
40854
+ const value = normalized.key_ops;
40855
+ const keyOps = Array.isArray(value) ? [...value] : void 0;
40856
+ if (!keyOps || keyOps.some((operation) => typeof operation !== "string") || new Set(keyOps).size !== keyOps.length) {
40857
+ throw new TypeError('"key_ops" (Key Operations) Parameter must be an array of unique strings');
40858
+ }
40859
+ normalized.key_ops = keyOps;
40860
+ }
40861
+ return normalized;
40862
+ }
40863
+
40628
40864
  // node_modules/jose/dist/webapi/lib/key.js
40629
40865
  var tag = (key) => key[Symbol.toStringTag];
40630
40866
  var jwkMatchesOp = (entry, key, usage) => {
@@ -40650,12 +40886,17 @@ function checkKeyType(entry, key, usage) {
40650
40886
  const privateKey = usage === "decrypt" || usage === "sign";
40651
40887
  if (secret && key instanceof Uint8Array)
40652
40888
  return [BYTES, key];
40653
- if (isJWK(key)) {
40654
- if (secret ? !isSecretJWK(key) : !(privateKey ? isPrivateJWK(key) : isPublicJWK(key))) {
40889
+ if (isObject2(key)) {
40890
+ const normalized = normalizeJwk(key);
40891
+ if (typeof normalized.kty !== "string") {
40892
+ throw new TypeError(secret ? withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key", "Uint8Array") : withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key"));
40893
+ }
40894
+ const valid = secret ? normalized.kty === "oct" && typeof normalized.k === "string" : normalized.kty !== "oct" && (privateKey ? normalized.kty === "AKP" && typeof normalized.priv === "string" || typeof normalized.d === "string" : normalized.d === void 0 && normalized.priv === void 0);
40895
+ if (!valid) {
40655
40896
  throw new TypeError(secret ? `JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present` : `JSON Web Key for this operation must be a ${privateKey ? "private" : "public"} JWK`);
40656
40897
  }
40657
- jwkMatchesOp(entry, key, usage);
40658
- return [JWK, key];
40898
+ jwkMatchesOp(entry, normalized, usage);
40899
+ return [JWK, key, normalized];
40659
40900
  }
40660
40901
  if (!isKeyLike(key)) {
40661
40902
  throw new TypeError(secret ? withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key", "Uint8Array") : withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key"));
@@ -40694,7 +40935,7 @@ function cached2(key, alg, value) {
40694
40935
  if (entry) {
40695
40936
  entry[alg] = value;
40696
40937
  } else {
40697
- cache.set(key, { __proto__: null, [alg]: value });
40938
+ cache.set(key, { [alg]: value });
40698
40939
  }
40699
40940
  }
40700
40941
  return value ?? entry?.[alg];
@@ -40719,8 +40960,9 @@ async function prepareKey(entry, key, usage) {
40719
40960
  return tagged[1];
40720
40961
  case JWK: {
40721
40962
  const key2 = tagged[1];
40722
- if (key2.k) {
40723
- return decode2(key2.k);
40963
+ const normalized = tagged[2];
40964
+ if (normalized.kty === "oct") {
40965
+ return decode2(normalized.k);
40724
40966
  }
40725
40967
  if (!Object.isFrozen(key2)) {
40726
40968
  const { key_ops } = key2;
@@ -40728,7 +40970,7 @@ async function prepareKey(entry, key, usage) {
40728
40970
  Object.freeze(key_ops);
40729
40971
  Object.freeze(key2);
40730
40972
  }
40731
- return handleJWK(key2, key2, entry);
40973
+ return handleJWK(key2, normalized, entry);
40732
40974
  }
40733
40975
  case KEYOBJECT: {
40734
40976
  const keyObject = tagged[1];
@@ -40787,6 +41029,16 @@ function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader,
40787
41029
  }
40788
41030
  return protectedHeader.crit;
40789
41031
  }
41032
+ function validateB64(protectedHeader, extensions) {
41033
+ if (extensions.includes("b64")) {
41034
+ const b64 = protectedHeader.b64;
41035
+ if (typeof b64 !== "boolean") {
41036
+ throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean');
41037
+ }
41038
+ return b64;
41039
+ }
41040
+ return true;
41041
+ }
40790
41042
 
40791
41043
  // node_modules/jose/dist/webapi/lib/signing.js
40792
41044
  async function getSigKey(entry, key, usage) {
@@ -40886,64 +41138,42 @@ function jwsAlgorithm(alg) {
40886
41138
  function prepareVerify(options) {
40887
41139
  return [options && validateAlgorithms("algorithms", options.algorithms), options?.crit];
40888
41140
  }
40889
- async function verifySignature(jws, shared, key) {
40890
- const { protected: encodedProtected, header, payload: inputPayload } = jws;
40891
- let parsedProt = {};
40892
- if (encodedProtected) {
40893
- parsedProt = parseJoseHeader(encodedProtected, JWSInvalid, "JWS Protected Header is invalid");
40894
- }
40895
- let joseHeader;
40896
- if (header !== void 0) {
40897
- if (!isDisjoint(parsedProt, header)) {
40898
- throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
40899
- }
40900
- joseHeader = { ...parsedProt, ...header };
40901
- } else {
40902
- joseHeader = parsedProt;
40903
- }
40904
- const extensions = validateCrit(JWSInvalid, JWS_RECOGNIZED, shared[1], parsedProt, joseHeader);
40905
- let b64 = true;
40906
- if (extensions.includes("b64")) {
40907
- b64 = parsedProt.b64;
40908
- if (typeof b64 !== "boolean") {
40909
- throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean');
40910
- }
40911
- }
40912
- const { alg } = joseHeader;
41141
+ function parseProtectedHeader(encodedProtected, parsedProtected = encodedProtected === void 0 ? {} : parseJoseHeader(encodedProtected, JWSInvalid, "JWS Protected Header is invalid")) {
41142
+ return parsedProtected;
41143
+ }
41144
+ function validateJwsHeaders(parsedProt, joseHeader, shared) {
41145
+ const b64 = validateB64(parsedProt, validateCrit(JWSInvalid, JWS_RECOGNIZED, shared[1], parsedProt, joseHeader));
41146
+ const alg = joseHeader.alg;
40913
41147
  if (typeof alg !== "string" || !alg) {
40914
41148
  throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
40915
41149
  }
40916
41150
  if (shared[0] && !shared[0].has(alg)) {
40917
41151
  throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed');
40918
41152
  }
40919
- if (b64) {
40920
- if (typeof inputPayload !== "string") {
40921
- throw new JWSInvalid("JWS Payload must be a string");
40922
- }
40923
- } else if (typeof inputPayload !== "string" && !(inputPayload instanceof Uint8Array)) {
40924
- throw new JWSInvalid("JWS Payload must be a string or an Uint8Array instance");
41153
+ return [b64, alg];
41154
+ }
41155
+ function encodeCompactUnencodedPayload(payload) {
41156
+ try {
41157
+ return encode2(payload);
41158
+ } catch {
41159
+ throw new JWSInvalid("JWS Compact Serialization payload must use only ASCII characters");
40925
41160
  }
41161
+ }
41162
+ async function verifyPrepared(jws, shared, key, encodedProtected, parsedProt, alg, signingPayload) {
40926
41163
  let resolvedKey = false;
40927
41164
  if (typeof key === "function") {
40928
41165
  key = await key(parsedProt, jws);
40929
41166
  resolvedKey = true;
40930
41167
  }
41168
+ const b64 = typeof signingPayload === "string";
40931
41169
  const entry = jwsAlgorithm(alg);
40932
- const data = concat(encodedProtected !== void 0 ? encode2(encodedProtected) : new Uint8Array(), encode2("."), typeof inputPayload === "string" ? b64 ? shared[2] ??= encodeBase64url(inputPayload, "payload", JWSInvalid) : encoder.encode(inputPayload) : inputPayload);
41170
+ const data = concat(encodedProtected !== void 0 ? encode2(encodedProtected) : new Uint8Array(), encode2("."), b64 ? shared[2] ??= encodeBase64url(signingPayload, "payload", JWSInvalid) : signingPayload);
40933
41171
  const signature = decodeBase64url(jws.signature, "signature", JWSInvalid);
40934
41172
  const k = await prepareKey(entry, key, "verify");
40935
- const verified = await verify(entry, k, signature, data);
40936
- if (!verified) {
41173
+ if (!await verify(entry, k, signature, data)) {
40937
41174
  throw new JWSSignatureVerificationFailed();
40938
41175
  }
40939
- let payload;
40940
- if (b64) {
40941
- payload = decodeBase64url(inputPayload, "payload", JWSInvalid);
40942
- } else if (typeof inputPayload === "string") {
40943
- payload = encoder.encode(inputPayload);
40944
- } else {
40945
- payload = inputPayload;
40946
- }
41176
+ const payload = b64 ? decodeBase64url(signingPayload, "payload", JWSInvalid) : signingPayload;
40947
41177
  return [payload, parsedProt, b64, k, resolvedKey];
40948
41178
  }
40949
41179
  async function verifyCompact(jws, shared, key) {
@@ -40957,7 +41187,11 @@ async function verifyCompact(jws, shared, key) {
40957
41187
  if (length !== 3) {
40958
41188
  throw new JWSInvalid("Invalid Compact JWS");
40959
41189
  }
40960
- return verifySignature({ payload, protected: protectedHeader, signature }, shared, key);
41190
+ const compactJws = { payload, protected: protectedHeader, signature };
41191
+ const parsedProt = parseProtectedHeader(protectedHeader);
41192
+ const [b64, alg] = validateJwsHeaders(parsedProt, parsedProt, shared);
41193
+ const signingPayload = b64 ? payload : encodeCompactUnencodedPayload(payload);
41194
+ return verifyPrepared(compactJws, shared, key, protectedHeader, parsedProt, alg, signingPayload);
40961
41195
  }
40962
41196
 
40963
41197
  // node_modules/jose/dist/webapi/lib/jwt_claims_set.js
@@ -40972,13 +41206,22 @@ var multipliers = {
40972
41206
  };
40973
41207
  var REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;
40974
41208
  var checkFailed = "check_failed";
41209
+ function invalidDuration() {
41210
+ throw new TypeError("Invalid time period format");
41211
+ }
40975
41212
  function secs(str) {
41213
+ if (typeof str !== "string") {
41214
+ invalidDuration();
41215
+ }
40976
41216
  const matched = REGEX.exec(str);
40977
41217
  if (!matched || matched[4] && matched[1]) {
40978
- throw new TypeError("Invalid time period format");
41218
+ invalidDuration();
40979
41219
  }
40980
41220
  const value = parseFloat(matched[2]);
40981
41221
  const numericDate = Math.round(value * multipliers[matched[3][0].toLowerCase()]);
41222
+ if (!Number.isFinite(numericDate)) {
41223
+ invalidDuration();
41224
+ }
40982
41225
  if (matched[1] === "-" || matched[4] === "ago") {
40983
41226
  return -numericDate;
40984
41227
  }
@@ -40991,10 +41234,8 @@ function validateInput(label, input) {
40991
41234
  return input;
40992
41235
  }
40993
41236
  var normalizeTyp = (value) => {
40994
- if (value.includes("/")) {
40995
- return value.toLowerCase();
40996
- }
40997
- return `application/${value.toLowerCase()}`;
41237
+ const normalized = value.toLowerCase();
41238
+ return value.includes("/") ? normalized : `application/${normalized}`;
40998
41239
  };
40999
41240
  var checkAudiencePresence = (audPayload, audOption) => {
41000
41241
  if (typeof audPayload === "string") {
@@ -41027,7 +41268,7 @@ function validateClaimsSet(protectedHeader, encodedPayload, options = {}) {
41027
41268
  throw new JWTInvalid("JWT Claims Set must be a top-level JSON object");
41028
41269
  }
41029
41270
  const { typ } = options;
41030
- if (typ && (typeof protectedHeader.typ !== "string" || normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) {
41271
+ if (typ !== void 0 && (typeof protectedHeader.typ !== "string" || normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) {
41031
41272
  throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', payload, "typ", checkFailed);
41032
41273
  }
41033
41274
  const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options;
@@ -41066,7 +41307,7 @@ function validateClaimsSet(protectedHeader, encodedPayload, options = {}) {
41066
41307
  }
41067
41308
  validateInput("clockTolerance option", tolerance);
41068
41309
  const { currentDate } = options;
41069
- const now = validateInput("currentDate option", epoch(currentDate || /* @__PURE__ */ new Date()));
41310
+ const now = validateInput("currentDate option", epoch(currentDate === void 0 ? /* @__PURE__ */ new Date() : currentDate));
41070
41311
  const iat = validateNumericDate(payload, "iat", maxTokenAge !== void 0);
41071
41312
  const nbf = validateNumericDate(payload, "nbf");
41072
41313
  if (nbf !== void 0) {
@@ -41082,11 +41323,11 @@ function validateClaimsSet(protectedHeader, encodedPayload, options = {}) {
41082
41323
  }
41083
41324
  if (maxTokenAge !== void 0) {
41084
41325
  const age = now - iat;
41085
- const max = typeof maxTokenAge === "number" ? maxTokenAge : secs(maxTokenAge);
41326
+ const max = validateInput("maxTokenAge option", typeof maxTokenAge === "number" ? maxTokenAge : secs(maxTokenAge));
41086
41327
  if (age - tolerance > max) {
41087
41328
  throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', payload, "iat", checkFailed);
41088
41329
  }
41089
- if (age < 0 - tolerance) {
41330
+ if (age < -tolerance) {
41090
41331
  throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', payload, "iat", checkFailed);
41091
41332
  }
41092
41333
  }
@@ -41108,74 +41349,61 @@ async function jwtVerify(jwt, key, options) {
41108
41349
  }
41109
41350
 
41110
41351
  // node_modules/jose/dist/webapi/jwks/local.js
41111
- function signatureAlgorithm(alg) {
41112
- const entry = typeof alg === "string" ? JWS[alg] : void 0;
41113
- if (!entry || entry.secret) {
41114
- throw new JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set');
41115
- }
41116
- return entry;
41352
+ function isUsableJWK(jwk, entry, alg, kid) {
41353
+ const { kty, key_ops, ext, kid: jwkKid, alg: jwkAlg, use, crv } = snapshotJwk(jwk);
41354
+ const keyOps = Array.isArray(key_ops) ? [...key_ops] : key_ops;
41355
+ return (ext === void 0 || typeof ext === "boolean") && (keyOps === void 0 || Array.isArray(keyOps) && keyOps.every((operation, index) => typeof operation === "string" && keyOps.indexOf(operation) === index) && keyOps.includes("verify")) && entry.kty.includes(kty) && (kid === void 0 || typeof kid === "string" && kid === jwkKid) && (jwkAlg === void 0 ? kty !== "AKP" : alg === jwkAlg) && (use === void 0 || use === "sig") && (!entry.crv || crv === entry.crv);
41117
41356
  }
41118
- function isJWKSLike(jwks) {
41119
- if (!jwks || typeof jwks !== "object") {
41120
- return false;
41357
+ async function importWithAlgCache(cache2, jwk, entry) {
41358
+ const cached3 = cache2.get(jwk) || cache2.set(jwk, {}).get(jwk);
41359
+ const { alg } = entry;
41360
+ if (cached3[alg] === void 0) {
41361
+ const key = await jwkToKey(entry, { ...jwk, alg, ext: true });
41362
+ if (key.type !== "public") {
41363
+ throw new JWKSInvalid("JSON Web Key Set members must be public keys");
41364
+ }
41365
+ cached3[alg] = key;
41121
41366
  }
41122
- const { keys } = jwks;
41123
- return Array.isArray(keys) && keys.every(isObject2);
41367
+ return cached3[alg];
41124
41368
  }
41125
- var LocalJWKSetImpl = class {
41126
- #jwks;
41127
- #cached = /* @__PURE__ */ new WeakMap();
41128
- constructor(jwks) {
41129
- if (!isJWKSLike(jwks)) {
41130
- throw new JWKSInvalid("JSON Web Key Set malformed");
41131
- }
41132
- this.#jwks = structuredClone(jwks);
41369
+ function createLocalJWKSet(jwks) {
41370
+ let snapshot;
41371
+ try {
41372
+ snapshot = structuredClone(jwks);
41373
+ } catch {
41133
41374
  }
41134
- jwks() {
41135
- return this.#jwks;
41375
+ if (!isJwkSet(snapshot)) {
41376
+ throw new JWKSInvalid("JSON Web Key Set malformed");
41136
41377
  }
41137
- async getKey(protectedHeader, token) {
41378
+ const cached3 = /* @__PURE__ */ new WeakMap();
41379
+ const localJWKSet = async (protectedHeader, token) => {
41138
41380
  const { alg, kid } = { ...protectedHeader, ...token?.header };
41139
- const entry = signatureAlgorithm(alg);
41140
- const candidates = this.#jwks.keys.filter((jwk2) => entry.kty.includes(jwk2.kty) && (typeof kid !== "string" || kid === jwk2.kid) && (!(typeof jwk2.alg === "string" || jwk2.kty === "AKP") || alg === jwk2.alg) && (typeof jwk2.use !== "string" || jwk2.use === "sig") && (!Array.isArray(jwk2.key_ops) || jwk2.key_ops.includes("verify")) && (!entry.crv || jwk2.crv === entry.crv));
41381
+ const entry = typeof alg === "string" ? JWS[alg] : void 0;
41382
+ if (!entry || entry.secret) {
41383
+ throw new JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set');
41384
+ }
41385
+ const candidates = snapshot.keys.filter((jwk2) => isUsableJWK(jwk2, entry, alg, kid));
41141
41386
  const { 0: jwk, length } = candidates;
41142
- if (length === 0) {
41387
+ if (!length) {
41143
41388
  throw new JWKSNoMatchingKey();
41144
41389
  }
41145
41390
  if (length !== 1) {
41146
41391
  const error2 = new JWKSMultipleMatchingKeys();
41147
- const _cached = this.#cached;
41148
41392
  error2[Symbol.asyncIterator] = async function* () {
41149
41393
  for (const jwk2 of candidates) {
41150
41394
  try {
41151
- yield await importWithAlgCache(_cached, jwk2, entry);
41395
+ yield await importWithAlgCache(cached3, jwk2, entry);
41152
41396
  } catch {
41153
41397
  }
41154
41398
  }
41155
41399
  };
41156
41400
  throw error2;
41157
41401
  }
41158
- return importWithAlgCache(this.#cached, jwk, entry);
41159
- }
41160
- };
41161
- async function importWithAlgCache(cache2, jwk, entry) {
41162
- const cached3 = cache2.get(jwk) || cache2.set(jwk, { __proto__: null }).get(jwk);
41163
- if (cached3[entry.alg] === void 0) {
41164
- const key = await jwkToKey(entry, { ...jwk, alg: entry.alg, ext: true });
41165
- if (key.type !== "public") {
41166
- throw new JWKSInvalid("JSON Web Key Set members must be public keys");
41167
- }
41168
- cached3[entry.alg] = key;
41169
- }
41170
- return cached3[entry.alg];
41171
- }
41172
- function createLocalJWKSet(jwks) {
41173
- const set = new LocalJWKSetImpl(jwks);
41174
- const localJWKSet = async (protectedHeader, token) => set.getKey(protectedHeader, token);
41175
- Object.defineProperty(localJWKSet, "jwks", {
41176
- value: () => structuredClone(set.jwks())
41402
+ return importWithAlgCache(cached3, jwk, entry);
41403
+ };
41404
+ return Object.defineProperty(localJWKSet, "jwks", {
41405
+ value: () => structuredClone(snapshot)
41177
41406
  });
41178
- return localJWKSet;
41179
41407
  }
41180
41408
 
41181
41409
  // node_modules/jose/dist/webapi/jwks/remote.js
@@ -41185,7 +41413,7 @@ function isCloudflareWorkers() {
41185
41413
  var USER_AGENT;
41186
41414
  if (typeof navigator === "undefined" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) {
41187
41415
  const NAME = "jose";
41188
- const VERSION2 = "v6.2.9";
41416
+ const VERSION2 = "v6.2.10";
41189
41417
  USER_AGENT = `${NAME}/${VERSION2}`;
41190
41418
  }
41191
41419
  var customFetch = Symbol();
@@ -41211,130 +41439,112 @@ async function fetchJwks(url2, headers, signal, fetchImpl = fetch) {
41211
41439
  }
41212
41440
  }
41213
41441
  var jwksCache = Symbol();
41214
- function isFreshJwksCache(input, cacheMaxAge) {
41215
- if (typeof input !== "object" || input === null) {
41216
- return false;
41217
- }
41218
- if (!("uat" in input) || typeof input.uat !== "number" || Date.now() - input.uat >= cacheMaxAge) {
41219
- return false;
41220
- }
41221
- if (!("jwks" in input) || !isObject2(input.jwks) || !Array.isArray(input.jwks.keys) || !Array.prototype.every.call(input.jwks.keys, isObject2)) {
41222
- return false;
41442
+ function isFreshFor(timestamp, duration3) {
41443
+ return Number.isFinite(timestamp) && Date.now() < timestamp + duration3;
41444
+ }
41445
+ function validateDuration(value, fallback, option) {
41446
+ if (Number.isNaN(value)) {
41447
+ throw new TypeError(`"${option}" option must not be NaN`);
41223
41448
  }
41224
- return true;
41449
+ return typeof value === "number" ? value : fallback;
41225
41450
  }
41226
- var RemoteJWKSetImpl = class {
41227
- #url;
41228
- #timeoutDuration;
41229
- #cooldownDuration;
41230
- #cacheMaxAge;
41231
- #jwksTimestamp;
41232
- #pendingFetch;
41233
- #headers;
41234
- #customFetch;
41235
- #local;
41236
- #cache;
41237
- constructor(url2, options) {
41238
- if (!(url2 instanceof URL)) {
41239
- throw new TypeError("url must be an instance of URL");
41240
- }
41241
- this.#url = new URL(url2.href);
41242
- const opts = options ?? {};
41243
- this.#timeoutDuration = typeof opts.timeoutDuration === "number" ? opts.timeoutDuration : 5e3;
41244
- this.#cooldownDuration = typeof opts.cooldownDuration === "number" ? opts.cooldownDuration : 3e4;
41245
- this.#cacheMaxAge = typeof opts.cacheMaxAge === "number" ? opts.cacheMaxAge : 6e5;
41246
- this.#headers = new Headers(opts.headers);
41247
- if (USER_AGENT && !this.#headers.has("User-Agent")) {
41248
- this.#headers.set("User-Agent", USER_AGENT);
41249
- }
41250
- if (!this.#headers.has("accept")) {
41251
- this.#headers.set("accept", "application/json");
41252
- this.#headers.append("accept", "application/jwk-set+json");
41253
- }
41254
- this.#customFetch = opts[customFetch];
41255
- const cache2 = opts[jwksCache];
41256
- if (cache2 !== void 0) {
41257
- this.#cache = cache2;
41258
- if (isFreshJwksCache(cache2, this.#cacheMaxAge)) {
41259
- this.#jwksTimestamp = this.#cache.uat;
41260
- this.#local = createLocalJWKSet(this.#cache.jwks);
41261
- }
41262
- }
41263
- }
41264
- pendingFetch() {
41265
- return !!this.#pendingFetch;
41266
- }
41267
- #validFor(duration3) {
41268
- return typeof this.#jwksTimestamp === "number" && Date.now() < this.#jwksTimestamp + duration3;
41269
- }
41270
- coolingDown() {
41271
- return this.#validFor(this.#cooldownDuration);
41272
- }
41273
- fresh() {
41274
- return this.#validFor(this.#cacheMaxAge);
41275
- }
41276
- jwks() {
41277
- return this.#local?.jwks();
41278
- }
41279
- async getKey(protectedHeader, token) {
41280
- if (!this.#local || !this.fresh()) {
41281
- await this.reload();
41451
+ function createRemoteJWKSet(url2, options) {
41452
+ if (!(url2 instanceof URL)) {
41453
+ throw new TypeError("url must be an instance of URL");
41454
+ }
41455
+ const href = new URL(url2.href).href;
41456
+ const opts = options ?? {};
41457
+ const timeoutOption = opts.timeoutDuration;
41458
+ if (typeof timeoutOption === "number" && (!Number.isInteger(timeoutOption) || timeoutOption < 0)) {
41459
+ throw new TypeError('"timeoutDuration" option must be a non-negative integer');
41460
+ }
41461
+ const timeoutDuration = typeof timeoutOption === "number" ? timeoutOption : 5e3;
41462
+ const cooldownDuration = validateDuration(opts.cooldownDuration, 3e4, "cooldownDuration");
41463
+ const cacheMaxAge = validateDuration(opts.cacheMaxAge, 6e5, "cacheMaxAge");
41464
+ const headers = new Headers(opts.headers);
41465
+ if (USER_AGENT && !headers.has("User-Agent")) {
41466
+ headers.set("User-Agent", USER_AGENT);
41467
+ }
41468
+ if (!headers.has("accept")) {
41469
+ headers.set("accept", "application/json, application/jwk-set+json");
41470
+ }
41471
+ const fetchImpl = opts[customFetch];
41472
+ const cache2 = opts[jwksCache];
41473
+ let jwksTimestamp;
41474
+ let pendingFetch;
41475
+ let reloadSequence = 0;
41476
+ let appliedSequence = 0;
41477
+ let local;
41478
+ if (cache2 && typeof cache2 === "object") {
41479
+ const { uat, jwks } = cache2;
41480
+ if (isFreshFor(uat, cacheMaxAge) && isJwkSet(jwks)) {
41481
+ jwksTimestamp = uat;
41482
+ local = createLocalJWKSet(jwks);
41483
+ }
41484
+ }
41485
+ const reload = async () => {
41486
+ if (pendingFetch && isCloudflareWorkers()) {
41487
+ pendingFetch = void 0;
41488
+ }
41489
+ if (!pendingFetch) {
41490
+ const sequence = ++reloadSequence;
41491
+ const current = pendingFetch = fetchJwks(href, headers, AbortSignal.timeout(timeoutDuration), fetchImpl).then((json) => {
41492
+ const next = createLocalJWKSet(json);
41493
+ if (sequence <= appliedSequence) {
41494
+ return;
41495
+ }
41496
+ local = next;
41497
+ const updatedAt = Date.now();
41498
+ if (cache2) {
41499
+ cache2.uat = updatedAt;
41500
+ cache2.jwks = json;
41501
+ }
41502
+ jwksTimestamp = updatedAt;
41503
+ appliedSequence = sequence;
41504
+ }).finally(() => {
41505
+ if (pendingFetch === current) {
41506
+ pendingFetch = void 0;
41507
+ }
41508
+ });
41509
+ }
41510
+ await pendingFetch;
41511
+ };
41512
+ const remoteJWKSet = async (protectedHeader, token) => {
41513
+ if (!local || !isFreshFor(jwksTimestamp, cacheMaxAge)) {
41514
+ await reload();
41282
41515
  }
41283
41516
  try {
41284
- return await this.#local(protectedHeader, token);
41517
+ return await local(protectedHeader, token);
41285
41518
  } catch (err) {
41286
- if (err instanceof JWKSNoMatchingKey) {
41287
- if (this.coolingDown() === false) {
41288
- await this.reload();
41289
- return this.#local(protectedHeader, token);
41290
- }
41519
+ if (err instanceof JWKSNoMatchingKey && !isFreshFor(jwksTimestamp, cooldownDuration)) {
41520
+ await reload();
41521
+ return local(protectedHeader, token);
41291
41522
  }
41292
41523
  throw err;
41293
41524
  }
41294
- }
41295
- async reload() {
41296
- if (this.#pendingFetch && isCloudflareWorkers()) {
41297
- this.#pendingFetch = void 0;
41298
- }
41299
- this.#pendingFetch ||= fetchJwks(this.#url.href, this.#headers, AbortSignal.timeout(this.#timeoutDuration), this.#customFetch).then((json) => {
41300
- this.#local = createLocalJWKSet(json);
41301
- if (this.#cache) {
41302
- this.#cache.uat = Date.now();
41303
- this.#cache.jwks = json;
41304
- }
41305
- this.#jwksTimestamp = Date.now();
41306
- }).finally(() => {
41307
- this.#pendingFetch = void 0;
41308
- });
41309
- await this.#pendingFetch;
41310
- }
41311
- };
41312
- function createRemoteJWKSet(url2, options) {
41313
- const set = new RemoteJWKSetImpl(url2, options);
41314
- const remoteJWKSet = async (protectedHeader, token) => set.getKey(protectedHeader, token);
41315
- Object.defineProperties(remoteJWKSet, {
41525
+ };
41526
+ return Object.defineProperties(remoteJWKSet, {
41316
41527
  coolingDown: {
41317
- get: () => set.coolingDown(),
41528
+ get: () => isFreshFor(jwksTimestamp, cooldownDuration),
41318
41529
  enumerable: true
41319
41530
  },
41320
41531
  fresh: {
41321
- get: () => set.fresh(),
41532
+ get: () => isFreshFor(jwksTimestamp, cacheMaxAge),
41322
41533
  enumerable: true
41323
41534
  },
41324
41535
  reload: {
41325
- value: () => set.reload(),
41536
+ value: reload,
41326
41537
  enumerable: true
41327
41538
  },
41328
41539
  reloading: {
41329
- get: () => set.pendingFetch(),
41540
+ get: () => !!pendingFetch,
41330
41541
  enumerable: true
41331
41542
  },
41332
41543
  jwks: {
41333
- value: () => set.jwks(),
41544
+ value: () => local?.jwks(),
41334
41545
  enumerable: true
41335
41546
  }
41336
41547
  });
41337
- return remoteJWKSet;
41338
41548
  }
41339
41549
 
41340
41550
  // node_modules/@casys/mcp-server/src/auth/provider.ts
@@ -47626,6 +47836,14 @@ function roundedTotalFallbackWarning(original, patched) {
47626
47836
  }
47627
47837
 
47628
47838
  // src/tools/sales.ts
47839
+ function viewerDocument(value, doctype, name) {
47840
+ const record2 = typeof value === "object" && value !== null ? value : {};
47841
+ return {
47842
+ ...record2,
47843
+ ...typeof record2.name === "string" || !name ? {} : { name },
47844
+ doctype
47845
+ };
47846
+ }
47629
47847
  function mapLineItems(items, options) {
47630
47848
  if (!Array.isArray(items) || items.length === 0) {
47631
47849
  throw new Error(
@@ -47906,7 +48124,7 @@ var salesTools = [
47906
48124
  throw new Error("[erpnext_sales_order_get] 'name' is required");
47907
48125
  }
47908
48126
  const doc = await ctx.client.get("Sales Order", input.name);
47909
- return { data: doc };
48127
+ return { data: viewerDocument(doc, "Sales Order", input.name) };
47910
48128
  }
47911
48129
  },
47912
48130
  {
@@ -47987,8 +48205,12 @@ var salesTools = [
47987
48205
  }
47988
48206
  const doc = await ctx.client.create("Sales Order", data);
47989
48207
  return {
47990
- data: doc,
47991
- message: `Sales Order ${doc.name} created successfully`
48208
+ data: viewerDocument(doc, "Sales Order"),
48209
+ message: `Sales Order ${doc.name} created successfully`,
48210
+ refreshRequest: {
48211
+ toolName: "erpnext_sales_order_get",
48212
+ arguments: { name: doc.name }
48213
+ }
47992
48214
  };
47993
48215
  }
47994
48216
  },
@@ -48078,8 +48300,16 @@ var salesTools = [
48078
48300
  ctx.client.invalidate("Sales Order", input.name);
48079
48301
  const warnings = roundedTotalFallbackWarning(docWithDoctype, patchedDoc);
48080
48302
  return {
48081
- data: result,
48303
+ data: viewerDocument(
48304
+ result,
48305
+ "Sales Order",
48306
+ input.name
48307
+ ),
48082
48308
  message: `Sales Order ${input.name} submitted successfully`,
48309
+ refreshRequest: {
48310
+ toolName: "erpnext_sales_order_get",
48311
+ arguments: { name: input.name }
48312
+ },
48083
48313
  ...warnings.length > 0 ? { warnings } : {}
48084
48314
  };
48085
48315
  }
@@ -48205,7 +48435,11 @@ var salesTools = [
48205
48435
  }
48206
48436
  const doc = await ctx.client.get("Sales Invoice", input.name);
48207
48437
  return {
48208
- data: doc,
48438
+ data: viewerDocument(
48439
+ doc,
48440
+ "Sales Invoice",
48441
+ input.name
48442
+ ),
48209
48443
  _meta: INVOICE_META
48210
48444
  };
48211
48445
  }
@@ -48291,9 +48525,13 @@ var salesTools = [
48291
48525
  }
48292
48526
  const doc = await ctx.client.create("Sales Invoice", data);
48293
48527
  return {
48294
- data: doc,
48528
+ data: viewerDocument(doc, "Sales Invoice"),
48295
48529
  message: `Sales Invoice ${doc.name} created successfully`,
48296
- _meta: INVOICE_META
48530
+ _meta: INVOICE_META,
48531
+ refreshRequest: {
48532
+ toolName: "erpnext_sales_invoice_get",
48533
+ arguments: { name: doc.name }
48534
+ }
48297
48535
  };
48298
48536
  }
48299
48537
  },
@@ -48327,9 +48565,17 @@ var salesTools = [
48327
48565
  ctx.client.invalidate("Sales Invoice", input.name);
48328
48566
  const warnings = roundedTotalFallbackWarning(docWithDoctype, patchedDoc);
48329
48567
  return {
48330
- data: result,
48568
+ data: viewerDocument(
48569
+ result,
48570
+ "Sales Invoice",
48571
+ input.name
48572
+ ),
48331
48573
  message: `Sales Invoice ${input.name} submitted successfully`,
48332
48574
  _meta: INVOICE_META,
48575
+ refreshRequest: {
48576
+ toolName: "erpnext_sales_invoice_get",
48577
+ arguments: { name: input.name }
48578
+ },
48333
48579
  ...warnings.length > 0 ? { warnings } : {}
48334
48580
  };
48335
48581
  }
@@ -48435,7 +48681,7 @@ var salesTools = [
48435
48681
  throw new Error("[erpnext_quotation_get] 'name' is required");
48436
48682
  }
48437
48683
  const doc = await ctx.client.get("Quotation", input.name);
48438
- return { data: doc };
48684
+ return { data: viewerDocument(doc, "Quotation", input.name) };
48439
48685
  }
48440
48686
  },
48441
48687
  {
@@ -48529,8 +48775,12 @@ var salesTools = [
48529
48775
  }
48530
48776
  const doc = await ctx.client.create("Quotation", data);
48531
48777
  return {
48532
- data: doc,
48533
- message: `Quotation ${doc.name} created successfully`
48778
+ data: viewerDocument(doc, "Quotation"),
48779
+ message: `Quotation ${doc.name} created successfully`,
48780
+ refreshRequest: {
48781
+ toolName: "erpnext_quotation_get",
48782
+ arguments: { name: doc.name }
48783
+ }
48534
48784
  };
48535
48785
  }
48536
48786
  }
@@ -48816,12 +49066,16 @@ var inventoryTools = [
48816
49066
  name: "erpnext_stock_entry_list",
48817
49067
  annotations: { readOnlyHint: true },
48818
49068
  _meta: DOCLIST_META,
48819
- description: "List Stock Entries (material transfers, receipts, issues). Fields: name, stock_entry_type, posting_date, from_warehouse, to_warehouse, total_amount. Filterable by stock_entry_type, date range.",
49069
+ description: "List Stock Entries (material transfers, receipts, issues). Fields: name, stock_entry_type, posting_date, from_warehouse, to_warehouse, total_amount. Filterable by item_code, stock_entry_type, date range.",
48820
49070
  category: "inventory",
48821
49071
  inputSchema: {
48822
49072
  type: "object",
48823
49073
  properties: {
48824
49074
  limit: { type: "number", description: "Max results (default 20)" },
49075
+ item_code: {
49076
+ type: "string",
49077
+ description: "Exact item code present in a Stock Entry line"
49078
+ },
48825
49079
  stock_entry_type: {
48826
49080
  type: "string",
48827
49081
  description: "Filter by type (Material Issue, Material Receipt, Material Transfer, etc.)"
@@ -48836,6 +49090,14 @@ var inventoryTools = [
48836
49090
  handler: async (input, ctx) => {
48837
49091
  const limit = input.limit ?? 20;
48838
49092
  const filters = [];
49093
+ if (input.item_code) {
49094
+ filters.push([
49095
+ "Stock Entry Detail",
49096
+ "item_code",
49097
+ "=",
49098
+ input.item_code
49099
+ ]);
49100
+ }
48839
49101
  if (input.stock_entry_type) {
48840
49102
  filters.push([
48841
49103
  "stock_entry_type",
@@ -52453,6 +52715,81 @@ var assetsTools = [
52453
52715
  // src/tools/operations.ts
52454
52716
  var operationsTools = [
52455
52717
  // ── File Attachments ───────────────────────────────────────────────────────
52718
+ {
52719
+ name: "erpnext_file_list",
52720
+ annotations: { readOnlyHint: true },
52721
+ description: "List the files attached to an ERPNext document. Returns name, size, privacy and URL for each attachment. Pairs with erpnext_file_upload: that one attaches, this one reads back.",
52722
+ category: "operations",
52723
+ inputSchema: {
52724
+ type: "object",
52725
+ properties: {
52726
+ attached_to_doctype: {
52727
+ type: "string",
52728
+ description: "DocType of the document whose attachments to list.",
52729
+ minLength: 1
52730
+ },
52731
+ attached_to_name: {
52732
+ type: "string",
52733
+ description: "Name/ID of the document whose attachments to list.",
52734
+ minLength: 1
52735
+ },
52736
+ limit: {
52737
+ type: "number",
52738
+ description: "Maximum number of files to return. Defaults to 50.",
52739
+ minimum: 1,
52740
+ maximum: 500
52741
+ }
52742
+ },
52743
+ required: ["attached_to_doctype", "attached_to_name"]
52744
+ },
52745
+ handler: async (input, ctx) => {
52746
+ for (const field of ["attached_to_doctype", "attached_to_name"]) {
52747
+ if (typeof input[field] !== "string" || !input[field].trim()) {
52748
+ throw new Error(
52749
+ `[erpnext_file_list] '${field}' must be a non-empty string`
52750
+ );
52751
+ }
52752
+ }
52753
+ if (input.limit !== void 0 && (typeof input.limit !== "number" || !Number.isInteger(input.limit) || input.limit < 1 || input.limit > 500)) {
52754
+ throw new Error(
52755
+ "[erpnext_file_list] 'limit' must be an integer between 1 and 500"
52756
+ );
52757
+ }
52758
+ const files = await ctx.client.list("File", {
52759
+ fields: [
52760
+ "name",
52761
+ "file_name",
52762
+ "file_url",
52763
+ "file_size",
52764
+ "is_private",
52765
+ "attached_to_field",
52766
+ "creation",
52767
+ "modified",
52768
+ "owner"
52769
+ ],
52770
+ filters: [
52771
+ ["attached_to_doctype", "=", input.attached_to_doctype],
52772
+ ["attached_to_name", "=", input.attached_to_name]
52773
+ ],
52774
+ order_by: "creation desc",
52775
+ limit: input.limit ?? 50
52776
+ });
52777
+ return {
52778
+ count: files.length,
52779
+ data: files.map((file) => ({
52780
+ name: file.name,
52781
+ file_name: file.file_name,
52782
+ file_url: file.file_url,
52783
+ file_size: file.file_size ?? null,
52784
+ is_private: file.is_private === 1,
52785
+ attached_to_field: file.attached_to_field ?? null,
52786
+ creation: file.creation,
52787
+ modified: file.modified,
52788
+ owner: file.owner
52789
+ }))
52790
+ };
52791
+ }
52792
+ },
52456
52793
  {
52457
52794
  name: "erpnext_file_upload",
52458
52795
  annotations: { destructiveHint: true },
@@ -52805,10 +53142,52 @@ var operationsTools = [
52805
53142
  },
52806
53143
  filters: {
52807
53144
  type: "array",
52808
- description: 'Frappe filters as array of [fieldname, operator, value] tuples. Example: [["status","=","Open"],["company","=","Acme"]]',
53145
+ description: 'Frappe filters as array of [fieldname, operator, value] tuples, or [child doctype, fieldname, operator, value] to filter on a child table. Values may be strings, numbers, booleans, null, or string/number arrays for in/not in. Example: [["status","=","Open"],["company","=","Acme"]]',
52809
53146
  items: {
52810
53147
  type: "array",
52811
- items: { type: "string" }
53148
+ anyOf: [
53149
+ {
53150
+ prefixItems: [
53151
+ { type: "string", minLength: 1 },
53152
+ { type: "string", minLength: 1 },
53153
+ {
53154
+ oneOf: [
53155
+ { type: ["string", "number", "boolean", "null"] },
53156
+ {
53157
+ type: "array",
53158
+ items: { type: ["string", "number"] }
53159
+ }
53160
+ ]
53161
+ }
53162
+ ],
53163
+ minItems: 3,
53164
+ maxItems: 3
53165
+ },
53166
+ {
53167
+ prefixItems: [
53168
+ { type: "string", minLength: 1 },
53169
+ { type: "string", minLength: 1 },
53170
+ { type: "string", minLength: 1 },
53171
+ {
53172
+ oneOf: [
53173
+ { type: ["string", "number", "boolean", "null"] },
53174
+ {
53175
+ type: "array",
53176
+ items: { type: ["string", "number"] }
53177
+ }
53178
+ ]
53179
+ }
53180
+ ],
53181
+ minItems: 4,
53182
+ maxItems: 4
53183
+ },
53184
+ {
53185
+ // 3.0.x advertised arbitrary string arrays. Keep accepting
53186
+ // that legacy surface while describing real 3/4-part Frappe
53187
+ // tuples precisely for modern clients.
53188
+ items: { type: "string" }
53189
+ }
53190
+ ]
52812
53191
  }
52813
53192
  },
52814
53193
  limit: { type: "number", description: "Max results (default 20)" },
@@ -53215,7 +53594,6 @@ var analyticsTools = [
53215
53594
  const invoices2 = await ctx.client.list("Sales Invoice", {
53216
53595
  fields: ["name", "status", "grand_total"],
53217
53596
  filters: [["docstatus", "!=", 2]],
53218
- // exclude cancelled
53219
53597
  limit: 500,
53220
53598
  order_by: "modified desc"
53221
53599
  });
@@ -53551,6 +53929,7 @@ var analyticsTools = [
53551
53929
  color: "#fbbf24",
53552
53930
  type: "line",
53553
53931
  yAxisId: "right",
53932
+ unit: "orders",
53554
53933
  showDots: true
53555
53934
  }
53556
53935
  ],
@@ -54006,7 +54385,9 @@ var analyticsTools = [
54006
54385
  category: "analytics",
54007
54386
  inputSchema: { type: "object", properties: {} },
54008
54387
  handler: async (_input, ctx) => {
54009
- const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
54388
+ const now = /* @__PURE__ */ new Date();
54389
+ const pad = (n) => String(n).padStart(2, "0");
54390
+ const today = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
54010
54391
  const invoices = await ctx.client.list("Sales Invoice", {
54011
54392
  fields: ["outstanding_amount", "due_date"],
54012
54393
  filters: [
@@ -55616,46 +55997,190 @@ var DOCTYPE_GET_TOOLS = {
55616
55997
  };
55617
55998
  var DOCTYPE_SEND_MESSAGE_HINTS = {
55618
55999
  "Customer": [
55619
- { label: "Orders", message: "Show sales orders for customer {id}" },
55620
- { label: "Invoices", message: "Show sales invoices for customer {id}" }
56000
+ {
56001
+ key: "orders",
56002
+ label: "Orders",
56003
+ message: "Show sales orders for customer {id}",
56004
+ tool: "erpnext_sales_order_list",
56005
+ args: { customer: "{id}", limit: 20 }
56006
+ },
56007
+ {
56008
+ key: "invoices",
56009
+ label: "Invoices",
56010
+ message: "Show sales invoices for customer {id}",
56011
+ tool: "erpnext_sales_invoice_list",
56012
+ args: { customer: "{id}", limit: 20 }
56013
+ }
55621
56014
  ],
55622
56015
  "Sales Order": [
55623
- { label: "Invoice", message: "Show invoices linked to sales order {id}" },
55624
- { label: "Delivery", message: "Show delivery notes for sales order {id}" }
56016
+ {
56017
+ key: "invoice",
56018
+ label: "Invoice",
56019
+ message: "Show invoices linked to sales order {id}",
56020
+ tool: "erpnext_doc_list",
56021
+ args: {
56022
+ doctype: "Sales Invoice",
56023
+ fields: ["name", "customer", "posting_date", "status", "grand_total"],
56024
+ filters: [["Sales Invoice Item", "sales_order", "=", "{id}"]],
56025
+ limit: 20
56026
+ }
56027
+ },
56028
+ {
56029
+ key: "delivery",
56030
+ label: "Delivery",
56031
+ message: "Show delivery notes for sales order {id}",
56032
+ tool: "erpnext_doc_list",
56033
+ args: {
56034
+ doctype: "Delivery Note",
56035
+ fields: ["name", "customer", "posting_date", "status"],
56036
+ filters: [["Delivery Note Item", "against_sales_order", "=", "{id}"]],
56037
+ limit: 20
56038
+ }
56039
+ }
55625
56040
  ],
55626
56041
  "Sales Invoice": [
55627
- { label: "Payments", message: "Show payment entries for invoice {id}" }
56042
+ {
56043
+ key: "payments",
56044
+ label: "Payments",
56045
+ message: "Show payment entries for invoice {id}",
56046
+ tool: "erpnext_doc_list",
56047
+ args: {
56048
+ doctype: "Payment Entry",
56049
+ fields: [
56050
+ "name",
56051
+ "posting_date",
56052
+ "paid_amount",
56053
+ "mode_of_payment",
56054
+ "docstatus"
56055
+ ],
56056
+ filters: [["Payment Entry Reference", "reference_name", "=", "{id}"]],
56057
+ limit: 20
56058
+ }
56059
+ }
55628
56060
  ],
55629
56061
  "Item": [
55630
- { label: "Stock", message: "Show stock balance for item {id}" },
55631
- { label: "Orders", message: "Show sales orders containing item {id}" }
56062
+ {
56063
+ key: "stock",
56064
+ label: "Stock",
56065
+ message: "Show stock balance for item {id}",
56066
+ tool: "erpnext_stock_balance",
56067
+ args: { item_code: "{id}" }
56068
+ },
56069
+ {
56070
+ key: "orders",
56071
+ label: "Orders",
56072
+ message: "Show sales orders containing item {id}",
56073
+ tool: "erpnext_doc_list",
56074
+ args: {
56075
+ doctype: "Sales Order",
56076
+ fields: ["name", "customer", "transaction_date", "status"],
56077
+ filters: [["Sales Order Item", "item_code", "=", "{id}"]],
56078
+ limit: 20
56079
+ }
56080
+ }
55632
56081
  ],
55633
56082
  "Supplier": [
55634
- { label: "PO", message: "Show purchase orders for supplier {id}" },
55635
- { label: "Invoices", message: "Show purchase invoices for supplier {id}" }
56083
+ {
56084
+ key: "po",
56085
+ label: "PO",
56086
+ message: "Show purchase orders for supplier {id}",
56087
+ tool: "erpnext_purchase_order_list",
56088
+ args: { supplier: "{id}", limit: 20 }
56089
+ },
56090
+ {
56091
+ key: "invoices",
56092
+ label: "Invoices",
56093
+ message: "Show purchase invoices for supplier {id}",
56094
+ tool: "erpnext_purchase_invoice_list",
56095
+ args: { supplier: "{id}", limit: 20 }
56096
+ }
55636
56097
  ],
55637
56098
  "Purchase Order": [
55638
- { label: "Receipt", message: "Show purchase receipts for order {id}" },
55639
- { label: "Invoice", message: "Show purchase invoices for order {id}" }
56099
+ {
56100
+ key: "receipt",
56101
+ label: "Receipt",
56102
+ message: "Show purchase receipts for order {id}",
56103
+ tool: "erpnext_doc_list",
56104
+ args: {
56105
+ doctype: "Purchase Receipt",
56106
+ fields: ["name", "supplier", "posting_date", "status"],
56107
+ filters: [["Purchase Receipt Item", "purchase_order", "=", "{id}"]],
56108
+ limit: 20
56109
+ }
56110
+ },
56111
+ {
56112
+ key: "invoice",
56113
+ label: "Invoice",
56114
+ message: "Show purchase invoices for order {id}",
56115
+ tool: "erpnext_doc_list",
56116
+ args: {
56117
+ doctype: "Purchase Invoice",
56118
+ fields: ["name", "supplier", "posting_date", "status", "grand_total"],
56119
+ filters: [["Purchase Invoice Item", "purchase_order", "=", "{id}"]],
56120
+ limit: 20
56121
+ }
56122
+ }
55640
56123
  ],
55641
56124
  "Employee": [
55642
- { label: "Attendance", message: "Show attendance for employee {id}" },
55643
- { label: "Leaves", message: "Show leave applications for employee {id}" }
56125
+ {
56126
+ key: "attendance",
56127
+ label: "Attendance",
56128
+ message: "Show attendance for employee {id}",
56129
+ tool: "erpnext_attendance_list",
56130
+ args: { employee: "{id}", limit: 20 }
56131
+ },
56132
+ {
56133
+ key: "leaves",
56134
+ label: "Leaves",
56135
+ message: "Show leave applications for employee {id}",
56136
+ tool: "erpnext_leave_application_list",
56137
+ args: { employee: "{id}", limit: 20 }
56138
+ }
55644
56139
  ],
55645
56140
  "Project": [
55646
- { label: "Tasks", message: "Show tasks for project {id}" },
55647
- { label: "Timesheets", message: "Show timesheets for project {id}" }
56141
+ {
56142
+ key: "tasks",
56143
+ label: "Tasks",
56144
+ message: "Show tasks for project {id}",
56145
+ tool: "erpnext_task_list",
56146
+ args: { project: "{id}", limit: 20 }
56147
+ },
56148
+ {
56149
+ key: "timesheets",
56150
+ label: "Timesheets",
56151
+ message: "Show timesheets for project {id}",
56152
+ tool: "erpnext_timesheet_list",
56153
+ args: { project: "{id}", limit: 20 }
56154
+ }
55648
56155
  ],
55649
56156
  "Task": [
55650
- { label: "Timesheets", message: "Show timesheets for task {id}" }
56157
+ {
56158
+ key: "timesheets",
56159
+ label: "Timesheets",
56160
+ message: "Show timesheets for task {id}",
56161
+ tool: "erpnext_doc_list",
56162
+ args: {
56163
+ doctype: "Timesheet",
56164
+ fields: ["name", "employee", "start_date", "total_hours", "status"],
56165
+ filters: [["Timesheet Detail", "task", "=", "{id}"]],
56166
+ limit: 20
56167
+ }
56168
+ }
55651
56169
  ],
55652
56170
  "Lead": [
55653
- { label: "Opportunities", message: "Show opportunities for lead {id}" }
56171
+ {
56172
+ key: "opportunities",
56173
+ label: "Opportunities",
56174
+ message: "Show opportunities for lead {id}",
56175
+ tool: "erpnext_opportunity_list",
56176
+ // Le handler exige opportunity_from avec party_name.
56177
+ args: { opportunity_from: "Lead", party_name: "{id}", limit: 20 }
56178
+ }
55654
56179
  ]
55655
56180
  };
55656
56181
  var KPI_DRILL_DOWN = {
55657
56182
  "erpnext_kpi_revenue": {
55658
- _drillDown: "Show all sales invoices for this month",
56183
+ _drillDown: "Show all sales orders for this month",
55659
56184
  _trendDrillDown: "Show revenue trend chart for the last 12 months"
55660
56185
  },
55661
56186
  "erpnext_kpi_outstanding": {
@@ -55667,7 +56192,7 @@ var KPI_DRILL_DOWN = {
55667
56192
  _trendDrillDown: "Show order breakdown chart for the last 6 months"
55668
56193
  },
55669
56194
  "erpnext_kpi_gross_margin": {
55670
- _drillDown: "Show gross profit breakdown by item",
56195
+ _drillDown: "Show the non-cancelled Sales Order Items and Bin valuation rates used to estimate this gross margin",
55671
56196
  _trendDrillDown: "Show profit and loss chart for the last 12 months"
55672
56197
  },
55673
56198
  "erpnext_kpi_overdue": {
@@ -55678,12 +56203,521 @@ var KPI_DRILL_DOWN = {
55678
56203
  var CHART_DRILL_DOWN = {
55679
56204
  "erpnext_sales_chart": "Show sales invoices for {label}",
55680
56205
  "erpnext_stock_chart": "Show stock balance for item {label}",
55681
- "erpnext_revenue_trend": "Show sales invoices for month {label}",
56206
+ "erpnext_revenue_trend": "Show sales orders for month {label}",
55682
56207
  "erpnext_order_breakdown": "Show sales orders for {label}",
55683
- "erpnext_ar_aging": "Show overdue sales invoices in the {label} aging bucket",
56208
+ "erpnext_ar_aging": "Show outstanding sales invoices for customer {label}",
55684
56209
  "erpnext_gross_profit": "Show gross profit details for {label}",
55685
- "erpnext_profit_loss": "Show accounting details for month {label}"
56210
+ "erpnext_profit_loss": "Show submitted sales and purchase orders for month {label}"
56211
+ };
56212
+ var INVOICE_ITEM_HINTS = [
56213
+ {
56214
+ key: "item",
56215
+ label: "Item",
56216
+ message: "Show item {item}",
56217
+ tool: "erpnext_item_get",
56218
+ args: { name: "{item}" },
56219
+ kind: "record"
56220
+ },
56221
+ {
56222
+ key: "stock",
56223
+ label: "Stock",
56224
+ message: "Show stock balance for item {item}",
56225
+ tool: "erpnext_stock_balance",
56226
+ args: { item_code: "{item}", limit: 50 },
56227
+ kind: "list"
56228
+ }
56229
+ ];
56230
+ var INVOICE_HINTS = {
56231
+ "Sales Invoice": [
56232
+ {
56233
+ key: "payments",
56234
+ label: "Payments",
56235
+ message: "Show payment entries for invoice {id}",
56236
+ tool: "erpnext_doc_list",
56237
+ args: {
56238
+ doctype: "Payment Entry",
56239
+ fields: [
56240
+ "name",
56241
+ "posting_date",
56242
+ "paid_amount",
56243
+ "mode_of_payment",
56244
+ "docstatus"
56245
+ ],
56246
+ filters: [["Payment Entry Reference", "reference_name", "=", "{id}"]],
56247
+ limit: 20
56248
+ },
56249
+ kind: "list"
56250
+ },
56251
+ {
56252
+ key: "customer",
56253
+ label: "Customer",
56254
+ message: "Show customer {party}",
56255
+ tool: "erpnext_customer_get",
56256
+ args: { name: "{party}" },
56257
+ kind: "record"
56258
+ },
56259
+ ...INVOICE_ITEM_HINTS
56260
+ ],
56261
+ "Purchase Invoice": [
56262
+ {
56263
+ key: "payments",
56264
+ label: "Payments",
56265
+ message: "Show payment entries for invoice {id}",
56266
+ tool: "erpnext_doc_list",
56267
+ args: {
56268
+ doctype: "Payment Entry",
56269
+ fields: [
56270
+ "name",
56271
+ "posting_date",
56272
+ "paid_amount",
56273
+ "mode_of_payment",
56274
+ "docstatus"
56275
+ ],
56276
+ filters: [["Payment Entry Reference", "reference_name", "=", "{id}"]],
56277
+ limit: 20
56278
+ },
56279
+ kind: "list"
56280
+ },
56281
+ {
56282
+ key: "supplier",
56283
+ label: "Supplier",
56284
+ message: "Show supplier {party}",
56285
+ tool: "erpnext_supplier_get",
56286
+ args: { name: "{party}" },
56287
+ kind: "record"
56288
+ },
56289
+ ...INVOICE_ITEM_HINTS
56290
+ ]
56291
+ };
56292
+ var STOCK_HINTS = [
56293
+ {
56294
+ key: "item",
56295
+ label: "Item",
56296
+ message: "Show item {id}",
56297
+ tool: "erpnext_item_get",
56298
+ args: { name: "{id}" },
56299
+ kind: "record"
56300
+ },
56301
+ {
56302
+ key: "movements",
56303
+ label: "Stock entries",
56304
+ message: "Show stock entries for item {id}",
56305
+ tool: "erpnext_doc_list",
56306
+ args: {
56307
+ doctype: "Stock Entry",
56308
+ fields: ["name", "posting_date", "stock_entry_type", "docstatus"],
56309
+ filters: [["Stock Entry Detail", "item_code", "=", "{id}"]],
56310
+ limit: 20
56311
+ },
56312
+ kind: "list"
56313
+ },
56314
+ {
56315
+ key: "warehouse",
56316
+ label: "Warehouse stock",
56317
+ message: "Show stock chart for warehouse {warehouse}",
56318
+ tool: "erpnext_stock_chart",
56319
+ args: { warehouse: "{warehouse}", limit: 10 },
56320
+ kind: "chart"
56321
+ }
56322
+ ];
56323
+ function monthRange(now) {
56324
+ const y = now.getFullYear();
56325
+ const m = now.getMonth();
56326
+ const pad = (n) => String(n).padStart(2, "0");
56327
+ const last = new Date(y, m + 1, 0).getDate();
56328
+ return {
56329
+ from: `${y}-${pad(m + 1)}-01`,
56330
+ to: `${y}-${pad(m + 1)}-${pad(last)}`,
56331
+ today: `${y}-${pad(m + 1)}-${pad(now.getDate())}`
56332
+ };
56333
+ }
56334
+ var INVOICE_LIST_FIELDS = [
56335
+ "name",
56336
+ "customer",
56337
+ "posting_date",
56338
+ "due_date",
56339
+ "status",
56340
+ "outstanding_amount"
56341
+ ];
56342
+ var KPI_JUMPS = {
56343
+ "erpnext_kpi_revenue": (r) => ({
56344
+ number: {
56345
+ key: "sales_orders_month",
56346
+ label: "Sales orders this month",
56347
+ tool: "erpnext_doc_list",
56348
+ args: {
56349
+ doctype: "Sales Order",
56350
+ fields: [
56351
+ "name",
56352
+ "customer",
56353
+ "transaction_date",
56354
+ "status",
56355
+ "grand_total"
56356
+ ],
56357
+ filters: [
56358
+ ["transaction_date", ">=", r.from],
56359
+ ["transaction_date", "<=", r.to],
56360
+ // comme le KPI : les commandes annulées ne comptent pas
56361
+ ["docstatus", "<", 2]
56362
+ ],
56363
+ limit: 20
56364
+ },
56365
+ kind: "list"
56366
+ },
56367
+ trend: {
56368
+ key: "revenue_trend",
56369
+ label: "Revenue trend",
56370
+ tool: "erpnext_revenue_trend",
56371
+ args: { months: 12 },
56372
+ kind: "chart"
56373
+ }
56374
+ }),
56375
+ "erpnext_kpi_outstanding": () => ({
56376
+ number: {
56377
+ key: "unpaid_invoices",
56378
+ label: "Unpaid invoices",
56379
+ tool: "erpnext_doc_list",
56380
+ args: {
56381
+ doctype: "Sales Invoice",
56382
+ fields: INVOICE_LIST_FIELDS,
56383
+ filters: [["outstanding_amount", ">", 0], ["docstatus", "=", 1]],
56384
+ limit: 20
56385
+ },
56386
+ kind: "list"
56387
+ },
56388
+ trend: {
56389
+ key: "receivables_aging",
56390
+ label: "Receivables aging",
56391
+ tool: "erpnext_ar_aging",
56392
+ args: {},
56393
+ kind: "chart"
56394
+ }
56395
+ }),
56396
+ "erpnext_kpi_orders": (r) => ({
56397
+ number: {
56398
+ key: "sales_orders_month",
56399
+ label: "Sales orders this month",
56400
+ tool: "erpnext_doc_list",
56401
+ args: {
56402
+ doctype: "Sales Order",
56403
+ fields: [
56404
+ "name",
56405
+ "customer",
56406
+ "transaction_date",
56407
+ "status",
56408
+ "grand_total"
56409
+ ],
56410
+ filters: [
56411
+ ["transaction_date", ">=", r.from],
56412
+ ["transaction_date", "<=", r.to],
56413
+ // comme le KPI : les commandes annulées ne comptent pas
56414
+ ["docstatus", "<", 2]
56415
+ ],
56416
+ limit: 20
56417
+ },
56418
+ kind: "list"
56419
+ },
56420
+ trend: {
56421
+ key: "order_breakdown",
56422
+ label: "Order breakdown",
56423
+ tool: "erpnext_order_breakdown",
56424
+ args: {},
56425
+ kind: "chart"
56426
+ }
56427
+ }),
56428
+ "erpnext_kpi_gross_margin": () => ({
56429
+ trend: {
56430
+ key: "profit_loss",
56431
+ label: "Profit and loss",
56432
+ tool: "erpnext_profit_loss",
56433
+ args: { months: 12 },
56434
+ kind: "chart"
56435
+ }
56436
+ }),
56437
+ "erpnext_kpi_overdue": (r) => ({
56438
+ number: {
56439
+ key: "overdue_invoices",
56440
+ label: "Overdue invoices",
56441
+ tool: "erpnext_doc_list",
56442
+ args: {
56443
+ doctype: "Sales Invoice",
56444
+ fields: INVOICE_LIST_FIELDS,
56445
+ filters: [
56446
+ ["due_date", "<", r.today],
56447
+ ["outstanding_amount", ">", 0],
56448
+ ["docstatus", "=", 1]
56449
+ ],
56450
+ limit: 20
56451
+ },
56452
+ kind: "list"
56453
+ },
56454
+ trend: {
56455
+ key: "receivables_aging",
56456
+ label: "Receivables aging",
56457
+ tool: "erpnext_ar_aging",
56458
+ args: {},
56459
+ kind: "chart"
56460
+ }
56461
+ })
56462
+ };
56463
+ var FUNNEL_LIST_FIELDS = {
56464
+ "Leads": [
56465
+ "name",
56466
+ "lead_name",
56467
+ "company_name",
56468
+ "status",
56469
+ "lead_owner",
56470
+ "creation"
56471
+ ],
56472
+ "Opportunities": [
56473
+ "name",
56474
+ "opportunity_from",
56475
+ "party_name",
56476
+ "status",
56477
+ "opportunity_amount",
56478
+ "currency",
56479
+ "probability",
56480
+ "opportunity_owner",
56481
+ "transaction_date"
56482
+ ],
56483
+ "Quotations": [
56484
+ "name",
56485
+ "party_name",
56486
+ "transaction_date",
56487
+ "status",
56488
+ "grand_total"
56489
+ ],
56490
+ "Orders": [
56491
+ "name",
56492
+ "customer",
56493
+ "transaction_date",
56494
+ "status",
56495
+ "grand_total"
56496
+ ]
56497
+ };
56498
+ var FUNNEL_STAGE_JUMPS = {
56499
+ "Leads": {
56500
+ key: "leads",
56501
+ label: "Leads",
56502
+ tool: "erpnext_lead_list",
56503
+ args: { limit: 20 },
56504
+ kind: "list"
56505
+ },
56506
+ "Opportunities": {
56507
+ key: "opportunities",
56508
+ label: "Opportunities",
56509
+ tool: "erpnext_opportunity_list",
56510
+ args: { limit: 20 },
56511
+ kind: "list"
56512
+ },
56513
+ "Quotations": {
56514
+ key: "quotations",
56515
+ label: "Quotations",
56516
+ tool: "erpnext_doc_list",
56517
+ args: {
56518
+ doctype: "Quotation",
56519
+ fields: FUNNEL_LIST_FIELDS.Quotations,
56520
+ filters: [["docstatus", "!=", 2]],
56521
+ limit: 20
56522
+ },
56523
+ kind: "list"
56524
+ },
56525
+ "Orders": {
56526
+ key: "sales_orders",
56527
+ label: "Sales orders",
56528
+ tool: "erpnext_doc_list",
56529
+ args: {
56530
+ doctype: "Sales Order",
56531
+ fields: FUNNEL_LIST_FIELDS.Orders,
56532
+ filters: [["docstatus", "!=", 2]],
56533
+ limit: 20
56534
+ },
56535
+ kind: "list"
56536
+ }
55686
56537
  };
56538
+ function funnelPeriodStart(period, now) {
56539
+ const year = now.getFullYear();
56540
+ const pad = (value) => String(value).padStart(2, "0");
56541
+ if (period === "this_month") {
56542
+ return `${year}-${pad(now.getMonth() + 1)}-01`;
56543
+ }
56544
+ if (period === "this_quarter") {
56545
+ const firstMonth = Math.floor(now.getMonth() / 3) * 3 + 1;
56546
+ return `${year}-${pad(firstMonth)}-01`;
56547
+ }
56548
+ if (period === "this_year") return `${year}-01-01`;
56549
+ return void 0;
56550
+ }
56551
+ function funnelStageJumps(args, now) {
56552
+ const since = funnelPeriodStart(args.period, now);
56553
+ if (!since) return FUNNEL_STAGE_JUMPS;
56554
+ const scopedJump = (stage, doctype, dateField) => {
56555
+ const base = FUNNEL_STAGE_JUMPS[stage];
56556
+ const baseFilters = Array.isArray(base.args.filters) ? base.args.filters : [];
56557
+ return {
56558
+ ...base,
56559
+ tool: "erpnext_doc_list",
56560
+ args: {
56561
+ doctype,
56562
+ fields: FUNNEL_LIST_FIELDS[stage],
56563
+ filters: [[dateField, ">=", since], ...baseFilters],
56564
+ limit: 20
56565
+ }
56566
+ };
56567
+ };
56568
+ return {
56569
+ "Leads": scopedJump("Leads", "Lead", "creation"),
56570
+ "Opportunities": scopedJump(
56571
+ "Opportunities",
56572
+ "Opportunity",
56573
+ "transaction_date"
56574
+ ),
56575
+ "Quotations": scopedJump(
56576
+ "Quotations",
56577
+ "Quotation",
56578
+ "transaction_date"
56579
+ ),
56580
+ "Orders": scopedJump("Orders", "Sales Order", "transaction_date")
56581
+ };
56582
+ }
56583
+ var SALES_ORDER_LIST_FIELDS = [
56584
+ "name",
56585
+ "customer",
56586
+ "transaction_date",
56587
+ "status",
56588
+ "grand_total"
56589
+ ];
56590
+ var PURCHASE_ORDER_LIST_FIELDS = [
56591
+ "name",
56592
+ "supplier",
56593
+ "transaction_date",
56594
+ "status",
56595
+ "grand_total"
56596
+ ];
56597
+ function monthLabel(d) {
56598
+ return `${d.toLocaleString("en", { month: "short" })} ${d.getFullYear().toString().slice(2)}`;
56599
+ }
56600
+ function monthBuckets(monthsBack, now) {
56601
+ const buckets = [];
56602
+ for (let m = 0; m < monthsBack; m++) {
56603
+ const d = new Date(
56604
+ now.getFullYear(),
56605
+ now.getMonth() - monthsBack + 1 + m,
56606
+ 1
56607
+ );
56608
+ buckets.push({ label: monthLabel(d), range: monthRange(d) });
56609
+ }
56610
+ return buckets;
56611
+ }
56612
+ var docList = (label, doctype, fields, filters) => ({
56613
+ label,
56614
+ tool: "erpnext_doc_list",
56615
+ args: { doctype, fields, filters, limit: 20 },
56616
+ kind: "list"
56617
+ });
56618
+ function chartPointJumps(toolName, args, labels, now) {
56619
+ const jumps = {};
56620
+ const byLabel = (make) => {
56621
+ for (const label of labels) {
56622
+ if (label === "Unknown") continue;
56623
+ jumps[label] = make(label);
56624
+ }
56625
+ };
56626
+ switch (toolName) {
56627
+ case "erpnext_revenue_trend": {
56628
+ const months = Number(args.months ?? 6);
56629
+ for (const { label, range } of monthBuckets(months, now)) {
56630
+ if (!labels.includes(label)) continue;
56631
+ jumps[label] = docList(label, "Sales Order", SALES_ORDER_LIST_FIELDS, [
56632
+ ["transaction_date", ">=", range.from],
56633
+ ["transaction_date", "<=", range.to],
56634
+ ["docstatus", "<", 2]
56635
+ ]);
56636
+ }
56637
+ break;
56638
+ }
56639
+ case "erpnext_sales_chart": {
56640
+ const groupBy = String(args.group_by ?? "customer");
56641
+ byLabel((label) => {
56642
+ const filters = [
56643
+ groupBy === "item" ? ["Sales Invoice Item", "item_name", "=", label] : groupBy === "status" ? ["status", "=", label] : ["customer_name", "=", label]
56644
+ ];
56645
+ if (groupBy === "status") {
56646
+ filters.push(["docstatus", "!=", 2]);
56647
+ } else if (groupBy === "item" || args.include_drafts !== true) {
56648
+ filters.push(["docstatus", "=", 1]);
56649
+ }
56650
+ return docList(label, "Sales Invoice", INVOICE_LIST_FIELDS, filters);
56651
+ });
56652
+ break;
56653
+ }
56654
+ case "erpnext_order_breakdown":
56655
+ case "erpnext_revenue_vs_orders":
56656
+ byLabel(
56657
+ (label) => docList(label, "Sales Order", SALES_ORDER_LIST_FIELDS, [
56658
+ ["customer_name", "=", label],
56659
+ ["docstatus", "<", 2]
56660
+ ])
56661
+ );
56662
+ break;
56663
+ case "erpnext_ar_aging":
56664
+ case "erpnext_profit_loss":
56665
+ return void 0;
56666
+ case "erpnext_gross_profit": {
56667
+ const groupBy = String(args.group_by ?? "item");
56668
+ byLabel(
56669
+ (label) => docList(label, "Sales Invoice", INVOICE_LIST_FIELDS, [
56670
+ groupBy === "customer" ? ["customer_name", "=", label] : ["Sales Invoice Item", "item_name", "=", label],
56671
+ ["docstatus", "=", 1]
56672
+ ])
56673
+ );
56674
+ break;
56675
+ }
56676
+ case "erpnext_stock_chart":
56677
+ byLabel((label) => ({
56678
+ label,
56679
+ tool: "erpnext_stock_balance",
56680
+ args: {
56681
+ item_code: label,
56682
+ ...typeof args.warehouse === "string" ? { warehouse: args.warehouse } : {},
56683
+ limit: 50
56684
+ },
56685
+ kind: "list"
56686
+ }));
56687
+ break;
56688
+ default:
56689
+ return void 0;
56690
+ }
56691
+ return Object.keys(jumps).length > 0 ? jumps : void 0;
56692
+ }
56693
+ function chartSeriesPointJumps(toolName, args, labels, now) {
56694
+ if (toolName !== "erpnext_profit_loss") return void 0;
56695
+ const jumps = {};
56696
+ const months = Number(args.months ?? 6);
56697
+ for (const { label, range } of monthBuckets(months, now)) {
56698
+ if (!labels.includes(label)) continue;
56699
+ const filters = [
56700
+ ["transaction_date", ">=", range.from],
56701
+ ["transaction_date", "<=", range.to],
56702
+ ["docstatus", "=", 1]
56703
+ ];
56704
+ jumps[label] = {
56705
+ "Income": docList(
56706
+ `${label} \xB7 Income`,
56707
+ "Sales Order",
56708
+ SALES_ORDER_LIST_FIELDS,
56709
+ filters
56710
+ ),
56711
+ "Expenses": docList(
56712
+ `${label} \xB7 Expenses`,
56713
+ "Purchase Order",
56714
+ PURCHASE_ORDER_LIST_FIELDS,
56715
+ filters
56716
+ )
56717
+ };
56718
+ }
56719
+ return Object.keys(jumps).length > 0 ? jumps : void 0;
56720
+ }
55687
56721
  function isChartViewer(result) {
55688
56722
  const uri = result._meta?.ui?.resourceUri;
55689
56723
  return uri === "ui://mcp-erpnext/chart-viewer";
@@ -55692,6 +56726,28 @@ function isKpiViewer(result) {
55692
56726
  const uri = result._meta?.ui?.resourceUri;
55693
56727
  return uri === "ui://mcp-erpnext/kpi-viewer";
55694
56728
  }
56729
+ function isFunnelViewer(result) {
56730
+ const uri = result._meta?.ui?.resourceUri;
56731
+ return uri === "ui://mcp-erpnext/funnel-viewer";
56732
+ }
56733
+ function resultDoctype(result) {
56734
+ if (typeof result.doctype === "string") return result.doctype;
56735
+ const data = result.data;
56736
+ if (isRecord7(data) && typeof data.doctype === "string") return data.doctype;
56737
+ return void 0;
56738
+ }
56739
+ function isInvoiceViewer(result) {
56740
+ const uri = result._meta?.ui?.resourceUri;
56741
+ return uri === "ui://mcp-erpnext/invoice-viewer";
56742
+ }
56743
+ function isStockViewer(result) {
56744
+ const uri = result._meta?.ui?.resourceUri;
56745
+ return uri === "ui://mcp-erpnext/stock-viewer";
56746
+ }
56747
+ function isKanbanViewer(result) {
56748
+ const uri = result._meta?.ui?.resourceUri;
56749
+ return uri === "ui://mcp-erpnext/kanban-viewer";
56750
+ }
55695
56751
  function isDoclistResult(result) {
55696
56752
  return typeof result.doctype === "string" && Array.isArray(result.data);
55697
56753
  }
@@ -55699,7 +56755,181 @@ function isDoclistViewer(result) {
55699
56755
  const uri = result._meta?.ui?.resourceUri;
55700
56756
  return uri === "ui://mcp-erpnext/doclist-viewer";
55701
56757
  }
55702
- function withUiRefreshRequest(result, toolName, args) {
56758
+ var VIEWER_TOOL_CANDIDATES = {
56759
+ "ui://mcp-erpnext/invoice-viewer": [
56760
+ "erpnext_item_get",
56761
+ "erpnext_stock_balance"
56762
+ ],
56763
+ "ui://mcp-erpnext/doclist-viewer": [],
56764
+ "ui://mcp-erpnext/kanban-viewer": [
56765
+ "erpnext_doc_get",
56766
+ "erpnext_doc_update",
56767
+ "erpnext_user_list",
56768
+ "erpnext_doc_assign",
56769
+ "erpnext_doc_unassign"
56770
+ ],
56771
+ "ui://mcp-erpnext/stock-viewer": [
56772
+ "erpnext_item_get",
56773
+ "erpnext_stock_entry_list"
56774
+ ]
56775
+ };
56776
+ var SUBMITTABLE_VIEWER_DOCTYPES = /* @__PURE__ */ new Set([
56777
+ "Quotation",
56778
+ "Sales Order",
56779
+ "Delivery Note",
56780
+ "Sales Invoice",
56781
+ "Purchase Order",
56782
+ "Purchase Receipt",
56783
+ "Purchase Invoice",
56784
+ "Stock Entry",
56785
+ "Journal Entry",
56786
+ "Payment Entry",
56787
+ "Timesheet",
56788
+ "Leave Application",
56789
+ "Salary Slip",
56790
+ "BOM",
56791
+ "Work Order",
56792
+ "Job Card",
56793
+ "Asset",
56794
+ "Asset Movement",
56795
+ "Shipment"
56796
+ ]);
56797
+ var INVOICE_DEDICATED_MUTATION_TOOLS = {
56798
+ "Sales Order": [
56799
+ "erpnext_sales_order_submit",
56800
+ "erpnext_sales_order_cancel"
56801
+ ],
56802
+ "Sales Invoice": ["erpnext_sales_invoice_submit"]
56803
+ };
56804
+ function addDoctypeMutationCandidates(target, uri, doctype) {
56805
+ if (!doctype || !SUBMITTABLE_VIEWER_DOCTYPES.has(doctype)) return;
56806
+ if (uri === "ui://mcp-erpnext/invoice-viewer" || uri === "ui://mcp-erpnext/doclist-viewer") {
56807
+ target.add("erpnext_doc_submit");
56808
+ target.add("erpnext_doc_cancel");
56809
+ }
56810
+ if (uri === "ui://mcp-erpnext/invoice-viewer") {
56811
+ for (const tool of INVOICE_DEDICATED_MUTATION_TOOLS[doctype] ?? []) {
56812
+ target.add(tool);
56813
+ }
56814
+ }
56815
+ }
56816
+ function addJumpTools(target, jumps) {
56817
+ if (!jumps) return;
56818
+ for (const jump of Object.values(jumps)) target.add(jump.tool);
56819
+ }
56820
+ function addSeriesJumpTools(target, jumps) {
56821
+ if (!jumps) return;
56822
+ for (const seriesJumps of Object.values(jumps)) {
56823
+ addJumpTools(target, seriesJumps);
56824
+ }
56825
+ }
56826
+ function availableViewerToolNames(result, availableToolNames) {
56827
+ const candidates = /* @__PURE__ */ new Set();
56828
+ const uri = result._meta?.ui?.resourceUri;
56829
+ for (const name of uri ? VIEWER_TOOL_CANDIDATES[uri] ?? [] : []) {
56830
+ candidates.add(name);
56831
+ }
56832
+ addDoctypeMutationCandidates(candidates, uri, resultDoctype(result));
56833
+ if (result.refreshRequest) candidates.add(result.refreshRequest.toolName);
56834
+ if (result._rowAction) candidates.add(result._rowAction.toolName);
56835
+ for (const hint of result._sendMessageHints ?? []) {
56836
+ if (hint.tool) candidates.add(hint.tool);
56837
+ }
56838
+ addJumpTools(
56839
+ candidates,
56840
+ result._jumps ? Object.fromEntries(
56841
+ Object.entries(result._jumps).filter(
56842
+ (entry) => entry[1] !== void 0
56843
+ )
56844
+ ) : void 0
56845
+ );
56846
+ addJumpTools(candidates, result._stageJumps);
56847
+ addJumpTools(candidates, result._pointJumps);
56848
+ addSeriesJumpTools(candidates, result._seriesPointJumps);
56849
+ if (typeof result.moveToolName === "string") {
56850
+ candidates.add(result.moveToolName);
56851
+ }
56852
+ return [...candidates].filter((name) => availableToolNames.has(name)).sort();
56853
+ }
56854
+ function filterJumpMap(jumps, availableToolNames) {
56855
+ const available = Object.fromEntries(
56856
+ Object.entries(jumps).filter(
56857
+ ([, jump]) => availableToolNames.has(jump.tool)
56858
+ )
56859
+ );
56860
+ return Object.keys(available).length > 0 ? available : void 0;
56861
+ }
56862
+ function filterSeriesJumpMap(jumps, availableToolNames) {
56863
+ const available = {};
56864
+ for (const [label, seriesJumps] of Object.entries(jumps)) {
56865
+ const filtered = filterJumpMap(seriesJumps, availableToolNames);
56866
+ if (filtered) available[label] = filtered;
56867
+ }
56868
+ return Object.keys(available).length > 0 ? available : void 0;
56869
+ }
56870
+ function filterNavJumpsByAvailableTools(result, availableToolNames) {
56871
+ if (!availableToolNames) return result;
56872
+ const filtered = { ...result };
56873
+ if (result._jumps) {
56874
+ const jumps = filterJumpMap(
56875
+ Object.fromEntries(
56876
+ Object.entries(result._jumps).filter(
56877
+ (entry) => entry[1] !== void 0
56878
+ )
56879
+ ),
56880
+ availableToolNames
56881
+ );
56882
+ if (jumps) filtered._jumps = jumps;
56883
+ else delete filtered._jumps;
56884
+ }
56885
+ if (result._stageJumps) {
56886
+ const jumps = filterJumpMap(result._stageJumps, availableToolNames);
56887
+ if (jumps) filtered._stageJumps = jumps;
56888
+ else delete filtered._stageJumps;
56889
+ }
56890
+ if (result._pointJumps) {
56891
+ const jumps = filterJumpMap(result._pointJumps, availableToolNames);
56892
+ if (jumps) filtered._pointJumps = jumps;
56893
+ else delete filtered._pointJumps;
56894
+ }
56895
+ if (result._seriesPointJumps) {
56896
+ const jumps = filterSeriesJumpMap(
56897
+ result._seriesPointJumps,
56898
+ availableToolNames
56899
+ );
56900
+ if (jumps) filtered._seriesPointJumps = jumps;
56901
+ else delete filtered._seriesPointJumps;
56902
+ }
56903
+ if (result._rowAction && !availableToolNames.has(result._rowAction.toolName)) {
56904
+ const doctype = resultDoctype(result);
56905
+ if (doctype && availableToolNames.has("erpnext_doc_get")) {
56906
+ filtered._rowAction = {
56907
+ toolName: "erpnext_doc_get",
56908
+ idField: "name",
56909
+ argName: "name",
56910
+ extraArgs: { doctype }
56911
+ };
56912
+ } else {
56913
+ delete filtered._rowAction;
56914
+ }
56915
+ }
56916
+ if (result._sendMessageHints) {
56917
+ filtered._sendMessageHints = result._sendMessageHints.map((hint) => {
56918
+ if (!hint.tool || availableToolNames.has(hint.tool)) return hint;
56919
+ return { key: hint.key, label: hint.label, message: hint.message };
56920
+ });
56921
+ }
56922
+ filtered._availableTools = availableViewerToolNames(
56923
+ filtered,
56924
+ availableToolNames
56925
+ );
56926
+ return filtered;
56927
+ }
56928
+ function withViewerToolCapabilities(result, availableToolNames) {
56929
+ if (!isRecord7(result) || !hasUiResource(result)) return result;
56930
+ return filterNavJumpsByAvailableTools(result, availableToolNames);
56931
+ }
56932
+ function withUiRefreshRequest(result, toolName, args, now = /* @__PURE__ */ new Date(), availableToolNames) {
55703
56933
  if (!isRecord7(result) || !hasUiResource(result)) {
55704
56934
  return result;
55705
56935
  }
@@ -55749,10 +56979,79 @@ function withUiRefreshRequest(result, toolName, args) {
55749
56979
  }
55750
56980
  }
55751
56981
  }
55752
- return enriched;
56982
+ if (isKpiViewer(enriched) && !enriched._jumps) {
56983
+ const jumps = KPI_JUMPS[toolName];
56984
+ if (jumps) enriched._jumps = jumps(monthRange(now));
56985
+ }
56986
+ if (isFunnelViewer(enriched) && !enriched._stageJumps) {
56987
+ enriched._stageJumps = funnelStageJumps(args, now);
56988
+ }
56989
+ if (isChartViewer(enriched) && Array.isArray(enriched.labels)) {
56990
+ const labels = enriched.labels.map(String);
56991
+ if (!enriched._pointJumps) {
56992
+ const jumps = chartPointJumps(toolName, args, labels, now);
56993
+ if (jumps) enriched._pointJumps = jumps;
56994
+ }
56995
+ if (!enriched._seriesPointJumps) {
56996
+ const jumps = chartSeriesPointJumps(toolName, args, labels, now);
56997
+ if (jumps) enriched._seriesPointJumps = jumps;
56998
+ }
56999
+ }
57000
+ if (!enriched._sendMessageHints) {
57001
+ const doctype = resultDoctype(enriched);
57002
+ if (isInvoiceViewer(enriched) && doctype) {
57003
+ const hints = INVOICE_HINTS[doctype];
57004
+ if (hints) enriched._sendMessageHints = hints;
57005
+ } else if (isStockViewer(enriched)) {
57006
+ enriched._sendMessageHints = STOCK_HINTS;
57007
+ } else if (isKanbanViewer(enriched) && doctype) {
57008
+ const hints = DOCTYPE_SEND_MESSAGE_HINTS[doctype];
57009
+ if (hints) enriched._sendMessageHints = hints;
57010
+ }
57011
+ }
57012
+ return filterNavJumpsByAvailableTools(enriched, availableToolNames);
55753
57013
  }
55754
57014
 
55755
57015
  // src/client.ts
57016
+ function isRecord8(value) {
57017
+ return typeof value === "object" && value !== null && !Array.isArray(value);
57018
+ }
57019
+ function withSafeUiRefresh(result, tool, args, availableToolNames) {
57020
+ const readOnly = tool.annotations?.readOnlyHint === true;
57021
+ if (!isRecord8(result)) {
57022
+ return result;
57023
+ }
57024
+ const resultMeta = isRecord8(result._meta) ? result._meta : {};
57025
+ const declaredUi = tool._meta?.ui;
57026
+ const viewerResult = declaredUi && !isRecord8(resultMeta.ui) ? {
57027
+ ...result,
57028
+ _meta: { ...resultMeta, ...tool._meta, ui: declaredUi }
57029
+ } : result;
57030
+ const request = isRecord8(viewerResult.refreshRequest) ? viewerResult.refreshRequest : null;
57031
+ const target = request && typeof request.toolName === "string" ? getToolByName(request.toolName) : void 0;
57032
+ const hasSafeExplicitRefresh = request !== null && typeof request.toolName === "string" && availableToolNames.has(request.toolName) && isRecord8(request.arguments) && (request.toolName === tool.name ? readOnly : target?.annotations?.readOnlyHint === true);
57033
+ if (hasSafeExplicitRefresh) {
57034
+ return withUiRefreshRequest(
57035
+ viewerResult,
57036
+ tool.name,
57037
+ args,
57038
+ /* @__PURE__ */ new Date(),
57039
+ availableToolNames
57040
+ );
57041
+ }
57042
+ let sanitized = viewerResult;
57043
+ if ("refreshRequest" in viewerResult) {
57044
+ sanitized = { ...viewerResult };
57045
+ delete sanitized.refreshRequest;
57046
+ }
57047
+ return readOnly ? withUiRefreshRequest(
57048
+ sanitized,
57049
+ tool.name,
57050
+ args,
57051
+ /* @__PURE__ */ new Date(),
57052
+ availableToolNames
57053
+ ) : withViewerToolCapabilities(sanitized, availableToolNames);
57054
+ }
55756
57055
  var ErpNextToolsClient = class {
55757
57056
  tools;
55758
57057
  enableLinkDisambiguation;
@@ -55793,6 +57092,7 @@ var ErpNextToolsClient = class {
55793
57092
  */
55794
57093
  buildHandlersMap() {
55795
57094
  const handlers = /* @__PURE__ */ new Map();
57095
+ const availableToolNames = new Set(this.tools.map((tool) => tool.name));
55796
57096
  for (const tool of this.tools) {
55797
57097
  const toolMeta = tool._meta;
55798
57098
  handlers.set(tool.name, async (args, mcpContext) => {
@@ -55815,10 +57115,11 @@ var ErpNextToolsClient = class {
55815
57115
  if (execution.result !== null && typeof execution.result === "object" && !Array.isArray(execution.result) && execution.result.resultType === "input_required") {
55816
57116
  return execution.result;
55817
57117
  }
55818
- const result = withUiRefreshRequest(
57118
+ const result = withSafeUiRefresh(
55819
57119
  execution.result,
55820
- tool.name,
55821
- execution.args
57120
+ tool,
57121
+ execution.args,
57122
+ availableToolNames
55822
57123
  );
55823
57124
  const r = result !== null && typeof result === "object" && !Array.isArray(result) ? result : null;
55824
57125
  const resultUi = r?._meta && typeof r._meta === "object" && r._meta.ui;
@@ -55845,7 +57146,12 @@ var ErpNextToolsClient = class {
55845
57146
  }
55846
57147
  const client = getFrappeClient();
55847
57148
  const result = await tool.handler(args, { client });
55848
- return withUiRefreshRequest(result, tool.name, args);
57149
+ return withSafeUiRefresh(
57150
+ result,
57151
+ tool,
57152
+ args,
57153
+ new Set(this.tools.map((candidate) => candidate.name))
57154
+ );
55849
57155
  }
55850
57156
  /** Get tool count */
55851
57157
  get count() {
@@ -56102,7 +57408,7 @@ async function main() {
56102
57408
  );
56103
57409
  const server = new McpApp({
56104
57410
  name: "mcp-erpnext",
56105
- version: "3.0.2",
57411
+ version: "3.1.0-beta.1",
56106
57412
  transport: "stateless",
56107
57413
  cache: {
56108
57414
  ttlMs: 36e5,