untappd-mcp 2.1.1 → 2.1.3
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 +2 -0
- package/dist/bundle.js +403 -129
- package/dist/cache/store.js +14 -4
- package/dist/cache/sync-beers.js +54 -25
- package/dist/tools/checkin.js +199 -32
- package/dist/version.js +1 -1
- package/mint.yaml +9 -0
- package/package.json +4 -4
- package/server.json +2 -2
package/dist/bundle.js
CHANGED
|
@@ -1585,8 +1585,8 @@ var require_regexes = __commonJS({
|
|
|
1585
1585
|
}
|
|
1586
1586
|
exports.ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
|
|
1587
1587
|
exports.ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
|
|
1588
|
-
var mac3 = (
|
|
1589
|
-
const escapedDelim = util.escapeRegex(
|
|
1588
|
+
var mac3 = (delimiter2) => {
|
|
1589
|
+
const escapedDelim = util.escapeRegex(delimiter2 ?? ":");
|
|
1590
1590
|
return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
|
|
1591
1591
|
};
|
|
1592
1592
|
exports.mac = mac3;
|
|
@@ -2282,7 +2282,7 @@ var require_versions = __commonJS({
|
|
|
2282
2282
|
exports.version = {
|
|
2283
2283
|
major: 4,
|
|
2284
2284
|
minor: 6,
|
|
2285
|
-
patch:
|
|
2285
|
+
patch: 5
|
|
2286
2286
|
};
|
|
2287
2287
|
(function() {
|
|
2288
2288
|
var keys = Object.getOwnPropertyNames(exports);
|
|
@@ -4851,7 +4851,7 @@ var require_memoizer = __commonJS({
|
|
|
4851
4851
|
var NONE2 = 0;
|
|
4852
4852
|
var ASSUMED2 = 1;
|
|
4853
4853
|
var PROVEN2 = 2;
|
|
4854
|
-
function isRecursive2(inst, stack,
|
|
4854
|
+
function isRecursive2(inst, stack, resolve3) {
|
|
4855
4855
|
const cached2 = recursive2.get(inst);
|
|
4856
4856
|
if (cached2 !== void 0)
|
|
4857
4857
|
return cached2 ? PROVEN2 : NONE2;
|
|
@@ -4861,7 +4861,7 @@ var require_memoizer = __commonJS({
|
|
|
4861
4861
|
let result = NONE2;
|
|
4862
4862
|
const check2 = (child) => {
|
|
4863
4863
|
if (result !== PROVEN2 && child?._zod) {
|
|
4864
|
-
const answer = isRecursive2(child, stack,
|
|
4864
|
+
const answer = isRecursive2(child, stack, resolve3);
|
|
4865
4865
|
if (answer > result)
|
|
4866
4866
|
result = answer;
|
|
4867
4867
|
}
|
|
@@ -4872,7 +4872,7 @@ var require_memoizer = __commonJS({
|
|
|
4872
4872
|
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
4873
4873
|
if (spread && !desc.enumerable)
|
|
4874
4874
|
continue;
|
|
4875
|
-
const child = desc.get ? ASSUMED2 : desc.value?._zod ? isRecursive2(desc.value, stack,
|
|
4875
|
+
const child = desc.get ? ASSUMED2 : desc.value?._zod ? isRecursive2(desc.value, stack, resolve3) : NONE2;
|
|
4876
4876
|
if (child > answer)
|
|
4877
4877
|
answer = child;
|
|
4878
4878
|
}
|
|
@@ -4936,7 +4936,7 @@ var require_memoizer = __commonJS({
|
|
|
4936
4936
|
break;
|
|
4937
4937
|
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
4938
4938
|
case "lazy": {
|
|
4939
|
-
const inner = def._cachedInner ?? (
|
|
4939
|
+
const inner = def._cachedInner ?? (resolve3 ? inst._zod.innerType : void 0);
|
|
4940
4940
|
merge2(inner ? isRecursive2(inner, stack, false) : ASSUMED2);
|
|
4941
4941
|
break;
|
|
4942
4942
|
}
|
|
@@ -5000,7 +5000,7 @@ var require_memoizer = __commonJS({
|
|
|
5000
5000
|
return bucket;
|
|
5001
5001
|
}
|
|
5002
5002
|
var handoff2;
|
|
5003
|
-
var
|
|
5003
|
+
var open3 = [];
|
|
5004
5004
|
var memo3 = {
|
|
5005
5005
|
alloc(_inst, payload, empty) {
|
|
5006
5006
|
const bucket = handoff2;
|
|
@@ -5009,7 +5009,7 @@ var require_memoizer = __commonJS({
|
|
|
5009
5009
|
handoff2 = void 0;
|
|
5010
5010
|
const entry = { value: empty, issues: null };
|
|
5011
5011
|
bucket.set(payload.value, entry);
|
|
5012
|
-
|
|
5012
|
+
open3.push(entry);
|
|
5013
5013
|
return empty;
|
|
5014
5014
|
},
|
|
5015
5015
|
guard(inst) {
|
|
@@ -5080,10 +5080,10 @@ var require_memoizer = __commonJS({
|
|
|
5080
5080
|
return payload;
|
|
5081
5081
|
}
|
|
5082
5082
|
handoff2 = bucket;
|
|
5083
|
-
const depth =
|
|
5083
|
+
const depth = open3.length;
|
|
5084
5084
|
const result = base(payload, ctx);
|
|
5085
5085
|
handoff2 = void 0;
|
|
5086
|
-
const entry =
|
|
5086
|
+
const entry = open3.length > depth ? open3.pop() : void 0;
|
|
5087
5087
|
if (result instanceof Promise) {
|
|
5088
5088
|
return result.then((r) => {
|
|
5089
5089
|
if (entry)
|
|
@@ -27718,14 +27718,14 @@ function inputRequiredRoundsExceededMessage(method, maxRounds) {
|
|
|
27718
27718
|
return `Multi-round-trip request '${method}' still required input after ${maxRounds} rounds (inputRequired.maxRounds)`;
|
|
27719
27719
|
}
|
|
27720
27720
|
function sleep(ms, signal) {
|
|
27721
|
-
return new Promise((
|
|
27721
|
+
return new Promise((resolve3, reject) => {
|
|
27722
27722
|
if (signal?.aborted) {
|
|
27723
27723
|
reject(signal.reason instanceof SdkError ? signal.reason : new SdkError(SdkErrorCode.RequestTimeout, String(signal.reason)));
|
|
27724
27724
|
return;
|
|
27725
27725
|
}
|
|
27726
27726
|
const timer = setTimeout(() => {
|
|
27727
27727
|
signal?.removeEventListener("abort", onAbort);
|
|
27728
|
-
|
|
27728
|
+
resolve3();
|
|
27729
27729
|
}, ms);
|
|
27730
27730
|
const onAbort = () => {
|
|
27731
27731
|
clearTimeout(timer);
|
|
@@ -28519,7 +28519,7 @@ var Protocol = class {
|
|
|
28519
28519
|
const flowStartedAt = Date.now();
|
|
28520
28520
|
let onAbort;
|
|
28521
28521
|
let cleanupMessageId;
|
|
28522
|
-
return new Promise((
|
|
28522
|
+
return new Promise((resolve3, reject) => {
|
|
28523
28523
|
const earlyReject = (error62) => {
|
|
28524
28524
|
reject(error62);
|
|
28525
28525
|
};
|
|
@@ -28587,7 +28587,7 @@ var Protocol = class {
|
|
|
28587
28587
|
}
|
|
28588
28588
|
if (decoded.kind === "invalid") return reject(decoded.error);
|
|
28589
28589
|
if (decoded.kind === "input_required") {
|
|
28590
|
-
if (options?.allowInputRequired === true) return
|
|
28590
|
+
if (options?.allowInputRequired === true) return resolve3(manualInputRequiredValue(decoded));
|
|
28591
28591
|
const flow = {
|
|
28592
28592
|
codec: codec2,
|
|
28593
28593
|
request,
|
|
@@ -28599,11 +28599,11 @@ var Protocol = class {
|
|
|
28599
28599
|
params
|
|
28600
28600
|
}, resultSchema, legOptions)
|
|
28601
28601
|
};
|
|
28602
|
-
return
|
|
28602
|
+
return resolve3(this._resolveNonCompleteResult(decoded, flow));
|
|
28603
28603
|
}
|
|
28604
28604
|
const result = decoded.result;
|
|
28605
28605
|
validateStandardSchema(resultSchema, result).then((parseResult) => {
|
|
28606
|
-
if (parseResult.success)
|
|
28606
|
+
if (parseResult.success) resolve3(parseResult.data);
|
|
28607
28607
|
else reject(new SdkError(SdkErrorCode.InvalidResult, `Invalid result for ${request.method}: ${parseResult.error}`));
|
|
28608
28608
|
}, reject);
|
|
28609
28609
|
});
|
|
@@ -31515,7 +31515,7 @@ var require_compile2 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
31515
31515
|
ref = (0, resolve_1.resolveUrl)(this.opts.uriResolver, baseId, ref);
|
|
31516
31516
|
const schOrFunc = root.refs[ref];
|
|
31517
31517
|
if (schOrFunc) return schOrFunc;
|
|
31518
|
-
let _sch =
|
|
31518
|
+
let _sch = resolve3.call(this, root, ref);
|
|
31519
31519
|
if (_sch === void 0) {
|
|
31520
31520
|
const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
|
|
31521
31521
|
const { schemaId } = this.opts;
|
|
@@ -31541,7 +31541,7 @@ var require_compile2 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
31541
31541
|
function sameSchemaEnv(s1, s2) {
|
|
31542
31542
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
31543
31543
|
}
|
|
31544
|
-
function
|
|
31544
|
+
function resolve3(root, ref) {
|
|
31545
31545
|
let sch;
|
|
31546
31546
|
while (typeof (sch = this.refs[ref]) == "string") ref = sch;
|
|
31547
31547
|
return sch || this.schemas[ref] || resolveSchema.call(this, root, ref);
|
|
@@ -31991,47 +31991,47 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
31991
31991
|
else if (typeof uri === "object") uri = parse3(serialize(uri, options), options);
|
|
31992
31992
|
return uri;
|
|
31993
31993
|
}
|
|
31994
|
-
function
|
|
31994
|
+
function resolve3(baseURI, relativeURI, options) {
|
|
31995
31995
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
31996
31996
|
const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
31997
31997
|
schemelessOptions.skipEscape = true;
|
|
31998
31998
|
return serialize(resolved, schemelessOptions);
|
|
31999
31999
|
}
|
|
32000
|
-
function resolveComponent(base,
|
|
32000
|
+
function resolveComponent(base, relative2, options, skipNormalization) {
|
|
32001
32001
|
const target = {};
|
|
32002
32002
|
if (!skipNormalization) {
|
|
32003
32003
|
base = parse3(serialize(base, options), options);
|
|
32004
|
-
|
|
32004
|
+
relative2 = parse3(serialize(relative2, options), options);
|
|
32005
32005
|
}
|
|
32006
32006
|
options = options || {};
|
|
32007
|
-
if (!options.tolerant &&
|
|
32008
|
-
target.scheme =
|
|
32009
|
-
target.userinfo =
|
|
32010
|
-
target.host =
|
|
32011
|
-
target.port =
|
|
32012
|
-
target.path = removeDotSegments(
|
|
32013
|
-
target.query =
|
|
32007
|
+
if (!options.tolerant && relative2.scheme) {
|
|
32008
|
+
target.scheme = relative2.scheme;
|
|
32009
|
+
target.userinfo = relative2.userinfo;
|
|
32010
|
+
target.host = relative2.host;
|
|
32011
|
+
target.port = relative2.port;
|
|
32012
|
+
target.path = removeDotSegments(relative2.path || "");
|
|
32013
|
+
target.query = relative2.query;
|
|
32014
32014
|
} else {
|
|
32015
|
-
if (
|
|
32016
|
-
target.userinfo =
|
|
32017
|
-
target.host =
|
|
32018
|
-
target.port =
|
|
32019
|
-
target.path = removeDotSegments(
|
|
32020
|
-
target.query =
|
|
32015
|
+
if (relative2.userinfo !== void 0 || relative2.host !== void 0 || relative2.port !== void 0) {
|
|
32016
|
+
target.userinfo = relative2.userinfo;
|
|
32017
|
+
target.host = relative2.host;
|
|
32018
|
+
target.port = relative2.port;
|
|
32019
|
+
target.path = removeDotSegments(relative2.path || "");
|
|
32020
|
+
target.query = relative2.query;
|
|
32021
32021
|
} else {
|
|
32022
|
-
if (!
|
|
32022
|
+
if (!relative2.path) {
|
|
32023
32023
|
target.path = base.path;
|
|
32024
|
-
if (
|
|
32024
|
+
if (relative2.query !== void 0) target.query = relative2.query;
|
|
32025
32025
|
else target.query = base.query;
|
|
32026
32026
|
} else {
|
|
32027
|
-
if (
|
|
32027
|
+
if (relative2.path[0] === "/") target.path = removeDotSegments(relative2.path);
|
|
32028
32028
|
else {
|
|
32029
|
-
if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) target.path = "/" +
|
|
32030
|
-
else if (!base.path) target.path =
|
|
32031
|
-
else target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) +
|
|
32029
|
+
if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) target.path = "/" + relative2.path;
|
|
32030
|
+
else if (!base.path) target.path = relative2.path;
|
|
32031
|
+
else target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative2.path;
|
|
32032
32032
|
target.path = removeDotSegments(target.path);
|
|
32033
32033
|
}
|
|
32034
|
-
target.query =
|
|
32034
|
+
target.query = relative2.query;
|
|
32035
32035
|
}
|
|
32036
32036
|
target.userinfo = base.userinfo;
|
|
32037
32037
|
target.host = base.host;
|
|
@@ -32039,7 +32039,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
32039
32039
|
}
|
|
32040
32040
|
target.scheme = base.scheme;
|
|
32041
32041
|
}
|
|
32042
|
-
target.fragment =
|
|
32042
|
+
target.fragment = relative2.fragment;
|
|
32043
32043
|
return target;
|
|
32044
32044
|
}
|
|
32045
32045
|
function equal(uriA, uriB, options) {
|
|
@@ -32165,7 +32165,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
32165
32165
|
const fastUri = {
|
|
32166
32166
|
SCHEMES,
|
|
32167
32167
|
normalize,
|
|
32168
|
-
resolve,
|
|
32168
|
+
resolve: resolve3,
|
|
32169
32169
|
resolveComponent,
|
|
32170
32170
|
equal,
|
|
32171
32171
|
serialize,
|
|
@@ -37538,7 +37538,7 @@ var StdioServerTransport = class {
|
|
|
37538
37538
|
}
|
|
37539
37539
|
send(message) {
|
|
37540
37540
|
if (this._closed) return Promise.reject(/* @__PURE__ */ new Error("StdioServerTransport is closed"));
|
|
37541
|
-
return new Promise((
|
|
37541
|
+
return new Promise((resolve3, reject) => {
|
|
37542
37542
|
const json2 = serializeMessage(message);
|
|
37543
37543
|
let settled = false;
|
|
37544
37544
|
const onError = (error62) => {
|
|
@@ -37553,14 +37553,14 @@ var StdioServerTransport = class {
|
|
|
37553
37553
|
settled = true;
|
|
37554
37554
|
this._stdout.off("error", onError);
|
|
37555
37555
|
this._stdout.off("drain", onDrain);
|
|
37556
|
-
|
|
37556
|
+
resolve3();
|
|
37557
37557
|
};
|
|
37558
37558
|
this._stdout.once("error", onError);
|
|
37559
37559
|
if (this._stdout.write(json2)) {
|
|
37560
37560
|
if (settled) return;
|
|
37561
37561
|
settled = true;
|
|
37562
37562
|
this._stdout.off("error", onError);
|
|
37563
|
-
|
|
37563
|
+
resolve3();
|
|
37564
37564
|
} else if (!settled) this._stdout.once("drain", onDrain);
|
|
37565
37565
|
});
|
|
37566
37566
|
}
|
|
@@ -37614,14 +37614,14 @@ var StdioConnectionChannel = class {
|
|
|
37614
37614
|
*/
|
|
37615
37615
|
async whenRequestsAnswered(timeoutMs) {
|
|
37616
37616
|
if (this._closed || this._pendingRequests.size === 0) return true;
|
|
37617
|
-
return await new Promise((
|
|
37617
|
+
return await new Promise((resolve3) => {
|
|
37618
37618
|
const waiter = () => {
|
|
37619
37619
|
clearTimeout(timer);
|
|
37620
|
-
|
|
37620
|
+
resolve3(true);
|
|
37621
37621
|
};
|
|
37622
37622
|
const timer = setTimeout(() => {
|
|
37623
37623
|
this._drainWaiters = this._drainWaiters.filter((pending) => pending !== waiter);
|
|
37624
|
-
|
|
37624
|
+
resolve3(false);
|
|
37625
37625
|
}, timeoutMs);
|
|
37626
37626
|
this._drainWaiters.push(waiter);
|
|
37627
37627
|
});
|
|
@@ -38019,13 +38019,28 @@ var API_KEY_RE = new RegExp([
|
|
|
38019
38019
|
"whsec_[A-Za-z0-9]{16,}\\b"
|
|
38020
38020
|
// webhook signing secret (Stripe-style)
|
|
38021
38021
|
].map((p) => `\\b${p}`).join("|"), "g");
|
|
38022
|
-
var QUERY_SECRET_RE = /([?&](?:
|
|
38022
|
+
var QUERY_SECRET_RE = /([?&](?:(?:access|refresh|id|auth|session|csrf|xsrf)[_-]?token|client[_-]?secret|api[_-]?secret|api[_-]?key|password|passwd|signature|token|key|sig)=)[^&#\s"'<>`]+/gi;
|
|
38023
|
+
var OAUTH_CODE_RE = /([?&]code=)(?=[^&#\s"'<>`]{16,})[^&#\s"'<>`]+/gi;
|
|
38024
|
+
var FORM_PASSWORD_RE = /((?:^|[\s,;:"'(\[{])(?:password|passwd)=)[^&#\s"'<>`]+/gim;
|
|
38025
|
+
var HEADER_SECRET_RE = /(\b(?:x[-_][a-z0-9_-]*?(?:api[-_]?key|token|secret|auth)[a-z0-9_-]*|api[-_]?key)\s*:\s*)[^\s,;"'<>`]+/gi;
|
|
38023
38026
|
var AWS_SIGV4_RE = /([?&]X-Amz-(?:Signature|Security-Token|Credential)=)[^&#\s"'<>`]+/gi;
|
|
38024
|
-
var JSON_SECRET_KEYS =
|
|
38025
|
-
|
|
38026
|
-
|
|
38027
|
+
var JSON_SECRET_KEYS = [
|
|
38028
|
+
"(?:access|refresh|id|auth|session|bearer|csrf|xsrf)[_-]?token",
|
|
38029
|
+
"client[_-]?secret",
|
|
38030
|
+
"api[_-]?secret",
|
|
38031
|
+
"(?:x[_-])?api[_-]?key",
|
|
38032
|
+
"private[_-]?key",
|
|
38033
|
+
"x[_-][a-z0-9_-]*?(?:api[_-]?key|token|secret|auth)[a-z0-9_-]*",
|
|
38034
|
+
"(?:proxy-)?authorization",
|
|
38035
|
+
"password",
|
|
38036
|
+
"passwd",
|
|
38037
|
+
"secret",
|
|
38038
|
+
"token"
|
|
38039
|
+
].join("|");
|
|
38040
|
+
var JSON_SECRET_DQ_RE = new RegExp(`("(?:${JSON_SECRET_KEYS})"\\s*:\\s*")(?:[^"\\\\]|\\\\.)*(")`, "gi");
|
|
38041
|
+
var JSON_SECRET_SQ_RE = new RegExp(`('(?:${JSON_SECRET_KEYS})'\\s*:\\s*')(?:[^'\\\\]|\\\\.)*(')`, "gi");
|
|
38027
38042
|
function redactSecrets(text) {
|
|
38028
|
-
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]");
|
|
38043
|
+
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(HEADER_SECRET_RE, "$1[REDACTED]").replace(QUERY_SECRET_RE, "$1[REDACTED]").replace(OAUTH_CODE_RE, "$1[REDACTED]").replace(FORM_PASSWORD_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]");
|
|
38029
38044
|
}
|
|
38030
38045
|
function truncateErrorMessage(text, max = DEFAULT_ERROR_MESSAGE_MAX) {
|
|
38031
38046
|
const str2 = text === null || text === void 0 ? "" : String(text);
|
|
@@ -40037,8 +40052,8 @@ function emoji() {
|
|
|
40037
40052
|
}
|
|
40038
40053
|
var ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
|
|
40039
40054
|
var ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
|
|
40040
|
-
var mac = (
|
|
40041
|
-
const escapedDelim = escapeRegex(
|
|
40055
|
+
var mac = (delimiter2) => {
|
|
40056
|
+
const escapedDelim = escapeRegex(delimiter2 ?? ":");
|
|
40042
40057
|
return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
|
|
40043
40058
|
};
|
|
40044
40059
|
var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
|
|
@@ -40630,7 +40645,7 @@ ${content.join("\n")}
|
|
|
40630
40645
|
var version = {
|
|
40631
40646
|
major: 4,
|
|
40632
40647
|
minor: 6,
|
|
40633
|
-
patch:
|
|
40648
|
+
patch: 5
|
|
40634
40649
|
};
|
|
40635
40650
|
|
|
40636
40651
|
// node_modules/zod/v4/core/schemas.js
|
|
@@ -43066,7 +43081,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
|
|
|
43066
43081
|
var NONE = 0;
|
|
43067
43082
|
var ASSUMED = 1;
|
|
43068
43083
|
var PROVEN = 2;
|
|
43069
|
-
function isRecursive(inst, stack,
|
|
43084
|
+
function isRecursive(inst, stack, resolve3) {
|
|
43070
43085
|
const cached2 = recursive.get(inst);
|
|
43071
43086
|
if (cached2 !== void 0)
|
|
43072
43087
|
return cached2 ? PROVEN : NONE;
|
|
@@ -43076,7 +43091,7 @@ function isRecursive(inst, stack, resolve) {
|
|
|
43076
43091
|
let result = NONE;
|
|
43077
43092
|
const check2 = (child) => {
|
|
43078
43093
|
if (result !== PROVEN && child?._zod) {
|
|
43079
|
-
const answer = isRecursive(child, stack,
|
|
43094
|
+
const answer = isRecursive(child, stack, resolve3);
|
|
43080
43095
|
if (answer > result)
|
|
43081
43096
|
result = answer;
|
|
43082
43097
|
}
|
|
@@ -43087,7 +43102,7 @@ function isRecursive(inst, stack, resolve) {
|
|
|
43087
43102
|
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
43088
43103
|
if (spread && !desc.enumerable)
|
|
43089
43104
|
continue;
|
|
43090
|
-
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack,
|
|
43105
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve3) : NONE;
|
|
43091
43106
|
if (child > answer)
|
|
43092
43107
|
answer = child;
|
|
43093
43108
|
}
|
|
@@ -43151,7 +43166,7 @@ function isRecursive(inst, stack, resolve) {
|
|
|
43151
43166
|
break;
|
|
43152
43167
|
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
43153
43168
|
case "lazy": {
|
|
43154
|
-
const inner = def._cachedInner ?? (
|
|
43169
|
+
const inner = def._cachedInner ?? (resolve3 ? inst._zod.innerType : void 0);
|
|
43155
43170
|
merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
43156
43171
|
break;
|
|
43157
43172
|
}
|
|
@@ -57844,13 +57859,47 @@ async function createMcpServer(opts) {
|
|
|
57844
57859
|
}
|
|
57845
57860
|
return server;
|
|
57846
57861
|
}
|
|
57862
|
+
var DEFAULT_SHUTDOWN_TIMEOUT_MS = 5e3;
|
|
57863
|
+
var DEFAULT_REPEAT_SIGNAL_GRACE_MS = 500;
|
|
57847
57864
|
function withGracefulShutdown(target, opts = {}) {
|
|
57848
57865
|
const shouldExit = opts.exit ?? true;
|
|
57866
|
+
if (opts.timeoutMs !== void 0 && !(Number.isFinite(opts.timeoutMs) && opts.timeoutMs > 0)) {
|
|
57867
|
+
throw new RangeError("withGracefulShutdown: timeoutMs must be a finite number greater than 0.");
|
|
57868
|
+
}
|
|
57869
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS;
|
|
57870
|
+
if (opts.repeatSignalGraceMs !== void 0 && !(Number.isFinite(opts.repeatSignalGraceMs) && opts.repeatSignalGraceMs >= 0)) {
|
|
57871
|
+
throw new RangeError("withGracefulShutdown: repeatSignalGraceMs must be a finite number >= 0.");
|
|
57872
|
+
}
|
|
57873
|
+
const repeatGraceMs = opts.repeatSignalGraceMs ?? DEFAULT_REPEAT_SIGNAL_GRACE_MS;
|
|
57849
57874
|
let shuttingDown = false;
|
|
57875
|
+
let firstSignalAt = 0;
|
|
57876
|
+
let exited = false;
|
|
57877
|
+
const exitOnce = () => {
|
|
57878
|
+
if (exited)
|
|
57879
|
+
return;
|
|
57880
|
+
exited = true;
|
|
57881
|
+
process.exit(0);
|
|
57882
|
+
};
|
|
57850
57883
|
const handler = (signal) => {
|
|
57851
|
-
if (shuttingDown)
|
|
57884
|
+
if (shuttingDown) {
|
|
57885
|
+
if (Date.now() - firstSignalAt < repeatGraceMs)
|
|
57886
|
+
return;
|
|
57887
|
+
if (shouldExit) {
|
|
57888
|
+
console.error(`[mcp-utils] second ${signal} during shutdown \u2014 exiting now`);
|
|
57889
|
+
exitOnce();
|
|
57890
|
+
}
|
|
57852
57891
|
return;
|
|
57892
|
+
}
|
|
57853
57893
|
shuttingDown = true;
|
|
57894
|
+
firstSignalAt = Date.now();
|
|
57895
|
+
let timer;
|
|
57896
|
+
if (shouldExit) {
|
|
57897
|
+
timer = setTimeout(() => {
|
|
57898
|
+
console.error(`[mcp-utils] graceful shutdown on ${signal} did not finish in ${timeoutMs}ms \u2014 exiting`);
|
|
57899
|
+
exitOnce();
|
|
57900
|
+
}, timeoutMs);
|
|
57901
|
+
timer.unref?.();
|
|
57902
|
+
}
|
|
57854
57903
|
void (async () => {
|
|
57855
57904
|
try {
|
|
57856
57905
|
if (opts.onSignal)
|
|
@@ -57859,8 +57908,10 @@ function withGracefulShutdown(target, opts = {}) {
|
|
|
57859
57908
|
} catch (err) {
|
|
57860
57909
|
console.error(`[mcp-utils] error during graceful shutdown on ${signal}: ${err instanceof Error ? err.message : String(err)}`);
|
|
57861
57910
|
} finally {
|
|
57911
|
+
if (timer !== void 0)
|
|
57912
|
+
clearTimeout(timer);
|
|
57862
57913
|
if (shouldExit)
|
|
57863
|
-
|
|
57914
|
+
exitOnce();
|
|
57864
57915
|
}
|
|
57865
57916
|
})();
|
|
57866
57917
|
};
|
|
@@ -57890,6 +57941,8 @@ function runMcp(opts) {
|
|
|
57890
57941
|
}
|
|
57891
57942
|
|
|
57892
57943
|
// node_modules/@chrischall/mcp-utils/dist/config/index.js
|
|
57944
|
+
import { homedir } from "node:os";
|
|
57945
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
57893
57946
|
var PLACEHOLDER_RE = /^\$\{[^}]*\}$/;
|
|
57894
57947
|
function readEnvVar(key, opts = {}) {
|
|
57895
57948
|
const env = opts.env ?? process.env;
|
|
@@ -57902,6 +57955,15 @@ function readEnvVar(key, opts = {}) {
|
|
|
57902
57955
|
}
|
|
57903
57956
|
return opts.default;
|
|
57904
57957
|
}
|
|
57958
|
+
function expandPath(p) {
|
|
57959
|
+
let expanded = p;
|
|
57960
|
+
if (p === "~") {
|
|
57961
|
+
expanded = homedir();
|
|
57962
|
+
} else if (p.startsWith("~/")) {
|
|
57963
|
+
expanded = join(homedir(), p.slice(2));
|
|
57964
|
+
}
|
|
57965
|
+
return isAbsolute(expanded) ? expanded : resolve(expanded);
|
|
57966
|
+
}
|
|
57905
57967
|
async function loadDotenvSafely(opts = {}) {
|
|
57906
57968
|
try {
|
|
57907
57969
|
const mod = await import(
|
|
@@ -57921,10 +57983,67 @@ async function loadDotenvSafely(opts = {}) {
|
|
|
57921
57983
|
|
|
57922
57984
|
// node_modules/@chrischall/mcp-utils/dist/fs/index.js
|
|
57923
57985
|
import { openAsBlob } from "node:fs";
|
|
57986
|
+
import { open as open2 } from "node:fs/promises";
|
|
57987
|
+
|
|
57988
|
+
// node_modules/@chrischall/mcp-utils/dist/fs/confine.js
|
|
57989
|
+
import { existsSync, realpathSync } from "node:fs";
|
|
57990
|
+
import { dirname, isAbsolute as isAbsolute2, relative, resolve as resolve2, sep } from "node:path";
|
|
57991
|
+
function isInside(root, target) {
|
|
57992
|
+
const rel = relative(root, target);
|
|
57993
|
+
return rel === "" || !rel.startsWith(`..${sep}`) && rel !== ".." && !isAbsolute2(rel);
|
|
57994
|
+
}
|
|
57995
|
+
function realPathAllowingMissing(p) {
|
|
57996
|
+
const abs = resolve2(p);
|
|
57997
|
+
let existing = abs;
|
|
57998
|
+
const tail = [];
|
|
57999
|
+
while (!existsSync(existing)) {
|
|
58000
|
+
const parent = dirname(existing);
|
|
58001
|
+
if (parent === existing)
|
|
58002
|
+
break;
|
|
58003
|
+
tail.unshift(existing.slice(parent.length).replace(/^[/\\]+/, ""));
|
|
58004
|
+
existing = parent;
|
|
58005
|
+
}
|
|
58006
|
+
let real;
|
|
58007
|
+
try {
|
|
58008
|
+
real = realpathSync(existing);
|
|
58009
|
+
} catch {
|
|
58010
|
+
real = existing;
|
|
58011
|
+
}
|
|
58012
|
+
return tail.length > 0 ? resolve2(real, ...tail) : real;
|
|
58013
|
+
}
|
|
58014
|
+
function assertPathWithinRoots(path, roots) {
|
|
58015
|
+
const target = realPathAllowingMissing(expandPath(path));
|
|
58016
|
+
for (const root of roots) {
|
|
58017
|
+
if (isInside(realPathAllowingMissing(expandPath(root)), target))
|
|
58018
|
+
return target;
|
|
58019
|
+
}
|
|
58020
|
+
throw new Error(`Path is outside the allowed directories: ${path}`);
|
|
58021
|
+
}
|
|
58022
|
+
|
|
58023
|
+
// node_modules/@chrischall/mcp-utils/dist/fs/output.js
|
|
58024
|
+
function sniffMimeBytes(bytes) {
|
|
58025
|
+
const buf = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
58026
|
+
if (buf.length >= 8 && buf.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) {
|
|
58027
|
+
return "image/png";
|
|
58028
|
+
}
|
|
58029
|
+
if (buf.length >= 3 && buf[0] === 255 && buf[1] === 216 && buf[2] === 255) {
|
|
58030
|
+
return "image/jpeg";
|
|
58031
|
+
}
|
|
58032
|
+
if (buf.length >= 12 && buf.subarray(0, 4).toString("latin1") === "RIFF" && buf.subarray(8, 12).toString("latin1") === "WEBP") {
|
|
58033
|
+
return "image/webp";
|
|
58034
|
+
}
|
|
58035
|
+
if (buf.length >= 4 && buf.subarray(0, 4).toString("latin1") === "GIF8") {
|
|
58036
|
+
return "image/gif";
|
|
58037
|
+
}
|
|
58038
|
+
return void 0;
|
|
58039
|
+
}
|
|
58040
|
+
|
|
58041
|
+
// node_modules/@chrischall/mcp-utils/dist/fs/index.js
|
|
57924
58042
|
async function fileBlob(path, opts = {}) {
|
|
58043
|
+
const target = opts.allowedRoots ? assertPathWithinRoots(path, opts.allowedRoots) : path;
|
|
57925
58044
|
let blob;
|
|
57926
58045
|
try {
|
|
57927
|
-
blob = await openAsBlob(
|
|
58046
|
+
blob = await openAsBlob(target, opts.type !== void 0 ? { type: opts.type } : void 0);
|
|
57928
58047
|
} catch {
|
|
57929
58048
|
throw new Error(`Cannot read file for upload: ${path}`);
|
|
57930
58049
|
}
|
|
@@ -57933,6 +58052,22 @@ async function fileBlob(path, opts = {}) {
|
|
|
57933
58052
|
}
|
|
57934
58053
|
return blob;
|
|
57935
58054
|
}
|
|
58055
|
+
async function readFileHead(path, bytes, opts = {}) {
|
|
58056
|
+
const target = opts.allowedRoots ? assertPathWithinRoots(path, opts.allowedRoots) : path;
|
|
58057
|
+
let fh;
|
|
58058
|
+
try {
|
|
58059
|
+
fh = await open2(target, "r");
|
|
58060
|
+
} catch {
|
|
58061
|
+
throw new Error(`Cannot read file: ${path}`);
|
|
58062
|
+
}
|
|
58063
|
+
try {
|
|
58064
|
+
const buf = Buffer.alloc(bytes);
|
|
58065
|
+
const { bytesRead } = await fh.read(buf, 0, bytes, 0);
|
|
58066
|
+
return buf.subarray(0, bytesRead);
|
|
58067
|
+
} finally {
|
|
58068
|
+
await fh.close();
|
|
58069
|
+
}
|
|
58070
|
+
}
|
|
57936
58071
|
|
|
57937
58072
|
// node_modules/@chrischall/mcp-utils/dist/http/index.js
|
|
57938
58073
|
function buildQueryString(params) {
|
|
@@ -57978,9 +58113,12 @@ var pageSchema = {
|
|
|
57978
58113
|
page_size: external_exports.number().int().min(1).max(200).default(50).describe("Number of items per page (1-200).")
|
|
57979
58114
|
};
|
|
57980
58115
|
function toolAnnotations(opts = {}) {
|
|
58116
|
+
if (opts.readOnly === true && opts.destructive === true) {
|
|
58117
|
+
throw new Error("toolAnnotations: readOnly: true contradicts destructive: true \u2014 a destructive tool is not read-only.");
|
|
58118
|
+
}
|
|
57981
58119
|
return {
|
|
57982
58120
|
...opts.title !== void 0 ? { title: opts.title } : {},
|
|
57983
|
-
readOnlyHint: opts.readOnly ??
|
|
58121
|
+
readOnlyHint: opts.readOnly ?? opts.destructive === void 0,
|
|
57984
58122
|
...opts.idempotent !== void 0 ? { idempotentHint: opts.idempotent } : {},
|
|
57985
58123
|
...opts.destructive !== void 0 ? { destructiveHint: opts.destructive } : {},
|
|
57986
58124
|
...opts.openWorld !== void 0 ? { openWorldHint: opts.openWorld } : {}
|
|
@@ -57988,14 +58126,14 @@ function toolAnnotations(opts = {}) {
|
|
|
57988
58126
|
}
|
|
57989
58127
|
|
|
57990
58128
|
// src/version.ts
|
|
57991
|
-
var VERSION = "2.1.
|
|
58129
|
+
var VERSION = "2.1.3";
|
|
57992
58130
|
|
|
57993
58131
|
// src/client.ts
|
|
57994
|
-
import { dirname, join } from "path";
|
|
58132
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
57995
58133
|
import { fileURLToPath } from "url";
|
|
57996
58134
|
if (import.meta.url) {
|
|
57997
|
-
const __dirname =
|
|
57998
|
-
await loadDotenvSafely({ path:
|
|
58135
|
+
const __dirname = dirname2(fileURLToPath(import.meta.url));
|
|
58136
|
+
await loadDotenvSafely({ path: join2(__dirname, "..", ".env"), override: false });
|
|
57999
58137
|
}
|
|
58000
58138
|
var BASE_URL = "https://api.untappd.com/v4";
|
|
58001
58139
|
var SERVICE = "Untappd";
|
|
@@ -58495,7 +58633,9 @@ var SCHEMA_STATEMENTS = [
|
|
|
58495
58633
|
beers_offset INTEGER,
|
|
58496
58634
|
beers_total INTEGER,
|
|
58497
58635
|
beers_complete INTEGER NOT NULL DEFAULT 0,
|
|
58498
|
-
served_backfill_last INTEGER NOT NULL DEFAULT 0
|
|
58636
|
+
served_backfill_last INTEGER NOT NULL DEFAULT 0,
|
|
58637
|
+
beers_accepted_gap INTEGER NOT NULL DEFAULT 0,
|
|
58638
|
+
beers_rescan_target INTEGER
|
|
58499
58639
|
)`
|
|
58500
58640
|
];
|
|
58501
58641
|
var MIGRATIONS = [
|
|
@@ -58504,7 +58644,9 @@ var MIGRATIONS = [
|
|
|
58504
58644
|
"ALTER TABLE sync_state ADD COLUMN beers_offset INTEGER",
|
|
58505
58645
|
"ALTER TABLE sync_state ADD COLUMN beers_total INTEGER",
|
|
58506
58646
|
"ALTER TABLE sync_state ADD COLUMN beers_complete INTEGER NOT NULL DEFAULT 0",
|
|
58507
|
-
"ALTER TABLE sync_state ADD COLUMN served_backfill_last INTEGER NOT NULL DEFAULT 0"
|
|
58647
|
+
"ALTER TABLE sync_state ADD COLUMN served_backfill_last INTEGER NOT NULL DEFAULT 0",
|
|
58648
|
+
"ALTER TABLE sync_state ADD COLUMN beers_accepted_gap INTEGER NOT NULL DEFAULT 0",
|
|
58649
|
+
"ALTER TABLE sync_state ADD COLUMN beers_rescan_target INTEGER"
|
|
58508
58650
|
];
|
|
58509
58651
|
var CheckinStoreCore = class {
|
|
58510
58652
|
constructor(db) {
|
|
@@ -58626,7 +58768,9 @@ var CheckinStoreCore = class {
|
|
|
58626
58768
|
beers_offset: num(row.beers_offset),
|
|
58627
58769
|
beers_total: num(row.beers_total),
|
|
58628
58770
|
beers_complete: Number(row.beers_complete) === 1,
|
|
58629
|
-
served_backfill_last: Number(row.served_backfill_last) === 1
|
|
58771
|
+
served_backfill_last: Number(row.served_backfill_last) === 1,
|
|
58772
|
+
beers_accepted_gap: num(row.beers_accepted_gap) ?? 0,
|
|
58773
|
+
beers_rescan_target: num(row.beers_rescan_target)
|
|
58630
58774
|
};
|
|
58631
58775
|
}
|
|
58632
58776
|
/**
|
|
@@ -58650,19 +58794,22 @@ var CheckinStoreCore = class {
|
|
|
58650
58794
|
beers_offset: pick2("beers_offset", null),
|
|
58651
58795
|
beers_total: pick2("beers_total", null),
|
|
58652
58796
|
beers_complete: pick2("beers_complete", false),
|
|
58653
|
-
served_backfill_last: pick2("served_backfill_last", false)
|
|
58797
|
+
served_backfill_last: pick2("served_backfill_last", false),
|
|
58798
|
+
beers_accepted_gap: pick2("beers_accepted_gap", 0),
|
|
58799
|
+
beers_rescan_target: pick2("beers_rescan_target", null)
|
|
58654
58800
|
};
|
|
58655
58801
|
this.db.run(
|
|
58656
58802
|
`INSERT INTO sync_state
|
|
58657
|
-
(username, oldest_max_id, newest_checkin_id, catchup_max_id, last_synced_at, backfill_complete, total_checkins, checkins_truncated, beers_offset, beers_total, beers_complete, served_backfill_last)
|
|
58658
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
58803
|
+
(username, oldest_max_id, newest_checkin_id, catchup_max_id, last_synced_at, backfill_complete, total_checkins, checkins_truncated, beers_offset, beers_total, beers_complete, served_backfill_last, beers_accepted_gap, beers_rescan_target)
|
|
58804
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
58659
58805
|
ON CONFLICT(username) DO UPDATE SET
|
|
58660
58806
|
oldest_max_id=excluded.oldest_max_id, newest_checkin_id=excluded.newest_checkin_id,
|
|
58661
58807
|
catchup_max_id=excluded.catchup_max_id, last_synced_at=excluded.last_synced_at,
|
|
58662
58808
|
backfill_complete=excluded.backfill_complete, total_checkins=excluded.total_checkins,
|
|
58663
58809
|
checkins_truncated=excluded.checkins_truncated, beers_offset=excluded.beers_offset,
|
|
58664
58810
|
beers_total=excluded.beers_total, beers_complete=excluded.beers_complete,
|
|
58665
|
-
served_backfill_last=excluded.served_backfill_last
|
|
58811
|
+
served_backfill_last=excluded.served_backfill_last, beers_accepted_gap=excluded.beers_accepted_gap,
|
|
58812
|
+
beers_rescan_target=excluded.beers_rescan_target`,
|
|
58666
58813
|
[
|
|
58667
58814
|
key,
|
|
58668
58815
|
next.oldest_max_id,
|
|
@@ -58675,7 +58822,9 @@ var CheckinStoreCore = class {
|
|
|
58675
58822
|
next.beers_offset,
|
|
58676
58823
|
next.beers_total,
|
|
58677
58824
|
next.beers_complete ? 1 : 0,
|
|
58678
|
-
next.served_backfill_last ? 1 : 0
|
|
58825
|
+
next.served_backfill_last ? 1 : 0,
|
|
58826
|
+
next.beers_accepted_gap,
|
|
58827
|
+
next.beers_rescan_target
|
|
58679
58828
|
]
|
|
58680
58829
|
);
|
|
58681
58830
|
}
|
|
@@ -59637,19 +59786,108 @@ function registerWishlistTools(server, client2) {
|
|
|
59637
59786
|
}
|
|
59638
59787
|
|
|
59639
59788
|
// src/tools/checkin.ts
|
|
59640
|
-
import {
|
|
59641
|
-
import { extname } from "node:path";
|
|
59789
|
+
import { realpathSync as realpathSync2, statSync } from "node:fs";
|
|
59790
|
+
import { delimiter, extname } from "node:path";
|
|
59642
59791
|
var CheckinIdSchema = external_exports.number().int().positive().describe("Untappd check-in id");
|
|
59643
59792
|
var PHOTO_CONTENT_TYPES = { jpg: "image/jpeg", png: "image/png" };
|
|
59644
59793
|
function photoExt(path) {
|
|
59645
59794
|
const ext = extname(path).slice(1).toLowerCase();
|
|
59646
59795
|
return ext === "jpeg" ? "jpg" : ext;
|
|
59647
59796
|
}
|
|
59797
|
+
var MAX_PHOTO_BYTES = 15 * 1024 * 1024;
|
|
59798
|
+
function photoRoots() {
|
|
59799
|
+
const raw = readEnvVar("UNTAPPD_PHOTO_DIR");
|
|
59800
|
+
const roots = raw?.split(delimiter).filter(Boolean);
|
|
59801
|
+
return roots && roots.length > 0 ? roots : void 0;
|
|
59802
|
+
}
|
|
59803
|
+
async function checkPhoto(photoPath) {
|
|
59804
|
+
const ext = photoExt(photoPath);
|
|
59805
|
+
if (!(ext in PHOTO_CONTENT_TYPES)) {
|
|
59806
|
+
throw createHelpfulError(`Unsupported photo type "${ext || "(none)"}".`, {
|
|
59807
|
+
hint: "Attach a .jpg, .jpeg, or .png file."
|
|
59808
|
+
});
|
|
59809
|
+
}
|
|
59810
|
+
const roots = photoRoots();
|
|
59811
|
+
if (roots) {
|
|
59812
|
+
try {
|
|
59813
|
+
assertPathWithinRoots(photoPath, roots);
|
|
59814
|
+
} catch {
|
|
59815
|
+
throw createHelpfulError("The photo is outside the allowed photo directory.", {
|
|
59816
|
+
hint: "UNTAPPD_PHOTO_DIR restricts which files can be attached to a check-in."
|
|
59817
|
+
});
|
|
59818
|
+
}
|
|
59819
|
+
}
|
|
59820
|
+
let real;
|
|
59821
|
+
let size;
|
|
59822
|
+
try {
|
|
59823
|
+
real = realpathSync2(photoPath);
|
|
59824
|
+
const st = statSync(real);
|
|
59825
|
+
if (!st.isFile()) throw new Error("not a file");
|
|
59826
|
+
size = st.size;
|
|
59827
|
+
} catch {
|
|
59828
|
+
throw new McpToolError("Photo file not found or not readable.");
|
|
59829
|
+
}
|
|
59830
|
+
if (size > MAX_PHOTO_BYTES) {
|
|
59831
|
+
throw createHelpfulError(`Photo is too large (${size} bytes; the limit is ${MAX_PHOTO_BYTES}).`, {
|
|
59832
|
+
hint: "Attach a normal-sized JPEG or PNG photo."
|
|
59833
|
+
});
|
|
59834
|
+
}
|
|
59835
|
+
const sniffed = sniffMimeBytes(await readFileHead(real, 16));
|
|
59836
|
+
if (sniffed !== PHOTO_CONTENT_TYPES[ext]) {
|
|
59837
|
+
throw createHelpfulError(
|
|
59838
|
+
sniffed === "image/jpeg" || sniffed === "image/png" ? `Photo content (${sniffed}) does not match its .${ext} extension.` : "The file is not a JPEG or PNG image.",
|
|
59839
|
+
{ hint: "Attach a real .jpg/.jpeg or .png photo." }
|
|
59840
|
+
);
|
|
59841
|
+
}
|
|
59842
|
+
return { path: real, size_bytes: size, ext, content_type: sniffed };
|
|
59843
|
+
}
|
|
59648
59844
|
var RatingSchema = external_exports.number().min(0).max(5).refine((r) => Math.round(r * 4) === r * 4, { message: "rating must be a multiple of 0.25" });
|
|
59649
|
-
function
|
|
59650
|
-
const
|
|
59651
|
-
const
|
|
59652
|
-
|
|
59845
|
+
function gmtOffsetHours(timeZone, at) {
|
|
59846
|
+
const name = new Intl.DateTimeFormat("en-US", { timeZone, timeZoneName: "longOffset" }).formatToParts(at).find((p) => p.type === "timeZoneName")?.value;
|
|
59847
|
+
const m = /GMT([+-])(\d{1,2})(?::(\d{2}))?/.exec(name ?? "");
|
|
59848
|
+
if (!m) return 0;
|
|
59849
|
+
const hours = Number(m[2]) + Number(m[3] ?? 0) / 60;
|
|
59850
|
+
return m[1] === "-" ? -hours : hours;
|
|
59851
|
+
}
|
|
59852
|
+
function checkinTimezone(requested) {
|
|
59853
|
+
const timezone = requested ?? readEnvVar("UNTAPPD_TIMEZONE") ?? (Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC");
|
|
59854
|
+
try {
|
|
59855
|
+
return { timezone, gmt_offset: gmtOffsetHours(timezone, /* @__PURE__ */ new Date()) };
|
|
59856
|
+
} catch {
|
|
59857
|
+
throw createHelpfulError(`Unknown timezone "${timezone}".`, {
|
|
59858
|
+
hint: 'Pass an IANA timezone name such as "America/New_York" or "Europe/London".'
|
|
59859
|
+
});
|
|
59860
|
+
}
|
|
59861
|
+
}
|
|
59862
|
+
var RECOVERY_WINDOW_MS = 3e4;
|
|
59863
|
+
async function nonIdempotentWrite(run, unknownOutcome) {
|
|
59864
|
+
try {
|
|
59865
|
+
return await run();
|
|
59866
|
+
} catch (e) {
|
|
59867
|
+
if (e instanceof UnreachableError) throw new McpToolError(unknownOutcome);
|
|
59868
|
+
throw e;
|
|
59869
|
+
}
|
|
59870
|
+
}
|
|
59871
|
+
async function findRecentCheckin(client2, bid, sentAt) {
|
|
59872
|
+
const self = client2.loginName;
|
|
59873
|
+
if (!self) return null;
|
|
59874
|
+
try {
|
|
59875
|
+
const data = await client2.get(
|
|
59876
|
+
`/user/checkins/${encodeURIComponent(self)}`,
|
|
59877
|
+
{ limit: 5 }
|
|
59878
|
+
);
|
|
59879
|
+
const matches = [];
|
|
59880
|
+
for (const it of data?.checkins?.items ?? []) {
|
|
59881
|
+
const c = it;
|
|
59882
|
+
const at = Date.parse(c.created_at ?? "");
|
|
59883
|
+
if (c.beer?.bid === bid && typeof c.checkin_id === "number" && at >= sentAt - RECOVERY_WINDOW_MS) {
|
|
59884
|
+
matches.push(c.checkin_id);
|
|
59885
|
+
}
|
|
59886
|
+
}
|
|
59887
|
+
if (matches.length === 1) return matches[0];
|
|
59888
|
+
} catch {
|
|
59889
|
+
}
|
|
59890
|
+
return null;
|
|
59653
59891
|
}
|
|
59654
59892
|
function registerCheckinTools(server, client2) {
|
|
59655
59893
|
server.registerTool(
|
|
@@ -59672,7 +59910,10 @@ function registerCheckinTools(server, client2) {
|
|
|
59672
59910
|
note: "Dry run \u2014 re-run with confirm: true to toggle your toast on this check-in."
|
|
59673
59911
|
});
|
|
59674
59912
|
}
|
|
59675
|
-
const data = await
|
|
59913
|
+
const data = await nonIdempotentWrite(
|
|
59914
|
+
() => client2.write("POST", `/checkin/toast/${checkin_id}`),
|
|
59915
|
+
`Untappd did not answer the toast request for check-in ${checkin_id} in time, so it may or may not have been applied. Toast is a TOGGLE: retrying could remove a toast that did land. Check with untappd_checkin_info (checkin_id ${checkin_id}) before retrying.`
|
|
59916
|
+
);
|
|
59676
59917
|
return minifiedResult({ toggled: true, checkin_id, result: data?.result, like_type: data?.like_type });
|
|
59677
59918
|
}
|
|
59678
59919
|
);
|
|
@@ -59698,7 +59939,10 @@ function registerCheckinTools(server, client2) {
|
|
|
59698
59939
|
note: "Dry run \u2014 re-run with confirm: true to post this comment to your Untappd account."
|
|
59699
59940
|
});
|
|
59700
59941
|
}
|
|
59701
|
-
const data = await
|
|
59942
|
+
const data = await nonIdempotentWrite(
|
|
59943
|
+
() => client2.write("POST", `/checkin/addcomment/${checkin_id}`, { form: { comment } }),
|
|
59944
|
+
`Untappd did not answer in time, so the comment may have been posted already. Check the comments with untappd_checkin_info (checkin_id ${checkin_id}) before retrying, or it may be posted twice.`
|
|
59945
|
+
);
|
|
59702
59946
|
return minifiedResult({ posted: true, checkin_id, response: data });
|
|
59703
59947
|
}
|
|
59704
59948
|
);
|
|
@@ -59761,24 +60005,21 @@ function registerCheckinTools(server, client2) {
|
|
|
59761
60005
|
rating: RatingSchema.optional().describe("Rating 0\u20135 in 0.25 increments (omit for no rating)"),
|
|
59762
60006
|
shout: external_exports.string().max(2e3).optional().describe("Optional shout / comment text for the check-in"),
|
|
59763
60007
|
foursquare_id: external_exports.string().optional().describe("Optional Foursquare venue id to tag the check-in location"),
|
|
59764
|
-
photo_path: external_exports.string().optional().describe(
|
|
60008
|
+
photo_path: external_exports.string().optional().describe(
|
|
60009
|
+
"Optional path to a local JPEG/PNG photo (max 15 MB) to attach \u2014 it is published publicly. Only use a file the user explicitly chose; the dry run shows the resolved path and size for them to confirm."
|
|
60010
|
+
),
|
|
59765
60011
|
geolat: external_exports.number().optional().describe("Optional latitude of the check-in"),
|
|
59766
60012
|
geolng: external_exports.number().optional().describe("Optional longitude of the check-in"),
|
|
59767
60013
|
container_id: external_exports.number().int().optional().describe("Optional serving container id (e.g. 1 = draft, 2 = bottle, 3 = can)"),
|
|
60014
|
+
timezone: external_exports.string().min(1).optional().describe(
|
|
60015
|
+
"The drinker's IANA timezone (e.g. America/New_York), which sets the check-in's local time. Defaults to UNTAPPD_TIMEZONE, else the server's own zone \u2014 which on a hosted connector is usually UTC, so pass it when you know where the user is."
|
|
60016
|
+
),
|
|
59768
60017
|
confirm: schemaConfirm
|
|
59769
60018
|
})
|
|
59770
60019
|
},
|
|
59771
|
-
async ({ bid, rating, shout, foursquare_id, photo_path, geolat, geolng, container_id, confirm }) => {
|
|
59772
|
-
const { timezone, gmt_offset } =
|
|
59773
|
-
|
|
59774
|
-
if (photo_path !== void 0) {
|
|
59775
|
-
ext = photoExt(photo_path);
|
|
59776
|
-
if (!(ext in PHOTO_CONTENT_TYPES)) {
|
|
59777
|
-
throw createHelpfulError(`Unsupported photo type "${ext || "(none)"}".`, {
|
|
59778
|
-
hint: "Attach a .jpg, .jpeg, or .png file."
|
|
59779
|
-
});
|
|
59780
|
-
}
|
|
59781
|
-
}
|
|
60020
|
+
async ({ bid, rating, shout, foursquare_id, photo_path, geolat, geolng, container_id, timezone: requestedTz, confirm }) => {
|
|
60021
|
+
const { timezone, gmt_offset } = checkinTimezone(requestedTz);
|
|
60022
|
+
const photo = photo_path !== void 0 ? await checkPhoto(photo_path) : void 0;
|
|
59782
60023
|
const form = {
|
|
59783
60024
|
bid,
|
|
59784
60025
|
rating: rating !== void 0 ? rating.toFixed(2) : void 0,
|
|
@@ -59789,8 +60030,8 @@ function registerCheckinTools(server, client2) {
|
|
|
59789
60030
|
container_id,
|
|
59790
60031
|
timezone,
|
|
59791
60032
|
gmt_offset,
|
|
59792
|
-
is_photo:
|
|
59793
|
-
photo_file_ext:
|
|
60033
|
+
is_photo: photo ? "true" : "false",
|
|
60034
|
+
photo_file_ext: photo?.ext,
|
|
59794
60035
|
platform: "ios"
|
|
59795
60036
|
};
|
|
59796
60037
|
if (confirm !== true) {
|
|
@@ -59798,22 +60039,41 @@ function registerCheckinTools(server, client2) {
|
|
|
59798
60039
|
dryRun: true,
|
|
59799
60040
|
action: "checkin",
|
|
59800
60041
|
form,
|
|
59801
|
-
photo:
|
|
60042
|
+
photo: photo ? { ...photo, note: "this exact file will be uploaded PUBLICLY after the check-in is created" } : void 0,
|
|
59802
60043
|
note: "Dry run \u2014 re-run with confirm: true to POST this check-in to your public Untappd feed."
|
|
59803
60044
|
});
|
|
59804
60045
|
}
|
|
59805
60046
|
let blob;
|
|
59806
|
-
if (
|
|
59807
|
-
|
|
59808
|
-
|
|
60047
|
+
if (photo) {
|
|
60048
|
+
blob = await fileBlob(photo.path, { maxBytes: MAX_PHOTO_BYTES, label: "Photo", allowedRoots: photoRoots() });
|
|
60049
|
+
}
|
|
60050
|
+
const sentAt = Date.now();
|
|
60051
|
+
let data;
|
|
60052
|
+
try {
|
|
60053
|
+
data = await client2.write("POST", "/checkin/add", { form });
|
|
60054
|
+
} catch (e) {
|
|
60055
|
+
if (!(e instanceof UnreachableError)) throw e;
|
|
60056
|
+
const found = await findRecentCheckin(client2, bid, sentAt);
|
|
60057
|
+
if (found === null) {
|
|
60058
|
+
throw new McpToolError(
|
|
60059
|
+
"Untappd did not answer the check-in request in time, so the check-in may have been created anyway (it could not be confirmed either way). Look at your latest check-ins with untappd_user_checkins before retrying \u2014 retrying a check-in that did land posts it twice."
|
|
60060
|
+
);
|
|
60061
|
+
}
|
|
60062
|
+
return minifiedResult({
|
|
60063
|
+
checked_in: true,
|
|
60064
|
+
checkin_id: found,
|
|
60065
|
+
recovered: true,
|
|
60066
|
+
photo_attached: false,
|
|
60067
|
+
...photo ? { photo_error: `Check-in ${found} was created, but its photo upload URL was lost with the timed-out response, so no photo was attached.` } : {},
|
|
60068
|
+
note: "Untappd did not answer in time, but the check-in was found on your account \u2014 it was created. Do not retry."
|
|
60069
|
+
});
|
|
59809
60070
|
}
|
|
59810
|
-
const data = await client2.write("POST", "/checkin/add", { form });
|
|
59811
60071
|
let photo_attached = false;
|
|
59812
60072
|
let photo_error;
|
|
59813
|
-
if (
|
|
60073
|
+
if (photo) {
|
|
59814
60074
|
if (data?.photo_upload?.url && data.checkin_id) {
|
|
59815
60075
|
try {
|
|
59816
|
-
await client2.putBinary(data.photo_upload.url, blob,
|
|
60076
|
+
await client2.putBinary(data.photo_upload.url, blob, photo.content_type);
|
|
59817
60077
|
await client2.write("POST", "/photo/uploadComplete", {
|
|
59818
60078
|
form: { checkin_id: data.checkin_id, destination_url: data.photo_upload.destination_url }
|
|
59819
60079
|
});
|
|
@@ -60123,6 +60383,7 @@ async function syncCheckins(client2, cache, rawUsername, options = {}) {
|
|
|
60123
60383
|
|
|
60124
60384
|
// src/cache/sync-beers.ts
|
|
60125
60385
|
var PAGE_LIMIT2 = 50;
|
|
60386
|
+
var RESUME_OVERLAP = 10;
|
|
60126
60387
|
async function fetchBeersPage(client2, encodedUser, offset) {
|
|
60127
60388
|
const data = await client2.get(
|
|
60128
60389
|
`/user/beers/${encodedUser}`,
|
|
@@ -60145,8 +60406,11 @@ async function syncUserBeers(client2, cache, rawUsername, maxPages = 10) {
|
|
|
60145
60406
|
const now = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
60146
60407
|
const prior = await cache.getState(rawUsername);
|
|
60147
60408
|
const incremental = (prior?.beers_complete ?? false) && !!prior?.last_synced_at;
|
|
60148
|
-
let
|
|
60409
|
+
let refreshing = incremental;
|
|
60410
|
+
let offset = incremental ? 0 : Math.max(0, (prior?.beers_offset ?? 0) - RESUME_OVERLAP);
|
|
60149
60411
|
let total = prior?.beers_total ?? null;
|
|
60412
|
+
let acceptedGap = prior?.beers_accepted_gap ?? 0;
|
|
60413
|
+
let rescanTarget = incremental ? null : prior?.beers_rescan_target ?? null;
|
|
60150
60414
|
let complete = false;
|
|
60151
60415
|
let pages = 0;
|
|
60152
60416
|
let added = 0;
|
|
@@ -60160,31 +60424,41 @@ async function syncUserBeers(client2, cache, rawUsername, maxPages = 10) {
|
|
|
60160
60424
|
});
|
|
60161
60425
|
}
|
|
60162
60426
|
};
|
|
60427
|
+
const gapNow = async () => total === null ? 0 : total - await cache.distinctBeersCount(rawUsername);
|
|
60163
60428
|
for (; pages < maxPages && !complete; ) {
|
|
60164
60429
|
const page = pages === 0 ? await firstFetch(offset) : await fetchBeersPage(client2, encodedUser, offset);
|
|
60165
60430
|
pages++;
|
|
60166
60431
|
if (page.total !== null) total = page.total;
|
|
60167
|
-
|
|
60168
|
-
|
|
60169
|
-
|
|
60170
|
-
|
|
60171
|
-
|
|
60172
|
-
|
|
60173
|
-
|
|
60174
|
-
|
|
60175
|
-
|
|
60432
|
+
let atEnd = page.items.length === 0;
|
|
60433
|
+
if (!atEnd) {
|
|
60434
|
+
const rows = rowsOf2(rawUsername, page.items);
|
|
60435
|
+
const netNew = await cache.upsertDistinctBeers(rawUsername, rows);
|
|
60436
|
+
added += netNew;
|
|
60437
|
+
offset += page.items.length;
|
|
60438
|
+
if (total !== null && offset >= total) atEnd = true;
|
|
60439
|
+
else if (page.items.length < PAGE_LIMIT2) atEnd = true;
|
|
60440
|
+
else if (refreshing && netNew === 0) atEnd = true;
|
|
60441
|
+
else if (rescanTarget !== null && await gapNow() <= rescanTarget) atEnd = true;
|
|
60442
|
+
}
|
|
60443
|
+
if (atEnd) {
|
|
60444
|
+
const gap = await gapNow();
|
|
60445
|
+
if (gap > acceptedGap && rescanTarget === null) {
|
|
60446
|
+
rescanTarget = acceptedGap;
|
|
60447
|
+
acceptedGap = gap;
|
|
60448
|
+
refreshing = false;
|
|
60449
|
+
offset = 0;
|
|
60450
|
+
} else {
|
|
60451
|
+
complete = true;
|
|
60452
|
+
rescanTarget = null;
|
|
60453
|
+
acceptedGap = Math.max(0, gap);
|
|
60454
|
+
}
|
|
60176
60455
|
}
|
|
60177
|
-
const rows = rowsOf2(rawUsername, page.items);
|
|
60178
|
-
const netNew = await cache.upsertDistinctBeers(rawUsername, rows);
|
|
60179
|
-
added += netNew;
|
|
60180
|
-
offset += page.items.length;
|
|
60181
|
-
if (total !== null && offset >= total) complete = true;
|
|
60182
|
-
else if (page.items.length < PAGE_LIMIT2) complete = true;
|
|
60183
|
-
else if (incremental && netNew === 0) complete = true;
|
|
60184
60456
|
await cache.setState(rawUsername, {
|
|
60185
|
-
beers_offset:
|
|
60457
|
+
beers_offset: refreshing ? total ?? offset : offset,
|
|
60186
60458
|
beers_total: total,
|
|
60187
60459
|
beers_complete: complete,
|
|
60460
|
+
beers_accepted_gap: acceptedGap,
|
|
60461
|
+
beers_rescan_target: rescanTarget,
|
|
60188
60462
|
last_synced_at: now()
|
|
60189
60463
|
});
|
|
60190
60464
|
}
|
|
@@ -60518,8 +60792,8 @@ function registerCacheTools(server, client2, cacheProvider) {
|
|
|
60518
60792
|
// src/cache/db.ts
|
|
60519
60793
|
import { DatabaseSync } from "node:sqlite";
|
|
60520
60794
|
import { mkdirSync } from "node:fs";
|
|
60521
|
-
import { dirname as
|
|
60522
|
-
import { homedir } from "node:os";
|
|
60795
|
+
import { dirname as dirname3, join as join3 } from "node:path";
|
|
60796
|
+
import { homedir as homedir2 } from "node:os";
|
|
60523
60797
|
var NodeSqlDriver = class {
|
|
60524
60798
|
constructor(db) {
|
|
60525
60799
|
this.db = db;
|
|
@@ -60556,7 +60830,7 @@ var CheckinCache = class _CheckinCache extends LocalCacheStore {
|
|
|
60556
60830
|
db;
|
|
60557
60831
|
/** Open (creating parent dirs) a file-backed cache, or `:memory:` for tests. */
|
|
60558
60832
|
static open(path) {
|
|
60559
|
-
if (path !== ":memory:") mkdirSync(
|
|
60833
|
+
if (path !== ":memory:") mkdirSync(dirname3(path), { recursive: true });
|
|
60560
60834
|
return new _CheckinCache(new DatabaseSync(path));
|
|
60561
60835
|
}
|
|
60562
60836
|
close() {
|
|
@@ -60564,7 +60838,7 @@ var CheckinCache = class _CheckinCache extends LocalCacheStore {
|
|
|
60564
60838
|
}
|
|
60565
60839
|
};
|
|
60566
60840
|
function defaultCachePath() {
|
|
60567
|
-
return readEnvVar("UNTAPPD_CACHE_DB") ??
|
|
60841
|
+
return readEnvVar("UNTAPPD_CACHE_DB") ?? join3(homedir2(), ".untappd-mcp", "checkins.db");
|
|
60568
60842
|
}
|
|
60569
60843
|
|
|
60570
60844
|
// src/index.ts
|