@pingroom/sdk 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +144 -12
  2. package/dist/client.d.ts +67 -18
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +275 -111
  5. package/dist/client.js.map +1 -1
  6. package/dist/errors.d.ts +8 -3
  7. package/dist/errors.d.ts.map +1 -1
  8. package/dist/errors.js +9 -3
  9. package/dist/errors.js.map +1 -1
  10. package/dist/http.d.ts +12 -1
  11. package/dist/http.d.ts.map +1 -1
  12. package/dist/http.js +40 -17
  13. package/dist/http.js.map +1 -1
  14. package/dist/internal/async.d.ts +2 -0
  15. package/dist/internal/async.d.ts.map +1 -1
  16. package/dist/internal/async.js +6 -0
  17. package/dist/internal/async.js.map +1 -1
  18. package/dist/internal/guards.d.ts +9 -0
  19. package/dist/internal/guards.d.ts.map +1 -1
  20. package/dist/internal/guards.js +21 -0
  21. package/dist/internal/guards.js.map +1 -1
  22. package/dist/internal/retry.d.ts +58 -0
  23. package/dist/internal/retry.d.ts.map +1 -0
  24. package/dist/internal/retry.js +108 -0
  25. package/dist/internal/retry.js.map +1 -0
  26. package/dist/internal/url.d.ts +9 -0
  27. package/dist/internal/url.d.ts.map +1 -1
  28. package/dist/internal/url.js +25 -0
  29. package/dist/internal/url.js.map +1 -1
  30. package/dist/linkPing.d.ts.map +1 -1
  31. package/dist/linkPing.js +6 -2
  32. package/dist/linkPing.js.map +1 -1
  33. package/dist/mcp.d.ts.map +1 -1
  34. package/dist/mcp.js +10 -2
  35. package/dist/mcp.js.map +1 -1
  36. package/dist/types.d.ts +182 -18
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/version.d.ts +1 -1
  39. package/dist/version.js +1 -1
  40. package/dist/webhooks.d.ts +20 -3
  41. package/dist/webhooks.d.ts.map +1 -1
  42. package/dist/webhooks.js +14 -9
  43. package/dist/webhooks.js.map +1 -1
  44. package/package.json +1 -1
@@ -0,0 +1,58 @@
1
+ import { PingRoomError } from '../errors.js';
2
+ /** First retry delay after a transient failure, in ms. */
3
+ export declare const TRANSIENT_BACKOFF_BASE_MS = 1000;
4
+ /** Ceiling on the exponential backoff (a server Retry-After may ask for longer). */
5
+ export declare const TRANSIENT_BACKOFF_CAP_MS = 30000;
6
+ /**
7
+ * How long past the last-seen `expires_at` a wait keeps retrying an
8
+ * unreachable API. The server reports `expired` once expires_at passes, so
9
+ * after this the only outcome left is one that cannot be read. Covers clock
10
+ * skew. Same bound as the CLI.
11
+ */
12
+ export declare const WAIT_EXPIRY_GRACE_MS: number;
13
+ /** The bound on an unbroken outage while no response has carried `expires_at`. */
14
+ export declare const WAIT_UNKNOWN_EXPIRY_OUTAGE_MS: number;
15
+ /**
16
+ * A failure a read loop may retry: a dropped connection, a request deadline,
17
+ * a 429 (the wait routes share one 30/min bucket per human), or a 5xx.
18
+ * Everything else — 401/403/404/422, a refused redirect, a malformed response —
19
+ * is permanent and must surface to the caller.
20
+ */
21
+ export declare function isTransientError(error: unknown): error is PingRoomError;
22
+ /**
23
+ * Delay before retrying after the `failures`-th consecutive transient failure:
24
+ * exponential from `baseMs`, capped at 30 s. A server `retryAfter` replaces the
25
+ * exponential step, but is never waited for less than `baseMs`.
26
+ */
27
+ export declare function transientDelayMs(error: PingRoomError, failures: number, baseMs?: number): number;
28
+ export interface PollUntilSettledOptions<T> {
29
+ /** One bounded long-poll. Its errors are retried only when transient. */
30
+ poll: () => Promise<unknown>;
31
+ /** Check the response's minimal shape; throw `invalid_response` otherwise. */
32
+ validate: (value: unknown) => T;
33
+ /** True once the validated value is terminal. */
34
+ settled: (value: T) => boolean;
35
+ signal?: AbortSignal;
36
+ /** Minimum time between the starts of two polls, in ms. Default 0. */
37
+ minIntervalMs?: number;
38
+ /** Read `expires_at` (an ISO time) from a validated response; it bounds an outage. */
39
+ expiresAt?: (value: T) => unknown;
40
+ /** Names what is waited on in the give-up message, e.g. `approval a1`. */
41
+ what: string;
42
+ /** Called before each retry of a transient failure; `attempt` counts consecutive failures from 1. */
43
+ onRetry?: (error: PingRoomError, attempt: number) => void;
44
+ }
45
+ /**
46
+ * The shared human-in-the-loop wait loop. Polls until a validated response is
47
+ * terminal; retries transient failures with backoff; rejects with the
48
+ * signal's reason once it aborts. A response that fails validation is never
49
+ * returned as an outcome.
50
+ *
51
+ * The retries are bounded even without a signal. Once only failures have come
52
+ * back since the last valid response, and the last-seen `expires_at` plus
53
+ * {@link WAIT_EXPIRY_GRACE_MS} has passed (or, before any `expires_at` was
54
+ * seen, after {@link WAIT_UNKNOWN_EXPIRY_OUTAGE_MS} of unbroken failures), the
55
+ * wait rejects with `unavailable`, the last failure as its `cause`.
56
+ */
57
+ export declare function pollUntilSettled<T>(options: PollUntilSettledOptions<T>): Promise<T>;
58
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/internal/retry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG7C,0DAA0D;AAC1D,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAC9C,oFAAoF;AACpF,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAG/C;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,QAAa,CAAC;AAC/C,kFAAkF;AAClF,eAAO,MAAM,6BAA6B,QAAc,CAAC;AAEzD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAQvE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAkC,GACzC,MAAM,CAQR;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC;IACxC,yEAAyE;IACzE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,8EAA8E;IAC9E,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC,CAAC;IAChC,iDAAiD;IACjD,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sFAAsF;IACtF,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAClC,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,qGAAqG;IACrG,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3D;AAeD;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAyCzF"}
@@ -0,0 +1,108 @@
1
+ import { PingRoomError } from '../errors.js';
2
+ import { sleep, throwIfAborted } from './async.js';
3
+ /** First retry delay after a transient failure, in ms. */
4
+ export const TRANSIENT_BACKOFF_BASE_MS = 1000;
5
+ /** Ceiling on the exponential backoff (a server Retry-After may ask for longer). */
6
+ export const TRANSIENT_BACKOFF_CAP_MS = 30_000;
7
+ /** setTimeout fires immediately above this, so no delay may exceed it. */
8
+ const MAX_TIMER_MS = 2_147_483_647;
9
+ /**
10
+ * How long past the last-seen `expires_at` a wait keeps retrying an
11
+ * unreachable API. The server reports `expired` once expires_at passes, so
12
+ * after this the only outcome left is one that cannot be read. Covers clock
13
+ * skew. Same bound as the CLI.
14
+ */
15
+ export const WAIT_EXPIRY_GRACE_MS = 5 * 60_000;
16
+ /** The bound on an unbroken outage while no response has carried `expires_at`. */
17
+ export const WAIT_UNKNOWN_EXPIRY_OUTAGE_MS = 15 * 60_000;
18
+ /**
19
+ * A failure a read loop may retry: a dropped connection, a request deadline,
20
+ * a 429 (the wait routes share one 30/min bucket per human), or a 5xx.
21
+ * Everything else — 401/403/404/422, a refused redirect, a malformed response —
22
+ * is permanent and must surface to the caller.
23
+ */
24
+ export function isTransientError(error) {
25
+ return (error instanceof PingRoomError
26
+ && (error.code === 'network_error'
27
+ || error.code === 'timeout'
28
+ || error.status === 429
29
+ || error.status >= 500));
30
+ }
31
+ /**
32
+ * Delay before retrying after the `failures`-th consecutive transient failure:
33
+ * exponential from `baseMs`, capped at 30 s. A server `retryAfter` replaces the
34
+ * exponential step, but is never waited for less than `baseMs`.
35
+ */
36
+ export function transientDelayMs(error, failures, baseMs = TRANSIENT_BACKOFF_BASE_MS) {
37
+ const base = Number.isFinite(baseMs) && baseMs >= 0 ? baseMs : TRANSIENT_BACKOFF_BASE_MS;
38
+ const retryAfter = error.retryAfter;
39
+ if (typeof retryAfter === 'number' && Number.isFinite(retryAfter) && retryAfter >= 0) {
40
+ return Math.min(MAX_TIMER_MS, Math.max(retryAfter * 1000, base));
41
+ }
42
+ const step = Math.min(Math.max(0, failures - 1), 5);
43
+ return Math.min(MAX_TIMER_MS, Math.max(base, TRANSIENT_BACKOFF_CAP_MS), base * 2 ** step);
44
+ }
45
+ function timeOf(value) {
46
+ const at = typeof value === 'string' ? Date.parse(value) : NaN;
47
+ return Number.isFinite(at) ? at : null;
48
+ }
49
+ function unavailable(last, since, what) {
50
+ const reason = last.status > 0 ? `HTTP ${last.status}` : (last.code ?? 'network error');
51
+ return new PingRoomError(`PingRoom unavailable since ${new Date(since).toISOString()} (${reason}); stopped waiting for ${what}.`, { code: 'unavailable', cause: last });
52
+ }
53
+ /**
54
+ * The shared human-in-the-loop wait loop. Polls until a validated response is
55
+ * terminal; retries transient failures with backoff; rejects with the
56
+ * signal's reason once it aborts. A response that fails validation is never
57
+ * returned as an outcome.
58
+ *
59
+ * The retries are bounded even without a signal. Once only failures have come
60
+ * back since the last valid response, and the last-seen `expires_at` plus
61
+ * {@link WAIT_EXPIRY_GRACE_MS} has passed (or, before any `expires_at` was
62
+ * seen, after {@link WAIT_UNKNOWN_EXPIRY_OUTAGE_MS} of unbroken failures), the
63
+ * wait rejects with `unavailable`, the last failure as its `cause`.
64
+ */
65
+ export async function pollUntilSettled(options) {
66
+ const { poll, validate, settled, signal, minIntervalMs = 0, expiresAt, what, onRetry } = options;
67
+ let failures = 0;
68
+ let failingSince = null;
69
+ // expires_at plus grace, from the last valid response that carried one.
70
+ let deadline = null;
71
+ for (;;) {
72
+ throwIfAborted(signal);
73
+ const startedAt = Date.now();
74
+ let value;
75
+ try {
76
+ value = validate(await poll());
77
+ }
78
+ catch (error) {
79
+ throwIfAborted(signal);
80
+ if (!isTransientError(error)) {
81
+ throw error;
82
+ }
83
+ failures += 1;
84
+ failingSince ??= Date.now();
85
+ const remaining = (deadline ?? failingSince + WAIT_UNKNOWN_EXPIRY_OUTAGE_MS) - Date.now();
86
+ if (remaining <= 0) {
87
+ throw unavailable(error, failingSince, what);
88
+ }
89
+ onRetry?.(error, failures);
90
+ // Never sleep past the bound: the last attempt lands on it, not after it.
91
+ await sleep(Math.min(transientDelayMs(error, failures), remaining), signal);
92
+ continue;
93
+ }
94
+ failures = 0;
95
+ failingSince = null;
96
+ const expiry = expiresAt ? timeOf(expiresAt(value)) : null;
97
+ if (expiry !== null) {
98
+ deadline = expiry + WAIT_EXPIRY_GRACE_MS;
99
+ }
100
+ if (settled(value)) {
101
+ return value;
102
+ }
103
+ // An injected transport can resolve pending polls immediately. Yield
104
+ // between them so timer-driven cancellation and deadlines can run.
105
+ await sleep(Math.max(0, minIntervalMs - (Date.now() - startedAt)), signal);
106
+ }
107
+ }
108
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/internal/retry.ts"],"names":[],"mappings":"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"}
@@ -12,4 +12,13 @@ export declare function assertSecureUrl(rawUrl: string, allowInsecure: boolean):
12
12
  * errors, so a message copied from one must not reach a caller's logs as-is.
13
13
  */
14
14
  export declare function redactUrlInMessage(message: string, url: URL, rawUrl: string): string;
15
+ /**
16
+ * Every request goes out with `redirect: 'manual'` (Cloudflare Workers throw
17
+ * on `'error'`), so a redirect comes back as a response instead of being
18
+ * followed. Refuse it: a 307/308 would replay pairing secrets, uploaded bytes
19
+ * or a webhook body to whatever origin `Location` names. Browsers report a
20
+ * manual redirect as an `opaqueredirect` with status 0; other runtimes return
21
+ * the 3xx itself.
22
+ */
23
+ export declare function refuseRedirect(res: Response): void;
15
24
  //# sourceMappingURL=url.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../src/internal/url.ts"],"names":[],"mappings":"AAEA,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGxD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,GAAG,GAAG,CAsB3E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAUpF"}
1
+ {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../src/internal/url.ts"],"names":[],"mappings":"AAEA,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGxD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,GAAG,GAAG,CAsB3E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAUpF;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAelD"}
@@ -48,4 +48,29 @@ export function redactUrlInMessage(message, url, rawUrl) {
48
48
  }
49
49
  return out;
50
50
  }
51
+ /**
52
+ * Every request goes out with `redirect: 'manual'` (Cloudflare Workers throw
53
+ * on `'error'`), so a redirect comes back as a response instead of being
54
+ * followed. Refuse it: a 307/308 would replay pairing secrets, uploaded bytes
55
+ * or a webhook body to whatever origin `Location` names. Browsers report a
56
+ * manual redirect as an `opaqueredirect` with status 0; other runtimes return
57
+ * the 3xx itself.
58
+ */
59
+ export function refuseRedirect(res) {
60
+ if (res.type === 'opaqueredirect' || (res.status >= 300 && res.status < 400)) {
61
+ // Release the body, best effort. A custom `fetch` such as node-fetch hands
62
+ // back a Node Readable with no cancel(); calling it threw a TypeError that
63
+ // surfaced as a retryable network_error instead of this refusal.
64
+ try {
65
+ res.body?.cancel?.()?.catch?.(() => { });
66
+ }
67
+ catch {
68
+ // Ignored: the refusal below is what matters.
69
+ }
70
+ throw new PingRoomError('Refusing to follow a redirect; credentials and request bodies are never forwarded.', {
71
+ code: 'redirect_refused',
72
+ status: res.status,
73
+ });
74
+ }
75
+ }
51
76
  //# sourceMappingURL=url.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"url.js","sourceRoot":"","sources":["../../src/internal/url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,MAAM,CAAC,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACvE,OAAO,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAC3F,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,aAAsB;IACpE,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;QAC1E,2CAA2C;QAC3C,MAAM,IAAI,aAAa,CAAC,+DAA+D,EAAE;YACvF,IAAI,EAAE,aAAa;SACpB,CAAC,CAAC;IACL,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,GAAG,CAAC;IACb,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,aAAa,IAAI,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;QAChF,OAAO,GAAG,CAAC;IACb,CAAC;IACD,MAAM,IAAI,aAAa,CACrB,sDAAsD,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,IAAI,KAAK;QAClF,sEAAsE,EACxE,EAAE,IAAI,EAAE,cAAc,EAAE,CACzB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe,EAAE,GAAQ,EAAE,MAAc;IAC1E,MAAM,QAAQ,GAAG,GAAG,GAAG,CAAC,MAAM,aAAa,CAAC;IAC5C,IAAI,GAAG,GAAG,OAAO,CAAC;IAClB,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,IAAI,IAAI;YAAE,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjD,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7E,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"url.js","sourceRoot":"","sources":["../../src/internal/url.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"linkPing.d.ts","sourceRoot":"","sources":["../src/linkPing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,aAAa;IAC5B,2FAA2F;IAC3F,GAAG,EAAE,MAAM,CAAC;IACZ,oFAAoF;IACpF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAKD,wFAAwF;AACxF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,YAAY,CAmB3D"}
1
+ {"version":3,"file":"linkPing.d.ts","sourceRoot":"","sources":["../src/linkPing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,aAAa;IAC5B,2FAA2F;IAC3F,GAAG,EAAE,MAAM,CAAC;IACZ,oFAAoF;IACpF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAUD,wFAAwF;AACxF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,YAAY,CAmB3D"}
package/dist/linkPing.js CHANGED
@@ -13,6 +13,10 @@
13
13
  */
14
14
  const URL_MAX = 2048;
15
15
  const LABEL_MAX = 26;
16
+ /** Count code points, as the server's mb_strlen does — an emoji is one character, not two. */
17
+ function characterLength(value) {
18
+ return Array.from(value).length;
19
+ }
16
20
  /** Build the `data` fragment for a link ping. Spread it into a ping's `data` object. */
17
21
  export function linkPing(input) {
18
22
  let parsed;
@@ -25,10 +29,10 @@ export function linkPing(input) {
25
29
  if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
26
30
  throw new TypeError('linkPing: url must be an absolute http(s) URL');
27
31
  }
28
- if (input.url.length > URL_MAX) {
32
+ if (characterLength(input.url) > URL_MAX) {
29
33
  throw new TypeError(`linkPing: url must be at most ${URL_MAX} characters`);
30
34
  }
31
- if (input.buttonLabel !== undefined && input.buttonLabel.length > LABEL_MAX) {
35
+ if (input.buttonLabel !== undefined && characterLength(input.buttonLabel) > LABEL_MAX) {
32
36
  throw new TypeError(`linkPing: buttonLabel must be at most ${LABEL_MAX} characters`);
33
37
  }
34
38
  const out = { url: input.url };
@@ -1 +1 @@
1
- {"version":3,"file":"linkPing.js","sourceRoot":"","sources":["../src/linkPing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAeH,MAAM,OAAO,GAAG,IAAI,CAAC;AACrB,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB,wFAAwF;AACxF,MAAM,UAAU,QAAQ,CAAC,KAAoB;IAC3C,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChE,MAAM,IAAI,SAAS,CAAC,+CAA+C,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC;QAC/B,MAAM,IAAI,SAAS,CAAC,iCAAiC,OAAO,aAAa,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QAC5E,MAAM,IAAI,SAAS,CAAC,yCAAyC,SAAS,aAAa,CAAC,CAAC;IACvF,CAAC;IACD,MAAM,GAAG,GAAiB,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC;IAC7C,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;QAAE,GAAG,CAAC,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC;IAC1E,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"linkPing.js","sourceRoot":"","sources":["../src/linkPing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAeH,MAAM,OAAO,GAAG,IAAI,CAAC;AACrB,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB,8FAA8F;AAC9F,SAAS,eAAe,CAAC,KAAa;IACpC,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;AAClC,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,QAAQ,CAAC,KAAoB;IAC3C,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChE,MAAM,IAAI,SAAS,CAAC,+CAA+C,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,EAAE,CAAC;QACzC,MAAM,IAAI,SAAS,CAAC,iCAAiC,OAAO,aAAa,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,eAAe,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,SAAS,EAAE,CAAC;QACtF,MAAM,IAAI,SAAS,CAAC,yCAAyC,SAAS,aAAa,CAAC,CAAC;IACvF,CAAC;IACD,MAAM,GAAG,GAAiB,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC;IAC7C,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;QAAE,GAAG,CAAC,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC;IAC1E,OAAO,GAAG,CAAC;AACb,CAAC"}
package/dist/mcp.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAG5C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,CAAC;IACxE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IACtE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;GAIG;AACH,qBAAa,SAAS;IAOlB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAPvB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,cAAc,CAA6C;IACnE,OAAO,CAAC,gBAAgB,CAAoC;IAC5D,OAAO,CAAC,eAAe,CAAuB;gBAG3B,IAAI,EAAE,UAAU,EAChB,IAAI,SAAmB;IAG1C,4FAA4F;IACtF,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAgBrF;;;OAGG;IACH,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAc1E,gFAAgF;IAChF,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAIjE,SAAS,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC;IAK1C,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAAC,aAAa,CAAC;YAK1E,iBAAiB;YAsBjB,MAAM;IAQpB,OAAO,CAAC,OAAO;CAMhB"}
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAG5C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,CAAC;IACxE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IACtE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;GAIG;AACH,qBAAa,SAAS;IAOlB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAPvB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,cAAc,CAA6C;IACnE,OAAO,CAAC,gBAAgB,CAAoC;IAC5D,OAAO,CAAC,eAAe,CAAuB;gBAG3B,IAAI,EAAE,UAAU,EAChB,IAAI,SAAmB;IAG1C,4FAA4F;IACtF,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAwBrF;;;OAGG;IACH,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAc1E,gFAAgF;IAChF,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAIjE,SAAS,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC;IAK1C,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAAC,aAAa,CAAC;YAK1E,iBAAiB;YAsBjB,MAAM;IAQpB,OAAO,CAAC,OAAO;CAMhB"}
package/dist/mcp.js CHANGED
@@ -24,13 +24,21 @@ export class McpClient {
24
24
  body: envelope,
25
25
  headers: this.headers(),
26
26
  });
27
- if (res && res.error) {
27
+ const isObject = res !== null && typeof res === 'object' && !Array.isArray(res);
28
+ if (isObject && res.error) {
28
29
  throw new PingRoomError(`MCP error ${res.error.code}: ${res.error.message}`, {
29
30
  code: `mcp_${res.error.code}`,
30
31
  body: res.error,
31
32
  });
32
33
  }
33
- return res?.result;
34
+ // A 2xx that is not a JSON-RPC response (no body, an HTML page, an object
35
+ // with neither member) must fail here, not as a TypeError in the caller.
36
+ if (!isObject || !Object.prototype.hasOwnProperty.call(res, 'result')) {
37
+ throw new PingRoomError('MCP endpoint returned a response with neither `result` nor `error`.', {
38
+ code: 'mcp_invalid_response',
39
+ });
40
+ }
41
+ return res.result;
34
42
  }
35
43
  /**
36
44
  * Perform the MCP initialize handshake once, including the required
package/dist/mcp.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}