@chrischall/mcp-utils 0.1.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 (50) hide show
  1. package/README.md +235 -0
  2. package/dist/auth/index.d.ts +223 -0
  3. package/dist/auth/index.d.ts.map +1 -0
  4. package/dist/auth/index.js +267 -0
  5. package/dist/auth/index.js.map +1 -0
  6. package/dist/config/index.d.ts +86 -0
  7. package/dist/config/index.d.ts.map +1 -0
  8. package/dist/config/index.js +121 -0
  9. package/dist/config/index.js.map +1 -0
  10. package/dist/errors/index.d.ts +90 -0
  11. package/dist/errors/index.d.ts.map +1 -0
  12. package/dist/errors/index.js +157 -0
  13. package/dist/errors/index.js.map +1 -0
  14. package/dist/fetchproxy/index.d.ts +156 -0
  15. package/dist/fetchproxy/index.d.ts.map +1 -0
  16. package/dist/fetchproxy/index.js +197 -0
  17. package/dist/fetchproxy/index.js.map +1 -0
  18. package/dist/html/index.d.ts +142 -0
  19. package/dist/html/index.d.ts.map +1 -0
  20. package/dist/html/index.js +321 -0
  21. package/dist/html/index.js.map +1 -0
  22. package/dist/http/index.d.ts +202 -0
  23. package/dist/http/index.d.ts.map +1 -0
  24. package/dist/http/index.js +341 -0
  25. package/dist/http/index.js.map +1 -0
  26. package/dist/index.d.ts +23 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +23 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/response/index.d.ts +22 -0
  31. package/dist/response/index.d.ts.map +1 -0
  32. package/dist/response/index.js +61 -0
  33. package/dist/response/index.js.map +1 -0
  34. package/dist/server/index.d.ts +109 -0
  35. package/dist/server/index.d.ts.map +1 -0
  36. package/dist/server/index.js +95 -0
  37. package/dist/server/index.js.map +1 -0
  38. package/dist/session/index.d.ts +233 -0
  39. package/dist/session/index.d.ts.map +1 -0
  40. package/dist/session/index.js +404 -0
  41. package/dist/session/index.js.map +1 -0
  42. package/dist/test/index.d.ts +124 -0
  43. package/dist/test/index.d.ts.map +1 -0
  44. package/dist/test/index.js +181 -0
  45. package/dist/test/index.js.map +1 -0
  46. package/dist/zod/index.d.ts +130 -0
  47. package/dist/zod/index.d.ts.map +1 -0
  48. package/dist/zod/index.js +184 -0
  49. package/dist/zod/index.js.map +1 -0
  50. package/package.json +77 -0
package/README.md ADDED
@@ -0,0 +1,235 @@
1
+ # @chrischall/mcp-utils
2
+
3
+ Shared scaffolding for the **chrischall MCP fleet** — the generic MCP glue
4
+ hoisted out of ~19 sibling servers so each one no longer reimplements server
5
+ bootstrap, tool-result formatting, helpful errors, hardened env/config, a bearer
6
+ API-client kit, zod atoms, session registries, a fetchproxy transport adapter,
7
+ auth resolver skeletons, an in-memory test harness, and opt-in HTML helpers.
8
+
9
+ ```sh
10
+ npm install @chrischall/mcp-utils
11
+ ```
12
+
13
+ Peer dependencies: `@modelcontextprotocol/sdk` and `zod`. The `@fetchproxy/server`
14
+ and `node-html-parser` peers are **optional** — only needed if you import the
15
+ `/fetchproxy` or `/html` subpaths respectively. Their declared range is `*` so a
16
+ consumer pinning any version installs cleanly; the real requirement is enforced
17
+ at the subpath: **`/fetchproxy` needs `@fetchproxy/server` >= 0.11** (it
18
+ re-exports APIs added there — `withDeadline`, `backoffDelayMs`, `BRIDGE_CONCURRENCY`,
19
+ the bridge-error classifier). MCPs on older `@fetchproxy/server` can use the core
20
+ barrel freely; adopt `/fetchproxy` only after bumping to 0.11+.
21
+
22
+ ## Entry points
23
+
24
+ The core building blocks are re-exported from the package root. Heavier or
25
+ optional-dependency modules are published as **subpath entries** to keep the core
26
+ import light:
27
+
28
+ | Import | Contents |
29
+ | --- | --- |
30
+ | `@chrischall/mcp-utils` | core barrel: `server` + `response` + `errors` + `config` + `http` + `zod` + `auth` |
31
+ | `@chrischall/mcp-utils/session` | session registry, session store, token manager |
32
+ | `@chrischall/mcp-utils/fetchproxy` | fetchproxy transport adapter, bot-wall / retry / concurrency helpers |
33
+ | `@chrischall/mcp-utils/html` | opt-in HTML scraping helpers (needs `node-html-parser`) |
34
+ | `@chrischall/mcp-utils/test` | in-memory test harness for tool registration |
35
+
36
+ ```ts
37
+ import { createMcpServer, textResult, requireEnvVar } from '@chrischall/mcp-utils';
38
+ import { createSessionRegistry } from '@chrischall/mcp-utils/session';
39
+ import { createFetchproxyTransport } from '@chrischall/mcp-utils/fetchproxy';
40
+ ```
41
+
42
+ ## Modules
43
+
44
+ ### `server` — bootstrap & lifecycle
45
+
46
+ `createMcpServer`, `runMcp`, `withGracefulShutdown`.
47
+
48
+ ```ts
49
+ import { runMcp, textResult } from '@chrischall/mcp-utils';
50
+
51
+ await runMcp({
52
+ name: 'my-mcp',
53
+ version: '1.0.0',
54
+ register: (server) => {
55
+ server.tool('ping', {}, async () => textResult({ ok: true }));
56
+ },
57
+ // shutdown: { onSignal: () => client.close() },
58
+ });
59
+ ```
60
+
61
+ `runMcp` wires the server to a stdio transport and installs `SIGINT`/`SIGTERM`
62
+ handlers via `withGracefulShutdown`. Use `createMcpServer` directly if you need
63
+ the server instance without connecting a transport.
64
+
65
+ ### `response` — tool-result formatting
66
+
67
+ `textResult` / `jsonResult` (alias), `rawTextResult`, `imageResult`,
68
+ `errorResult`, `flattenJsonApi`.
69
+
70
+ ```ts
71
+ import { textResult, errorResult, flattenJsonApi } from '@chrischall/mcp-utils';
72
+
73
+ return textResult({ items }); // pretty-printed JSON
74
+ return errorResult('not found'); // { isError: true }
75
+ return textResult(flattenJsonApi(payload)); // collapse JSON:API envelopes
76
+ ```
77
+
78
+ ### `errors` — helpful errors
79
+
80
+ `McpToolError` and its subclasses (`SessionNotAuthenticatedError`,
81
+ `BotWallError`, `RateLimitError`, `UnreachableError`, `ModeMismatchError`),
82
+ plus `createHelpfulError`, `wrapToolError`, `truncateErrorMessage`, and
83
+ `messageOf`. This core module has **no runtime dependencies** — the fetchproxy
84
+ typed-error hierarchy (`Fetchproxy*Error`) and the `classifyBridgeError`
85
+ discriminator live in the [`/fetchproxy`](#fetchproxy) subpath instead, so
86
+ bearer-only MCPs can import the core barrel without installing
87
+ `@fetchproxy/server`.
88
+
89
+ ```ts
90
+ import { wrapToolError, SessionNotAuthenticatedError } from '@chrischall/mcp-utils';
91
+
92
+ try {
93
+ if (!token) throw new SessionNotAuthenticatedError({ hint: 'run the login tool first' });
94
+ } catch (err) {
95
+ throw wrapToolError('my_tool', err);
96
+ }
97
+ ```
98
+
99
+ Every error carries an optional `hint` — a "here's how to fix it" string the
100
+ tool surface can show the user.
101
+
102
+ ### `config` — hardened env/config
103
+
104
+ `readEnvVar`, `requireEnvVar`, `parseBoolEnv`, `expandPath`, `loadDotenvSafely`.
105
+
106
+ ```ts
107
+ import { requireEnvVar, parseBoolEnv, expandPath } from '@chrischall/mcp-utils';
108
+
109
+ const apiKey = requireEnvVar('MY_API_KEY');
110
+ const debug = parseBoolEnv('MY_DEBUG', { default: false });
111
+ const home = expandPath('~/.config/my-mcp');
112
+ ```
113
+
114
+ `loadDotenvSafely` is a no-throw `.env` loader (returns `false` instead of
115
+ failing when the file is absent).
116
+
117
+ ### `http` — bearer API-client kit
118
+
119
+ `createApiClient` plus building blocks: `buildQueryString`, `buildOptionalBody`,
120
+ `formatApiError`, `parseLinkHeader`, `parseCookieJar`, JWT helpers
121
+ (`decodeJwtExp`, `decodeJwtSessionId`, `validateJwtExpiry`), and the
122
+ `UnauthorizedError` / `RateLimitedError` classes.
123
+
124
+ ```ts
125
+ import { createApiClient } from '@chrischall/mcp-utils';
126
+
127
+ const api = createApiClient({
128
+ baseUrl: 'https://api.example.com',
129
+ getToken: () => store.currentToken(), // resolved per-request; sync or async
130
+ serviceName: 'Example',
131
+ retry: { count: 1, delayMs: 2000 }, // fleet-wide "retry once after 2s" default
132
+ });
133
+
134
+ const data = await api.get('/v1/things', { query: { page: 2 } });
135
+ ```
136
+
137
+ ### `zod` — schema atoms
138
+
139
+ Reusable schemas (`PositiveInt`, `NonNegInt`, `NonEmptyString`, `IsoDate`,
140
+ `IsoTime`, `schemaOrigin`, `schemaConfirm`), pagination helpers
141
+ (`paginationSchema`, `pageSchema`, `calculateOffset`), tool-annotation builders
142
+ (`toolAnnotations`), and time normalizers (`extractTime`, `normalizeTime`).
143
+
144
+ ```ts
145
+ import { paginationSchema, calculateOffset, toolAnnotations } from '@chrischall/mcp-utils';
146
+
147
+ const inputSchema = { ...paginationSchema, q: NonEmptyString };
148
+ const offset = calculateOffset(page, size);
149
+ const annotations = toolAnnotations({ readOnly: true });
150
+ ```
151
+
152
+ ### `auth` — auth resolver skeletons
153
+
154
+ `createAuthResolver`, `resolveAuthPattern`, `sessionLoginFlow`,
155
+ `createOAuth2Refresher`, and the supporting `FetchproxySession` /
156
+ `AuthPattern` types.
157
+
158
+ ```ts
159
+ import { createAuthResolver, createOAuth2Refresher } from '@chrischall/mcp-utils';
160
+
161
+ const resolver = createAuthResolver({ /* ... */ });
162
+ const refresh = createOAuth2Refresher({ /* ... */ });
163
+ ```
164
+
165
+ ### `session` — session registry & token manager *(subpath)*
166
+
167
+ ```ts
168
+ import {
169
+ createSessionRegistry,
170
+ registerSessionTools,
171
+ TokenManager,
172
+ } from '@chrischall/mcp-utils/session';
173
+
174
+ const registry = createSessionRegistry();
175
+ registerSessionTools(server, { registry /* ... */ });
176
+ ```
177
+
178
+ Includes `SessionStore`, `normalizeOrigin`, `AuthMode`, and `TokenManager`
179
+ (with `TOKEN_REFRESH_SKEW_MS` for proactive refresh).
180
+
181
+ ### `fetchproxy` — transport adapter *(subpath, optional peer)*
182
+
183
+ ```ts
184
+ import {
185
+ createFetchproxyTransport,
186
+ createBootstrapOpts,
187
+ mapWithConcurrency,
188
+ TokenBucket,
189
+ classifyBotWall,
190
+ } from '@chrischall/mcp-utils/fetchproxy';
191
+ ```
192
+
193
+ Wraps `@fetchproxy/server` with the fleet's transport, bot-wall classification,
194
+ deadline/retry, token-bucket rate limiting, and bounded-concurrency helpers, and
195
+ re-exports the fetchproxy typed-error hierarchy.
196
+
197
+ ### `html` — scraping helpers *(subpath, optional peer)*
198
+
199
+ ```ts
200
+ import {
201
+ parsePropertyTable,
202
+ findLinksUnderHeading,
203
+ extractJsonFromHtml,
204
+ extractPlainTextFromHtml,
205
+ } from '@chrischall/mcp-utils/html';
206
+ ```
207
+
208
+ Requires the optional `node-html-parser` peer. Also provides `urlToPath`,
209
+ `locationToSlug`, and `buildIdExtractor`.
210
+
211
+ ### `test` — in-memory test harness *(subpath)*
212
+
213
+ ```ts
214
+ import { createTestHarness, parseToolResult } from '@chrischall/mcp-utils/test';
215
+
216
+ const harness = createTestHarness();
217
+ register(harness.server);
218
+ const result = await harness.call('ping', {});
219
+ expect(parseToolResult(result)).toEqual({ ok: true });
220
+ ```
221
+
222
+ Also includes `versionSyncTest`, `mockFetchproxyBootstrap`, `setupClientMocks`,
223
+ and `makeBootstrapResult`.
224
+
225
+ ## Development
226
+
227
+ ```sh
228
+ npm run build # tsc -b → dist/
229
+ npm test # vitest run
230
+ npm run test:watch # vitest (watch mode)
231
+ ```
232
+
233
+ ## License
234
+
235
+ MIT
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Auth resolver skeletons — the shared *shape* of the credential-resolution
3
+ * logic duplicated across the fleet (resy / opentable / ofw / zola /
4
+ * signupgenius / creditkarma / canvas / infinitecampus auth.ts).
5
+ *
6
+ * This module owns the **skeleton** only. Per-site parameters (which env var,
7
+ * which cookies to declare, how to parse the session blob, which CSRF input to
8
+ * scrape) are *injected*; nothing here branches on site identity. Site-specific
9
+ * OAuth choreographies (e.g. Skylight's `/auth/session` → `/oauth/authorize` →
10
+ * `/oauth/token` dance) stay per-MCP — they are not a shared shape.
11
+ *
12
+ * Four pieces:
13
+ * - {@link createAuthResolver} — the three-path resolver
14
+ * (env credential → fetchproxy one-shot read → actionable error).
15
+ * - {@link resolveAuthPattern} — the four-path variant
16
+ * (token → OAuth → session-scrape → fetchproxy), each path an injected
17
+ * resolver tried in priority order.
18
+ * - {@link sessionLoginFlow} — CSRF-scrape + cookie POST + success-marker,
19
+ * the shared CSRF+cookie login primitive (canvas / IC / ofw / signupgenius).
20
+ * - {@link createOAuth2Refresher} — an OAuth2 `refresh_token`-grant refresher
21
+ * with optional retry and in-flight race-safety.
22
+ *
23
+ * Security posture: env reads go through the hardened {@link readEnvVar}
24
+ * (placeholder / `'null'` / `'undefined'` suppression); thrown errors never
25
+ * echo the offending secret value and run upstream bodies through
26
+ * {@link truncateErrorMessage} (redaction + truncation) before surfacing.
27
+ */
28
+ import { type EnvSource } from '../config/index.js';
29
+ /** A `@fetchproxy/bootstrap` session blob: declared cookies / storage, by key. */
30
+ export interface FetchproxySession {
31
+ cookies: Record<string, string>;
32
+ localStorage?: Record<string, string>;
33
+ sessionStorage?: Record<string, string>;
34
+ }
35
+ /**
36
+ * The injected `@fetchproxy/bootstrap`-shaped function. Kept as a parameter (not
37
+ * a hard import) so the heavy bridge dep stays out of this module and tests can
38
+ * mock the module boundary, exactly as every fleet `auth.ts` does today.
39
+ */
40
+ export type BootstrapFn = (opts: unknown) => Promise<FetchproxySession>;
41
+ /** Result of {@link createAuthResolver}'s resolver — opaque credential + provenance. */
42
+ export interface ResolvedCredential {
43
+ /** The resolved credential (token / cookie header / refresh JWT — opaque). */
44
+ credential: string;
45
+ /** Which path produced it. Diagnostics / cache-keying only — do not branch on it. */
46
+ source: 'env' | 'fetchproxy';
47
+ }
48
+ /** Options for {@link createAuthResolver}. */
49
+ export interface AuthResolverOptions {
50
+ /** Env var holding the credential when the user supplies it directly (path 1). */
51
+ envVar: string;
52
+ /**
53
+ * Env var that, when truthy, disables the fetchproxy fallback (path 2). When
54
+ * omitted, the fallback is always attempted. Mirrors `*_DISABLE_FETCHPROXY`.
55
+ */
56
+ disableEnvVar?: string;
57
+ /** Injected `@fetchproxy/bootstrap` function (mocked at the boundary in tests). */
58
+ bootstrap: BootstrapFn;
59
+ /** The opts object passed verbatim to {@link bootstrap} (domains, declare, …). */
60
+ bootstrapOptions: unknown;
61
+ /**
62
+ * Lift the credential out of the fetchproxy session blob. Returns the
63
+ * credential string, or `undefined`/`''` when the signed-in tab didn't carry
64
+ * it (→ surfaced as a "sign in" error).
65
+ */
66
+ parseTokens: (session: FetchproxySession) => string | undefined;
67
+ /** Human-readable service name for the not-signed-in error (e.g. "Zola"). */
68
+ serviceName?: string;
69
+ /** Host to point the user at when the browser session is missing (e.g. "zola.com"). */
70
+ signInHost?: string;
71
+ /** Env source. Defaults to {@link process.env}. */
72
+ env?: EnvSource;
73
+ }
74
+ /**
75
+ * Build the canonical **three-path** auth resolver:
76
+ *
77
+ * 1. **Env credential** — `envVar` set (after hardened {@link readEnvVar}
78
+ * sanitization) → returned directly, no network.
79
+ * 2. **fetchproxy one-shot read** — unless `disableEnvVar` is truthy, call the
80
+ * injected `bootstrap` to snapshot the user's signed-in browser session,
81
+ * then `parseTokens` to extract the credential. fetchproxy is invoked once;
82
+ * it is never in the hot path.
83
+ * 3. **Actionable error** — nothing configured: an error naming the env var
84
+ * and the sign-in fallback so the user can pick a fix.
85
+ *
86
+ * The returned `source` is for diagnostics; callers must treat the credential
87
+ * as opaque and not branch on it.
88
+ */
89
+ export declare function createAuthResolver(opts: AuthResolverOptions): () => Promise<ResolvedCredential>;
90
+ /** Result of a {@link resolveAuthPattern} path resolver — opaque credential + provenance. */
91
+ export interface PatternResult {
92
+ /** The resolved credential (bearer / cookie header — opaque to the caller). */
93
+ credential: string;
94
+ /** Which path produced it. Diagnostics only — callers should not branch on it. */
95
+ source: string;
96
+ }
97
+ /** A single path resolver. Returning a value claims the path; throwing aborts. */
98
+ export type PathResolver = () => Promise<PatternResult>;
99
+ /**
100
+ * The four ordered paths of the "Pattern A template" (canvas / IC). A path is
101
+ * **configured** iff its resolver is provided; the *first* configured path, in
102
+ * this fixed priority order, runs. This is the only ordering — it never branches
103
+ * on which site is calling.
104
+ */
105
+ export interface AuthPattern {
106
+ /** Path 1: a stateless personal-access-token credential. */
107
+ token?: PathResolver;
108
+ /** Path 2: an OAuth `refresh_token` grant. */
109
+ oauth?: PathResolver;
110
+ /** Path 3: a username/password session-scrape (CSRF + cookie login). */
111
+ sessionScrape?: PathResolver;
112
+ /** Path 4: a fetchproxy one-shot browser-session read. */
113
+ fetchproxy?: PathResolver;
114
+ }
115
+ /**
116
+ * Resolve auth via the four-path priority **token → OAuth → session-scrape →
117
+ * fetchproxy**. Runs the first *provided* resolver in that order (a missing
118
+ * resolver = an unconfigured path). A resolver that throws propagates — a
119
+ * partial-config error (the user's mistake) must surface, not silently fall
120
+ * through. Throws an actionable error when no path is configured at all.
121
+ */
122
+ export declare function resolveAuthPattern(pattern: AuthPattern): Promise<PatternResult>;
123
+ /** Options for {@link sessionLoginFlow}. */
124
+ export interface SessionLoginOptions {
125
+ /** URL of the login page to GET (carries the CSRF input + sets a session cookie). */
126
+ loginUrl: string;
127
+ /** URL to POST the credentials to. */
128
+ postUrl: string;
129
+ /** Regex with one capture group that extracts the CSRF token from the page HTML. */
130
+ csrfRegex: RegExp;
131
+ /** Form field name the CSRF token is submitted under. Defaults to `'csrfToken'`. */
132
+ csrfField?: string;
133
+ /**
134
+ * Cookie name that signals a successful login *and* is returned as `token`.
135
+ * Its presence after the POST is the success marker.
136
+ */
137
+ tokenField: string;
138
+ /** Form field name the email/username is submitted under. Defaults to `'email'`. */
139
+ emailField?: string;
140
+ /** Form field name the password is submitted under. Defaults to `'password'`. */
141
+ passwordField?: string;
142
+ /** The user's email / username. */
143
+ email: string;
144
+ /** The user's password. */
145
+ password: string;
146
+ /** Extra static form fields to include in the POST body (per-site form params). */
147
+ extraFields?: Record<string, string>;
148
+ /** Header sent on both requests (e.g. a desktop `User-Agent`). */
149
+ userAgent?: string;
150
+ /** Injectable fetch (defaults to global `fetch`) — for tests. */
151
+ fetchImpl?: typeof fetch;
152
+ }
153
+ /** Result of {@link sessionLoginFlow}. */
154
+ export interface SessionLoginResult {
155
+ /** Value of the `tokenField` cookie set on a successful login. */
156
+ token: string;
157
+ /** Full `Cookie` header (deduped jar) for subsequent authenticated requests. */
158
+ cookies: string;
159
+ }
160
+ /**
161
+ * The shared CSRF + cookie login primitive (canvas / IC / ofw / signupgenius):
162
+ *
163
+ * 1. GET `loginUrl` — capture the session cookie(s) and scrape the CSRF token
164
+ * out of the page with `csrfRegex`.
165
+ * 2. POST `postUrl` (`application/x-www-form-urlencoded`) with the scraped CSRF
166
+ * token, credentials, and any `extraFields`, carrying the GET's cookies.
167
+ * 3. Merge `Set-Cookie`s from both responses (deduped, deletions dropped) and
168
+ * require the `tokenField` cookie as the success marker — its value is the
169
+ * returned `token`; its absence means the credentials were rejected.
170
+ *
171
+ * Per-site form parameters and the CSRF regex are injected; the flow itself is
172
+ * site-agnostic.
173
+ */
174
+ export declare function sessionLoginFlow(opts: SessionLoginOptions): Promise<SessionLoginResult>;
175
+ /** Options for {@link createOAuth2Refresher}. */
176
+ export interface OAuth2RefresherOptions {
177
+ /** Token endpoint to POST the grant to. */
178
+ endpoint: string;
179
+ /** The refresh token to exchange. */
180
+ refreshToken: string;
181
+ /** OAuth2 grant type. Defaults to `'refresh_token'`. */
182
+ grantType?: string;
183
+ /** Extra form params (e.g. `client_id`, `client_secret`, `scope`). */
184
+ params?: Record<string, string>;
185
+ /**
186
+ * Retry policy for a failed exchange. `count` is *additional* attempts after
187
+ * the first; `delayMs` is the fixed wait between attempts. Omit to never retry.
188
+ */
189
+ retry?: {
190
+ count: number;
191
+ delayMs: number;
192
+ };
193
+ /** Injectable fetch (defaults to global `fetch`) — for tests. */
194
+ fetchImpl?: typeof fetch;
195
+ }
196
+ /** Result of an {@link createOAuth2Refresher} exchange. */
197
+ export interface OAuth2RefreshResult {
198
+ /** The new access token. */
199
+ accessToken: string;
200
+ /** A rotated refresh token, when the server returned one. */
201
+ refreshToken?: string;
202
+ /** `expires_in` (seconds), when the server returned one. */
203
+ expiresIn?: number;
204
+ /** Absolute expiry (`now + expires_in`), when `expires_in` was present. */
205
+ expiresAt?: Date;
206
+ }
207
+ /**
208
+ * Build a race-safe OAuth2 `refresh_token`-grant refresher. The returned
209
+ * function POSTs the form-encoded grant to `endpoint` and parses the standard
210
+ * `{ access_token, refresh_token?, expires_in? }` body.
211
+ *
212
+ * Race-safety: concurrent calls share a single in-flight exchange (the
213
+ * canonical token-refresh-race guard — `skylight`/`canvas`/`creditkarma`/`zola`
214
+ * all hand-roll this). The in-flight promise is cleared once it settles, so a
215
+ * later refresh starts fresh and a *rejected* exchange does not poison the next
216
+ * caller.
217
+ *
218
+ * Errors run through {@link truncateErrorMessage} (redaction + truncation)
219
+ * before surfacing, so an upstream error body can't leak a bearer token or
220
+ * blow up a tool result.
221
+ */
222
+ export declare function createOAuth2Refresher(opts: OAuth2RefresherOptions): () => Promise<OAuth2RefreshResult>;
223
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"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"}