infinitecampus-mcp 2.6.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +1 -1
- package/dist/bundle.js +743 -176
- package/dist/index.js +16 -2
- package/dist/tools/_shared.js +3 -3
- package/dist/tools/assessments.js +3 -3
- package/dist/tools/assignments.js +3 -3
- package/dist/tools/attendance.js +3 -3
- package/dist/tools/attendance_events.js +3 -3
- package/dist/tools/behavior.js +3 -3
- package/dist/tools/calendar.js +3 -3
- package/dist/tools/districts.js +6 -3
- package/dist/tools/documents.js +6 -5
- package/dist/tools/features.js +3 -3
- package/dist/tools/fees.js +3 -3
- package/dist/tools/foodservice.js +3 -3
- package/dist/tools/grades.js +3 -3
- package/dist/tools/healthcheck.js +62 -0
- package/dist/tools/messages.js +5 -5
- package/dist/tools/recent_grades.js +3 -3
- package/dist/tools/schedule.js +3 -3
- package/dist/tools/students.js +3 -3
- package/dist/tools/teachers.js +3 -3
- package/dist/view.js +37 -0
- package/package.json +2 -2
- package/server.json +2 -2
- package/skills/ic/SKILL.md +9 -2
package/dist/bundle.js
CHANGED
|
@@ -3116,9 +3116,28 @@ var require_utils = __commonJS({
|
|
|
3116
3116
|
"use strict";
|
|
3117
3117
|
var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
|
|
3118
3118
|
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);
|
|
3119
|
+
var isPort = RegExp.prototype.test.bind(/^\d*$/u);
|
|
3119
3120
|
var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
|
|
3120
3121
|
var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
|
|
3121
|
-
var isPathCharacter = RegExp.prototype.test.bind(/^[
|
|
3122
|
+
var isPathCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/]$/u);
|
|
3123
|
+
var isQueryFragmentCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/?]$/u);
|
|
3124
|
+
var isUserinfoCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:]$/u);
|
|
3125
|
+
var BYTE_HEX = new Array(256);
|
|
3126
|
+
{
|
|
3127
|
+
const HEX_DIGITS = "0123456789ABCDEF";
|
|
3128
|
+
for (let i = 0; i < 256; i++) {
|
|
3129
|
+
BYTE_HEX[i] = "%" + HEX_DIGITS[i >> 4] + HEX_DIGITS[i & 15];
|
|
3130
|
+
}
|
|
3131
|
+
}
|
|
3132
|
+
function percentEncodeNonAscii(cp) {
|
|
3133
|
+
if (cp < 2048) {
|
|
3134
|
+
return BYTE_HEX[192 | cp >> 6] + BYTE_HEX[128 | cp & 63];
|
|
3135
|
+
}
|
|
3136
|
+
if (cp < 65536) {
|
|
3137
|
+
return BYTE_HEX[224 | cp >> 12] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
|
|
3138
|
+
}
|
|
3139
|
+
return BYTE_HEX[240 | cp >> 18] + BYTE_HEX[128 | cp >> 12 & 63] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
|
|
3140
|
+
}
|
|
3122
3141
|
function stringArrayToHexStripped(input) {
|
|
3123
3142
|
let acc = "";
|
|
3124
3143
|
let code = 0;
|
|
@@ -3143,91 +3162,105 @@ var require_utils = __commonJS({
|
|
|
3143
3162
|
}
|
|
3144
3163
|
return acc;
|
|
3145
3164
|
}
|
|
3165
|
+
var isHextet = RegExp.prototype.test.bind(/^[\dA-Fa-f]{1,4}$/);
|
|
3166
|
+
var isIPvFuture = RegExp.prototype.test.bind(/^[vV][\dA-Fa-f]+\.[A-Za-z\d\-._~!$&'()*+,;=:]+$/);
|
|
3167
|
+
var isZoneCharacter = RegExp.prototype.test.bind(/^[A-Za-z\d\-._~]$/);
|
|
3146
3168
|
var nonSimpleDomain = RegExp.prototype.test.bind(/[^!"$&'()*+,\-.;=_`a-z{}~]/u);
|
|
3147
|
-
function
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
if (hex3 !== "") {
|
|
3155
|
-
address.push(hex3);
|
|
3156
|
-
} else {
|
|
3157
|
-
output.error = true;
|
|
3158
|
-
return false;
|
|
3169
|
+
function isZoneIdentifier(zone) {
|
|
3170
|
+
if (zone.length === 0) return false;
|
|
3171
|
+
for (let i = 0; i < zone.length; i++) {
|
|
3172
|
+
if (isZoneCharacter(zone[i])) continue;
|
|
3173
|
+
if (zone[i] === "%" && i + 2 < zone.length && isHexPair(zone.slice(i + 1, i + 3))) {
|
|
3174
|
+
i += 2;
|
|
3175
|
+
continue;
|
|
3159
3176
|
}
|
|
3160
|
-
|
|
3177
|
+
return false;
|
|
3161
3178
|
}
|
|
3162
3179
|
return true;
|
|
3163
3180
|
}
|
|
3164
|
-
function
|
|
3165
|
-
let
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
let
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
}
|
|
3177
|
-
if (cursor === ":") {
|
|
3178
|
-
if (endipv6Encountered === true) {
|
|
3179
|
-
endIpv6 = true;
|
|
3180
|
-
}
|
|
3181
|
-
if (!consume(buffer, address, output)) {
|
|
3182
|
-
break;
|
|
3181
|
+
function compressIPv6ZeroRun(hextets) {
|
|
3182
|
+
let bestStart = -1;
|
|
3183
|
+
let bestLength = 0;
|
|
3184
|
+
let runStart = -1;
|
|
3185
|
+
let runLength = 0;
|
|
3186
|
+
for (let i = 0; i < hextets.length; i++) {
|
|
3187
|
+
if (hextets[i] === "0") {
|
|
3188
|
+
if (runStart === -1) runStart = i;
|
|
3189
|
+
runLength++;
|
|
3190
|
+
if (runLength > bestLength) {
|
|
3191
|
+
bestLength = runLength;
|
|
3192
|
+
bestStart = runStart;
|
|
3183
3193
|
}
|
|
3184
|
-
if (++tokenCount > 7) {
|
|
3185
|
-
output.error = true;
|
|
3186
|
-
break;
|
|
3187
|
-
}
|
|
3188
|
-
if (i > 0 && input[i - 1] === ":") {
|
|
3189
|
-
endipv6Encountered = true;
|
|
3190
|
-
}
|
|
3191
|
-
address.push(":");
|
|
3192
|
-
continue;
|
|
3193
|
-
} else if (cursor === "%") {
|
|
3194
|
-
if (!consume(buffer, address, output)) {
|
|
3195
|
-
break;
|
|
3196
|
-
}
|
|
3197
|
-
consume = consumeIsZone;
|
|
3198
3194
|
} else {
|
|
3199
|
-
|
|
3195
|
+
runStart = -1;
|
|
3196
|
+
runLength = 0;
|
|
3197
|
+
}
|
|
3198
|
+
}
|
|
3199
|
+
if (bestLength < 2) return hextets.join(":");
|
|
3200
|
+
const head = hextets.slice(0, bestStart).join(":");
|
|
3201
|
+
const tail = hextets.slice(bestStart + bestLength).join(":");
|
|
3202
|
+
return head + "::" + tail;
|
|
3203
|
+
}
|
|
3204
|
+
function normalizeIPv6Address(input) {
|
|
3205
|
+
const compression = input.indexOf("::");
|
|
3206
|
+
if (compression !== -1 && input.indexOf("::", compression + 1) !== -1) return void 0;
|
|
3207
|
+
const left = compression === -1 ? input.split(":") : input.slice(0, compression).split(":");
|
|
3208
|
+
const right = compression === -1 ? [] : input.slice(compression + 2).split(":");
|
|
3209
|
+
if (compression !== -1) {
|
|
3210
|
+
if (left.length === 1 && left[0] === "") left.length = 0;
|
|
3211
|
+
if (right.length === 1 && right[0] === "") right.length = 0;
|
|
3212
|
+
}
|
|
3213
|
+
const parts = left.concat(right);
|
|
3214
|
+
let hextetCount = 0;
|
|
3215
|
+
for (let i = 0; i < parts.length; i++) {
|
|
3216
|
+
const part = parts[i];
|
|
3217
|
+
if (part === "") return void 0;
|
|
3218
|
+
if (part.indexOf(".") !== -1) {
|
|
3219
|
+
if (i !== parts.length - 1 || compression !== -1 && right.length === 0 || !isIPv4(part)) return void 0;
|
|
3220
|
+
hextetCount += 2;
|
|
3200
3221
|
continue;
|
|
3201
3222
|
}
|
|
3223
|
+
if (!isHextet(part)) return void 0;
|
|
3224
|
+
parts[i] = parseInt(part, 16).toString(16);
|
|
3225
|
+
hextetCount++;
|
|
3202
3226
|
}
|
|
3203
|
-
if (
|
|
3204
|
-
if (
|
|
3205
|
-
|
|
3206
|
-
} else if (endIpv6) {
|
|
3207
|
-
address.push(buffer.join(""));
|
|
3208
|
-
} else {
|
|
3209
|
-
address.push(stringArrayToHexStripped(buffer));
|
|
3210
|
-
}
|
|
3227
|
+
if (compression === -1) {
|
|
3228
|
+
if (hextetCount !== 8) return void 0;
|
|
3229
|
+
return compressIPv6ZeroRun(parts);
|
|
3211
3230
|
}
|
|
3212
|
-
|
|
3213
|
-
|
|
3231
|
+
if (hextetCount >= 8) return void 0;
|
|
3232
|
+
const expanded = parts.slice(0, left.length);
|
|
3233
|
+
for (let i = hextetCount; i < 8; i++) expanded.push("0");
|
|
3234
|
+
for (let i = left.length; i < parts.length; i++) expanded.push(parts[i]);
|
|
3235
|
+
return compressIPv6ZeroRun(expanded);
|
|
3214
3236
|
}
|
|
3215
3237
|
function normalizeIPv6(host) {
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
}
|
|
3219
|
-
|
|
3220
|
-
if (
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3238
|
+
const bracketed = host[0] === "[" && host[host.length - 1] === "]";
|
|
3239
|
+
const hasBracket = host[0] === "[" || host[host.length - 1] === "]";
|
|
3240
|
+
if (hasBracket && !bracketed) return { host, isIPV6: false, error: true };
|
|
3241
|
+
let input = bracketed ? host.slice(1, -1) : host;
|
|
3242
|
+
if (bracketed && isIPvFuture(input)) {
|
|
3243
|
+
input = input.toLowerCase();
|
|
3244
|
+
return { host: `[${input}]`, escapedHost: input, isIPV6: false, isIPVFuture: true };
|
|
3245
|
+
}
|
|
3246
|
+
if (findToken(input, ":") < 2) {
|
|
3247
|
+
return { host, isIPV6: false, error: bracketed };
|
|
3248
|
+
}
|
|
3249
|
+
let zoneIdentifier = "";
|
|
3250
|
+
const zoneSeparator = input.indexOf("%");
|
|
3251
|
+
if (zoneSeparator !== -1) {
|
|
3252
|
+
const separatorLength = input.slice(zoneSeparator, zoneSeparator + 3).toLowerCase() === "%25" ? 3 : 1;
|
|
3253
|
+
zoneIdentifier = input.slice(zoneSeparator + separatorLength);
|
|
3254
|
+
if (!isZoneIdentifier(zoneIdentifier)) return { host, isIPV6: false, error: true };
|
|
3255
|
+
input = input.slice(0, zoneSeparator);
|
|
3256
|
+
}
|
|
3257
|
+
const address = normalizeIPv6Address(input);
|
|
3258
|
+
if (address === void 0) return { host, isIPV6: false, error: true };
|
|
3259
|
+
return {
|
|
3260
|
+
host: address + (zoneIdentifier ? "%" + zoneIdentifier : ""),
|
|
3261
|
+
escapedHost: address + (zoneIdentifier ? "%25" + zoneIdentifier : ""),
|
|
3262
|
+
isIPV6: true
|
|
3263
|
+
};
|
|
3231
3264
|
}
|
|
3232
3265
|
function findToken(str, token) {
|
|
3233
3266
|
let ind = 0;
|
|
@@ -3346,7 +3379,8 @@ var require_utils = __commonJS({
|
|
|
3346
3379
|
function normalizePathEncoding(input) {
|
|
3347
3380
|
let output = "";
|
|
3348
3381
|
for (let i = 0; i < input.length; i++) {
|
|
3349
|
-
|
|
3382
|
+
const ch = input[i];
|
|
3383
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3350
3384
|
const hex3 = input.slice(i + 1, i + 3);
|
|
3351
3385
|
if (isHexPair(hex3)) {
|
|
3352
3386
|
const normalizedHex = hex3.toUpperCase();
|
|
@@ -3360,10 +3394,152 @@ var require_utils = __commonJS({
|
|
|
3360
3394
|
continue;
|
|
3361
3395
|
}
|
|
3362
3396
|
}
|
|
3363
|
-
if (isPathCharacter(
|
|
3364
|
-
output +=
|
|
3397
|
+
if (isPathCharacter(ch)) {
|
|
3398
|
+
output += ch;
|
|
3365
3399
|
} else {
|
|
3366
|
-
|
|
3400
|
+
const code = input.charCodeAt(i);
|
|
3401
|
+
if (code < 128) {
|
|
3402
|
+
output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
|
|
3403
|
+
} else if (code < 55296 || code > 57343) {
|
|
3404
|
+
output += percentEncodeNonAscii(code);
|
|
3405
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3406
|
+
const low = input.charCodeAt(i + 1);
|
|
3407
|
+
if (low >= 56320 && low <= 57343) {
|
|
3408
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3409
|
+
i++;
|
|
3410
|
+
} else {
|
|
3411
|
+
output += percentEncodeNonAscii(65533);
|
|
3412
|
+
}
|
|
3413
|
+
} else {
|
|
3414
|
+
output += percentEncodeNonAscii(65533);
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3417
|
+
}
|
|
3418
|
+
return output;
|
|
3419
|
+
}
|
|
3420
|
+
function serializePathEncoding(input, pathNoScheme = false) {
|
|
3421
|
+
let output = "";
|
|
3422
|
+
let firstSegment = pathNoScheme && input[0] !== "/";
|
|
3423
|
+
for (let i = 0; i < input.length; i++) {
|
|
3424
|
+
const ch = input[i];
|
|
3425
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3426
|
+
const hex3 = input.slice(i + 1, i + 3);
|
|
3427
|
+
if (isHexPair(hex3)) {
|
|
3428
|
+
output += "%" + hex3.toUpperCase();
|
|
3429
|
+
i += 2;
|
|
3430
|
+
continue;
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
3433
|
+
if (ch === "/") {
|
|
3434
|
+
firstSegment = false;
|
|
3435
|
+
}
|
|
3436
|
+
if (isPathCharacter(ch) && (ch !== ":" || !firstSegment)) {
|
|
3437
|
+
output += ch;
|
|
3438
|
+
} else {
|
|
3439
|
+
const code = input.charCodeAt(i);
|
|
3440
|
+
if (code < 128) {
|
|
3441
|
+
output += BYTE_HEX[code];
|
|
3442
|
+
} else if (code < 55296 || code > 57343) {
|
|
3443
|
+
output += percentEncodeNonAscii(code);
|
|
3444
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3445
|
+
const low = input.charCodeAt(i + 1);
|
|
3446
|
+
if (low >= 56320 && low <= 57343) {
|
|
3447
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3448
|
+
i++;
|
|
3449
|
+
} else {
|
|
3450
|
+
output += percentEncodeNonAscii(65533);
|
|
3451
|
+
}
|
|
3452
|
+
} else {
|
|
3453
|
+
output += percentEncodeNonAscii(65533);
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
3457
|
+
return output;
|
|
3458
|
+
}
|
|
3459
|
+
function encodeComponent(input, isAllowed) {
|
|
3460
|
+
let output = "";
|
|
3461
|
+
for (let i = 0; i < input.length; i++) {
|
|
3462
|
+
const ch = input[i];
|
|
3463
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3464
|
+
const hex3 = input.slice(i + 1, i + 3);
|
|
3465
|
+
if (isHexPair(hex3)) {
|
|
3466
|
+
output += "%" + hex3.toUpperCase();
|
|
3467
|
+
i += 2;
|
|
3468
|
+
continue;
|
|
3469
|
+
}
|
|
3470
|
+
}
|
|
3471
|
+
if (isAllowed(ch)) {
|
|
3472
|
+
output += ch;
|
|
3473
|
+
} else {
|
|
3474
|
+
const code = input.charCodeAt(i);
|
|
3475
|
+
if (code < 128) {
|
|
3476
|
+
output += BYTE_HEX[code];
|
|
3477
|
+
} else if (code < 55296 || code > 57343) {
|
|
3478
|
+
output += percentEncodeNonAscii(code);
|
|
3479
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3480
|
+
const low = input.charCodeAt(i + 1);
|
|
3481
|
+
if (low >= 56320 && low <= 57343) {
|
|
3482
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3483
|
+
i++;
|
|
3484
|
+
} else {
|
|
3485
|
+
output += percentEncodeNonAscii(65533);
|
|
3486
|
+
}
|
|
3487
|
+
} else {
|
|
3488
|
+
output += percentEncodeNonAscii(65533);
|
|
3489
|
+
}
|
|
3490
|
+
}
|
|
3491
|
+
}
|
|
3492
|
+
return output;
|
|
3493
|
+
}
|
|
3494
|
+
function encodeUserinfo(input) {
|
|
3495
|
+
return encodeComponent(input, isUserinfoCharacter);
|
|
3496
|
+
}
|
|
3497
|
+
function encodeQuery(input) {
|
|
3498
|
+
return encodeComponent(input, isQueryFragmentCharacter);
|
|
3499
|
+
}
|
|
3500
|
+
function encodeFragment(input) {
|
|
3501
|
+
return encodeComponent(input, isQueryFragmentCharacter);
|
|
3502
|
+
}
|
|
3503
|
+
function isEscapeSafe(cp) {
|
|
3504
|
+
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;
|
|
3505
|
+
}
|
|
3506
|
+
function normalizeQueryFragmentEncoding(input) {
|
|
3507
|
+
let output = "";
|
|
3508
|
+
for (let i = 0; i < input.length; i++) {
|
|
3509
|
+
const ch = input[i];
|
|
3510
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3511
|
+
const hex3 = input.slice(i + 1, i + 3);
|
|
3512
|
+
if (isHexPair(hex3)) {
|
|
3513
|
+
const normalizedHex = hex3.toUpperCase();
|
|
3514
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
3515
|
+
if (isUnreserved(decoded)) {
|
|
3516
|
+
output += decoded;
|
|
3517
|
+
} else {
|
|
3518
|
+
output += "%" + normalizedHex;
|
|
3519
|
+
}
|
|
3520
|
+
i += 2;
|
|
3521
|
+
continue;
|
|
3522
|
+
}
|
|
3523
|
+
}
|
|
3524
|
+
if (isQueryFragmentCharacter(ch)) {
|
|
3525
|
+
output += ch;
|
|
3526
|
+
} else {
|
|
3527
|
+
const code = input.charCodeAt(i);
|
|
3528
|
+
if (code < 128) {
|
|
3529
|
+
output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
|
|
3530
|
+
} else if (code < 55296 || code > 57343) {
|
|
3531
|
+
output += percentEncodeNonAscii(code);
|
|
3532
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3533
|
+
const low = input.charCodeAt(i + 1);
|
|
3534
|
+
if (low >= 56320 && low <= 57343) {
|
|
3535
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3536
|
+
i++;
|
|
3537
|
+
} else {
|
|
3538
|
+
output += percentEncodeNonAscii(65533);
|
|
3539
|
+
}
|
|
3540
|
+
} else {
|
|
3541
|
+
output += percentEncodeNonAscii(65533);
|
|
3542
|
+
}
|
|
3367
3543
|
}
|
|
3368
3544
|
}
|
|
3369
3545
|
return output;
|
|
@@ -3386,14 +3562,18 @@ var require_utils = __commonJS({
|
|
|
3386
3562
|
function recomposeAuthority(component) {
|
|
3387
3563
|
const uriTokens = [];
|
|
3388
3564
|
if (component.userinfo !== void 0) {
|
|
3389
|
-
uriTokens.push(component.userinfo);
|
|
3565
|
+
uriTokens.push(encodeUserinfo(component.userinfo));
|
|
3390
3566
|
uriTokens.push("@");
|
|
3391
3567
|
}
|
|
3392
3568
|
if (component.host !== void 0) {
|
|
3393
|
-
let host =
|
|
3569
|
+
let host = component.host;
|
|
3394
3570
|
if (!isIPv4(host)) {
|
|
3395
|
-
|
|
3396
|
-
if (ipV6res.isIPV6
|
|
3571
|
+
let ipV6res = normalizeIPv6(host);
|
|
3572
|
+
if (ipV6res.isIPV6 !== true && ipV6res.isIPVFuture !== true) {
|
|
3573
|
+
host = normalizePercentEncoding(host, true);
|
|
3574
|
+
ipV6res = normalizeIPv6(host);
|
|
3575
|
+
}
|
|
3576
|
+
if (ipV6res.isIPV6 === true || ipV6res.isIPVFuture === true) {
|
|
3397
3577
|
host = `[${ipV6res.escapedHost}]`;
|
|
3398
3578
|
} else {
|
|
3399
3579
|
host = reescapeHostDelimiters(host, false);
|
|
@@ -3402,8 +3582,12 @@ var require_utils = __commonJS({
|
|
|
3402
3582
|
uriTokens.push(host);
|
|
3403
3583
|
}
|
|
3404
3584
|
if (typeof component.port === "number" || typeof component.port === "string") {
|
|
3585
|
+
const port = String(component.port);
|
|
3586
|
+
if (!isPort(port)) {
|
|
3587
|
+
throw new TypeError("URI port is malformed.");
|
|
3588
|
+
}
|
|
3405
3589
|
uriTokens.push(":");
|
|
3406
|
-
uriTokens.push(
|
|
3590
|
+
uriTokens.push(port);
|
|
3407
3591
|
}
|
|
3408
3592
|
return uriTokens.length ? uriTokens.join("") : void 0;
|
|
3409
3593
|
}
|
|
@@ -3413,6 +3597,11 @@ var require_utils = __commonJS({
|
|
|
3413
3597
|
reescapeHostDelimiters,
|
|
3414
3598
|
normalizePercentEncoding,
|
|
3415
3599
|
normalizePathEncoding,
|
|
3600
|
+
serializePathEncoding,
|
|
3601
|
+
normalizeQueryFragmentEncoding,
|
|
3602
|
+
encodeUserinfo,
|
|
3603
|
+
encodeQuery,
|
|
3604
|
+
encodeFragment,
|
|
3416
3605
|
escapePreservingEscapes,
|
|
3417
3606
|
removeDotSegments,
|
|
3418
3607
|
isIPv4,
|
|
@@ -3428,7 +3617,7 @@ var require_schemes = __commonJS({
|
|
|
3428
3617
|
"node_modules/fast-uri/lib/schemes.js"(exports, module) {
|
|
3429
3618
|
"use strict";
|
|
3430
3619
|
var { isUUID } = require_utils();
|
|
3431
|
-
var URN_REG =
|
|
3620
|
+
var URN_REG = /^([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-./:;=@]|%[\da-f]{2})+)$/iu;
|
|
3432
3621
|
var supportedSchemeNames = (
|
|
3433
3622
|
/** @type {const} */
|
|
3434
3623
|
[
|
|
@@ -3489,9 +3678,10 @@ var require_schemes = __commonJS({
|
|
|
3489
3678
|
wsComponent.secure = void 0;
|
|
3490
3679
|
}
|
|
3491
3680
|
if (wsComponent.resourceName) {
|
|
3492
|
-
const
|
|
3681
|
+
const queryIndex = wsComponent.resourceName.indexOf("?");
|
|
3682
|
+
const path = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
|
|
3493
3683
|
wsComponent.path = path && path !== "/" ? path : void 0;
|
|
3494
|
-
wsComponent.query =
|
|
3684
|
+
wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1);
|
|
3495
3685
|
wsComponent.resourceName = void 0;
|
|
3496
3686
|
}
|
|
3497
3687
|
wsComponent.fragment = void 0;
|
|
@@ -3503,7 +3693,7 @@ var require_schemes = __commonJS({
|
|
|
3503
3693
|
return urnComponent;
|
|
3504
3694
|
}
|
|
3505
3695
|
const matches = urnComponent.path.match(URN_REG);
|
|
3506
|
-
if (matches) {
|
|
3696
|
+
if (matches && matches[0] === urnComponent.path) {
|
|
3507
3697
|
const scheme = options.scheme || urnComponent.scheme || "urn";
|
|
3508
3698
|
urnComponent.nid = matches[1].toLowerCase();
|
|
3509
3699
|
urnComponent.nss = matches[2];
|
|
@@ -3637,8 +3827,17 @@ var require_schemes = __commonJS({
|
|
|
3637
3827
|
var require_fast_uri = __commonJS({
|
|
3638
3828
|
"node_modules/fast-uri/index.js"(exports, module) {
|
|
3639
3829
|
"use strict";
|
|
3640
|
-
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding,
|
|
3830
|
+
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
|
|
3641
3831
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
3832
|
+
var VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u;
|
|
3833
|
+
var MALFORMED_SCHEME_ERROR = "URI scheme is malformed.";
|
|
3834
|
+
function decodeValidScheme(scheme) {
|
|
3835
|
+
const decodedScheme = unescape(String(scheme));
|
|
3836
|
+
if (!VALID_SCHEME.test(decodedScheme)) {
|
|
3837
|
+
throw new TypeError(MALFORMED_SCHEME_ERROR);
|
|
3838
|
+
}
|
|
3839
|
+
return decodedScheme;
|
|
3840
|
+
}
|
|
3642
3841
|
function normalize(uri, options) {
|
|
3643
3842
|
if (typeof uri === "string") {
|
|
3644
3843
|
uri = /** @type {T} */
|
|
@@ -3651,12 +3850,34 @@ var require_fast_uri = __commonJS({
|
|
|
3651
3850
|
}
|
|
3652
3851
|
function resolve2(baseURI, relativeURI, options) {
|
|
3653
3852
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3654
|
-
const {
|
|
3655
|
-
|
|
3656
|
-
|
|
3853
|
+
const {
|
|
3854
|
+
parsed: baseParsed,
|
|
3855
|
+
malformedAuthorityOrPort: baseMalformed,
|
|
3856
|
+
malformedPercentEncoding: baseMalformedPercentEncoding,
|
|
3857
|
+
malformedSchemeSpecific: baseMalformedSchemeSpecific,
|
|
3858
|
+
malformedHost: baseMalformedHost,
|
|
3859
|
+
malformedScheme: baseMalformedScheme
|
|
3860
|
+
} = parseWithStatus(baseURI, schemelessOptions);
|
|
3861
|
+
const {
|
|
3862
|
+
parsed: relativeParsed,
|
|
3863
|
+
malformedAuthorityOrPort: relativeMalformed,
|
|
3864
|
+
malformedPercentEncoding: relativeMalformedPercentEncoding,
|
|
3865
|
+
malformedSchemeSpecific: relativeMalformedSchemeSpecific,
|
|
3866
|
+
malformedHost: relativeMalformedHost,
|
|
3867
|
+
malformedScheme: relativeMalformedScheme
|
|
3868
|
+
} = parseWithStatus(relativeURI, schemelessOptions);
|
|
3869
|
+
if (baseMalformed || relativeMalformed || baseMalformedPercentEncoding || relativeMalformedPercentEncoding || baseMalformedSchemeSpecific || relativeMalformedSchemeSpecific || baseMalformedHost || relativeMalformedHost || baseMalformedScheme || relativeMalformedScheme) {
|
|
3657
3870
|
throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
|
|
3658
3871
|
}
|
|
3659
3872
|
const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
|
|
3873
|
+
const resolvedSchemeHandler = getSchemeHandler(options && options.scheme || resolved.scheme);
|
|
3874
|
+
const resolvedHost = resolved.host;
|
|
3875
|
+
const resolvedHostIsIP = resolvedHost !== void 0 && resolvedHost !== "" && (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
|
|
3876
|
+
canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
|
|
3877
|
+
const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !/\P{ASCII}/u.test(resolvedHost);
|
|
3878
|
+
if (resolved.error && !encodedASCIIHost) {
|
|
3879
|
+
throw new Error(resolved.error);
|
|
3880
|
+
}
|
|
3660
3881
|
schemelessOptions.skipEscape = true;
|
|
3661
3882
|
return serialize(resolved, schemelessOptions);
|
|
3662
3883
|
}
|
|
@@ -3716,7 +3937,7 @@ var require_fast_uri = __commonJS({
|
|
|
3716
3937
|
function equal(uriA, uriB, options) {
|
|
3717
3938
|
const normalizedA = normalizeComparableURI(uriA, options);
|
|
3718
3939
|
const normalizedB = normalizeComparableURI(uriB, options);
|
|
3719
|
-
return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA
|
|
3940
|
+
return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA === normalizedB;
|
|
3720
3941
|
}
|
|
3721
3942
|
function serialize(cmpts, opts) {
|
|
3722
3943
|
const component = {
|
|
@@ -3737,19 +3958,22 @@ var require_fast_uri = __commonJS({
|
|
|
3737
3958
|
};
|
|
3738
3959
|
const options = Object.assign({}, opts);
|
|
3739
3960
|
const uriTokens = [];
|
|
3961
|
+
if (component.scheme) {
|
|
3962
|
+
component.scheme = decodeValidScheme(component.scheme);
|
|
3963
|
+
}
|
|
3740
3964
|
const schemeHandler = getSchemeHandler(options.scheme || component.scheme);
|
|
3741
3965
|
if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
|
|
3966
|
+
const hasAuthority = component.userinfo !== void 0 || component.host !== void 0 || component.port !== void 0;
|
|
3967
|
+
const pathNoScheme = !options.skipEscape && component.scheme === void 0 && !hasAuthority;
|
|
3742
3968
|
if (component.path !== void 0) {
|
|
3743
3969
|
if (!options.skipEscape) {
|
|
3744
|
-
component.path =
|
|
3745
|
-
if (component.scheme !== void 0) {
|
|
3746
|
-
component.path = component.path.split("%3A").join(":");
|
|
3747
|
-
}
|
|
3970
|
+
component.path = serializePathEncoding(component.path, pathNoScheme);
|
|
3748
3971
|
} else {
|
|
3749
3972
|
component.path = normalizePercentEncoding(component.path);
|
|
3750
3973
|
}
|
|
3751
3974
|
}
|
|
3752
3975
|
if (options.reference !== "suffix" && component.scheme) {
|
|
3976
|
+
component.scheme = decodeValidScheme(component.scheme);
|
|
3753
3977
|
uriTokens.push(component.scheme, ":");
|
|
3754
3978
|
}
|
|
3755
3979
|
const authority = recomposeAuthority(component);
|
|
@@ -3767,16 +3991,19 @@ var require_fast_uri = __commonJS({
|
|
|
3767
3991
|
if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
|
|
3768
3992
|
s = removeDotSegments(s);
|
|
3769
3993
|
}
|
|
3994
|
+
if (pathNoScheme) {
|
|
3995
|
+
s = serializePathEncoding(s, true);
|
|
3996
|
+
}
|
|
3770
3997
|
if (authority === void 0 && s[0] === "/" && s[1] === "/") {
|
|
3771
3998
|
s = "/%2F" + s.slice(2);
|
|
3772
3999
|
}
|
|
3773
4000
|
uriTokens.push(s);
|
|
3774
4001
|
}
|
|
3775
4002
|
if (component.query !== void 0) {
|
|
3776
|
-
uriTokens.push("?", component.query);
|
|
4003
|
+
uriTokens.push("?", encodeQuery(component.query));
|
|
3777
4004
|
}
|
|
3778
4005
|
if (component.fragment !== void 0) {
|
|
3779
|
-
uriTokens.push("#", component.fragment);
|
|
4006
|
+
uriTokens.push("#", encodeFragment(component.fragment));
|
|
3780
4007
|
}
|
|
3781
4008
|
return uriTokens.join("");
|
|
3782
4009
|
}
|
|
@@ -3792,6 +4019,35 @@ var require_fast_uri = __commonJS({
|
|
|
3792
4019
|
}
|
|
3793
4020
|
return void 0;
|
|
3794
4021
|
}
|
|
4022
|
+
function hasMalformedPercentEncoding(component) {
|
|
4023
|
+
if (component === void 0) return false;
|
|
4024
|
+
let percent = component.indexOf("%");
|
|
4025
|
+
while (percent !== -1) {
|
|
4026
|
+
if (percent + 2 >= component.length || !/^[\da-f]{2}$/iu.test(component.slice(percent + 1, percent + 3))) {
|
|
4027
|
+
return true;
|
|
4028
|
+
}
|
|
4029
|
+
percent = component.indexOf("%", percent + 3);
|
|
4030
|
+
}
|
|
4031
|
+
return false;
|
|
4032
|
+
}
|
|
4033
|
+
function isIPLiteral(host) {
|
|
4034
|
+
return host[0] === "[" && host[host.length - 1] === "]";
|
|
4035
|
+
}
|
|
4036
|
+
function hasMalformedComponentPercentEncoding(matches) {
|
|
4037
|
+
const host = matches[4];
|
|
4038
|
+
return hasMalformedPercentEncoding(matches[3]) || host !== void 0 && !isIPLiteral(host) && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]);
|
|
4039
|
+
}
|
|
4040
|
+
function canonicalizeHost(parsed, options, schemeHandler, isIP2) {
|
|
4041
|
+
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP2 === false && nonSimpleDomain(parsed.host)) {
|
|
4042
|
+
try {
|
|
4043
|
+
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
4044
|
+
} catch (e) {
|
|
4045
|
+
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
|
|
4046
|
+
return true;
|
|
4047
|
+
}
|
|
4048
|
+
}
|
|
4049
|
+
return false;
|
|
4050
|
+
}
|
|
3795
4051
|
function parseWithStatus(uri, opts) {
|
|
3796
4052
|
const options = Object.assign({}, opts);
|
|
3797
4053
|
const parsed = {
|
|
@@ -3804,6 +4060,11 @@ var require_fast_uri = __commonJS({
|
|
|
3804
4060
|
fragment: void 0
|
|
3805
4061
|
};
|
|
3806
4062
|
let malformedAuthorityOrPort = false;
|
|
4063
|
+
let malformedPercentEncoding = false;
|
|
4064
|
+
let malformedSchemeSpecific = false;
|
|
4065
|
+
let malformedHost = false;
|
|
4066
|
+
let malformedIPLiteral = false;
|
|
4067
|
+
let malformedScheme = false;
|
|
3807
4068
|
let isIP2 = false;
|
|
3808
4069
|
if (options.reference === "suffix") {
|
|
3809
4070
|
if (options.scheme) {
|
|
@@ -3840,6 +4101,19 @@ var require_fast_uri = __commonJS({
|
|
|
3840
4101
|
parsed.path = matches[6] || "";
|
|
3841
4102
|
parsed.query = matches[7];
|
|
3842
4103
|
parsed.fragment = matches[8];
|
|
4104
|
+
if (parsed.scheme !== void 0) {
|
|
4105
|
+
const decodedScheme = unescape(parsed.scheme);
|
|
4106
|
+
if (VALID_SCHEME.test(decodedScheme)) {
|
|
4107
|
+
parsed.scheme = decodedScheme.toLowerCase();
|
|
4108
|
+
} else {
|
|
4109
|
+
parsed.error = parsed.error || MALFORMED_SCHEME_ERROR;
|
|
4110
|
+
malformedScheme = true;
|
|
4111
|
+
}
|
|
4112
|
+
}
|
|
4113
|
+
malformedPercentEncoding = hasMalformedComponentPercentEncoding(matches);
|
|
4114
|
+
if (malformedPercentEncoding) {
|
|
4115
|
+
parsed.error = parsed.error || "URI contains malformed percent-encoding.";
|
|
4116
|
+
}
|
|
3843
4117
|
if (isNaN(parsed.port)) {
|
|
3844
4118
|
parsed.port = matches[5];
|
|
3845
4119
|
}
|
|
@@ -3851,9 +4125,16 @@ var require_fast_uri = __commonJS({
|
|
|
3851
4125
|
if (parsed.host) {
|
|
3852
4126
|
const ipv4result = isIPv4(parsed.host);
|
|
3853
4127
|
if (ipv4result === false) {
|
|
4128
|
+
const bracketedIPLiteral = isIPLiteral(parsed.host);
|
|
4129
|
+
const hasIPLiteralBracket = parsed.host.indexOf("[") !== -1 || parsed.host.indexOf("]") !== -1;
|
|
3854
4130
|
const ipv6result = normalizeIPv6(parsed.host);
|
|
3855
|
-
|
|
3856
|
-
|
|
4131
|
+
isIP2 = ipv6result.isIPV6 || ipv6result.isIPVFuture === true;
|
|
4132
|
+
malformedIPLiteral = hasIPLiteralBracket && (!bracketedIPLiteral || ipv6result.error === true);
|
|
4133
|
+
parsed.host = isIP2 ? ipv6result.host : ipv6result.host.toLowerCase();
|
|
4134
|
+
if (malformedIPLiteral) {
|
|
4135
|
+
parsed.error = parsed.error || "URI host is malformed.";
|
|
4136
|
+
malformedAuthorityOrPort = true;
|
|
4137
|
+
}
|
|
3857
4138
|
} else {
|
|
3858
4139
|
isIP2 = true;
|
|
3859
4140
|
}
|
|
@@ -3871,42 +4152,36 @@ var require_fast_uri = __commonJS({
|
|
|
3871
4152
|
parsed.error = parsed.error || "URI is not a " + options.reference + " reference.";
|
|
3872
4153
|
}
|
|
3873
4154
|
const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
|
|
3874
|
-
if (!
|
|
3875
|
-
|
|
3876
|
-
try {
|
|
3877
|
-
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
3878
|
-
} catch (e) {
|
|
3879
|
-
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
|
|
3880
|
-
}
|
|
3881
|
-
}
|
|
4155
|
+
if (!malformedIPLiteral) {
|
|
4156
|
+
malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP2);
|
|
3882
4157
|
}
|
|
3883
4158
|
if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
|
|
3884
4159
|
if (uri.indexOf("%") !== -1) {
|
|
3885
|
-
if (parsed.
|
|
3886
|
-
parsed.
|
|
3887
|
-
|
|
3888
|
-
if (parsed.host !== void 0) {
|
|
3889
|
-
parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP2);
|
|
4160
|
+
if (parsed.host !== void 0 && !malformedIPLiteral) {
|
|
4161
|
+
const host = isIP2 ? parsed.host : normalizePercentEncoding(parsed.host, true);
|
|
4162
|
+
parsed.host = reescapeHostDelimiters(host, isIP2);
|
|
3890
4163
|
}
|
|
3891
4164
|
}
|
|
3892
4165
|
if (parsed.path) {
|
|
3893
4166
|
parsed.path = normalizePathEncoding(parsed.path);
|
|
3894
4167
|
}
|
|
4168
|
+
if (parsed.query) {
|
|
4169
|
+
parsed.query = normalizeQueryFragmentEncoding(parsed.query);
|
|
4170
|
+
}
|
|
3895
4171
|
if (parsed.fragment) {
|
|
3896
|
-
|
|
3897
|
-
parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
|
|
3898
|
-
} catch {
|
|
3899
|
-
parsed.error = parsed.error || "URI malformed";
|
|
3900
|
-
}
|
|
4172
|
+
parsed.fragment = normalizeQueryFragmentEncoding(parsed.fragment);
|
|
3901
4173
|
}
|
|
3902
4174
|
}
|
|
3903
4175
|
if (schemeHandler && schemeHandler.parse) {
|
|
3904
4176
|
schemeHandler.parse(parsed, options);
|
|
4177
|
+
if (schemeHandler === SCHEMES.urn && parsed.nid === void 0) {
|
|
4178
|
+
malformedSchemeSpecific = true;
|
|
4179
|
+
}
|
|
3905
4180
|
}
|
|
3906
4181
|
} else {
|
|
3907
4182
|
parsed.error = parsed.error || "URI can not be parsed.";
|
|
3908
4183
|
}
|
|
3909
|
-
return { parsed, malformedAuthorityOrPort };
|
|
4184
|
+
return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme };
|
|
3910
4185
|
}
|
|
3911
4186
|
function parse3(uri, opts) {
|
|
3912
4187
|
return parseWithStatus(uri, opts).parsed;
|
|
@@ -3915,20 +4190,28 @@ var require_fast_uri = __commonJS({
|
|
|
3915
4190
|
return normalizeStringWithStatus(uri, opts).normalized;
|
|
3916
4191
|
}
|
|
3917
4192
|
function normalizeStringWithStatus(uri, opts) {
|
|
3918
|
-
const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
|
|
4193
|
+
const { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = parseWithStatus(uri, opts);
|
|
3919
4194
|
return {
|
|
3920
|
-
normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
|
|
3921
|
-
malformedAuthorityOrPort
|
|
4195
|
+
normalized: malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? uri : serialize(parsed, opts),
|
|
4196
|
+
malformedAuthorityOrPort,
|
|
4197
|
+
malformedPercentEncoding,
|
|
4198
|
+
malformedSchemeSpecific,
|
|
4199
|
+
malformedHost,
|
|
4200
|
+
malformedScheme
|
|
3922
4201
|
};
|
|
3923
4202
|
}
|
|
3924
4203
|
function normalizeComparableURI(uri, opts) {
|
|
3925
|
-
if (typeof uri
|
|
3926
|
-
|
|
3927
|
-
return malformedAuthorityOrPort ? void 0 : normalized;
|
|
4204
|
+
if (typeof uri !== "string" && typeof uri !== "object") {
|
|
4205
|
+
return void 0;
|
|
3928
4206
|
}
|
|
3929
|
-
|
|
3930
|
-
|
|
4207
|
+
let value;
|
|
4208
|
+
try {
|
|
4209
|
+
value = typeof uri === "string" ? uri : serialize(uri, opts);
|
|
4210
|
+
} catch {
|
|
4211
|
+
return void 0;
|
|
3931
4212
|
}
|
|
4213
|
+
const { normalized, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = normalizeStringWithStatus(value, opts);
|
|
4214
|
+
return malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? void 0 : normalized;
|
|
3932
4215
|
}
|
|
3933
4216
|
var fastUri = {
|
|
3934
4217
|
SCHEMES,
|
|
@@ -34682,6 +34965,7 @@ var StdioServerTransport = class {
|
|
|
34682
34965
|
};
|
|
34683
34966
|
|
|
34684
34967
|
// node_modules/@chrischall/mcp-utils/dist/errors/index.js
|
|
34968
|
+
var DEFAULT_ERROR_MESSAGE_MAX = 500;
|
|
34685
34969
|
var McpToolError = class extends Error {
|
|
34686
34970
|
/** Actionable remediation text, when one applies. */
|
|
34687
34971
|
hint;
|
|
@@ -34720,13 +35004,95 @@ var JSON_SECRET_SQ_RE = new RegExp(`('(?:${JSON_SECRET_KEYS})'\\s*:\\s*')[^']*('
|
|
|
34720
35004
|
function redactSecrets(text) {
|
|
34721
35005
|
return text.replace(BEARER_RE, "$1[REDACTED]").replace(BASIC_AUTH_RE, "$1[REDACTED]").replace(SET_COOKIE_RE, "$1$2=[REDACTED]").replace(COOKIE_HEADER_RE, (_m, prefix, pairs) => `${prefix}${pairs.replace(/=[^;,\s]*/g, "=[REDACTED]")}`).replace(API_KEY_RE, "[REDACTED]").replace(QUERY_SECRET_RE, "$1[REDACTED]").replace(AWS_SIGV4_RE, "$1[REDACTED]").replace(JSON_SECRET_DQ_RE, "$1[REDACTED]$2").replace(JSON_SECRET_SQ_RE, "$1[REDACTED]$2").replace(JWT_RE, "[REDACTED]");
|
|
34722
35006
|
}
|
|
35007
|
+
function truncateErrorMessage(text, max = DEFAULT_ERROR_MESSAGE_MAX) {
|
|
35008
|
+
const str = text === null || text === void 0 ? "" : String(text);
|
|
35009
|
+
const redacted = redactSecrets(str);
|
|
35010
|
+
if (redacted.length <= max)
|
|
35011
|
+
return redacted;
|
|
35012
|
+
return `${redacted.slice(0, max)}\u2026 [truncated]`;
|
|
35013
|
+
}
|
|
35014
|
+
function messageOf(err) {
|
|
35015
|
+
if (err instanceof Error)
|
|
35016
|
+
return err.message;
|
|
35017
|
+
return String(err);
|
|
35018
|
+
}
|
|
35019
|
+
|
|
35020
|
+
// node_modules/@chrischall/mcp-utils/dist/response/view.js
|
|
35021
|
+
var VIEWS = ["compact", "full", "raw"];
|
|
35022
|
+
var DEFAULT_VIEW = "compact";
|
|
35023
|
+
var BLURB = {
|
|
35024
|
+
compact: '"compact" (default) drops fields the response already carries elsewhere',
|
|
35025
|
+
full: '"full" returns every field this server understands',
|
|
35026
|
+
raw: '"raw" returns the upstream payload unprojected'
|
|
35027
|
+
};
|
|
35028
|
+
function viewParam(honoured, opts = {}) {
|
|
35029
|
+
if (honoured.length < 2) {
|
|
35030
|
+
throw new Error("viewParam needs at least two rungs: a parameter offering one value decides nothing");
|
|
35031
|
+
}
|
|
35032
|
+
if (!honoured.includes("compact")) {
|
|
35033
|
+
throw new Error('viewParam must offer "compact": a tool with no cheap rung has nothing to default to');
|
|
35034
|
+
}
|
|
35035
|
+
const ordered = VIEWS.filter((v) => honoured.includes(v));
|
|
35036
|
+
const sentence = `Response shape: ${ordered.map((v) => BLURB[v]).join("; ")}.`;
|
|
35037
|
+
return external_exports.enum(Object.fromEntries(ordered.map((v) => [v, v]))).optional().describe(opts.note ? `${sentence} ${opts.note}` : sentence);
|
|
35038
|
+
}
|
|
35039
|
+
function resolveView(value, honoured) {
|
|
35040
|
+
return value !== void 0 && honoured.includes(value) ? value : DEFAULT_VIEW;
|
|
35041
|
+
}
|
|
35042
|
+
function minifiedResult(data) {
|
|
35043
|
+
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
35044
|
+
}
|
|
35045
|
+
|
|
35046
|
+
// node_modules/@chrischall/mcp-utils/dist/response/media.js
|
|
35047
|
+
var MEDIA_NOUN = "(?:avatar|picture|photo|thumbnail|thumb|image|icon|banner|profile_pic(?:ture)?|logo)";
|
|
35048
|
+
var MEDIA_QUALIFIER = "(?:primary|secondary|main|default|cover|hero|profile|master|rendered|small|medium|large|full|original|tall)";
|
|
35049
|
+
var MEDIA_KEY = new RegExp(`^(?:(?:${MEDIA_QUALIFIER}|${MEDIA_NOUN})[_-]?)?${MEDIA_NOUN}s?(?:[_-]?(?:link|uri|url|src)s?)?$`, "i");
|
|
35050
|
+
var MEDIA_URL = /^https?:\/\/[^\s]+?\.(png|jpe?g|gif|webp|svg|avif|bmp|ico)([?#]|$)/i;
|
|
35051
|
+
function stripMediaUrls(value, opts = {}) {
|
|
35052
|
+
const keep = normalizeRules(opts.keep ?? []);
|
|
35053
|
+
const drop = normalizeRules(opts.drop ?? []);
|
|
35054
|
+
return walk(value, keep, drop);
|
|
35055
|
+
}
|
|
35056
|
+
function normalizeRules(rules) {
|
|
35057
|
+
return rules.map((rule) => typeof rule === "string" ? rule.toLowerCase() : new RegExp(rule.source, rule.flags));
|
|
35058
|
+
}
|
|
35059
|
+
function matchesRule(key, rules) {
|
|
35060
|
+
const lower = key.toLowerCase();
|
|
35061
|
+
for (const rule of rules) {
|
|
35062
|
+
if (typeof rule === "string") {
|
|
35063
|
+
if (rule === lower)
|
|
35064
|
+
return true;
|
|
35065
|
+
continue;
|
|
35066
|
+
}
|
|
35067
|
+
rule.lastIndex = 0;
|
|
35068
|
+
if (rule.test(key))
|
|
35069
|
+
return true;
|
|
35070
|
+
}
|
|
35071
|
+
return false;
|
|
35072
|
+
}
|
|
35073
|
+
function walk(value, keep, drop) {
|
|
35074
|
+
if (Array.isArray(value))
|
|
35075
|
+
return value.map((v) => walk(v, keep, drop));
|
|
35076
|
+
if (value === null || typeof value !== "object")
|
|
35077
|
+
return value;
|
|
35078
|
+
if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
|
|
35079
|
+
return value;
|
|
35080
|
+
const out = {};
|
|
35081
|
+
for (const [key, v] of Object.entries(value)) {
|
|
35082
|
+
if (matchesRule(key, keep)) {
|
|
35083
|
+
out[key] = v;
|
|
35084
|
+
continue;
|
|
35085
|
+
}
|
|
35086
|
+
if (MEDIA_KEY.test(key) || matchesRule(key, drop))
|
|
35087
|
+
continue;
|
|
35088
|
+
if (typeof v === "string" && MEDIA_URL.test(v))
|
|
35089
|
+
continue;
|
|
35090
|
+
out[key] = walk(v, keep, drop);
|
|
35091
|
+
}
|
|
35092
|
+
return out;
|
|
35093
|
+
}
|
|
34723
35094
|
|
|
34724
35095
|
// node_modules/@chrischall/mcp-utils/dist/response/index.js
|
|
34725
|
-
function textResult(data) {
|
|
34726
|
-
return {
|
|
34727
|
-
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
34728
|
-
};
|
|
34729
|
-
}
|
|
34730
35096
|
function errorResult(message) {
|
|
34731
35097
|
return {
|
|
34732
35098
|
content: [{ type: "text", text: redactSecrets(message) }],
|
|
@@ -39015,6 +39381,144 @@ var BootstrapDisabledError = class extends Error {
|
|
|
39015
39381
|
}
|
|
39016
39382
|
};
|
|
39017
39383
|
|
|
39384
|
+
// node_modules/@chrischall/mcp-utils/dist/healthcheck/index.js
|
|
39385
|
+
function statusOf(err) {
|
|
39386
|
+
if (typeof err !== "object" || err === null)
|
|
39387
|
+
return void 0;
|
|
39388
|
+
const s = err.status ?? err.statusCode;
|
|
39389
|
+
return typeof s === "number" ? s : void 0;
|
|
39390
|
+
}
|
|
39391
|
+
var CREDENTIAL_ARMS = /* @__PURE__ */ new Set([
|
|
39392
|
+
"ok",
|
|
39393
|
+
"no_credential",
|
|
39394
|
+
"credential_rejected",
|
|
39395
|
+
"timeout",
|
|
39396
|
+
"http",
|
|
39397
|
+
"transport",
|
|
39398
|
+
"unknown"
|
|
39399
|
+
]);
|
|
39400
|
+
function isArm(kind) {
|
|
39401
|
+
return kind !== void 0 && CREDENTIAL_ARMS.has(kind);
|
|
39402
|
+
}
|
|
39403
|
+
function credentialHint(arm, prefix, hostLabel, source2) {
|
|
39404
|
+
switch (arm) {
|
|
39405
|
+
case "ok":
|
|
39406
|
+
return `Credential from '${source2}' works: ${hostLabel} accepted an authenticated request. If a real tool still fails, the problem is that tool, not auth.`;
|
|
39407
|
+
case "no_credential":
|
|
39408
|
+
return `No credential resolved. Nothing was available to authenticate with \u2014 sign in and reconnect the connector so ${prefix} receives a token, or set the documented environment variable.`;
|
|
39409
|
+
case "credential_rejected":
|
|
39410
|
+
return `${hostLabel} rejected the credential from '${source2}'. It is present but no longer valid \u2014 most often expired or revoked upstream. Re-authenticate and reconnect; retrying will not fix it.`;
|
|
39411
|
+
case "timeout":
|
|
39412
|
+
return `The credential from '${source2}' resolved, but ${hostLabel} did not answer in time. Usually transient \u2014 retry. If it persists, ${hostLabel} is slow or unreachable from here.`;
|
|
39413
|
+
case "http":
|
|
39414
|
+
return `${hostLabel} answered with an error status that is not an auth rejection. That is USUALLY a ${hostLabel}-side problem rather than an auth one \u2014 but a 404 here more often means the probe path is wrong than that ${hostLabel} is broken, so check error.message and probe.url before concluding anything about the credential.`;
|
|
39415
|
+
case "transport":
|
|
39416
|
+
return `Could not reach ${hostLabel} at all. Check network egress; the credential itself was never judged.`;
|
|
39417
|
+
default:
|
|
39418
|
+
return `Unexpected failure \u2014 see error.message.`;
|
|
39419
|
+
}
|
|
39420
|
+
}
|
|
39421
|
+
function registerCredentialHealthcheckTool(args) {
|
|
39422
|
+
const { server, prefix, hostLabel, probePath, resolveCredential, probeFn, classifyThrown, hints } = args;
|
|
39423
|
+
const probeUrl = probePath ? `https://${hostLabel}${probePath}` : void 0;
|
|
39424
|
+
server.registerTool(`${prefix}_healthcheck`, {
|
|
39425
|
+
title: "Verify credentials and upstream reachability",
|
|
39426
|
+
description: `Resolves the credential the way real tools do, then makes one authenticated request to ${hostLabel}. Reports which source supplied the credential, whether ${hostLabel} accepted it, the round-trip time, and a plain-English hint distinguishing 'no credential' from 'credential rejected' from 'a ${hostLabel}-side problem'. Call this when a real tool fails and you want to know which hop broke. Read-only; never returns the credential itself.`,
|
|
39427
|
+
annotations: {
|
|
39428
|
+
title: "Verify credentials and upstream reachability",
|
|
39429
|
+
readOnlyHint: true,
|
|
39430
|
+
idempotentHint: true,
|
|
39431
|
+
openWorldHint: true
|
|
39432
|
+
},
|
|
39433
|
+
inputSchema: {}
|
|
39434
|
+
}, async () => {
|
|
39435
|
+
let probeStarted = 0;
|
|
39436
|
+
let state;
|
|
39437
|
+
try {
|
|
39438
|
+
state = await resolveCredential();
|
|
39439
|
+
} catch (e) {
|
|
39440
|
+
const classified = classifyThrown?.(e);
|
|
39441
|
+
const result2 = {
|
|
39442
|
+
ok: false,
|
|
39443
|
+
// Still false, and still no source: a classification explains WHY
|
|
39444
|
+
// nothing resolved, it does not invent a credential that did.
|
|
39445
|
+
credential: { source: null, resolved: false },
|
|
39446
|
+
// No `url`: nothing was probed, and naming one implies it was tried.
|
|
39447
|
+
probe: { elapsed_ms: 0 },
|
|
39448
|
+
error: {
|
|
39449
|
+
kind: classified?.kind ?? "no_credential",
|
|
39450
|
+
message: truncateErrorMessage(messageOf(e)),
|
|
39451
|
+
...classified?.detail !== void 0 ? { detail: classified.detail } : {}
|
|
39452
|
+
},
|
|
39453
|
+
// The hint must follow the KIND beside it. Falling back to
|
|
39454
|
+
// `no_credential`'s copy under a classified kind would state a cause
|
|
39455
|
+
// the kind contradicts — the same disagreement this path exists to
|
|
39456
|
+
// remove. So: an inline hint wins; else the classified arm's own
|
|
39457
|
+
// copy (consumer override first); else, for a kind this module has
|
|
39458
|
+
// no copy for, the neutral `unknown` text rather than one that
|
|
39459
|
+
// asserts a cause; else the unclassified `no_credential` default.
|
|
39460
|
+
hint: classified?.hint ?? (isArm(classified?.kind) ? hints?.[classified.kind] ?? credentialHint(classified.kind, prefix, hostLabel, null) : classified !== void 0 ? credentialHint("unknown", prefix, hostLabel, null) : hints?.no_credential ?? credentialHint("no_credential", prefix, hostLabel, null))
|
|
39461
|
+
};
|
|
39462
|
+
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
39463
|
+
}
|
|
39464
|
+
const credential = {
|
|
39465
|
+
source: state.source,
|
|
39466
|
+
resolved: state.source !== null,
|
|
39467
|
+
...state.detail !== void 0 ? { detail: state.detail } : {}
|
|
39468
|
+
};
|
|
39469
|
+
if (!credential.resolved) {
|
|
39470
|
+
const result2 = {
|
|
39471
|
+
ok: false,
|
|
39472
|
+
credential,
|
|
39473
|
+
probe: { elapsed_ms: 0 },
|
|
39474
|
+
error: { kind: "no_credential", message: "no credential source resolved" },
|
|
39475
|
+
hint: hints?.no_credential ?? credentialHint("no_credential", prefix, hostLabel, null)
|
|
39476
|
+
};
|
|
39477
|
+
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
39478
|
+
}
|
|
39479
|
+
let arm = "ok";
|
|
39480
|
+
let error51;
|
|
39481
|
+
let status;
|
|
39482
|
+
let customHint;
|
|
39483
|
+
probeStarted = Date.now();
|
|
39484
|
+
try {
|
|
39485
|
+
await probeFn();
|
|
39486
|
+
} catch (e) {
|
|
39487
|
+
status = statusOf(e);
|
|
39488
|
+
const aborted2 = e instanceof Error && e.name === "AbortError";
|
|
39489
|
+
arm = status === 401 || status === 403 ? "credential_rejected" : status !== void 0 ? "http" : aborted2 || /timeout|timed out|ETIMEDOUT/i.test(messageOf(e)) ? "timeout" : /fetch failed|ENOTFOUND|ECONNREFUSED|ECONNRESET|network/i.test(messageOf(e)) ? "transport" : "unknown";
|
|
39490
|
+
let kind = arm;
|
|
39491
|
+
let detail;
|
|
39492
|
+
const custom2 = classifyThrown?.(e);
|
|
39493
|
+
if (custom2) {
|
|
39494
|
+
kind = custom2.kind;
|
|
39495
|
+
customHint = custom2.hint;
|
|
39496
|
+
detail = custom2.detail;
|
|
39497
|
+
}
|
|
39498
|
+
error51 = {
|
|
39499
|
+
kind,
|
|
39500
|
+
// Redacted AND bounded before it reaches the result: an upstream
|
|
39501
|
+
// failure routinely quotes what it was sent, and a healthcheck is
|
|
39502
|
+
// the tool people paste into a chat when something is broken.
|
|
39503
|
+
message: truncateErrorMessage(messageOf(e)),
|
|
39504
|
+
...detail !== void 0 ? { detail } : {}
|
|
39505
|
+
};
|
|
39506
|
+
}
|
|
39507
|
+
const result = {
|
|
39508
|
+
ok: error51 === void 0,
|
|
39509
|
+
credential,
|
|
39510
|
+
probe: {
|
|
39511
|
+
...probeUrl ? { url: probeUrl } : {},
|
|
39512
|
+
elapsed_ms: Date.now() - probeStarted,
|
|
39513
|
+
...status !== void 0 ? { status } : {}
|
|
39514
|
+
},
|
|
39515
|
+
...error51 ? { error: error51 } : {},
|
|
39516
|
+
hint: customHint ?? hints?.[arm] ?? credentialHint(arm, prefix, hostLabel, state.source)
|
|
39517
|
+
};
|
|
39518
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
39519
|
+
});
|
|
39520
|
+
}
|
|
39521
|
+
|
|
39018
39522
|
// src/config.ts
|
|
39019
39523
|
function readVar(env, key) {
|
|
39020
39524
|
return readEnvVar(key, { env });
|
|
@@ -39056,7 +39560,7 @@ function loadAccount(env = process.env) {
|
|
|
39056
39560
|
// package.json
|
|
39057
39561
|
var package_default = {
|
|
39058
39562
|
name: "infinitecampus-mcp",
|
|
39059
|
-
version: "2.
|
|
39563
|
+
version: "2.8.0",
|
|
39060
39564
|
mcpName: "io.github.chrischall/infinitecampus-mcp",
|
|
39061
39565
|
description: "Infinite Campus (Campus Parent) MCP server \u2014 multi-district read + message/document write",
|
|
39062
39566
|
author: "Claude Code (AI) <https://www.anthropic.com/claude>",
|
|
@@ -39101,7 +39605,7 @@ var package_default = {
|
|
|
39101
39605
|
typecheck: "tsc -p tsconfig.json --noEmit"
|
|
39102
39606
|
},
|
|
39103
39607
|
dependencies: {
|
|
39104
|
-
"@chrischall/mcp-utils": "^0.
|
|
39608
|
+
"@chrischall/mcp-utils": "^0.23.2",
|
|
39105
39609
|
"@fetchproxy/bootstrap": "^2.2.0",
|
|
39106
39610
|
"@fetchproxy/server": "^2.2.0",
|
|
39107
39611
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
@@ -40113,15 +40617,71 @@ var FileExistsError = class extends Error {
|
|
|
40113
40617
|
path;
|
|
40114
40618
|
};
|
|
40115
40619
|
|
|
40620
|
+
// src/view.ts
|
|
40621
|
+
var IC_VIEWS = ["compact", "full"];
|
|
40622
|
+
var NOTE = `compact strips image/avatar URLs from the response; "full" returns Infinite Campus's payload untouched. No field projection: this server has no verified record of which Infinite Campus fields matter, and inventing one would risk dropping a field a caller needs.`;
|
|
40623
|
+
var viewArg = () => viewParam(IC_VIEWS, { note: NOTE });
|
|
40624
|
+
function viewResponse(view, data) {
|
|
40625
|
+
const rung = resolveView(view, IC_VIEWS);
|
|
40626
|
+
return minifiedResult(rung === "compact" ? stripMediaUrls(data) : data);
|
|
40627
|
+
}
|
|
40628
|
+
|
|
40116
40629
|
// src/tools/districts.ts
|
|
40117
40630
|
function registerDistrictTools(server, client) {
|
|
40118
40631
|
server.registerTool("ic_list_districts", {
|
|
40119
40632
|
description: "List Infinite Campus districts configured for this MCP server. Returns names + base URLs (no credentials).",
|
|
40633
|
+
inputSchema: {
|
|
40634
|
+
view: viewArg()
|
|
40635
|
+
},
|
|
40120
40636
|
annotations: { readOnlyHint: true }
|
|
40121
|
-
}, async () => {
|
|
40637
|
+
}, async ({ view }) => {
|
|
40122
40638
|
await client.ensureDiscovery();
|
|
40123
40639
|
const data = client.listDistricts();
|
|
40124
|
-
return
|
|
40640
|
+
return viewResponse(view, data);
|
|
40641
|
+
});
|
|
40642
|
+
}
|
|
40643
|
+
|
|
40644
|
+
// src/tools/healthcheck.ts
|
|
40645
|
+
function registerHealthcheckTools(server, state) {
|
|
40646
|
+
registerCredentialHealthcheckTool({
|
|
40647
|
+
server,
|
|
40648
|
+
prefix: "ic",
|
|
40649
|
+
hostLabel: "your Infinite Campus portal",
|
|
40650
|
+
resolveCredential: async () => {
|
|
40651
|
+
if (!state.account || !state.client) {
|
|
40652
|
+
throw state.configError ?? new Error("Infinite Campus is not configured.");
|
|
40653
|
+
}
|
|
40654
|
+
const detail = {
|
|
40655
|
+
base_url: state.account.baseUrl,
|
|
40656
|
+
configured_district: state.account.district,
|
|
40657
|
+
auth_source: state.source ?? "unknown"
|
|
40658
|
+
};
|
|
40659
|
+
try {
|
|
40660
|
+
await state.client.ensureDiscovery();
|
|
40661
|
+
const districts = state.client.listDistricts();
|
|
40662
|
+
detail.districts = districts.map((d) => ({ name: d.name, linked: d.linked }));
|
|
40663
|
+
const linked = districts.filter((d) => d.linked).map((d) => d.name);
|
|
40664
|
+
detail.configured_district_is_linked = districts.some(
|
|
40665
|
+
(d) => d.name === state.account.district && d.linked
|
|
40666
|
+
);
|
|
40667
|
+
if (linked.length > 0) detail.linked_districts = linked;
|
|
40668
|
+
} catch {
|
|
40669
|
+
detail.districts = "unavailable (discovery needs a live session)";
|
|
40670
|
+
}
|
|
40671
|
+
return { source: state.source ?? "env", detail };
|
|
40672
|
+
},
|
|
40673
|
+
// Probe the district the account is actually LINKED to when that differs
|
|
40674
|
+
// from the configured one — probing a district you are not enrolled in
|
|
40675
|
+
// fails for a reason that has nothing to do with your credentials.
|
|
40676
|
+
probeFn: () => {
|
|
40677
|
+
const districts = state.client.listDistricts();
|
|
40678
|
+
const linked = districts.find((d) => d.linked);
|
|
40679
|
+
const district = linked?.name ?? state.account.district;
|
|
40680
|
+
return state.client.request(district, "/campus/api/portal/students");
|
|
40681
|
+
},
|
|
40682
|
+
hints: {
|
|
40683
|
+
credential_rejected: "Infinite Campus rejected the credentials. Check IC_USERNAME/IC_PASSWORD, or sign into your IC portal in the browser so the fetchproxy fallback can lift a session."
|
|
40684
|
+
}
|
|
40125
40685
|
});
|
|
40126
40686
|
}
|
|
40127
40687
|
|
|
@@ -40133,11 +40693,11 @@ function registerStudentTools(server, client) {
|
|
|
40133
40693
|
server.registerTool("ic_list_students", {
|
|
40134
40694
|
description: "List students enrolled under the parent account for a given district.",
|
|
40135
40695
|
annotations: { readOnlyHint: true },
|
|
40136
|
-
inputSchema: argsSchema.shape
|
|
40696
|
+
inputSchema: { ...argsSchema.shape, view: viewArg() }
|
|
40137
40697
|
}, async (rawArgs) => {
|
|
40138
40698
|
const args = argsSchema.parse(rawArgs);
|
|
40139
40699
|
const data = await client.request(args.district, "/campus/api/portal/students");
|
|
40140
|
-
return
|
|
40700
|
+
return viewResponse(rawArgs.view, data);
|
|
40141
40701
|
});
|
|
40142
40702
|
}
|
|
40143
40703
|
|
|
@@ -40152,12 +40712,12 @@ function registerScheduleTools(server, client) {
|
|
|
40152
40712
|
server.registerTool("ic_get_schedule", {
|
|
40153
40713
|
description: "Get a student's class schedule for a given date (default: today).",
|
|
40154
40714
|
annotations: { readOnlyHint: true },
|
|
40155
|
-
inputSchema: argsSchema2.shape
|
|
40715
|
+
inputSchema: { ...argsSchema2.shape, view: viewArg() }
|
|
40156
40716
|
}, async (rawArgs) => {
|
|
40157
40717
|
const args = argsSchema2.parse(rawArgs);
|
|
40158
40718
|
const params = new URLSearchParams({ personID: args.studentId });
|
|
40159
40719
|
const data = await client.request(args.district, `/campus/resources/portal/roster?${params}`);
|
|
40160
|
-
return
|
|
40720
|
+
return viewResponse(rawArgs.view, data);
|
|
40161
40721
|
});
|
|
40162
40722
|
}
|
|
40163
40723
|
|
|
@@ -40174,7 +40734,7 @@ function registerAssignmentTools(server, client) {
|
|
|
40174
40734
|
server.registerTool("ic_list_assignments", {
|
|
40175
40735
|
description: "List a student's assignments. The IC endpoint returns the full term history (~hundreds of items); date and missing filters are applied client-side. For a single course, pass courseId (the sectionID from ic_get_schedule).",
|
|
40176
40736
|
annotations: { readOnlyHint: true },
|
|
40177
|
-
inputSchema: argsSchema3.shape
|
|
40737
|
+
inputSchema: { ...argsSchema3.shape, view: viewArg() }
|
|
40178
40738
|
}, async (rawArgs) => {
|
|
40179
40739
|
const args = argsSchema3.parse(rawArgs);
|
|
40180
40740
|
const params = new URLSearchParams({ personID: args.studentId });
|
|
@@ -40195,7 +40755,7 @@ function registerAssignmentTools(server, client) {
|
|
|
40195
40755
|
if (args.missingOnly) {
|
|
40196
40756
|
data = data.filter((a) => a.missing);
|
|
40197
40757
|
}
|
|
40198
|
-
return
|
|
40758
|
+
return viewResponse(rawArgs.view, data);
|
|
40199
40759
|
});
|
|
40200
40760
|
}
|
|
40201
40761
|
|
|
@@ -40209,13 +40769,13 @@ function registerGradeTools(server, client) {
|
|
|
40209
40769
|
server.registerTool("ic_list_grades", {
|
|
40210
40770
|
description: "List a student's term grades and in-progress course grades.",
|
|
40211
40771
|
annotations: { readOnlyHint: true },
|
|
40212
|
-
inputSchema: argsSchema4.shape
|
|
40772
|
+
inputSchema: { ...argsSchema4.shape, view: viewArg() }
|
|
40213
40773
|
}, async (rawArgs) => {
|
|
40214
40774
|
const args = argsSchema4.parse(rawArgs);
|
|
40215
40775
|
const params = new URLSearchParams({ personID: args.studentId });
|
|
40216
40776
|
if (args.termId) params.set("termID", args.termId);
|
|
40217
40777
|
const data = await client.request(args.district, `/campus/resources/portal/grades?${params}`);
|
|
40218
|
-
return
|
|
40778
|
+
return viewResponse(rawArgs.view, data);
|
|
40219
40779
|
});
|
|
40220
40780
|
}
|
|
40221
40781
|
|
|
@@ -40224,14 +40784,14 @@ function is404(e) {
|
|
|
40224
40784
|
return e instanceof Error && e.message.startsWith("IC 404 ");
|
|
40225
40785
|
}
|
|
40226
40786
|
function featureDisabled(feature, district, data = []) {
|
|
40227
|
-
return
|
|
40787
|
+
return minifiedResult({ warning: "FeatureDisabled", feature, district, data });
|
|
40228
40788
|
}
|
|
40229
40789
|
async function findStudent(client, district, studentId) {
|
|
40230
40790
|
const students = await client.request(district, "/campus/api/portal/students");
|
|
40231
40791
|
return students.find((s) => String(s.personID) === studentId) ?? null;
|
|
40232
40792
|
}
|
|
40233
40793
|
function studentNotFound(studentId) {
|
|
40234
|
-
return
|
|
40794
|
+
return minifiedResult({ error: "StudentNotFound", studentId });
|
|
40235
40795
|
}
|
|
40236
40796
|
async function checkFeatureDisabled(client, district, studentId, student, flag, toolName, emptyData = []) {
|
|
40237
40797
|
const structureID = student.enrollments?.[0]?.structureID;
|
|
@@ -40284,7 +40844,7 @@ function registerAttendanceTools(server, client) {
|
|
|
40284
40844
|
server.registerTool("ic_list_attendance", {
|
|
40285
40845
|
description: "List a student's absences and tardies (per-course summary grouped by term). Auto-resolves enrollmentID from the student record.",
|
|
40286
40846
|
annotations: { readOnlyHint: true },
|
|
40287
|
-
inputSchema: argsSchema5.shape
|
|
40847
|
+
inputSchema: { ...argsSchema5.shape, view: viewArg() }
|
|
40288
40848
|
}, async (rawArgs) => {
|
|
40289
40849
|
const args = argsSchema5.parse(rawArgs);
|
|
40290
40850
|
const student = await findStudent(client, args.district, args.studentId);
|
|
@@ -40314,7 +40874,7 @@ function registerAttendanceTools(server, client) {
|
|
|
40314
40874
|
results.push({ ...entry, terms: trimmedTerms });
|
|
40315
40875
|
}
|
|
40316
40876
|
}
|
|
40317
|
-
return
|
|
40877
|
+
return viewResponse(rawArgs.view, results);
|
|
40318
40878
|
} catch (e) {
|
|
40319
40879
|
if (is404(e)) return featureDisabled("attendance", args.district);
|
|
40320
40880
|
throw e;
|
|
@@ -40333,7 +40893,7 @@ function registerBehaviorTools(server, client) {
|
|
|
40333
40893
|
server.registerTool("ic_list_behavior", {
|
|
40334
40894
|
description: "List a student's behavior events / referrals. Returns FeatureDisabled if the district has the behavior module turned off (detected via displayOptions or a 404 backstop).",
|
|
40335
40895
|
annotations: { readOnlyHint: true },
|
|
40336
|
-
inputSchema: argsSchema6.shape
|
|
40896
|
+
inputSchema: { ...argsSchema6.shape, view: viewArg() }
|
|
40337
40897
|
}, async (rawArgs) => {
|
|
40338
40898
|
const args = argsSchema6.parse(rawArgs);
|
|
40339
40899
|
const student = await findStudent(client, args.district, args.studentId);
|
|
@@ -40345,7 +40905,7 @@ function registerBehaviorTools(server, client) {
|
|
|
40345
40905
|
if (args.until) params.set("endDate", args.until);
|
|
40346
40906
|
try {
|
|
40347
40907
|
const data = await client.request(args.district, `/campus/resources/portal/behavior?${params}`);
|
|
40348
|
-
return
|
|
40908
|
+
return viewResponse(rawArgs.view, data);
|
|
40349
40909
|
} catch (e) {
|
|
40350
40910
|
if (is404(e)) return featureDisabled("behavior", args.district);
|
|
40351
40911
|
throw e;
|
|
@@ -40365,7 +40925,7 @@ function registerFoodServiceTools(server, client) {
|
|
|
40365
40925
|
server.registerTool("ic_list_food_service", {
|
|
40366
40926
|
description: "List a student's lunch balance and recent food-service transactions. Returns FeatureDisabled if the district has the module turned off (detected via displayOptions or a 404 backstop).",
|
|
40367
40927
|
annotations: { readOnlyHint: true },
|
|
40368
|
-
inputSchema: argsSchema7.shape
|
|
40928
|
+
inputSchema: { ...argsSchema7.shape, view: viewArg() }
|
|
40369
40929
|
}, async (rawArgs) => {
|
|
40370
40930
|
const args = argsSchema7.parse(rawArgs);
|
|
40371
40931
|
const student = await findStudent(client, args.district, args.studentId);
|
|
@@ -40385,7 +40945,7 @@ function registerFoodServiceTools(server, client) {
|
|
|
40385
40945
|
if (args.until) params.set("endDate", args.until);
|
|
40386
40946
|
try {
|
|
40387
40947
|
const data = await client.request(args.district, `/campus/resources/portal/foodService?${params}`);
|
|
40388
|
-
return
|
|
40948
|
+
return viewResponse(rawArgs.view, data);
|
|
40389
40949
|
} catch (e) {
|
|
40390
40950
|
if (is404(e)) return featureDisabled("foodService", args.district, EMPTY_FOOD);
|
|
40391
40951
|
throw e;
|
|
@@ -40510,7 +41070,7 @@ function registerMessageTools(server, client) {
|
|
|
40510
41070
|
server.registerTool("ic_list_messages", {
|
|
40511
41071
|
description: "List all parent-visible messages from three IC sources combined: (1) prism notifications (assignment alerts, grade postings, attendance alerts), (2) Messenger 2.0 inbox (teacher messages, district announcements with newMessage/actionRequired flags), and (3) portal userNotice announcements. Each section has its own count and items; if any source errors, that section contains an error field and the others still return normally. The `limit` arg caps the prism notifications only (the high-volume source). Note: listing inbox messages does not mark them as read in normal portal behavior, but some district configurations may update read-tracking; use ic_get_message for the full HTML body.",
|
|
40512
41072
|
annotations: { readOnlyHint: true },
|
|
40513
|
-
inputSchema: listArgs.shape
|
|
41073
|
+
inputSchema: { ...listArgs.shape, view: viewArg() }
|
|
40514
41074
|
}, async (rawArgs) => {
|
|
40515
41075
|
const args = listArgs.parse(rawArgs);
|
|
40516
41076
|
const limit = args.limit ?? 20;
|
|
@@ -40543,18 +41103,18 @@ function registerMessageTools(server, client) {
|
|
|
40543
41103
|
return { count: 0, items: [], error: e instanceof Error ? e.message : String(e) };
|
|
40544
41104
|
});
|
|
40545
41105
|
const [notifications, inbox, announcements] = await Promise.all([prismPromise, inboxPromise, noticePromise]);
|
|
40546
|
-
return
|
|
41106
|
+
return viewResponse(rawArgs.view, { notifications, inbox, announcements });
|
|
40547
41107
|
});
|
|
40548
41108
|
server.registerTool("ic_get_message", {
|
|
40549
41109
|
description: "Fetch the HTML body of an inbox message and return it parsed into { subject, date, body, url }. Takes a `messageUrl` which is the `url` field from an item returned by ic_list_messages' inbox section (e.g. 'portal/messageView.xsl?x=messenger.MessengerEngine-getMessageRecipientView&messageID=...'). Relative and /campus/-prefixed URLs are both accepted. Note: fetching the HTML body may mark the message as read on some district configurations; probe against an empty inbox could not confirm the side effect.",
|
|
40550
41110
|
annotations: { readOnlyHint: true },
|
|
40551
|
-
inputSchema: getArgs.shape
|
|
41111
|
+
inputSchema: { ...getArgs.shape, view: viewArg() }
|
|
40552
41112
|
}, async (rawArgs) => {
|
|
40553
41113
|
const args = getArgs.parse(rawArgs);
|
|
40554
41114
|
const path = normalizeMessageUrl(args.messageUrl);
|
|
40555
41115
|
const html = await client.request(args.district, path, { responseType: "text" });
|
|
40556
41116
|
const parsed = parseMessageHtml(html ?? "", path);
|
|
40557
|
-
return
|
|
41117
|
+
return viewResponse(rawArgs.view, parsed);
|
|
40558
41118
|
});
|
|
40559
41119
|
}
|
|
40560
41120
|
|
|
@@ -40573,7 +41133,7 @@ function registerDocumentTools(server, client) {
|
|
|
40573
41133
|
server.registerTool("ic_list_documents", {
|
|
40574
41134
|
description: "List a student's available documents (report cards, transcripts, schedules). Returns metadata only \u2014 use ic_download_document to fetch the file. Returns FeatureDisabled if the district has the module turned off.",
|
|
40575
41135
|
annotations: { readOnlyHint: true },
|
|
40576
|
-
inputSchema: listArgs2.shape
|
|
41136
|
+
inputSchema: { ...listArgs2.shape, view: viewArg() }
|
|
40577
41137
|
}, async (rawArgs) => {
|
|
40578
41138
|
const args = listArgs2.parse(rawArgs);
|
|
40579
41139
|
const student = await findStudent(client, args.district, args.studentId);
|
|
@@ -40594,7 +41154,7 @@ function registerDocumentTools(server, client) {
|
|
|
40594
41154
|
if (d.endYear !== void 0) out.endYear = d.endYear;
|
|
40595
41155
|
return out;
|
|
40596
41156
|
});
|
|
40597
|
-
return
|
|
41157
|
+
return viewResponse(rawArgs.view, trimmed);
|
|
40598
41158
|
} catch (e) {
|
|
40599
41159
|
if (is404(e)) return featureDisabled("documents", args.district);
|
|
40600
41160
|
throw e;
|
|
@@ -40610,10 +41170,10 @@ function registerDocumentTools(server, client) {
|
|
|
40610
41170
|
const meta3 = await client.download(args.district, args.documentId, args.destinationPath, {
|
|
40611
41171
|
overwrite: args.overwrite ?? false
|
|
40612
41172
|
});
|
|
40613
|
-
return
|
|
41173
|
+
return minifiedResult(meta3);
|
|
40614
41174
|
} catch (e) {
|
|
40615
41175
|
if (e instanceof Error && e.message.startsWith("IC download 404")) {
|
|
40616
|
-
return
|
|
41176
|
+
return minifiedResult({ warning: "FeatureDisabled", feature: "documents", district: args.district });
|
|
40617
41177
|
}
|
|
40618
41178
|
throw e;
|
|
40619
41179
|
}
|
|
@@ -40631,7 +41191,7 @@ function registerCalendarTools(server, client) {
|
|
|
40631
41191
|
server.registerTool("ic_list_school_days", {
|
|
40632
41192
|
description: "List a student's school days (instructional calendar) grouped by term. Returns one entry per enrollment, with term boundaries (Q1-Q4 start/end dates) and the school days inside each term \u2014 including comments like 'Teacher Workday' or 'Spring Break'. Use since/until to narrow the range.",
|
|
40633
41193
|
annotations: { readOnlyHint: true },
|
|
40634
|
-
inputSchema: argsSchema8.shape
|
|
41194
|
+
inputSchema: { ...argsSchema8.shape, view: viewArg() }
|
|
40635
41195
|
}, async (rawArgs) => {
|
|
40636
41196
|
const args = argsSchema8.parse(rawArgs);
|
|
40637
41197
|
const student = await findStudent(client, args.district, args.studentId);
|
|
@@ -40669,7 +41229,7 @@ function registerCalendarTools(server, client) {
|
|
|
40669
41229
|
terms: trimmedTerms
|
|
40670
41230
|
});
|
|
40671
41231
|
}
|
|
40672
|
-
return
|
|
41232
|
+
return viewResponse(rawArgs.view, result);
|
|
40673
41233
|
});
|
|
40674
41234
|
}
|
|
40675
41235
|
|
|
@@ -40727,7 +41287,7 @@ function registerAttendanceEventsTools(server, client) {
|
|
|
40727
41287
|
server.registerTool("ic_list_attendance_events", {
|
|
40728
41288
|
description: "List individual attendance events (absences, tardies, early releases) for a student. Each event has a code, description, excuse reason, and optional human-readable comments. Auto-resolves enrollmentID from the student record. Use since/until to filter by date and excusedOnly to show only excused events.",
|
|
40729
41289
|
annotations: { readOnlyHint: true },
|
|
40730
|
-
inputSchema: argsSchema9.shape
|
|
41290
|
+
inputSchema: { ...argsSchema9.shape, view: viewArg() }
|
|
40731
41291
|
}, async (rawArgs) => {
|
|
40732
41292
|
const args = argsSchema9.parse(rawArgs);
|
|
40733
41293
|
const student = await findStudent(client, args.district, args.studentId);
|
|
@@ -40760,7 +41320,7 @@ function registerAttendanceEventsTools(server, client) {
|
|
|
40760
41320
|
results.push(trimmed);
|
|
40761
41321
|
}
|
|
40762
41322
|
}
|
|
40763
|
-
return
|
|
41323
|
+
return viewResponse(rawArgs.view, results);
|
|
40764
41324
|
} catch (e) {
|
|
40765
41325
|
if (is404(e)) return featureDisabled("attendance_events", args.district);
|
|
40766
41326
|
throw e;
|
|
@@ -40799,7 +41359,7 @@ function registerRecentGradesTools(server, client) {
|
|
|
40799
41359
|
server.registerTool("ic_list_recent_grades", {
|
|
40800
41360
|
description: "List recently-graded assignments for a student. Server-side filtered by scoreModifiedDate. Pass since=YYYY-MM-DD to set the cutoff; defaults to 14 days ago.",
|
|
40801
41361
|
annotations: { readOnlyHint: true },
|
|
40802
|
-
inputSchema: argsSchema10.shape
|
|
41362
|
+
inputSchema: { ...argsSchema10.shape, view: viewArg() }
|
|
40803
41363
|
}, async (rawArgs) => {
|
|
40804
41364
|
const args = argsSchema10.parse(rawArgs);
|
|
40805
41365
|
const sinceDate = args.since ?? defaultSinceDate(/* @__PURE__ */ new Date());
|
|
@@ -40816,7 +41376,7 @@ function registerRecentGradesTools(server, client) {
|
|
|
40816
41376
|
}
|
|
40817
41377
|
return out;
|
|
40818
41378
|
});
|
|
40819
|
-
return
|
|
41379
|
+
return viewResponse(rawArgs.view, trimmed);
|
|
40820
41380
|
});
|
|
40821
41381
|
}
|
|
40822
41382
|
|
|
@@ -40850,7 +41410,7 @@ function registerTeacherTools(server, client) {
|
|
|
40850
41410
|
server.registerTool("ic_list_teachers", {
|
|
40851
41411
|
description: "List a student's teachers (per enrolled section) and assigned counselor(s). Combines two endpoints (section/contacts and studentCounselor/byUser). Response field shapes may vary slightly by district \u2014 core fields (firstName, lastName, email) are consistent; additional fields are passed through.",
|
|
40852
41412
|
annotations: { readOnlyHint: true },
|
|
40853
|
-
inputSchema: argsSchema11.shape
|
|
41413
|
+
inputSchema: { ...argsSchema11.shape, view: viewArg() }
|
|
40854
41414
|
}, async (rawArgs) => {
|
|
40855
41415
|
const args = argsSchema11.parse(rawArgs);
|
|
40856
41416
|
const personID = encodeURIComponent(args.studentId);
|
|
@@ -40871,7 +41431,7 @@ function registerTeacherTools(server, client) {
|
|
|
40871
41431
|
const [teachersRaw, counselorsRaw] = await Promise.all([teachersPromise, counselorsPromise]);
|
|
40872
41432
|
const teachers = toArray(teachersRaw).map((t) => trimRecord(t));
|
|
40873
41433
|
const counselors = toArray(counselorsRaw).map((c) => trimRecord(c));
|
|
40874
|
-
return
|
|
41434
|
+
return viewResponse(rawArgs.view, { counselors, teachers });
|
|
40875
41435
|
});
|
|
40876
41436
|
}
|
|
40877
41437
|
|
|
@@ -40884,7 +41444,7 @@ function registerAssessmentTools(server, client) {
|
|
|
40884
41444
|
server.registerTool("ic_list_assessments", {
|
|
40885
41445
|
description: "List a student's standardized test scores (state, national, district tests). Auto-resolves calendarID from each of the student's enrollments and returns one entry per enrollment. The shape of individual test records varies by district and test type \u2014 fields are passed through unchanged.",
|
|
40886
41446
|
annotations: { readOnlyHint: true },
|
|
40887
|
-
inputSchema: argsSchema12.shape
|
|
41447
|
+
inputSchema: { ...argsSchema12.shape, view: viewArg() }
|
|
40888
41448
|
}, async (rawArgs) => {
|
|
40889
41449
|
const args = argsSchema12.parse(rawArgs);
|
|
40890
41450
|
const student = await findStudent(client, args.district, args.studentId);
|
|
@@ -40922,7 +41482,7 @@ function registerAssessmentTools(server, client) {
|
|
|
40922
41482
|
if (feature404 && result.length === 0) {
|
|
40923
41483
|
return featureDisabled("assessments", args.district);
|
|
40924
41484
|
}
|
|
40925
|
-
return
|
|
41485
|
+
return viewResponse(rawArgs.view, result);
|
|
40926
41486
|
});
|
|
40927
41487
|
}
|
|
40928
41488
|
|
|
@@ -40935,7 +41495,7 @@ function registerFeeTools(server, client) {
|
|
|
40935
41495
|
server.registerTool("ic_list_fees", {
|
|
40936
41496
|
description: "List a student's fee assignments (charges owed) and running balance/surplus. Combines two endpoints: fee assignments and totalSurplus. Returns FeatureDisabled only if both endpoints 404; if only one works, returns that side with warning: 'PartialSuccess' and an issues[] explaining which endpoint failed.",
|
|
40937
41497
|
annotations: { readOnlyHint: true },
|
|
40938
|
-
inputSchema: argsSchema13.shape
|
|
41498
|
+
inputSchema: { ...argsSchema13.shape, view: viewArg() }
|
|
40939
41499
|
}, async (rawArgs) => {
|
|
40940
41500
|
const args = argsSchema13.parse(rawArgs);
|
|
40941
41501
|
const personIDEnc = encodeURIComponent(args.studentId);
|
|
@@ -40966,7 +41526,7 @@ function registerFeeTools(server, client) {
|
|
|
40966
41526
|
feeAssignments: assignments.ok ? assignments.value : [],
|
|
40967
41527
|
...issues.length > 0 ? { issues } : {}
|
|
40968
41528
|
};
|
|
40969
|
-
return
|
|
41529
|
+
return viewResponse(rawArgs.view, response);
|
|
40970
41530
|
});
|
|
40971
41531
|
}
|
|
40972
41532
|
|
|
@@ -40979,7 +41539,7 @@ function registerFeaturesTools(server, client) {
|
|
|
40979
41539
|
server.registerTool("ic_get_features", {
|
|
40980
41540
|
description: "List the district's displayOptions feature-flag allow-list for each of a student's enrollments. Each enrollment's `features` object is a map of ~90 flag names (attendance, behavior, assessment, documents, grades, schedule, etc.) to booleans. A `false` value means the district has that feature disabled for this enrollment; `true` or missing means it's available. Used internally by other tools to short-circuit disabled features, but exposed here so the LLM can answer capability questions directly.",
|
|
40981
41541
|
annotations: { readOnlyHint: true },
|
|
40982
|
-
inputSchema: argsSchema14.shape
|
|
41542
|
+
inputSchema: { ...argsSchema14.shape, view: viewArg() }
|
|
40983
41543
|
}, async (rawArgs) => {
|
|
40984
41544
|
const args = argsSchema14.parse(rawArgs);
|
|
40985
41545
|
const student = await findStudent(client, args.district, args.studentId);
|
|
@@ -40994,7 +41554,7 @@ function registerFeaturesTools(server, client) {
|
|
|
40994
41554
|
features
|
|
40995
41555
|
});
|
|
40996
41556
|
}
|
|
40997
|
-
return
|
|
41557
|
+
return viewResponse(rawArgs.view, result);
|
|
40998
41558
|
});
|
|
40999
41559
|
}
|
|
41000
41560
|
|
|
@@ -41018,12 +41578,15 @@ try {
|
|
|
41018
41578
|
}
|
|
41019
41579
|
var COMMON = {
|
|
41020
41580
|
name: "infinitecampus",
|
|
41021
|
-
version: "2.
|
|
41581
|
+
version: "2.8.0"
|
|
41022
41582
|
// x-release-please-version
|
|
41023
41583
|
};
|
|
41584
|
+
var healthState = { account, source, configError, client: null };
|
|
41024
41585
|
if (account) {
|
|
41025
41586
|
const client = new ICClient(account, { refreshSession });
|
|
41587
|
+
healthState.client = client;
|
|
41026
41588
|
const tools = [
|
|
41589
|
+
(server) => registerHealthcheckTools(server, healthState),
|
|
41027
41590
|
registerDistrictTools,
|
|
41028
41591
|
registerStudentTools,
|
|
41029
41592
|
registerScheduleTools,
|
|
@@ -41049,6 +41612,10 @@ ${AI_NOTICE}` });
|
|
|
41049
41612
|
} else {
|
|
41050
41613
|
const notConfigured = `[infinitecampus-mcp] Not configured: ${configError?.message ?? "unknown error"}
|
|
41051
41614
|
[infinitecampus-mcp] Server is running with no tools registered. Set the required env vars and reinstall.`;
|
|
41052
|
-
await runMcp({
|
|
41053
|
-
|
|
41615
|
+
await runMcp({
|
|
41616
|
+
...COMMON,
|
|
41617
|
+
tools: [(server) => registerHealthcheckTools(server, healthState)],
|
|
41618
|
+
banner: `${notConfigured}
|
|
41619
|
+
${AI_NOTICE}`
|
|
41620
|
+
});
|
|
41054
41621
|
}
|