creditkarma-mcp 2.1.4 → 2.2.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/dist/auth.js +13 -0
- package/dist/bundle.js +317 -17
- package/dist/index.js +1 -1
- package/package.json +3 -2
- package/server.json +2 -2
package/dist/auth.js
CHANGED
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
// `src/tools/auth.ts` extracts the CKAT JWTs the same way it does
|
|
59
59
|
// today.
|
|
60
60
|
import { bootstrap } from '@fetchproxy/bootstrap';
|
|
61
|
+
import { classifyBridgeError } from '@fetchproxy/server';
|
|
61
62
|
import pkg from '../package.json' with { type: 'json' };
|
|
62
63
|
import { extractCookieValue } from './client.js';
|
|
63
64
|
/**
|
|
@@ -143,6 +144,18 @@ export async function resolveAuth() {
|
|
|
143
144
|
return { cookies, source: 'fetchproxy' };
|
|
144
145
|
}
|
|
145
146
|
catch (e) {
|
|
147
|
+
// 0.8.0+ typed-error discrimination. The fetchproxy server already
|
|
148
|
+
// retries once on SW eviction (bridgeReviveDelayMs=2000 default), so
|
|
149
|
+
// a thrown FetchproxyBridgeDownError means the retry also failed —
|
|
150
|
+
// the extension's service worker is genuinely down and the user
|
|
151
|
+
// needs to wake it. The `.hint` is the actionable copy
|
|
152
|
+
// ("click the extension toolbar icon...") that we'd otherwise have
|
|
153
|
+
// to hand-write here. Surface it verbatim so users in path 3 get
|
|
154
|
+
// the same self-service guidance as path 4.
|
|
155
|
+
if (classifyBridgeError(e) === 'bridge_down') {
|
|
156
|
+
const downErr = e;
|
|
157
|
+
throw new Error(`CK auth: fetchproxy bridge is down (extension service worker unreachable after retry). ${downErr.hint}`);
|
|
158
|
+
}
|
|
146
159
|
const msg = e instanceof Error ? e.message : String(e);
|
|
147
160
|
throw new Error(`CK auth: no CK_COOKIES set, and fetchproxy fallback failed: ${msg}`);
|
|
148
161
|
}
|
package/dist/bundle.js
CHANGED
|
@@ -36406,6 +36406,52 @@ var FetchproxyHttpError = class extends Error {
|
|
|
36406
36406
|
this.name = "FetchproxyHttpError";
|
|
36407
36407
|
}
|
|
36408
36408
|
};
|
|
36409
|
+
var FetchproxyBridgeDownError = class extends FetchproxyProtocolError {
|
|
36410
|
+
originalError;
|
|
36411
|
+
retryAttempted;
|
|
36412
|
+
op;
|
|
36413
|
+
url;
|
|
36414
|
+
/** 0.8.0+: bridge role at throw time; `null` if listen() hadn't bound yet. */
|
|
36415
|
+
role;
|
|
36416
|
+
/** 0.8.0+: bridge port at throw time (the same port `listen()` bound to). */
|
|
36417
|
+
port;
|
|
36418
|
+
hint;
|
|
36419
|
+
constructor(args) {
|
|
36420
|
+
const retryAttempted = args.retryAttempted ?? false;
|
|
36421
|
+
const op = args.op ?? "fetch";
|
|
36422
|
+
const retryClause = retryAttempted ? `Server already burned a one-shot lazy-revive retry; SW is still down. ` : `Server lazy-revive retry was disabled (bridgeReviveDelayMs unset/0). `;
|
|
36423
|
+
const hint = `the fetchproxy extension's service worker is not responding ("${args.originalError}"). Chrome evicts extension service workers after ~30s idle by default. ${retryClause}Wake it by clicking the fetchproxy extension toolbar icon, then retry. If it keeps happening, reload the extension from chrome://extensions.`;
|
|
36424
|
+
super(`fetchproxy bridge down during ${op}${args.url ? ` (${args.url})` : ""}. ${hint}`);
|
|
36425
|
+
this.name = "FetchproxyBridgeDownError";
|
|
36426
|
+
this.originalError = args.originalError;
|
|
36427
|
+
this.retryAttempted = retryAttempted;
|
|
36428
|
+
this.op = op;
|
|
36429
|
+
if (args.url !== void 0)
|
|
36430
|
+
this.url = args.url;
|
|
36431
|
+
this.role = args.role ?? null;
|
|
36432
|
+
this.port = args.port ?? 0;
|
|
36433
|
+
this.hint = hint;
|
|
36434
|
+
}
|
|
36435
|
+
};
|
|
36436
|
+
var FetchproxyTimeoutError = class extends FetchproxyProtocolError {
|
|
36437
|
+
url;
|
|
36438
|
+
timeoutMs;
|
|
36439
|
+
/** 0.8.0+: bridge role at throw time; `null` if listen() hadn't bound yet. */
|
|
36440
|
+
role;
|
|
36441
|
+
/** 0.8.0+: bridge port at throw time. */
|
|
36442
|
+
port;
|
|
36443
|
+
/** 0.8.0+: actual elapsed milliseconds when the timer won the race. */
|
|
36444
|
+
elapsedMs;
|
|
36445
|
+
constructor(args) {
|
|
36446
|
+
super(`fetchproxy: ${args.url} did not respond within ${args.timeoutMs}ms`);
|
|
36447
|
+
this.name = "FetchproxyTimeoutError";
|
|
36448
|
+
this.url = args.url;
|
|
36449
|
+
this.timeoutMs = args.timeoutMs;
|
|
36450
|
+
this.role = args.role ?? null;
|
|
36451
|
+
this.port = args.port ?? 0;
|
|
36452
|
+
this.elapsedMs = args.elapsedMs ?? args.timeoutMs;
|
|
36453
|
+
}
|
|
36454
|
+
};
|
|
36409
36455
|
var SUBDOMAIN_LABEL_RE = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
|
|
36410
36456
|
function assertSubdomainLabel(label) {
|
|
36411
36457
|
if (!SUBDOMAIN_LABEL_RE.test(label)) {
|
|
@@ -36443,6 +36489,18 @@ var FetchproxyServer = class {
|
|
|
36443
36489
|
hostHandle = null;
|
|
36444
36490
|
peerHandle = null;
|
|
36445
36491
|
nextRequestId = 1;
|
|
36492
|
+
// 0.8.0+: process-wide freshness counters surfaced via bridgeHealth().
|
|
36493
|
+
// Replaces the local copies every downstream MCP was rolling on top
|
|
36494
|
+
// of its own transport adapter — see realty-mcp cohort drift notes.
|
|
36495
|
+
// Updated by recordSuccess / recordFailure from fetch + capture paths.
|
|
36496
|
+
// `lastExtensionMessageAt` (#23 ask 4) is updated whenever any inner
|
|
36497
|
+
// frame from the extension arrives — gives extension-side liveness
|
|
36498
|
+
// distinct from per-call success/failure.
|
|
36499
|
+
lastSuccessAt = null;
|
|
36500
|
+
lastFailureAt = null;
|
|
36501
|
+
lastFailureReason = null;
|
|
36502
|
+
consecutiveFailures = 0;
|
|
36503
|
+
lastExtensionMessageAt = null;
|
|
36446
36504
|
pending = /* @__PURE__ */ new Map();
|
|
36447
36505
|
// Separate pending map for read_cookies so the response shape (cookies
|
|
36448
36506
|
// string vs status/body) doesn't have to share a union type with fetch.
|
|
@@ -36511,6 +36569,12 @@ var FetchproxyServer = class {
|
|
|
36511
36569
|
key: d.key,
|
|
36512
36570
|
jsonPointer: d.jsonPointer
|
|
36513
36571
|
})),
|
|
36572
|
+
// 0.8.0+: timer + lazy-revive default to ON. Every realty MCP
|
|
36573
|
+
// adapter was about to set these to the same numbers anyway; the
|
|
36574
|
+
// back-door is `0` (explicit opt-out) if a caller genuinely wants
|
|
36575
|
+
// the legacy hang-forever / fail-once-on-SW-eviction behavior.
|
|
36576
|
+
fetchTimeoutMs: opts.fetchTimeoutMs ?? 3e4,
|
|
36577
|
+
bridgeReviveDelayMs: opts.bridgeReviveDelayMs ?? 2e3,
|
|
36514
36578
|
identityDir: opts.identityDir,
|
|
36515
36579
|
onPairCode: opts.onPairCode
|
|
36516
36580
|
};
|
|
@@ -36646,7 +36710,7 @@ var FetchproxyServer = class {
|
|
|
36646
36710
|
}
|
|
36647
36711
|
}
|
|
36648
36712
|
pairingErrorMessage(code) {
|
|
36649
|
-
return `fetchproxy: pairing required for ${this.opts.serverName}
|
|
36713
|
+
return `fetchproxy transport error: pairing required for ${this.opts.serverName}. Tell the user to open the Transporter browser extension popup and approve the pair request. The pair code is: ${code} \u2014 display this code to the user so they can verify it matches.`;
|
|
36650
36714
|
}
|
|
36651
36715
|
/**
|
|
36652
36716
|
* Raw single-shot fetch through the bridge. Most callers should prefer
|
|
@@ -36667,8 +36731,71 @@ var FetchproxyServer = class {
|
|
|
36667
36731
|
const pendingCode = this.currentPendingPairCode();
|
|
36668
36732
|
if (pendingCode !== null) {
|
|
36669
36733
|
const error51 = this.pairingErrorMessage(pendingCode);
|
|
36670
|
-
return {
|
|
36734
|
+
return {
|
|
36735
|
+
ok: false,
|
|
36736
|
+
error: error51,
|
|
36737
|
+
kind: classifyFetchError(error51),
|
|
36738
|
+
retryAttempted: false
|
|
36739
|
+
};
|
|
36740
|
+
}
|
|
36741
|
+
const first = await this._fetchOnceWithTimeout(init);
|
|
36742
|
+
const reviveMs = this.opts.bridgeReviveDelayMs;
|
|
36743
|
+
let final = first;
|
|
36744
|
+
if (!first.ok && first.kind === "content_script_unreachable" && reviveMs !== void 0 && reviveMs > 0) {
|
|
36745
|
+
await new Promise((r) => setTimeout(r, reviveMs));
|
|
36746
|
+
const second = await this._fetchOnceWithTimeout(init);
|
|
36747
|
+
if (second.ok)
|
|
36748
|
+
this.recordSuccess();
|
|
36749
|
+
else
|
|
36750
|
+
this.recordFailure(`${second.kind ?? "other"}: ${second.error}`);
|
|
36751
|
+
return { ...second, retryAttempted: true };
|
|
36671
36752
|
}
|
|
36753
|
+
if (first.ok)
|
|
36754
|
+
this.recordSuccess();
|
|
36755
|
+
else
|
|
36756
|
+
this.recordFailure(`${first.kind ?? "other"}: ${first.error}`);
|
|
36757
|
+
return { ...first, retryAttempted: false };
|
|
36758
|
+
}
|
|
36759
|
+
/**
|
|
36760
|
+
* 0.8.0+: snapshot of the bridge's process-wide freshness counters,
|
|
36761
|
+
* suitable for surfacing through a downstream MCP's healthcheck tool.
|
|
36762
|
+
* Counters reset on a success (consecutiveFailures), accumulate
|
|
36763
|
+
* across the process lifetime otherwise. Replaces the per-MCP
|
|
36764
|
+
* duplication the realty cohort had been rolling in their adapters.
|
|
36765
|
+
* `lastExtensionMessageAt` is updated whenever ANY inner frame
|
|
36766
|
+
* arrives from the extension — gives extension-side liveness
|
|
36767
|
+
* distinct from server-side success/failure of the user-visible
|
|
36768
|
+
* call (addresses #23 ask 4).
|
|
36769
|
+
*/
|
|
36770
|
+
bridgeHealth() {
|
|
36771
|
+
return {
|
|
36772
|
+
role: this.role,
|
|
36773
|
+
port: this.opts.port,
|
|
36774
|
+
serverVersion: this.opts.version,
|
|
36775
|
+
fetchTimeoutMs: this.opts.fetchTimeoutMs ?? 0,
|
|
36776
|
+
bridgeReviveDelayMs: this.opts.bridgeReviveDelayMs ?? 0,
|
|
36777
|
+
lastSuccessAt: this.lastSuccessAt,
|
|
36778
|
+
lastFailureAt: this.lastFailureAt,
|
|
36779
|
+
lastFailureReason: this.lastFailureReason,
|
|
36780
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
36781
|
+
lastExtensionMessageAt: this.lastExtensionMessageAt
|
|
36782
|
+
};
|
|
36783
|
+
}
|
|
36784
|
+
recordSuccess() {
|
|
36785
|
+
this.lastSuccessAt = Date.now();
|
|
36786
|
+
this.consecutiveFailures = 0;
|
|
36787
|
+
}
|
|
36788
|
+
recordFailure(reason) {
|
|
36789
|
+
this.lastFailureAt = Date.now();
|
|
36790
|
+
this.lastFailureReason = reason;
|
|
36791
|
+
this.consecutiveFailures += 1;
|
|
36792
|
+
}
|
|
36793
|
+
/**
|
|
36794
|
+
* Single bridge round-trip, wrapped by `fetchTimeoutMs` when set.
|
|
36795
|
+
* On timeout returns the `{ok:false, kind:'timeout'}` envelope —
|
|
36796
|
+
* the throwing surface is the convenience methods.
|
|
36797
|
+
*/
|
|
36798
|
+
async _fetchOnceWithTimeout(init) {
|
|
36672
36799
|
const id = this.nextRequestId++;
|
|
36673
36800
|
const inner = { type: "request", id, op: "fetch", init };
|
|
36674
36801
|
const pending = new Promise((resolve) => {
|
|
@@ -36679,7 +36806,61 @@ var FetchproxyServer = class {
|
|
|
36679
36806
|
} else if (this.peerHandle) {
|
|
36680
36807
|
await this.peerHandle.sendInner(inner);
|
|
36681
36808
|
}
|
|
36682
|
-
|
|
36809
|
+
const timeoutMs = this.opts.fetchTimeoutMs;
|
|
36810
|
+
if (timeoutMs === void 0 || timeoutMs <= 0)
|
|
36811
|
+
return pending;
|
|
36812
|
+
let timer;
|
|
36813
|
+
const start = Date.now();
|
|
36814
|
+
try {
|
|
36815
|
+
return await Promise.race([
|
|
36816
|
+
pending,
|
|
36817
|
+
new Promise((resolve) => {
|
|
36818
|
+
timer = setTimeout(() => {
|
|
36819
|
+
this.pending.delete(id);
|
|
36820
|
+
const elapsedMs = Date.now() - start;
|
|
36821
|
+
const error51 = `fetchproxy: ${init.url} did not respond within ${timeoutMs}ms`;
|
|
36822
|
+
resolve({
|
|
36823
|
+
ok: false,
|
|
36824
|
+
error: error51,
|
|
36825
|
+
kind: "timeout",
|
|
36826
|
+
retryAttempted: false,
|
|
36827
|
+
elapsedMs
|
|
36828
|
+
});
|
|
36829
|
+
}, timeoutMs);
|
|
36830
|
+
})
|
|
36831
|
+
]);
|
|
36832
|
+
} finally {
|
|
36833
|
+
if (timer)
|
|
36834
|
+
clearTimeout(timer);
|
|
36835
|
+
}
|
|
36836
|
+
}
|
|
36837
|
+
/**
|
|
36838
|
+
* Map an `ok:false` fetch result to its typed throwable. Centralizes
|
|
36839
|
+
* the kind-to-error-class switch so `request()` and (via the same
|
|
36840
|
+
* logic re-implemented inline) `captureRequestHeader()` agree on what
|
|
36841
|
+
* to throw.
|
|
36842
|
+
*/
|
|
36843
|
+
_typedErrorFor(result, url2, op, retryAttempted) {
|
|
36844
|
+
if (result.kind === "timeout") {
|
|
36845
|
+
return new FetchproxyTimeoutError({
|
|
36846
|
+
url: url2,
|
|
36847
|
+
timeoutMs: this.opts.fetchTimeoutMs ?? 0,
|
|
36848
|
+
role: this.role,
|
|
36849
|
+
port: this.opts.port,
|
|
36850
|
+
elapsedMs: result.elapsedMs
|
|
36851
|
+
});
|
|
36852
|
+
}
|
|
36853
|
+
if (result.kind === "content_script_unreachable") {
|
|
36854
|
+
return new FetchproxyBridgeDownError({
|
|
36855
|
+
originalError: result.error,
|
|
36856
|
+
retryAttempted,
|
|
36857
|
+
op,
|
|
36858
|
+
url: url2,
|
|
36859
|
+
role: this.role,
|
|
36860
|
+
port: this.opts.port
|
|
36861
|
+
});
|
|
36862
|
+
}
|
|
36863
|
+
return new FetchproxyProtocolError(result.error);
|
|
36683
36864
|
}
|
|
36684
36865
|
/**
|
|
36685
36866
|
* Convenience wrapper around `fetch()`. Builds the URL from a path
|
|
@@ -36702,8 +36883,18 @@ var FetchproxyServer = class {
|
|
|
36702
36883
|
if (opts.subdomain !== void 0)
|
|
36703
36884
|
assertSubdomainLabel(opts.subdomain);
|
|
36704
36885
|
const baseDomain = this.resolveBaseDomain(opts.domain);
|
|
36705
|
-
const
|
|
36706
|
-
|
|
36886
|
+
const isAbsolute = path.startsWith("http://") || path.startsWith("https://");
|
|
36887
|
+
let host;
|
|
36888
|
+
if (isAbsolute) {
|
|
36889
|
+
try {
|
|
36890
|
+
host = new URL(path).host;
|
|
36891
|
+
} catch {
|
|
36892
|
+
throw new Error(`FetchproxyServer.request: absolute path is not a valid URL: ${JSON.stringify(path)}`);
|
|
36893
|
+
}
|
|
36894
|
+
} else {
|
|
36895
|
+
host = opts.subdomain ? `${opts.subdomain}.${baseDomain}` : baseDomain;
|
|
36896
|
+
}
|
|
36897
|
+
const url2 = isAbsolute ? path : `https://${host}${path}`;
|
|
36707
36898
|
assertUrlInDomains("request url", url2, this.opts.domains);
|
|
36708
36899
|
const init = {
|
|
36709
36900
|
url: url2,
|
|
@@ -36714,7 +36905,7 @@ var FetchproxyServer = class {
|
|
|
36714
36905
|
};
|
|
36715
36906
|
const result = await this.fetch(init);
|
|
36716
36907
|
if (!result.ok) {
|
|
36717
|
-
throw
|
|
36908
|
+
throw this._typedErrorFor(result, init.url, "fetch", result.retryAttempted ?? false);
|
|
36718
36909
|
}
|
|
36719
36910
|
const response = {
|
|
36720
36911
|
status: result.status,
|
|
@@ -36924,10 +37115,73 @@ var FetchproxyServer = class {
|
|
|
36924
37115
|
}
|
|
36925
37116
|
await this.ensureConnected();
|
|
36926
37117
|
this.throwIfPendingPair();
|
|
36927
|
-
const
|
|
36928
|
-
|
|
36929
|
-
|
|
37118
|
+
const decls = this.opts.captureHeaders;
|
|
37119
|
+
let resolved;
|
|
37120
|
+
if (opts?.urlPattern !== void 0 && opts?.headerName !== void 0) {
|
|
37121
|
+
const found = decls.find((d) => d.urlPattern === opts.urlPattern && d.headerName === opts.headerName);
|
|
37122
|
+
if (!found) {
|
|
37123
|
+
throw new Error(`FetchproxyServer.captureRequestHeader: (urlPattern=${JSON.stringify(opts.urlPattern)}, headerName=${JSON.stringify(opts.headerName)}) not declared in captureHeaders`);
|
|
37124
|
+
}
|
|
37125
|
+
resolved = found;
|
|
37126
|
+
} else if (opts?.urlPattern === void 0 && opts?.headerName === void 0) {
|
|
37127
|
+
if (decls.length === 0) {
|
|
37128
|
+
throw new Error("FetchproxyServer.captureRequestHeader: no captureHeaders declared on this server \u2014 declare at least one entry in FetchproxyServerOpts.captureHeaders, or pass {urlPattern, headerName} explicitly");
|
|
37129
|
+
}
|
|
37130
|
+
if (decls.length > 1) {
|
|
37131
|
+
const list = decls.map((d) => `${JSON.stringify(d.urlPattern)}/${JSON.stringify(d.headerName)}`).join(", ");
|
|
37132
|
+
throw new Error(`FetchproxyServer.captureRequestHeader: multiple captureHeaders declared (${decls.length}: ${list}); pass {urlPattern, headerName} to disambiguate`);
|
|
37133
|
+
}
|
|
37134
|
+
resolved = decls[0];
|
|
37135
|
+
} else {
|
|
37136
|
+
throw new Error("FetchproxyServer.captureRequestHeader: pass both urlPattern AND headerName, or neither (which defaults to the single declared entry)");
|
|
36930
37137
|
}
|
|
37138
|
+
const callOpts = { ...resolved, ...opts?.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {} };
|
|
37139
|
+
try {
|
|
37140
|
+
const result = await this._captureRequestHeaderOnce(callOpts);
|
|
37141
|
+
this.recordSuccess();
|
|
37142
|
+
return result;
|
|
37143
|
+
} catch (err) {
|
|
37144
|
+
const swDown = err instanceof FetchproxyProtocolError && classifyFetchError(err.message) === "content_script_unreachable";
|
|
37145
|
+
if (!swDown) {
|
|
37146
|
+
this.recordFailure(`capture_request_header: ${err.message ?? String(err)}`);
|
|
37147
|
+
throw err;
|
|
37148
|
+
}
|
|
37149
|
+
const reviveMs = this.opts.bridgeReviveDelayMs ?? 0;
|
|
37150
|
+
if (reviveMs > 0) {
|
|
37151
|
+
await new Promise((r) => setTimeout(r, reviveMs));
|
|
37152
|
+
try {
|
|
37153
|
+
const result = await this._captureRequestHeaderOnce(callOpts);
|
|
37154
|
+
this.recordSuccess();
|
|
37155
|
+
return result;
|
|
37156
|
+
} catch (retryErr) {
|
|
37157
|
+
const stillDown = retryErr instanceof FetchproxyProtocolError && classifyFetchError(retryErr.message) === "content_script_unreachable";
|
|
37158
|
+
if (!stillDown) {
|
|
37159
|
+
this.recordFailure(`capture_request_header: ${retryErr.message ?? String(retryErr)}`);
|
|
37160
|
+
throw retryErr;
|
|
37161
|
+
}
|
|
37162
|
+
this.recordFailure(`capture_request_header bridge-down: ${retryErr.message}`);
|
|
37163
|
+
throw new FetchproxyBridgeDownError({
|
|
37164
|
+
originalError: retryErr.message,
|
|
37165
|
+
retryAttempted: true,
|
|
37166
|
+
op: "capture_request_header",
|
|
37167
|
+
url: resolved.urlPattern,
|
|
37168
|
+
role: this.role,
|
|
37169
|
+
port: this.opts.port
|
|
37170
|
+
});
|
|
37171
|
+
}
|
|
37172
|
+
}
|
|
37173
|
+
this.recordFailure(`capture_request_header bridge-down: ${err.message}`);
|
|
37174
|
+
throw new FetchproxyBridgeDownError({
|
|
37175
|
+
originalError: err.message,
|
|
37176
|
+
retryAttempted: false,
|
|
37177
|
+
op: "capture_request_header",
|
|
37178
|
+
url: resolved.urlPattern,
|
|
37179
|
+
role: this.role,
|
|
37180
|
+
port: this.opts.port
|
|
37181
|
+
});
|
|
37182
|
+
}
|
|
37183
|
+
}
|
|
37184
|
+
async _captureRequestHeaderOnce(opts) {
|
|
36931
37185
|
const id = this.nextRequestId++;
|
|
36932
37186
|
const inner = {
|
|
36933
37187
|
type: "request",
|
|
@@ -37036,18 +37290,35 @@ var FetchproxyServer = class {
|
|
|
37036
37290
|
onInner(inner) {
|
|
37037
37291
|
if (inner.type !== "response")
|
|
37038
37292
|
return;
|
|
37293
|
+
this.lastExtensionMessageAt = Date.now();
|
|
37039
37294
|
const fetchCb = this.pending.get(inner.id);
|
|
37040
37295
|
if (fetchCb) {
|
|
37041
37296
|
this.pending.delete(inner.id);
|
|
37042
37297
|
if (inner.ok) {
|
|
37043
37298
|
if (inner.op === void 0 || inner.op === "fetch") {
|
|
37044
|
-
fetchCb({
|
|
37299
|
+
fetchCb({
|
|
37300
|
+
ok: true,
|
|
37301
|
+
status: inner.status,
|
|
37302
|
+
url: inner.url,
|
|
37303
|
+
body: inner.body,
|
|
37304
|
+
retryAttempted: false
|
|
37305
|
+
});
|
|
37045
37306
|
} else {
|
|
37046
37307
|
const error51 = `unexpected ${inner.op} response on fetch awaiter`;
|
|
37047
|
-
fetchCb({
|
|
37308
|
+
fetchCb({
|
|
37309
|
+
ok: false,
|
|
37310
|
+
error: error51,
|
|
37311
|
+
kind: classifyFetchError(error51),
|
|
37312
|
+
retryAttempted: false
|
|
37313
|
+
});
|
|
37048
37314
|
}
|
|
37049
37315
|
} else {
|
|
37050
|
-
fetchCb({
|
|
37316
|
+
fetchCb({
|
|
37317
|
+
ok: false,
|
|
37318
|
+
error: inner.error,
|
|
37319
|
+
kind: classifyFetchError(inner.error),
|
|
37320
|
+
retryAttempted: false
|
|
37321
|
+
});
|
|
37051
37322
|
}
|
|
37052
37323
|
return;
|
|
37053
37324
|
}
|
|
@@ -37117,7 +37388,12 @@ var FetchproxyServer = class {
|
|
|
37117
37388
|
rejectAllPending(reason = "extension disconnected") {
|
|
37118
37389
|
const err = new FetchproxyProtocolError(reason);
|
|
37119
37390
|
for (const cb of this.pending.values()) {
|
|
37120
|
-
cb({
|
|
37391
|
+
cb({
|
|
37392
|
+
ok: false,
|
|
37393
|
+
error: err.message,
|
|
37394
|
+
kind: classifyFetchError(err.message),
|
|
37395
|
+
retryAttempted: false
|
|
37396
|
+
});
|
|
37121
37397
|
}
|
|
37122
37398
|
this.pending.clear();
|
|
37123
37399
|
for (const cb of this.pendingReadCookies.values()) {
|
|
@@ -37182,6 +37458,19 @@ var FetchproxyServer = class {
|
|
|
37182
37458
|
}
|
|
37183
37459
|
};
|
|
37184
37460
|
|
|
37461
|
+
// node_modules/@fetchproxy/server/dist/classify-bridge-error.js
|
|
37462
|
+
function classifyBridgeError(err) {
|
|
37463
|
+
if (err instanceof FetchproxyTimeoutError)
|
|
37464
|
+
return "timeout";
|
|
37465
|
+
if (err instanceof FetchproxyBridgeDownError)
|
|
37466
|
+
return "bridge_down";
|
|
37467
|
+
if (err instanceof FetchproxyHttpError)
|
|
37468
|
+
return "http";
|
|
37469
|
+
if (err instanceof FetchproxyProtocolError)
|
|
37470
|
+
return "protocol";
|
|
37471
|
+
return "other";
|
|
37472
|
+
}
|
|
37473
|
+
|
|
37185
37474
|
// node_modules/@fetchproxy/bootstrap/dist/index.js
|
|
37186
37475
|
var defaultFactory = (opts) => new FetchproxyServer(opts);
|
|
37187
37476
|
async function bootstrap(opts) {
|
|
@@ -37236,7 +37525,11 @@ async function bootstrap(opts) {
|
|
|
37236
37525
|
key: p.storageKey,
|
|
37237
37526
|
jsonPointer: p.jsonPointer
|
|
37238
37527
|
})),
|
|
37239
|
-
onPairCode: opts.onPairCode
|
|
37528
|
+
onPairCode: opts.onPairCode,
|
|
37529
|
+
// 0.8.0+ pass-through. Only forwarded when the caller set them;
|
|
37530
|
+
// unset → server defaults apply (30000 / 2000 in 0.8.0).
|
|
37531
|
+
...opts.fetchTimeoutMs !== void 0 ? { fetchTimeoutMs: opts.fetchTimeoutMs } : {},
|
|
37532
|
+
...opts.bridgeReviveDelayMs !== void 0 ? { bridgeReviveDelayMs: opts.bridgeReviveDelayMs } : {}
|
|
37240
37533
|
});
|
|
37241
37534
|
const storageDomainOpts = {};
|
|
37242
37535
|
if (opts.storageDomain !== void 0)
|
|
@@ -37339,7 +37632,7 @@ var BootstrapDisabledError = class extends Error {
|
|
|
37339
37632
|
// package.json
|
|
37340
37633
|
var package_default = {
|
|
37341
37634
|
name: "creditkarma-mcp",
|
|
37342
|
-
version: "2.
|
|
37635
|
+
version: "2.2.0",
|
|
37343
37636
|
mcpName: "io.github.chrischall/creditkarma-mcp",
|
|
37344
37637
|
description: "MCP server for Credit Karma \u2014 natural-language access to your transactions, spending, and accounts",
|
|
37345
37638
|
author: "Claude Code (AI) <https://www.anthropic.com/claude>",
|
|
@@ -37383,7 +37676,8 @@ var package_default = {
|
|
|
37383
37676
|
"test:coverage": "vitest run --coverage"
|
|
37384
37677
|
},
|
|
37385
37678
|
dependencies: {
|
|
37386
|
-
"@fetchproxy/bootstrap": "^0.
|
|
37679
|
+
"@fetchproxy/bootstrap": "^0.8.0",
|
|
37680
|
+
"@fetchproxy/server": "^0.8.0",
|
|
37387
37681
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
37388
37682
|
dotenv: "^17.4.2",
|
|
37389
37683
|
zod: "^4.4.3"
|
|
@@ -37453,6 +37747,12 @@ async function resolveAuth() {
|
|
|
37453
37747
|
const cookies = `CKTRKID=${cktrkid}; CKAT=${ckat}`;
|
|
37454
37748
|
return { cookies, source: "fetchproxy" };
|
|
37455
37749
|
} catch (e) {
|
|
37750
|
+
if (classifyBridgeError(e) === "bridge_down") {
|
|
37751
|
+
const downErr = e;
|
|
37752
|
+
throw new Error(
|
|
37753
|
+
`CK auth: fetchproxy bridge is down (extension service worker unreachable after retry). ${downErr.hint}`
|
|
37754
|
+
);
|
|
37755
|
+
}
|
|
37456
37756
|
const msg = e instanceof Error ? e.message : String(e);
|
|
37457
37757
|
throw new Error(
|
|
37458
37758
|
`CK auth: no CK_COOKIES set, and fetchproxy fallback failed: ${msg}`
|
|
@@ -37913,7 +38213,7 @@ async function main() {
|
|
|
37913
38213
|
mcpJsonPath
|
|
37914
38214
|
};
|
|
37915
38215
|
const server = new McpServer(
|
|
37916
|
-
{ name: "creditkarma-mcp", version: "2.
|
|
38216
|
+
{ name: "creditkarma-mcp", version: "2.2.0" }
|
|
37917
38217
|
// x-release-please-version
|
|
37918
38218
|
);
|
|
37919
38219
|
registerAuthTools(server, ctx);
|
package/dist/index.js
CHANGED
|
@@ -63,7 +63,7 @@ async function main() {
|
|
|
63
63
|
db,
|
|
64
64
|
mcpJsonPath
|
|
65
65
|
};
|
|
66
|
-
const server = new McpServer({ name: 'creditkarma-mcp', version: '2.
|
|
66
|
+
const server = new McpServer({ name: 'creditkarma-mcp', version: '2.2.0' } // x-release-please-version
|
|
67
67
|
);
|
|
68
68
|
registerAuthTools(server, ctx);
|
|
69
69
|
registerSyncTools(server, ctx);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "creditkarma-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"mcpName": "io.github.chrischall/creditkarma-mcp",
|
|
5
5
|
"description": "MCP server for Credit Karma — natural-language access to your transactions, spending, and accounts",
|
|
6
6
|
"author": "Claude Code (AI) <https://www.anthropic.com/claude>",
|
|
@@ -44,7 +44,8 @@
|
|
|
44
44
|
"test:coverage": "vitest run --coverage"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@fetchproxy/bootstrap": "^0.
|
|
47
|
+
"@fetchproxy/bootstrap": "^0.8.0",
|
|
48
|
+
"@fetchproxy/server": "^0.8.0",
|
|
48
49
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
49
50
|
"dotenv": "^17.4.2",
|
|
50
51
|
"zod": "^4.4.3"
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/chrischall/creditkarma-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "2.
|
|
9
|
+
"version": "2.2.0",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "creditkarma-mcp",
|
|
14
|
-
"version": "2.
|
|
14
|
+
"version": "2.2.0",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|