honeybook-mcp 0.2.4 → 0.3.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/dist/auth.js +6 -0
- package/dist/bundle.js +317 -17
- package/dist/index.js +1 -1
- package/package.json +3 -2
- package/server.json +2 -2
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"metadata": {
|
|
9
9
|
"description": "HoneyBook client-portal tools for Claude Code",
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.3.0"
|
|
11
11
|
},
|
|
12
12
|
"plugins": [
|
|
13
13
|
{
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"displayName": "HoneyBook",
|
|
16
16
|
"source": "./",
|
|
17
17
|
"description": "HoneyBook client-portal MCP for Claude — view wedding-vendor contracts and invoices via MCP",
|
|
18
|
-
"version": "0.
|
|
18
|
+
"version": "0.3.0",
|
|
19
19
|
"author": {
|
|
20
20
|
"name": "Chris Chall"
|
|
21
21
|
},
|
package/dist/auth.js
CHANGED
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
// - Persistence (sessionStore.add) is the existing side effect; tests
|
|
57
57
|
// verify the captured session round-trips through sessionStore.get.
|
|
58
58
|
import { bootstrap } from '@fetchproxy/bootstrap';
|
|
59
|
+
import { classifyBridgeError } from '@fetchproxy/server';
|
|
59
60
|
import pkg from '../package.json' with { type: 'json' };
|
|
60
61
|
import { sessionStore, normalizeOrigin } from './sessions.js';
|
|
61
62
|
/**
|
|
@@ -167,6 +168,11 @@ export async function captureSessionViaFetchproxy(opts) {
|
|
|
167
168
|
});
|
|
168
169
|
}
|
|
169
170
|
catch (e) {
|
|
171
|
+
// SW eviction retry exhausted — surface library's typed `.hint` instead of the generic "open magic link" message.
|
|
172
|
+
if (classifyBridgeError(e) === 'bridge_down') {
|
|
173
|
+
const downErr = e;
|
|
174
|
+
throw new Error(`HoneyBook auth: fetchproxy bridge is down (extension service worker unreachable after retry). ${downErr.hint}`);
|
|
175
|
+
}
|
|
170
176
|
const msg = e instanceof Error ? e.message : String(e);
|
|
171
177
|
throw new Error(`HoneyBook auth: fetchproxy capture failed: ${msg} — ` +
|
|
172
178
|
'open the vendor magic-link URL in Chrome (with the fetchproxy 0.3.0 extension installed), ' +
|
package/dist/bundle.js
CHANGED
|
@@ -36133,6 +36133,52 @@ var FetchproxyHttpError = class extends Error {
|
|
|
36133
36133
|
this.name = "FetchproxyHttpError";
|
|
36134
36134
|
}
|
|
36135
36135
|
};
|
|
36136
|
+
var FetchproxyBridgeDownError = class extends FetchproxyProtocolError {
|
|
36137
|
+
originalError;
|
|
36138
|
+
retryAttempted;
|
|
36139
|
+
op;
|
|
36140
|
+
url;
|
|
36141
|
+
/** 0.8.0+: bridge role at throw time; `null` if listen() hadn't bound yet. */
|
|
36142
|
+
role;
|
|
36143
|
+
/** 0.8.0+: bridge port at throw time (the same port `listen()` bound to). */
|
|
36144
|
+
port;
|
|
36145
|
+
hint;
|
|
36146
|
+
constructor(args) {
|
|
36147
|
+
const retryAttempted = args.retryAttempted ?? false;
|
|
36148
|
+
const op = args.op ?? "fetch";
|
|
36149
|
+
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). `;
|
|
36150
|
+
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.`;
|
|
36151
|
+
super(`fetchproxy bridge down during ${op}${args.url ? ` (${args.url})` : ""}. ${hint}`);
|
|
36152
|
+
this.name = "FetchproxyBridgeDownError";
|
|
36153
|
+
this.originalError = args.originalError;
|
|
36154
|
+
this.retryAttempted = retryAttempted;
|
|
36155
|
+
this.op = op;
|
|
36156
|
+
if (args.url !== void 0)
|
|
36157
|
+
this.url = args.url;
|
|
36158
|
+
this.role = args.role ?? null;
|
|
36159
|
+
this.port = args.port ?? 0;
|
|
36160
|
+
this.hint = hint;
|
|
36161
|
+
}
|
|
36162
|
+
};
|
|
36163
|
+
var FetchproxyTimeoutError = class extends FetchproxyProtocolError {
|
|
36164
|
+
url;
|
|
36165
|
+
timeoutMs;
|
|
36166
|
+
/** 0.8.0+: bridge role at throw time; `null` if listen() hadn't bound yet. */
|
|
36167
|
+
role;
|
|
36168
|
+
/** 0.8.0+: bridge port at throw time. */
|
|
36169
|
+
port;
|
|
36170
|
+
/** 0.8.0+: actual elapsed milliseconds when the timer won the race. */
|
|
36171
|
+
elapsedMs;
|
|
36172
|
+
constructor(args) {
|
|
36173
|
+
super(`fetchproxy: ${args.url} did not respond within ${args.timeoutMs}ms`);
|
|
36174
|
+
this.name = "FetchproxyTimeoutError";
|
|
36175
|
+
this.url = args.url;
|
|
36176
|
+
this.timeoutMs = args.timeoutMs;
|
|
36177
|
+
this.role = args.role ?? null;
|
|
36178
|
+
this.port = args.port ?? 0;
|
|
36179
|
+
this.elapsedMs = args.elapsedMs ?? args.timeoutMs;
|
|
36180
|
+
}
|
|
36181
|
+
};
|
|
36136
36182
|
var SUBDOMAIN_LABEL_RE = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
|
|
36137
36183
|
function assertSubdomainLabel(label) {
|
|
36138
36184
|
if (!SUBDOMAIN_LABEL_RE.test(label)) {
|
|
@@ -36170,6 +36216,18 @@ var FetchproxyServer = class {
|
|
|
36170
36216
|
hostHandle = null;
|
|
36171
36217
|
peerHandle = null;
|
|
36172
36218
|
nextRequestId = 1;
|
|
36219
|
+
// 0.8.0+: process-wide freshness counters surfaced via bridgeHealth().
|
|
36220
|
+
// Replaces the local copies every downstream MCP was rolling on top
|
|
36221
|
+
// of its own transport adapter — see realty-mcp cohort drift notes.
|
|
36222
|
+
// Updated by recordSuccess / recordFailure from fetch + capture paths.
|
|
36223
|
+
// `lastExtensionMessageAt` (#23 ask 4) is updated whenever any inner
|
|
36224
|
+
// frame from the extension arrives — gives extension-side liveness
|
|
36225
|
+
// distinct from per-call success/failure.
|
|
36226
|
+
lastSuccessAt = null;
|
|
36227
|
+
lastFailureAt = null;
|
|
36228
|
+
lastFailureReason = null;
|
|
36229
|
+
consecutiveFailures = 0;
|
|
36230
|
+
lastExtensionMessageAt = null;
|
|
36173
36231
|
pending = /* @__PURE__ */ new Map();
|
|
36174
36232
|
// Separate pending map for read_cookies so the response shape (cookies
|
|
36175
36233
|
// string vs status/body) doesn't have to share a union type with fetch.
|
|
@@ -36238,6 +36296,12 @@ var FetchproxyServer = class {
|
|
|
36238
36296
|
key: d.key,
|
|
36239
36297
|
jsonPointer: d.jsonPointer
|
|
36240
36298
|
})),
|
|
36299
|
+
// 0.8.0+: timer + lazy-revive default to ON. Every realty MCP
|
|
36300
|
+
// adapter was about to set these to the same numbers anyway; the
|
|
36301
|
+
// back-door is `0` (explicit opt-out) if a caller genuinely wants
|
|
36302
|
+
// the legacy hang-forever / fail-once-on-SW-eviction behavior.
|
|
36303
|
+
fetchTimeoutMs: opts.fetchTimeoutMs ?? 3e4,
|
|
36304
|
+
bridgeReviveDelayMs: opts.bridgeReviveDelayMs ?? 2e3,
|
|
36241
36305
|
identityDir: opts.identityDir,
|
|
36242
36306
|
onPairCode: opts.onPairCode
|
|
36243
36307
|
};
|
|
@@ -36373,7 +36437,7 @@ var FetchproxyServer = class {
|
|
|
36373
36437
|
}
|
|
36374
36438
|
}
|
|
36375
36439
|
pairingErrorMessage(code) {
|
|
36376
|
-
return `fetchproxy: pairing required for ${this.opts.serverName}
|
|
36440
|
+
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.`;
|
|
36377
36441
|
}
|
|
36378
36442
|
/**
|
|
36379
36443
|
* Raw single-shot fetch through the bridge. Most callers should prefer
|
|
@@ -36394,8 +36458,71 @@ var FetchproxyServer = class {
|
|
|
36394
36458
|
const pendingCode = this.currentPendingPairCode();
|
|
36395
36459
|
if (pendingCode !== null) {
|
|
36396
36460
|
const error51 = this.pairingErrorMessage(pendingCode);
|
|
36397
|
-
return {
|
|
36461
|
+
return {
|
|
36462
|
+
ok: false,
|
|
36463
|
+
error: error51,
|
|
36464
|
+
kind: classifyFetchError(error51),
|
|
36465
|
+
retryAttempted: false
|
|
36466
|
+
};
|
|
36467
|
+
}
|
|
36468
|
+
const first = await this._fetchOnceWithTimeout(init);
|
|
36469
|
+
const reviveMs = this.opts.bridgeReviveDelayMs;
|
|
36470
|
+
let final = first;
|
|
36471
|
+
if (!first.ok && first.kind === "content_script_unreachable" && reviveMs !== void 0 && reviveMs > 0) {
|
|
36472
|
+
await new Promise((r) => setTimeout(r, reviveMs));
|
|
36473
|
+
const second = await this._fetchOnceWithTimeout(init);
|
|
36474
|
+
if (second.ok)
|
|
36475
|
+
this.recordSuccess();
|
|
36476
|
+
else
|
|
36477
|
+
this.recordFailure(`${second.kind ?? "other"}: ${second.error}`);
|
|
36478
|
+
return { ...second, retryAttempted: true };
|
|
36398
36479
|
}
|
|
36480
|
+
if (first.ok)
|
|
36481
|
+
this.recordSuccess();
|
|
36482
|
+
else
|
|
36483
|
+
this.recordFailure(`${first.kind ?? "other"}: ${first.error}`);
|
|
36484
|
+
return { ...first, retryAttempted: false };
|
|
36485
|
+
}
|
|
36486
|
+
/**
|
|
36487
|
+
* 0.8.0+: snapshot of the bridge's process-wide freshness counters,
|
|
36488
|
+
* suitable for surfacing through a downstream MCP's healthcheck tool.
|
|
36489
|
+
* Counters reset on a success (consecutiveFailures), accumulate
|
|
36490
|
+
* across the process lifetime otherwise. Replaces the per-MCP
|
|
36491
|
+
* duplication the realty cohort had been rolling in their adapters.
|
|
36492
|
+
* `lastExtensionMessageAt` is updated whenever ANY inner frame
|
|
36493
|
+
* arrives from the extension — gives extension-side liveness
|
|
36494
|
+
* distinct from server-side success/failure of the user-visible
|
|
36495
|
+
* call (addresses #23 ask 4).
|
|
36496
|
+
*/
|
|
36497
|
+
bridgeHealth() {
|
|
36498
|
+
return {
|
|
36499
|
+
role: this.role,
|
|
36500
|
+
port: this.opts.port,
|
|
36501
|
+
serverVersion: this.opts.version,
|
|
36502
|
+
fetchTimeoutMs: this.opts.fetchTimeoutMs ?? 0,
|
|
36503
|
+
bridgeReviveDelayMs: this.opts.bridgeReviveDelayMs ?? 0,
|
|
36504
|
+
lastSuccessAt: this.lastSuccessAt,
|
|
36505
|
+
lastFailureAt: this.lastFailureAt,
|
|
36506
|
+
lastFailureReason: this.lastFailureReason,
|
|
36507
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
36508
|
+
lastExtensionMessageAt: this.lastExtensionMessageAt
|
|
36509
|
+
};
|
|
36510
|
+
}
|
|
36511
|
+
recordSuccess() {
|
|
36512
|
+
this.lastSuccessAt = Date.now();
|
|
36513
|
+
this.consecutiveFailures = 0;
|
|
36514
|
+
}
|
|
36515
|
+
recordFailure(reason) {
|
|
36516
|
+
this.lastFailureAt = Date.now();
|
|
36517
|
+
this.lastFailureReason = reason;
|
|
36518
|
+
this.consecutiveFailures += 1;
|
|
36519
|
+
}
|
|
36520
|
+
/**
|
|
36521
|
+
* Single bridge round-trip, wrapped by `fetchTimeoutMs` when set.
|
|
36522
|
+
* On timeout returns the `{ok:false, kind:'timeout'}` envelope —
|
|
36523
|
+
* the throwing surface is the convenience methods.
|
|
36524
|
+
*/
|
|
36525
|
+
async _fetchOnceWithTimeout(init) {
|
|
36399
36526
|
const id = this.nextRequestId++;
|
|
36400
36527
|
const inner = { type: "request", id, op: "fetch", init };
|
|
36401
36528
|
const pending = new Promise((resolve) => {
|
|
@@ -36406,7 +36533,61 @@ var FetchproxyServer = class {
|
|
|
36406
36533
|
} else if (this.peerHandle) {
|
|
36407
36534
|
await this.peerHandle.sendInner(inner);
|
|
36408
36535
|
}
|
|
36409
|
-
|
|
36536
|
+
const timeoutMs = this.opts.fetchTimeoutMs;
|
|
36537
|
+
if (timeoutMs === void 0 || timeoutMs <= 0)
|
|
36538
|
+
return pending;
|
|
36539
|
+
let timer;
|
|
36540
|
+
const start = Date.now();
|
|
36541
|
+
try {
|
|
36542
|
+
return await Promise.race([
|
|
36543
|
+
pending,
|
|
36544
|
+
new Promise((resolve) => {
|
|
36545
|
+
timer = setTimeout(() => {
|
|
36546
|
+
this.pending.delete(id);
|
|
36547
|
+
const elapsedMs = Date.now() - start;
|
|
36548
|
+
const error51 = `fetchproxy: ${init.url} did not respond within ${timeoutMs}ms`;
|
|
36549
|
+
resolve({
|
|
36550
|
+
ok: false,
|
|
36551
|
+
error: error51,
|
|
36552
|
+
kind: "timeout",
|
|
36553
|
+
retryAttempted: false,
|
|
36554
|
+
elapsedMs
|
|
36555
|
+
});
|
|
36556
|
+
}, timeoutMs);
|
|
36557
|
+
})
|
|
36558
|
+
]);
|
|
36559
|
+
} finally {
|
|
36560
|
+
if (timer)
|
|
36561
|
+
clearTimeout(timer);
|
|
36562
|
+
}
|
|
36563
|
+
}
|
|
36564
|
+
/**
|
|
36565
|
+
* Map an `ok:false` fetch result to its typed throwable. Centralizes
|
|
36566
|
+
* the kind-to-error-class switch so `request()` and (via the same
|
|
36567
|
+
* logic re-implemented inline) `captureRequestHeader()` agree on what
|
|
36568
|
+
* to throw.
|
|
36569
|
+
*/
|
|
36570
|
+
_typedErrorFor(result, url2, op, retryAttempted) {
|
|
36571
|
+
if (result.kind === "timeout") {
|
|
36572
|
+
return new FetchproxyTimeoutError({
|
|
36573
|
+
url: url2,
|
|
36574
|
+
timeoutMs: this.opts.fetchTimeoutMs ?? 0,
|
|
36575
|
+
role: this.role,
|
|
36576
|
+
port: this.opts.port,
|
|
36577
|
+
elapsedMs: result.elapsedMs
|
|
36578
|
+
});
|
|
36579
|
+
}
|
|
36580
|
+
if (result.kind === "content_script_unreachable") {
|
|
36581
|
+
return new FetchproxyBridgeDownError({
|
|
36582
|
+
originalError: result.error,
|
|
36583
|
+
retryAttempted,
|
|
36584
|
+
op,
|
|
36585
|
+
url: url2,
|
|
36586
|
+
role: this.role,
|
|
36587
|
+
port: this.opts.port
|
|
36588
|
+
});
|
|
36589
|
+
}
|
|
36590
|
+
return new FetchproxyProtocolError(result.error);
|
|
36410
36591
|
}
|
|
36411
36592
|
/**
|
|
36412
36593
|
* Convenience wrapper around `fetch()`. Builds the URL from a path
|
|
@@ -36429,8 +36610,18 @@ var FetchproxyServer = class {
|
|
|
36429
36610
|
if (opts.subdomain !== void 0)
|
|
36430
36611
|
assertSubdomainLabel(opts.subdomain);
|
|
36431
36612
|
const baseDomain = this.resolveBaseDomain(opts.domain);
|
|
36432
|
-
const
|
|
36433
|
-
|
|
36613
|
+
const isAbsolute = path.startsWith("http://") || path.startsWith("https://");
|
|
36614
|
+
let host;
|
|
36615
|
+
if (isAbsolute) {
|
|
36616
|
+
try {
|
|
36617
|
+
host = new URL(path).host;
|
|
36618
|
+
} catch {
|
|
36619
|
+
throw new Error(`FetchproxyServer.request: absolute path is not a valid URL: ${JSON.stringify(path)}`);
|
|
36620
|
+
}
|
|
36621
|
+
} else {
|
|
36622
|
+
host = opts.subdomain ? `${opts.subdomain}.${baseDomain}` : baseDomain;
|
|
36623
|
+
}
|
|
36624
|
+
const url2 = isAbsolute ? path : `https://${host}${path}`;
|
|
36434
36625
|
assertUrlInDomains("request url", url2, this.opts.domains);
|
|
36435
36626
|
const init = {
|
|
36436
36627
|
url: url2,
|
|
@@ -36441,7 +36632,7 @@ var FetchproxyServer = class {
|
|
|
36441
36632
|
};
|
|
36442
36633
|
const result = await this.fetch(init);
|
|
36443
36634
|
if (!result.ok) {
|
|
36444
|
-
throw
|
|
36635
|
+
throw this._typedErrorFor(result, init.url, "fetch", result.retryAttempted ?? false);
|
|
36445
36636
|
}
|
|
36446
36637
|
const response = {
|
|
36447
36638
|
status: result.status,
|
|
@@ -36651,10 +36842,73 @@ var FetchproxyServer = class {
|
|
|
36651
36842
|
}
|
|
36652
36843
|
await this.ensureConnected();
|
|
36653
36844
|
this.throwIfPendingPair();
|
|
36654
|
-
const
|
|
36655
|
-
|
|
36656
|
-
|
|
36845
|
+
const decls = this.opts.captureHeaders;
|
|
36846
|
+
let resolved;
|
|
36847
|
+
if (opts?.urlPattern !== void 0 && opts?.headerName !== void 0) {
|
|
36848
|
+
const found = decls.find((d) => d.urlPattern === opts.urlPattern && d.headerName === opts.headerName);
|
|
36849
|
+
if (!found) {
|
|
36850
|
+
throw new Error(`FetchproxyServer.captureRequestHeader: (urlPattern=${JSON.stringify(opts.urlPattern)}, headerName=${JSON.stringify(opts.headerName)}) not declared in captureHeaders`);
|
|
36851
|
+
}
|
|
36852
|
+
resolved = found;
|
|
36853
|
+
} else if (opts?.urlPattern === void 0 && opts?.headerName === void 0) {
|
|
36854
|
+
if (decls.length === 0) {
|
|
36855
|
+
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");
|
|
36856
|
+
}
|
|
36857
|
+
if (decls.length > 1) {
|
|
36858
|
+
const list = decls.map((d) => `${JSON.stringify(d.urlPattern)}/${JSON.stringify(d.headerName)}`).join(", ");
|
|
36859
|
+
throw new Error(`FetchproxyServer.captureRequestHeader: multiple captureHeaders declared (${decls.length}: ${list}); pass {urlPattern, headerName} to disambiguate`);
|
|
36860
|
+
}
|
|
36861
|
+
resolved = decls[0];
|
|
36862
|
+
} else {
|
|
36863
|
+
throw new Error("FetchproxyServer.captureRequestHeader: pass both urlPattern AND headerName, or neither (which defaults to the single declared entry)");
|
|
36657
36864
|
}
|
|
36865
|
+
const callOpts = { ...resolved, ...opts?.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {} };
|
|
36866
|
+
try {
|
|
36867
|
+
const result = await this._captureRequestHeaderOnce(callOpts);
|
|
36868
|
+
this.recordSuccess();
|
|
36869
|
+
return result;
|
|
36870
|
+
} catch (err) {
|
|
36871
|
+
const swDown = err instanceof FetchproxyProtocolError && classifyFetchError(err.message) === "content_script_unreachable";
|
|
36872
|
+
if (!swDown) {
|
|
36873
|
+
this.recordFailure(`capture_request_header: ${err.message ?? String(err)}`);
|
|
36874
|
+
throw err;
|
|
36875
|
+
}
|
|
36876
|
+
const reviveMs = this.opts.bridgeReviveDelayMs ?? 0;
|
|
36877
|
+
if (reviveMs > 0) {
|
|
36878
|
+
await new Promise((r) => setTimeout(r, reviveMs));
|
|
36879
|
+
try {
|
|
36880
|
+
const result = await this._captureRequestHeaderOnce(callOpts);
|
|
36881
|
+
this.recordSuccess();
|
|
36882
|
+
return result;
|
|
36883
|
+
} catch (retryErr) {
|
|
36884
|
+
const stillDown = retryErr instanceof FetchproxyProtocolError && classifyFetchError(retryErr.message) === "content_script_unreachable";
|
|
36885
|
+
if (!stillDown) {
|
|
36886
|
+
this.recordFailure(`capture_request_header: ${retryErr.message ?? String(retryErr)}`);
|
|
36887
|
+
throw retryErr;
|
|
36888
|
+
}
|
|
36889
|
+
this.recordFailure(`capture_request_header bridge-down: ${retryErr.message}`);
|
|
36890
|
+
throw new FetchproxyBridgeDownError({
|
|
36891
|
+
originalError: retryErr.message,
|
|
36892
|
+
retryAttempted: true,
|
|
36893
|
+
op: "capture_request_header",
|
|
36894
|
+
url: resolved.urlPattern,
|
|
36895
|
+
role: this.role,
|
|
36896
|
+
port: this.opts.port
|
|
36897
|
+
});
|
|
36898
|
+
}
|
|
36899
|
+
}
|
|
36900
|
+
this.recordFailure(`capture_request_header bridge-down: ${err.message}`);
|
|
36901
|
+
throw new FetchproxyBridgeDownError({
|
|
36902
|
+
originalError: err.message,
|
|
36903
|
+
retryAttempted: false,
|
|
36904
|
+
op: "capture_request_header",
|
|
36905
|
+
url: resolved.urlPattern,
|
|
36906
|
+
role: this.role,
|
|
36907
|
+
port: this.opts.port
|
|
36908
|
+
});
|
|
36909
|
+
}
|
|
36910
|
+
}
|
|
36911
|
+
async _captureRequestHeaderOnce(opts) {
|
|
36658
36912
|
const id = this.nextRequestId++;
|
|
36659
36913
|
const inner = {
|
|
36660
36914
|
type: "request",
|
|
@@ -36763,18 +37017,35 @@ var FetchproxyServer = class {
|
|
|
36763
37017
|
onInner(inner) {
|
|
36764
37018
|
if (inner.type !== "response")
|
|
36765
37019
|
return;
|
|
37020
|
+
this.lastExtensionMessageAt = Date.now();
|
|
36766
37021
|
const fetchCb = this.pending.get(inner.id);
|
|
36767
37022
|
if (fetchCb) {
|
|
36768
37023
|
this.pending.delete(inner.id);
|
|
36769
37024
|
if (inner.ok) {
|
|
36770
37025
|
if (inner.op === void 0 || inner.op === "fetch") {
|
|
36771
|
-
fetchCb({
|
|
37026
|
+
fetchCb({
|
|
37027
|
+
ok: true,
|
|
37028
|
+
status: inner.status,
|
|
37029
|
+
url: inner.url,
|
|
37030
|
+
body: inner.body,
|
|
37031
|
+
retryAttempted: false
|
|
37032
|
+
});
|
|
36772
37033
|
} else {
|
|
36773
37034
|
const error51 = `unexpected ${inner.op} response on fetch awaiter`;
|
|
36774
|
-
fetchCb({
|
|
37035
|
+
fetchCb({
|
|
37036
|
+
ok: false,
|
|
37037
|
+
error: error51,
|
|
37038
|
+
kind: classifyFetchError(error51),
|
|
37039
|
+
retryAttempted: false
|
|
37040
|
+
});
|
|
36775
37041
|
}
|
|
36776
37042
|
} else {
|
|
36777
|
-
fetchCb({
|
|
37043
|
+
fetchCb({
|
|
37044
|
+
ok: false,
|
|
37045
|
+
error: inner.error,
|
|
37046
|
+
kind: classifyFetchError(inner.error),
|
|
37047
|
+
retryAttempted: false
|
|
37048
|
+
});
|
|
36778
37049
|
}
|
|
36779
37050
|
return;
|
|
36780
37051
|
}
|
|
@@ -36844,7 +37115,12 @@ var FetchproxyServer = class {
|
|
|
36844
37115
|
rejectAllPending(reason = "extension disconnected") {
|
|
36845
37116
|
const err = new FetchproxyProtocolError(reason);
|
|
36846
37117
|
for (const cb of this.pending.values()) {
|
|
36847
|
-
cb({
|
|
37118
|
+
cb({
|
|
37119
|
+
ok: false,
|
|
37120
|
+
error: err.message,
|
|
37121
|
+
kind: classifyFetchError(err.message),
|
|
37122
|
+
retryAttempted: false
|
|
37123
|
+
});
|
|
36848
37124
|
}
|
|
36849
37125
|
this.pending.clear();
|
|
36850
37126
|
for (const cb of this.pendingReadCookies.values()) {
|
|
@@ -36909,6 +37185,19 @@ var FetchproxyServer = class {
|
|
|
36909
37185
|
}
|
|
36910
37186
|
};
|
|
36911
37187
|
|
|
37188
|
+
// node_modules/@fetchproxy/server/dist/classify-bridge-error.js
|
|
37189
|
+
function classifyBridgeError(err) {
|
|
37190
|
+
if (err instanceof FetchproxyTimeoutError)
|
|
37191
|
+
return "timeout";
|
|
37192
|
+
if (err instanceof FetchproxyBridgeDownError)
|
|
37193
|
+
return "bridge_down";
|
|
37194
|
+
if (err instanceof FetchproxyHttpError)
|
|
37195
|
+
return "http";
|
|
37196
|
+
if (err instanceof FetchproxyProtocolError)
|
|
37197
|
+
return "protocol";
|
|
37198
|
+
return "other";
|
|
37199
|
+
}
|
|
37200
|
+
|
|
36912
37201
|
// node_modules/@fetchproxy/bootstrap/dist/index.js
|
|
36913
37202
|
var defaultFactory = (opts) => new FetchproxyServer(opts);
|
|
36914
37203
|
async function bootstrap(opts) {
|
|
@@ -36963,7 +37252,11 @@ async function bootstrap(opts) {
|
|
|
36963
37252
|
key: p.storageKey,
|
|
36964
37253
|
jsonPointer: p.jsonPointer
|
|
36965
37254
|
})),
|
|
36966
|
-
onPairCode: opts.onPairCode
|
|
37255
|
+
onPairCode: opts.onPairCode,
|
|
37256
|
+
// 0.8.0+ pass-through. Only forwarded when the caller set them;
|
|
37257
|
+
// unset → server defaults apply (30000 / 2000 in 0.8.0).
|
|
37258
|
+
...opts.fetchTimeoutMs !== void 0 ? { fetchTimeoutMs: opts.fetchTimeoutMs } : {},
|
|
37259
|
+
...opts.bridgeReviveDelayMs !== void 0 ? { bridgeReviveDelayMs: opts.bridgeReviveDelayMs } : {}
|
|
36967
37260
|
});
|
|
36968
37261
|
const storageDomainOpts = {};
|
|
36969
37262
|
if (opts.storageDomain !== void 0)
|
|
@@ -37066,7 +37359,7 @@ var BootstrapDisabledError = class extends Error {
|
|
|
37066
37359
|
// package.json
|
|
37067
37360
|
var package_default = {
|
|
37068
37361
|
name: "honeybook-mcp",
|
|
37069
|
-
version: "0.
|
|
37362
|
+
version: "0.3.0",
|
|
37070
37363
|
mcpName: "io.github.chrischall/honeybook-mcp",
|
|
37071
37364
|
description: "HoneyBook client-portal MCP server for Claude",
|
|
37072
37365
|
author: "Claude Code (AI) <https://www.anthropic.com/claude>",
|
|
@@ -37106,7 +37399,8 @@ var package_default = {
|
|
|
37106
37399
|
"test:watch": "vitest"
|
|
37107
37400
|
},
|
|
37108
37401
|
dependencies: {
|
|
37109
|
-
"@fetchproxy/bootstrap": "^0.
|
|
37402
|
+
"@fetchproxy/bootstrap": "^0.8.0",
|
|
37403
|
+
"@fetchproxy/server": "^0.8.0",
|
|
37110
37404
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
37111
37405
|
dotenv: "^17.4.2",
|
|
37112
37406
|
zod: "^4.4.3"
|
|
@@ -37207,6 +37501,12 @@ async function captureSessionViaFetchproxy(opts) {
|
|
|
37207
37501
|
}
|
|
37208
37502
|
});
|
|
37209
37503
|
} catch (e) {
|
|
37504
|
+
if (classifyBridgeError(e) === "bridge_down") {
|
|
37505
|
+
const downErr = e;
|
|
37506
|
+
throw new Error(
|
|
37507
|
+
`HoneyBook auth: fetchproxy bridge is down (extension service worker unreachable after retry). ${downErr.hint}`
|
|
37508
|
+
);
|
|
37509
|
+
}
|
|
37210
37510
|
const msg = e instanceof Error ? e.message : String(e);
|
|
37211
37511
|
throw new Error(
|
|
37212
37512
|
`HoneyBook auth: fetchproxy capture failed: ${msg} \u2014 open the vendor magic-link URL in Chrome (with the fetchproxy 0.3.0 extension installed), then retry.`
|
|
@@ -37732,7 +38032,7 @@ try {
|
|
|
37732
38032
|
}
|
|
37733
38033
|
var server = new McpServer({
|
|
37734
38034
|
name: "honeybook-mcp",
|
|
37735
|
-
version: "0.
|
|
38035
|
+
version: "0.3.0"
|
|
37736
38036
|
// x-release-please-version
|
|
37737
38037
|
});
|
|
37738
38038
|
registerSessionTools(server);
|
package/dist/index.js
CHANGED
|
@@ -18,7 +18,7 @@ import { registerContractTools } from './tools/contracts.js';
|
|
|
18
18
|
import { registerInvoiceTools } from './tools/invoices.js';
|
|
19
19
|
const server = new McpServer({
|
|
20
20
|
name: 'honeybook-mcp',
|
|
21
|
-
version: '0.
|
|
21
|
+
version: '0.3.0', // x-release-please-version
|
|
22
22
|
});
|
|
23
23
|
registerSessionTools(server);
|
|
24
24
|
registerWorkspaceFileTools(server);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "honeybook-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"mcpName": "io.github.chrischall/honeybook-mcp",
|
|
5
5
|
"description": "HoneyBook client-portal MCP server for Claude",
|
|
6
6
|
"author": "Claude Code (AI) <https://www.anthropic.com/claude>",
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
"test:watch": "vitest"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@fetchproxy/bootstrap": "^0.
|
|
43
|
+
"@fetchproxy/bootstrap": "^0.8.0",
|
|
44
|
+
"@fetchproxy/server": "^0.8.0",
|
|
44
45
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
45
46
|
"dotenv": "^17.4.2",
|
|
46
47
|
"zod": "^4.4.3"
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/chrischall/honeybook-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.3.0",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "honeybook-mcp",
|
|
14
|
-
"version": "0.
|
|
14
|
+
"version": "0.3.0",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|