integrate-sdk 0.8.4 → 0.8.7

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.
@@ -1,4 +1,20 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
1
4
  var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
2
18
  var __export = (target, all) => {
3
19
  for (var name in all)
4
20
  __defProp(target, name, {
@@ -9,6 +25,7 @@ var __export = (target, all) => {
9
25
  });
10
26
  };
11
27
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
28
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
12
29
 
13
30
  // session-detector.ts
14
31
  var exports_session_detector = {};
@@ -151,2358 +168,6 @@ async function detectSessionContext(request) {
151
168
  }
152
169
  return;
153
170
  }
154
-
155
- // context-cookie.ts
156
- var exports_context_cookie = {};
157
- __export(exports_context_cookie, {
158
- readContextCookie: () => readContextCookie,
159
- getSetCookieHeader: () => getSetCookieHeader,
160
- getContextCookieFromRequest: () => getContextCookieFromRequest,
161
- getClearCookieHeader: () => getClearCookieHeader,
162
- createContextCookie: () => createContextCookie,
163
- CONTEXT_COOKIE_NAME: () => CONTEXT_COOKIE_NAME,
164
- CONTEXT_COOKIE_MAX_AGE: () => CONTEXT_COOKIE_MAX_AGE
165
- });
166
- async function deriveKey(secret) {
167
- const encoder = new TextEncoder;
168
- const secretData = encoder.encode(secret);
169
- const keyMaterial = await crypto.subtle.importKey("raw", secretData, { name: "PBKDF2" }, false, ["deriveBits", "deriveKey"]);
170
- const salt = encoder.encode("integrate-oauth-context-v1");
171
- return await crypto.subtle.deriveKey({
172
- name: "PBKDF2",
173
- salt,
174
- iterations: 1e5,
175
- hash: "SHA-256"
176
- }, keyMaterial, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
177
- }
178
- async function encryptPayload(payload, secret) {
179
- const key = await deriveKey(secret);
180
- const iv = crypto.getRandomValues(new Uint8Array(12));
181
- const encoder = new TextEncoder;
182
- const data = encoder.encode(JSON.stringify(payload));
183
- const encrypted = await crypto.subtle.encrypt({
184
- name: "AES-GCM",
185
- iv
186
- }, key, data);
187
- const combined = new Uint8Array(iv.length + encrypted.byteLength);
188
- combined.set(iv, 0);
189
- combined.set(new Uint8Array(encrypted), iv.length);
190
- return base64UrlEncode(combined);
191
- }
192
- async function decryptPayload(cookieValue, secret) {
193
- try {
194
- const combined = base64UrlDecode(cookieValue);
195
- const iv = combined.slice(0, 12);
196
- const encrypted = combined.slice(12);
197
- const key = await deriveKey(secret);
198
- const decrypted = await crypto.subtle.decrypt({
199
- name: "AES-GCM",
200
- iv
201
- }, key, encrypted);
202
- const decoder = new TextDecoder;
203
- const json = decoder.decode(decrypted);
204
- const payload = JSON.parse(json);
205
- const age = Date.now() - payload.timestamp;
206
- if (age > CONTEXT_COOKIE_MAX_AGE * 1000) {
207
- return;
208
- }
209
- return payload;
210
- } catch (error) {
211
- return;
212
- }
213
- }
214
- function base64UrlEncode(data) {
215
- const base64 = btoa(String.fromCharCode(...data));
216
- return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
217
- }
218
- function base64UrlDecode(str) {
219
- let base64 = str.replace(/-/g, "+").replace(/_/g, "/");
220
- const padding = base64.length % 4;
221
- if (padding) {
222
- base64 += "=".repeat(4 - padding);
223
- }
224
- const binary = atob(base64);
225
- const bytes = new Uint8Array(binary.length);
226
- for (let i = 0;i < binary.length; i++) {
227
- bytes[i] = binary.charCodeAt(i);
228
- }
229
- return bytes;
230
- }
231
- async function createContextCookie(context, provider, secret) {
232
- const payload = {
233
- context,
234
- provider,
235
- timestamp: Date.now()
236
- };
237
- return await encryptPayload(payload, secret);
238
- }
239
- async function readContextCookie(cookieValue, secret) {
240
- const payload = await decryptPayload(cookieValue, secret);
241
- if (!payload) {
242
- return;
243
- }
244
- return {
245
- context: payload.context,
246
- provider: payload.provider
247
- };
248
- }
249
- function getSetCookieHeader(cookieValue, maxAge = CONTEXT_COOKIE_MAX_AGE) {
250
- const attributes = [
251
- `${CONTEXT_COOKIE_NAME}=${cookieValue}`,
252
- `Max-Age=${maxAge}`,
253
- "HttpOnly",
254
- "Secure",
255
- "SameSite=Lax",
256
- "Path=/"
257
- ];
258
- return attributes.join("; ");
259
- }
260
- function getClearCookieHeader() {
261
- const attributes = [
262
- `${CONTEXT_COOKIE_NAME}=`,
263
- "Max-Age=0",
264
- "HttpOnly",
265
- "Secure",
266
- "SameSite=Lax",
267
- "Path=/"
268
- ];
269
- return attributes.join("; ");
270
- }
271
- function getContextCookieFromRequest(request) {
272
- const cookieHeader = request.headers.get("cookie");
273
- if (!cookieHeader) {
274
- return;
275
- }
276
- const cookies = cookieHeader.split(";");
277
- for (const cookie of cookies) {
278
- const [name, ...valueParts] = cookie.split("=");
279
- if (name && name.trim() === CONTEXT_COOKIE_NAME) {
280
- return valueParts.join("=").trim();
281
- }
282
- }
283
- return;
284
- }
285
- var CONTEXT_COOKIE_NAME = "__integrate_oauth_ctx", CONTEXT_COOKIE_MAX_AGE = 300;
286
-
287
- // base-handler.ts
288
- class OAuthHandler {
289
- config;
290
- serverUrl;
291
- apiKey;
292
- constructor(config) {
293
- this.config = config;
294
- if (!config || !config.providers) {
295
- throw new Error("OAuthHandler requires a valid config with providers");
296
- }
297
- this.serverUrl = config.serverUrl || MCP_SERVER_URL;
298
- this.apiKey = config.apiKey;
299
- }
300
- getHeaders(additionalHeaders) {
301
- const headers = {
302
- ...additionalHeaders
303
- };
304
- if (this.apiKey) {
305
- headers["X-API-KEY"] = this.apiKey;
306
- }
307
- return headers;
308
- }
309
- async handleAuthorize(request) {
310
- let webRequest;
311
- let authorizeRequest;
312
- if (request instanceof Request) {
313
- webRequest = request;
314
- authorizeRequest = await request.json();
315
- } else if (typeof request === "object" && "json" in request && typeof request.json === "function") {
316
- authorizeRequest = await request.json();
317
- } else {
318
- authorizeRequest = request;
319
- }
320
- const providerConfig = this.config.providers[authorizeRequest.provider];
321
- if (!providerConfig) {
322
- throw new Error(`Provider ${authorizeRequest.provider} not configured. Add OAuth credentials to your API route configuration.`);
323
- }
324
- if (!providerConfig.clientId || !providerConfig.clientSecret) {
325
- throw new Error(`Missing OAuth credentials for ${authorizeRequest.provider}. Check your environment variables.`);
326
- }
327
- const url = new URL("/oauth/authorize", this.serverUrl);
328
- url.searchParams.set("provider", authorizeRequest.provider);
329
- url.searchParams.set("client_id", providerConfig.clientId);
330
- url.searchParams.set("client_secret", providerConfig.clientSecret);
331
- const scopes = authorizeRequest.scopes || providerConfig.scopes || [];
332
- if (scopes.length > 0) {
333
- url.searchParams.set("scope", scopes.join(","));
334
- }
335
- url.searchParams.set("state", authorizeRequest.state);
336
- url.searchParams.set("code_challenge", authorizeRequest.codeChallenge);
337
- url.searchParams.set("code_challenge_method", authorizeRequest.codeChallengeMethod);
338
- const redirectUri = authorizeRequest.redirectUri || providerConfig.redirectUri;
339
- if (redirectUri) {
340
- url.searchParams.set("redirect_uri", redirectUri);
341
- }
342
- if (providerConfig.config) {
343
- for (const [key, value] of Object.entries(providerConfig.config)) {
344
- if (value !== undefined && value !== null) {
345
- url.searchParams.set(key, String(value));
346
- }
347
- }
348
- }
349
- const response = await fetch(url.toString(), {
350
- method: "GET",
351
- headers: this.getHeaders()
352
- });
353
- if (!response.ok) {
354
- const error = await response.text();
355
- throw new Error(`MCP server failed to generate authorization URL: ${error}`);
356
- }
357
- const data = await response.json();
358
- const result = data;
359
- if (webRequest) {
360
- try {
361
- const { detectSessionContext: detectSessionContext2 } = await Promise.resolve().then(() => exports_session_detector);
362
- const { createContextCookie: createContextCookie2, getSetCookieHeader: getSetCookieHeader2 } = await Promise.resolve().then(() => exports_context_cookie);
363
- let context;
364
- if (this.config.getSessionContext) {
365
- context = await this.config.getSessionContext(webRequest);
366
- }
367
- if (!context || !context.userId) {
368
- context = await detectSessionContext2(webRequest);
369
- }
370
- if (context && context.userId) {
371
- const secret = this.apiKey || providerConfig.clientSecret;
372
- const cookieValue = await createContextCookie2(context, authorizeRequest.provider, secret);
373
- result.setCookie = getSetCookieHeader2(cookieValue);
374
- }
375
- } catch (error) {
376
- console.warn("[OAuth] Failed to capture user context:", error);
377
- }
378
- }
379
- return result;
380
- }
381
- async handleCallback(request) {
382
- let webRequest;
383
- let callbackRequest;
384
- if (request instanceof Request) {
385
- webRequest = request;
386
- callbackRequest = await request.json();
387
- } else if (typeof request === "object" && "json" in request && typeof request.json === "function") {
388
- callbackRequest = await request.json();
389
- } else {
390
- callbackRequest = request;
391
- }
392
- const providerConfig = this.config.providers[callbackRequest.provider];
393
- if (!providerConfig) {
394
- throw new Error(`Provider ${callbackRequest.provider} not configured. Add OAuth credentials to your API route configuration.`);
395
- }
396
- if (!providerConfig.clientId || !providerConfig.clientSecret) {
397
- throw new Error(`Missing OAuth credentials for ${callbackRequest.provider}. Check your environment variables.`);
398
- }
399
- let context;
400
- if (webRequest) {
401
- try {
402
- const { getContextCookieFromRequest: getContextCookieFromRequest2, readContextCookie: readContextCookie2 } = await Promise.resolve().then(() => exports_context_cookie);
403
- const cookieValue = getContextCookieFromRequest2(webRequest);
404
- if (cookieValue) {
405
- const secret = this.apiKey || providerConfig.clientSecret;
406
- const contextData = await readContextCookie2(cookieValue, secret);
407
- if (contextData && contextData.provider === callbackRequest.provider) {
408
- context = contextData.context;
409
- }
410
- }
411
- } catch (error) {
412
- console.warn("[OAuth] Failed to restore user context:", error);
413
- }
414
- }
415
- const url = new URL("/oauth/callback", this.serverUrl);
416
- const response = await fetch(url.toString(), {
417
- method: "POST",
418
- headers: this.getHeaders({
419
- "Content-Type": "application/json"
420
- }),
421
- body: JSON.stringify({
422
- provider: callbackRequest.provider,
423
- code: callbackRequest.code,
424
- code_verifier: callbackRequest.codeVerifier,
425
- state: callbackRequest.state,
426
- client_id: providerConfig.clientId,
427
- client_secret: providerConfig.clientSecret,
428
- redirect_uri: providerConfig.redirectUri
429
- })
430
- });
431
- if (!response.ok) {
432
- const error = await response.text();
433
- throw new Error(`MCP server failed to exchange authorization code: ${error}`);
434
- }
435
- const data = await response.json();
436
- const result = data;
437
- if (this.config.setProviderToken) {
438
- try {
439
- const tokenData = {
440
- accessToken: result.accessToken,
441
- refreshToken: result.refreshToken,
442
- tokenType: result.tokenType,
443
- expiresIn: result.expiresIn,
444
- expiresAt: result.expiresAt,
445
- scopes: result.scopes
446
- };
447
- await this.config.setProviderToken(callbackRequest.provider, tokenData, context);
448
- } catch (error) {
449
- console.error("[OAuth] Failed to save provider token:", error);
450
- }
451
- }
452
- if (webRequest) {
453
- const { getClearCookieHeader: getClearCookieHeader2 } = await Promise.resolve().then(() => exports_context_cookie);
454
- result.clearCookie = getClearCookieHeader2();
455
- }
456
- return result;
457
- }
458
- async handleStatus(provider, accessToken) {
459
- const url = new URL("/oauth/status", this.serverUrl);
460
- url.searchParams.set("provider", provider);
461
- const response = await fetch(url.toString(), {
462
- method: "GET",
463
- headers: this.getHeaders({
464
- Authorization: `Bearer ${accessToken}`
465
- })
466
- });
467
- if (!response.ok) {
468
- if (response.status === 401) {
469
- return {
470
- authorized: false
471
- };
472
- }
473
- const error = await response.text();
474
- throw new Error(`MCP server failed to check authorization status: ${error}`);
475
- }
476
- const data = await response.json();
477
- return data;
478
- }
479
- async handleDisconnect(request, accessToken, webRequest) {
480
- if (!accessToken) {
481
- throw new Error("No access token provided. Cannot disconnect provider.");
482
- }
483
- if (webRequest && this.config.removeProviderToken) {
484
- try {
485
- let context;
486
- if (this.config.getSessionContext) {
487
- context = await this.config.getSessionContext(webRequest);
488
- }
489
- if (!context || !context.userId) {
490
- const { detectSessionContext: detectSessionContext2 } = await Promise.resolve().then(() => exports_session_detector);
491
- context = await detectSessionContext2(webRequest);
492
- }
493
- if (context) {
494
- try {
495
- await this.config.removeProviderToken(request.provider, context);
496
- } catch (error) {
497
- console.error(`Failed to delete token for ${request.provider} from database via removeProviderToken:`, error);
498
- }
499
- }
500
- } catch (error) {
501
- console.error(`Failed to extract context for disconnect:`, error);
502
- }
503
- }
504
- const url = new URL("/oauth/disconnect", this.serverUrl);
505
- const response = await fetch(url.toString(), {
506
- method: "POST",
507
- headers: this.getHeaders({
508
- "Content-Type": "application/json",
509
- Authorization: `Bearer ${accessToken}`
510
- }),
511
- body: JSON.stringify({
512
- provider: request.provider
513
- })
514
- });
515
- if (!response.ok) {
516
- const error = await response.text();
517
- throw new Error(`MCP server failed to disconnect provider: ${error}`);
518
- }
519
- const data = await response.json();
520
- return data;
521
- }
522
- async handleToolCall(request, authHeader) {
523
- const url = this.serverUrl;
524
- const headers = this.getHeaders({
525
- "Content-Type": "application/json"
526
- });
527
- if (authHeader && authHeader.startsWith("Bearer ")) {
528
- headers["Authorization"] = authHeader;
529
- }
530
- const jsonRpcRequest = {
531
- jsonrpc: "2.0",
532
- id: Date.now() + Math.random(),
533
- method: "tools/call",
534
- params: {
535
- name: request.name,
536
- arguments: request.arguments || {}
537
- }
538
- };
539
- const response = await fetch(url, {
540
- method: "POST",
541
- headers,
542
- body: JSON.stringify(jsonRpcRequest)
543
- });
544
- if (!response.ok) {
545
- const error = await response.text();
546
- throw new Error(`MCP server failed to execute tool call: ${error}`);
547
- }
548
- const jsonRpcResponse = await response.json();
549
- if (jsonRpcResponse.error) {
550
- const error = new Error(jsonRpcResponse.error.message || "Tool call failed");
551
- error.code = jsonRpcResponse.error.code;
552
- error.data = jsonRpcResponse.error.data;
553
- throw error;
554
- }
555
- return jsonRpcResponse.result;
556
- }
557
- }
558
- var MCP_SERVER_URL = "https://mcp.integrate.dev/api/v1/mcp";
559
-
560
- // ../oauth/pkce.ts
561
- var exports_pkce = {};
562
- __export(exports_pkce, {
563
- parseState: () => parseState,
564
- generateStateWithReturnUrl: () => generateStateWithReturnUrl,
565
- generateState: () => generateState,
566
- generateCodeVerifier: () => generateCodeVerifier,
567
- generateCodeChallenge: () => generateCodeChallenge
568
- });
569
- function generateCodeVerifier() {
570
- const array = new Uint8Array(32);
571
- if (typeof crypto !== "undefined" && crypto.getRandomValues) {
572
- crypto.getRandomValues(array);
573
- } else if (typeof globalThis !== "undefined" && globalThis.crypto) {
574
- globalThis.crypto.getRandomValues(array);
575
- } else {
576
- throw new Error("crypto.getRandomValues is not available. Please use Node.js 19+ or a modern browser.");
577
- }
578
- return base64UrlEncode2(array);
579
- }
580
- async function generateCodeChallenge(verifier) {
581
- const encoder = new TextEncoder;
582
- const data = encoder.encode(verifier);
583
- let hashBuffer;
584
- if (typeof crypto !== "undefined" && crypto.subtle) {
585
- hashBuffer = await crypto.subtle.digest("SHA-256", data);
586
- } else if (typeof globalThis !== "undefined" && globalThis.crypto?.subtle) {
587
- hashBuffer = await globalThis.crypto.subtle.digest("SHA-256", data);
588
- } else {
589
- throw new Error("crypto.subtle.digest is not available. Please use Node.js 19+ or a modern browser.");
590
- }
591
- return base64UrlEncode2(new Uint8Array(hashBuffer));
592
- }
593
- function generateState() {
594
- const array = new Uint8Array(16);
595
- if (typeof crypto !== "undefined" && crypto.getRandomValues) {
596
- crypto.getRandomValues(array);
597
- } else if (typeof globalThis !== "undefined" && globalThis.crypto) {
598
- globalThis.crypto.getRandomValues(array);
599
- } else {
600
- throw new Error("crypto.getRandomValues is not available. Please use Node.js 19+ or a modern browser.");
601
- }
602
- return base64UrlEncode2(array);
603
- }
604
- function generateStateWithReturnUrl(returnUrl) {
605
- const csrf = generateState();
606
- const stateData = returnUrl ? { csrf, returnUrl } : { csrf };
607
- const encoder = new TextEncoder;
608
- const jsonBytes = encoder.encode(JSON.stringify(stateData));
609
- return base64UrlEncode2(jsonBytes);
610
- }
611
- function parseState(state) {
612
- try {
613
- const decoded = base64UrlDecode2(state);
614
- const parsed = JSON.parse(decoded);
615
- if (typeof parsed === "string") {
616
- return { csrf: parsed };
617
- } else if (parsed && typeof parsed === "object") {
618
- return {
619
- csrf: parsed.csrf || state,
620
- returnUrl: parsed.returnUrl
621
- };
622
- }
623
- return { csrf: state };
624
- } catch {
625
- return { csrf: state };
626
- }
627
- }
628
- function base64UrlEncode2(array) {
629
- let base64 = "";
630
- if (typeof Buffer !== "undefined") {
631
- base64 = Buffer.from(array).toString("base64");
632
- } else {
633
- const binary = String.fromCharCode(...array);
634
- base64 = btoa(binary);
635
- }
636
- return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
637
- }
638
- function base64UrlDecode2(str) {
639
- let base64 = str.replace(/-/g, "+").replace(/_/g, "/");
640
- while (base64.length % 4 !== 0) {
641
- base64 += "=";
642
- }
643
- if (typeof Buffer !== "undefined") {
644
- return Buffer.from(base64, "base64").toString("utf-8");
645
- } else {
646
- const binary = atob(base64);
647
- const bytes = new Uint8Array(binary.length);
648
- for (let i = 0;i < binary.length; i++) {
649
- bytes[i] = binary.charCodeAt(i);
650
- }
651
- const decoder = new TextDecoder;
652
- return decoder.decode(bytes);
653
- }
654
- }
655
-
656
- // ../errors.ts
657
- var exports_errors = {};
658
- __export(exports_errors, {
659
- parseServerError: () => parseServerError,
660
- isTokenExpiredError: () => isTokenExpiredError,
661
- isAuthorizationError: () => isAuthorizationError,
662
- isAuthError: () => isAuthError,
663
- ToolCallError: () => ToolCallError,
664
- TokenExpiredError: () => TokenExpiredError,
665
- IntegrateSDKError: () => IntegrateSDKError,
666
- ConnectionError: () => ConnectionError,
667
- AuthorizationError: () => AuthorizationError,
668
- AuthenticationError: () => AuthenticationError
669
- });
670
- function isAuthError(error) {
671
- return error instanceof AuthenticationError;
672
- }
673
- function isTokenExpiredError(error) {
674
- return error instanceof TokenExpiredError;
675
- }
676
- function isAuthorizationError(error) {
677
- return error instanceof AuthorizationError;
678
- }
679
- function parseServerError(error, context) {
680
- if (error && typeof error === "object" && "jsonrpcError" in error) {
681
- const jsonrpcError = error.jsonrpcError;
682
- if (jsonrpcError && typeof jsonrpcError === "object") {
683
- return parseServerError(jsonrpcError, context);
684
- }
685
- }
686
- if (error && typeof error === "object" && "code" in error && "message" in error) {
687
- const code = error.code;
688
- const message = error.message || "Unknown error";
689
- if (code === -32600) {
690
- return new IntegrateSDKError(`Invalid request: ${message}`);
691
- }
692
- if (code === -32601) {
693
- return new IntegrateSDKError(`Method not found: ${message}`);
694
- }
695
- if (code === -32602) {
696
- return new IntegrateSDKError(`Invalid params: ${message}`);
697
- }
698
- if (code === 401 || code === -32001) {
699
- if (message.toLowerCase().includes("expired") || message.toLowerCase().includes("token")) {
700
- return new TokenExpiredError(message, context?.provider);
701
- }
702
- return new AuthenticationError(message, 401, context?.provider);
703
- }
704
- if (code === 403 || code === -32002) {
705
- return new AuthorizationError(message, 403);
706
- }
707
- if (context?.toolName) {
708
- return new ToolCallError(message, context.toolName, error);
709
- }
710
- return new IntegrateSDKError(message);
711
- }
712
- if (error instanceof Error) {
713
- const message = error.message;
714
- const statusCode = error.statusCode;
715
- if (statusCode === 401) {
716
- if (message.toLowerCase().includes("expired") || message.toLowerCase().includes("token")) {
717
- return new TokenExpiredError(message, context?.provider);
718
- }
719
- return new AuthenticationError(message, 401, context?.provider);
720
- }
721
- if (statusCode === 403) {
722
- return new AuthorizationError(message, 403);
723
- }
724
- if (message.includes("401") || message.includes("Unauthorized") || message.includes("unauthenticated")) {
725
- if (message.toLowerCase().includes("expired") || message.toLowerCase().includes("token")) {
726
- return new TokenExpiredError(message, context?.provider);
727
- }
728
- return new AuthenticationError(message, 401, context?.provider);
729
- }
730
- if (message.includes("403") || message.includes("Forbidden") || message.includes("unauthorized")) {
731
- return new AuthorizationError(message, 403);
732
- }
733
- if (context?.toolName) {
734
- return new ToolCallError(message, context.toolName, error);
735
- }
736
- return new IntegrateSDKError(message);
737
- }
738
- return new IntegrateSDKError(String(error));
739
- }
740
- var IntegrateSDKError, AuthenticationError, AuthorizationError, TokenExpiredError, ConnectionError, ToolCallError;
741
- var init_errors = __esm(() => {
742
- IntegrateSDKError = class IntegrateSDKError extends Error {
743
- constructor(message) {
744
- super(message);
745
- this.name = "IntegrateSDKError";
746
- }
747
- };
748
- AuthenticationError = class AuthenticationError extends IntegrateSDKError {
749
- statusCode;
750
- provider;
751
- constructor(message, statusCode, provider) {
752
- super(message);
753
- this.name = "AuthenticationError";
754
- this.statusCode = statusCode;
755
- this.provider = provider;
756
- }
757
- };
758
- AuthorizationError = class AuthorizationError extends IntegrateSDKError {
759
- statusCode;
760
- requiredScopes;
761
- constructor(message, statusCode, requiredScopes) {
762
- super(message);
763
- this.name = "AuthorizationError";
764
- this.statusCode = statusCode;
765
- this.requiredScopes = requiredScopes;
766
- }
767
- };
768
- TokenExpiredError = class TokenExpiredError extends AuthenticationError {
769
- constructor(message, provider) {
770
- super(message, 401, provider);
771
- this.name = "TokenExpiredError";
772
- }
773
- };
774
- ConnectionError = class ConnectionError extends IntegrateSDKError {
775
- statusCode;
776
- constructor(message, statusCode) {
777
- super(message);
778
- this.name = "ConnectionError";
779
- this.statusCode = statusCode;
780
- }
781
- };
782
- ToolCallError = class ToolCallError extends IntegrateSDKError {
783
- toolName;
784
- originalError;
785
- constructor(message, toolName, originalError) {
786
- super(message);
787
- this.name = "ToolCallError";
788
- this.toolName = toolName;
789
- this.originalError = originalError;
790
- }
791
- };
792
- });
793
-
794
- // nextjs.ts
795
- function createNextOAuthHandler(config) {
796
- const handler = new OAuthHandler(config);
797
- const handlers = {
798
- async authorize(req) {
799
- try {
800
- const result = await handler.handleAuthorize(req);
801
- const response = Response.json(result);
802
- if (result.setCookie) {
803
- response.headers.set("Set-Cookie", result.setCookie);
804
- }
805
- return response;
806
- } catch (error) {
807
- console.error("[OAuth Authorize] Error:", error);
808
- return Response.json({ error: error.message || "Failed to get authorization URL" }, { status: 500 });
809
- }
810
- },
811
- async callback(req) {
812
- try {
813
- const result = await handler.handleCallback(req);
814
- const response = Response.json(result);
815
- if (result.clearCookie) {
816
- response.headers.set("Set-Cookie", result.clearCookie);
817
- }
818
- return response;
819
- } catch (error) {
820
- console.error("[OAuth Callback] Error:", error);
821
- return Response.json({ error: error.message || "Failed to exchange authorization code" }, { status: 500 });
822
- }
823
- },
824
- async status(req) {
825
- try {
826
- const provider = req.nextUrl.searchParams.get("provider");
827
- const authHeader = req.headers.get("authorization");
828
- if (!provider) {
829
- return Response.json({ error: "Missing provider query parameter" }, { status: 400 });
830
- }
831
- if (!authHeader || !authHeader.startsWith("Bearer ")) {
832
- return Response.json({ error: "Missing or invalid Authorization header" }, { status: 400 });
833
- }
834
- const accessToken = authHeader.substring(7);
835
- const result = await handler.handleStatus(provider, accessToken);
836
- return Response.json(result);
837
- } catch (error) {
838
- console.error("[OAuth Status] Error:", error);
839
- return Response.json({ error: error.message || "Failed to check authorization status" }, { status: 500 });
840
- }
841
- },
842
- async disconnect(req) {
843
- try {
844
- const authHeader = req.headers.get("authorization");
845
- if (!authHeader || !authHeader.startsWith("Bearer ")) {
846
- return Response.json({ error: "Missing or invalid Authorization header" }, { status: 400 });
847
- }
848
- const accessToken = authHeader.substring(7);
849
- const body = await req.json();
850
- const { provider } = body;
851
- if (!provider) {
852
- return Response.json({ error: "Missing provider in request body" }, { status: 400 });
853
- }
854
- const result = await handler.handleDisconnect({ provider }, accessToken, req);
855
- return Response.json(result);
856
- } catch (error) {
857
- console.error("[OAuth Disconnect] Error:", error);
858
- return Response.json({ error: error.message || "Failed to disconnect provider" }, { status: 500 });
859
- }
860
- },
861
- createRoutes() {
862
- return {
863
- async POST(req, context) {
864
- const params = context.params instanceof Promise ? await context.params : context.params;
865
- const action = params.action;
866
- if (action === "authorize") {
867
- return handlers.authorize(req);
868
- }
869
- if (action === "callback") {
870
- return handlers.callback(req);
871
- }
872
- if (action === "disconnect") {
873
- return handlers.disconnect(req);
874
- }
875
- if (action === "mcp") {
876
- return handlers.mcp(req);
877
- }
878
- return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
879
- },
880
- async GET(req, context) {
881
- const params = context.params instanceof Promise ? await context.params : context.params;
882
- const action = params.action;
883
- if (action === "status") {
884
- return handlers.status(req);
885
- }
886
- return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
887
- }
888
- };
889
- },
890
- async mcp(req) {
891
- try {
892
- const body = await req.json();
893
- const authHeader = req.headers.get("authorization");
894
- const result = await handler.handleToolCall(body, authHeader);
895
- return Response.json(result);
896
- } catch (error) {
897
- console.error("[MCP Tool Call] Error:", error);
898
- return Response.json({ error: error.message || "Failed to execute tool call" }, { status: error.statusCode || 500 });
899
- }
900
- },
901
- toNextJsHandler(redirectConfig) {
902
- const defaultRedirectUrl = redirectConfig?.redirectUrl || "/";
903
- const errorRedirectUrl = redirectConfig?.errorRedirectUrl || "/auth-error";
904
- return {
905
- async POST(req, context) {
906
- const params = context.params instanceof Promise ? await context.params : context.params;
907
- const segments = params.all || [];
908
- if (segments.length === 2 && segments[0] === "oauth") {
909
- const action = segments[1];
910
- if (action === "authorize") {
911
- return handlers.authorize(req);
912
- }
913
- if (action === "callback") {
914
- return handlers.callback(req);
915
- }
916
- if (action === "disconnect") {
917
- return handlers.disconnect(req);
918
- }
919
- return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
920
- }
921
- if (segments.length === 1 && segments[0] === "mcp") {
922
- return handlers.mcp(req);
923
- }
924
- return Response.json({ error: `Invalid route: /${segments.join("/")}` }, { status: 404 });
925
- },
926
- async GET(req, context) {
927
- const params = context.params instanceof Promise ? await context.params : context.params;
928
- const segments = params.all || [];
929
- if (segments.length === 2 && segments[0] === "oauth") {
930
- const action = segments[1];
931
- if (action === "status") {
932
- return handlers.status(req);
933
- }
934
- if (action === "callback") {
935
- const { searchParams } = new URL(req.url);
936
- const code = searchParams.get("code");
937
- const state = searchParams.get("state");
938
- const error = searchParams.get("error");
939
- const errorDescription = searchParams.get("error_description");
940
- if (error) {
941
- const errorMsg = errorDescription || error;
942
- console.error("[OAuth Redirect] Error:", errorMsg);
943
- return Response.redirect(new URL(`${errorRedirectUrl}?error=${encodeURIComponent(errorMsg)}`, req.url));
944
- }
945
- if (!code || !state) {
946
- console.error("[OAuth Redirect] Missing code or state parameter");
947
- return Response.redirect(new URL(`${errorRedirectUrl}?error=${encodeURIComponent("Invalid OAuth callback")}`, req.url));
948
- }
949
- let returnUrl = defaultRedirectUrl;
950
- try {
951
- const { parseState: parseState2 } = await Promise.resolve().then(() => exports_pkce);
952
- const stateData = parseState2(state);
953
- if (stateData.returnUrl) {
954
- returnUrl = stateData.returnUrl;
955
- }
956
- } catch (e) {
957
- try {
958
- const referrer = req.headers?.get?.("referer") || req.headers?.get?.("referrer");
959
- if (referrer) {
960
- const referrerUrl = new URL(referrer);
961
- const currentUrl = new URL(req.url);
962
- if (referrerUrl.origin === currentUrl.origin) {
963
- returnUrl = referrerUrl.pathname + referrerUrl.search;
964
- }
965
- }
966
- } catch {}
967
- }
968
- const targetUrl = new URL(returnUrl, req.url);
969
- targetUrl.hash = `oauth_callback=${encodeURIComponent(JSON.stringify({ code, state }))}`;
970
- return Response.redirect(targetUrl);
971
- }
972
- return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
973
- }
974
- return Response.json({ error: `Invalid route: /${segments.join("/")}` }, { status: 404 });
975
- }
976
- };
977
- }
978
- };
979
- return handlers;
980
- }
981
-
982
- // ../protocol/jsonrpc.ts
983
- function parseMessage(message) {
984
- try {
985
- return JSON.parse(message);
986
- } catch (error) {
987
- throw new Error(`Failed to parse JSON-RPC message: ${error}`);
988
- }
989
- }
990
-
991
- // ../transport/http-session.ts
992
- class HttpSessionTransport {
993
- url;
994
- headers;
995
- timeout;
996
- messageHandlers = new Set;
997
- sessionId;
998
- sseController;
999
- connected = false;
1000
- constructor(options) {
1001
- this.url = options.url;
1002
- this.headers = options.headers || {};
1003
- this.timeout = options.timeout || 30000;
1004
- }
1005
- async connect() {
1006
- if (this.connected) {
1007
- return;
1008
- }
1009
- this.connected = true;
1010
- }
1011
- async sendRequest(method, params) {
1012
- if (!this.connected) {
1013
- throw new Error("Not connected to server");
1014
- }
1015
- const request = {
1016
- jsonrpc: "2.0",
1017
- id: Date.now() + Math.random(),
1018
- method,
1019
- params
1020
- };
1021
- const headers = {
1022
- ...this.headers,
1023
- "Content-Type": "application/json"
1024
- };
1025
- if (this.sessionId) {
1026
- headers["mcp-session-id"] = this.sessionId;
1027
- }
1028
- try {
1029
- const controller = new AbortController;
1030
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
1031
- const response = await fetch(this.url, {
1032
- method: "POST",
1033
- headers,
1034
- body: JSON.stringify(request),
1035
- signal: controller.signal
1036
- });
1037
- clearTimeout(timeoutId);
1038
- if (!response.ok) {
1039
- const error = new Error(`Request failed: ${response.statusText}`);
1040
- error.statusCode = response.status;
1041
- throw error;
1042
- }
1043
- if (!this.sessionId) {
1044
- const sid = response.headers.get("mcp-session-id");
1045
- if (sid) {
1046
- this.sessionId = sid;
1047
- console.log("Session established:", sid);
1048
- this.startSSEListener();
1049
- }
1050
- }
1051
- const jsonResponse = await response.json();
1052
- if ("error" in jsonResponse) {
1053
- const error = new Error(`JSON-RPC Error ${jsonResponse.error.code}: ${jsonResponse.error.message}`);
1054
- error.code = jsonResponse.error.code;
1055
- if (jsonResponse.error.data) {
1056
- error.data = jsonResponse.error.data;
1057
- }
1058
- error.jsonrpcError = jsonResponse.error;
1059
- throw error;
1060
- }
1061
- return jsonResponse.result;
1062
- } catch (error) {
1063
- if (error instanceof Error) {
1064
- if (error.name === "AbortError") {
1065
- const timeoutError = new Error("Request timeout");
1066
- timeoutError.code = -32000;
1067
- throw timeoutError;
1068
- }
1069
- throw error;
1070
- }
1071
- throw new Error(String(error));
1072
- }
1073
- }
1074
- async startSSEListener() {
1075
- if (!this.sessionId || this.sseController) {
1076
- return;
1077
- }
1078
- this.sseController = new AbortController;
1079
- try {
1080
- const response = await fetch(this.url, {
1081
- method: "GET",
1082
- headers: {
1083
- ...this.headers,
1084
- Accept: "text/event-stream",
1085
- "mcp-session-id": this.sessionId
1086
- },
1087
- signal: this.sseController.signal
1088
- });
1089
- if (!response.ok || !response.body) {
1090
- return;
1091
- }
1092
- this.processSSEStream(response.body);
1093
- } catch (error) {
1094
- if (error instanceof Error && error.name === "AbortError") {
1095
- return;
1096
- }
1097
- console.error("SSE connection error:", error);
1098
- }
1099
- }
1100
- async processSSEStream(body) {
1101
- const reader = body.getReader();
1102
- const decoder = new TextDecoder;
1103
- let buffer = "";
1104
- try {
1105
- while (true) {
1106
- const { done, value } = await reader.read();
1107
- if (done)
1108
- break;
1109
- buffer += decoder.decode(value, { stream: true });
1110
- const lines = buffer.split(`
1111
- `);
1112
- buffer = lines.pop() || "";
1113
- for (const line of lines) {
1114
- if (line.startsWith("data: ")) {
1115
- const data = line.slice(6).trim();
1116
- if (data) {
1117
- this.handleNotification(data);
1118
- }
1119
- }
1120
- }
1121
- }
1122
- } catch (error) {
1123
- if (error instanceof Error && error.name === "AbortError") {
1124
- return;
1125
- }
1126
- console.error("SSE stream error:", error);
1127
- } finally {
1128
- reader.releaseLock();
1129
- }
1130
- }
1131
- handleNotification(data) {
1132
- try {
1133
- const message = parseMessage(data);
1134
- this.messageHandlers.forEach((handler) => {
1135
- try {
1136
- handler(message);
1137
- } catch (error) {
1138
- console.error("Error in message handler:", error);
1139
- }
1140
- });
1141
- } catch (error) {
1142
- console.error("Failed to parse notification:", error);
1143
- }
1144
- }
1145
- onMessage(handler) {
1146
- this.messageHandlers.add(handler);
1147
- return () => {
1148
- this.messageHandlers.delete(handler);
1149
- };
1150
- }
1151
- async disconnect() {
1152
- if (!this.connected) {
1153
- return;
1154
- }
1155
- if (this.sseController) {
1156
- this.sseController.abort();
1157
- this.sseController = undefined;
1158
- }
1159
- this.messageHandlers.clear();
1160
- this.sessionId = undefined;
1161
- this.connected = false;
1162
- }
1163
- isConnected() {
1164
- return this.connected;
1165
- }
1166
- getSessionId() {
1167
- return this.sessionId;
1168
- }
1169
- setHeader(key, value) {
1170
- this.headers[key] = value;
1171
- }
1172
- removeHeader(key) {
1173
- delete this.headers[key];
1174
- }
1175
- getHeaders() {
1176
- return { ...this.headers };
1177
- }
1178
- }
1179
-
1180
- // ../client.ts
1181
- init_errors();
1182
-
1183
- // ../utils/naming.ts
1184
- function camelToSnake(str) {
1185
- return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
1186
- }
1187
- function methodToToolName(methodName, integrationId) {
1188
- const snakeCaseMethod = camelToSnake(methodName);
1189
- return `${integrationId}_${snakeCaseMethod}`;
1190
- }
1191
- // ../oauth/window-manager.ts
1192
- function isBrowser() {
1193
- return typeof window !== "undefined" && typeof window.document !== "undefined";
1194
- }
1195
-
1196
- class OAuthWindowManager {
1197
- popupWindow = null;
1198
- popupCheckInterval = null;
1199
- popupCheckTimeout = null;
1200
- openPopup(url, options) {
1201
- if (!isBrowser()) {
1202
- throw new Error("OAuthWindowManager.openPopup() can only be used in browser environments");
1203
- }
1204
- const width = options?.width || 600;
1205
- const height = options?.height || 700;
1206
- const left = window.screenX + (window.outerWidth - width) / 2;
1207
- const top = window.screenY + (window.outerHeight - height) / 2;
1208
- const features = [
1209
- `popup=yes`,
1210
- `width=${width}`,
1211
- `height=${height}`,
1212
- `left=${left}`,
1213
- `top=${top}`,
1214
- "toolbar=no",
1215
- "location=no",
1216
- "directories=no",
1217
- "status=no",
1218
- "menubar=no",
1219
- "scrollbars=yes",
1220
- "resizable=yes",
1221
- "copyhistory=no",
1222
- "noopener=no"
1223
- ].join(",");
1224
- const windowName = `oauth_popup_${Date.now()}`;
1225
- this.popupWindow = window.open(url, windowName, features);
1226
- if (!this.popupWindow) {
1227
- console.warn("Popup was blocked by the browser. Please allow popups for this site.");
1228
- return null;
1229
- }
1230
- this.popupWindow.focus();
1231
- return this.popupWindow;
1232
- }
1233
- openRedirect(url) {
1234
- if (!isBrowser()) {
1235
- throw new Error("OAuthWindowManager.openRedirect() can only be used in browser environments");
1236
- }
1237
- window.location.href = url;
1238
- }
1239
- listenForCallback(mode, timeoutMs = 5 * 60 * 1000) {
1240
- if (mode === "popup") {
1241
- return this.listenForPopupCallback(timeoutMs);
1242
- } else {
1243
- return this.listenForRedirectCallback();
1244
- }
1245
- }
1246
- listenForPopupCallback(timeoutMs) {
1247
- if (!isBrowser()) {
1248
- return Promise.reject(new Error("OAuth popup callback can only be used in browser environments"));
1249
- }
1250
- return new Promise((resolve, reject) => {
1251
- const timeout = setTimeout(() => {
1252
- this.cleanup();
1253
- reject(new Error("OAuth authorization timed out"));
1254
- }, timeoutMs);
1255
- const messageHandler = (event) => {
1256
- if (event.data && event.data.type === "oauth_callback") {
1257
- clearTimeout(timeout);
1258
- if (this.popupCheckTimeout) {
1259
- clearTimeout(this.popupCheckTimeout);
1260
- this.popupCheckTimeout = null;
1261
- }
1262
- window.removeEventListener("message", messageHandler);
1263
- const { code, state, error } = event.data;
1264
- if (error) {
1265
- this.cleanup();
1266
- reject(new Error(`OAuth error: ${error}`));
1267
- return;
1268
- }
1269
- if (!code || !state) {
1270
- this.cleanup();
1271
- reject(new Error("Invalid OAuth callback: missing code or state"));
1272
- return;
1273
- }
1274
- this.cleanup();
1275
- resolve({ code, state });
1276
- }
1277
- };
1278
- window.addEventListener("message", messageHandler);
1279
- this.popupCheckTimeout = setTimeout(() => {
1280
- this.popupCheckTimeout = null;
1281
- this.popupCheckInterval = setInterval(() => {
1282
- if (this.popupWindow?.closed) {
1283
- clearTimeout(timeout);
1284
- clearInterval(this.popupCheckInterval);
1285
- window.removeEventListener("message", messageHandler);
1286
- this.cleanup();
1287
- reject(new Error("OAuth popup was closed by user"));
1288
- }
1289
- }, 500);
1290
- }, 2000);
1291
- });
1292
- }
1293
- listenForRedirectCallback() {
1294
- if (!isBrowser()) {
1295
- return Promise.reject(new Error("OAuth redirect callback can only be used in browser environments"));
1296
- }
1297
- return new Promise((resolve, reject) => {
1298
- const params = new URLSearchParams(window.location.search);
1299
- let code = params.get("code");
1300
- let state = params.get("state");
1301
- let error = params.get("error");
1302
- let errorDescription = params.get("error_description");
1303
- if (!code && !error && window.location.hash) {
1304
- try {
1305
- const hash = window.location.hash.substring(1);
1306
- const hashParams = new URLSearchParams(hash);
1307
- const oauthCallback = hashParams.get("oauth_callback");
1308
- if (oauthCallback) {
1309
- const parsed = JSON.parse(decodeURIComponent(oauthCallback));
1310
- code = parsed.code;
1311
- state = parsed.state;
1312
- window.history.replaceState(null, "", window.location.pathname + window.location.search);
1313
- }
1314
- } catch (e) {
1315
- console.error("Failed to parse OAuth callback params from hash:", e);
1316
- }
1317
- }
1318
- if (!code && !error) {
1319
- try {
1320
- const stored = sessionStorage.getItem("oauth_callback_params");
1321
- if (stored) {
1322
- const parsed = JSON.parse(stored);
1323
- code = parsed.code;
1324
- state = parsed.state;
1325
- sessionStorage.removeItem("oauth_callback_params");
1326
- }
1327
- } catch (e) {
1328
- console.error("Failed to parse OAuth callback params from sessionStorage:", e);
1329
- }
1330
- }
1331
- if (error) {
1332
- const errorMsg = errorDescription || error;
1333
- reject(new Error(`OAuth error: ${errorMsg}`));
1334
- return;
1335
- }
1336
- if (!code || !state) {
1337
- reject(new Error("Invalid OAuth callback: missing code or state in URL"));
1338
- return;
1339
- }
1340
- resolve({ code, state });
1341
- });
1342
- }
1343
- cleanup() {
1344
- if (this.popupWindow && !this.popupWindow.closed) {
1345
- this.popupWindow.close();
1346
- }
1347
- this.popupWindow = null;
1348
- if (this.popupCheckInterval) {
1349
- clearInterval(this.popupCheckInterval);
1350
- this.popupCheckInterval = null;
1351
- }
1352
- if (this.popupCheckTimeout) {
1353
- clearTimeout(this.popupCheckTimeout);
1354
- this.popupCheckTimeout = null;
1355
- }
1356
- }
1357
- close() {
1358
- this.cleanup();
1359
- }
1360
- }
1361
-
1362
- // ../oauth/manager.ts
1363
- class OAuthManager {
1364
- pendingAuths = new Map;
1365
- providerTokens = new Map;
1366
- windowManager;
1367
- flowConfig;
1368
- oauthApiBase;
1369
- apiBaseUrl;
1370
- getTokenCallback;
1371
- setTokenCallback;
1372
- removeTokenCallback;
1373
- skipLocalStorage;
1374
- constructor(oauthApiBase, flowConfig, apiBaseUrl, tokenCallbacks) {
1375
- this.oauthApiBase = oauthApiBase;
1376
- this.apiBaseUrl = apiBaseUrl;
1377
- this.windowManager = new OAuthWindowManager;
1378
- this.flowConfig = {
1379
- mode: flowConfig?.mode || "redirect",
1380
- popupOptions: flowConfig?.popupOptions,
1381
- onAuthCallback: flowConfig?.onAuthCallback
1382
- };
1383
- this.getTokenCallback = tokenCallbacks?.getProviderToken;
1384
- this.setTokenCallback = tokenCallbacks?.setProviderToken;
1385
- this.removeTokenCallback = tokenCallbacks?.removeProviderToken;
1386
- this.skipLocalStorage = tokenCallbacks?.skipLocalStorage ?? !!tokenCallbacks?.getProviderToken;
1387
- this.cleanupExpiredPendingAuths();
1388
- }
1389
- async initiateFlow(provider, config, returnUrl) {
1390
- const codeVerifier = generateCodeVerifier();
1391
- const codeChallenge = await generateCodeChallenge(codeVerifier);
1392
- const state = generateStateWithReturnUrl(returnUrl);
1393
- const pendingAuth = {
1394
- provider,
1395
- state,
1396
- codeVerifier,
1397
- codeChallenge,
1398
- redirectUri: config.redirectUri,
1399
- returnUrl,
1400
- initiatedAt: Date.now()
1401
- };
1402
- this.pendingAuths.set(state, pendingAuth);
1403
- this.savePendingAuthToStorage(state, pendingAuth);
1404
- const authUrl = await this.getAuthorizationUrl(provider, state, codeChallenge, config.redirectUri);
1405
- if (this.flowConfig.mode === "popup") {
1406
- this.windowManager.openPopup(authUrl, this.flowConfig.popupOptions);
1407
- try {
1408
- const callbackParams = await this.windowManager.listenForCallback("popup");
1409
- await this.handleCallback(callbackParams.code, callbackParams.state);
1410
- } catch (error) {
1411
- this.pendingAuths.delete(state);
1412
- throw error;
1413
- }
1414
- } else {
1415
- this.windowManager.openRedirect(authUrl);
1416
- }
1417
- }
1418
- async handleCallback(code, state) {
1419
- let pendingAuth = this.pendingAuths.get(state);
1420
- if (!pendingAuth) {
1421
- pendingAuth = this.loadPendingAuthFromStorage(state);
1422
- }
1423
- if (!pendingAuth) {
1424
- throw new Error("Invalid state parameter: no matching OAuth flow found");
1425
- }
1426
- const fiveMinutes = 5 * 60 * 1000;
1427
- if (Date.now() - pendingAuth.initiatedAt > fiveMinutes) {
1428
- this.pendingAuths.delete(state);
1429
- this.removePendingAuthFromStorage(state);
1430
- throw new Error("OAuth flow expired: please try again");
1431
- }
1432
- if (this.flowConfig.onAuthCallback) {
1433
- try {
1434
- await this.flowConfig.onAuthCallback(pendingAuth.provider, code, state);
1435
- } catch (error) {
1436
- console.error("Custom OAuth callback handler failed:", error);
1437
- }
1438
- }
1439
- try {
1440
- const response = await this.exchangeCodeForToken(pendingAuth.provider, code, pendingAuth.codeVerifier, state);
1441
- const tokenData = {
1442
- accessToken: response.accessToken,
1443
- refreshToken: response.refreshToken,
1444
- tokenType: response.tokenType,
1445
- expiresIn: response.expiresIn,
1446
- expiresAt: response.expiresAt,
1447
- scopes: response.scopes
1448
- };
1449
- this.providerTokens.set(pendingAuth.provider, tokenData);
1450
- await this.saveProviderToken(pendingAuth.provider, tokenData);
1451
- this.pendingAuths.delete(state);
1452
- this.removePendingAuthFromStorage(state);
1453
- return { ...tokenData, provider: pendingAuth.provider };
1454
- } catch (error) {
1455
- this.pendingAuths.delete(state);
1456
- this.removePendingAuthFromStorage(state);
1457
- throw error;
1458
- }
1459
- }
1460
- async checkAuthStatus(provider) {
1461
- const tokenData = await this.getProviderToken(provider);
1462
- if (!tokenData) {
1463
- return {
1464
- authorized: false,
1465
- provider
1466
- };
1467
- }
1468
- return {
1469
- authorized: true,
1470
- provider,
1471
- scopes: tokenData.scopes,
1472
- expiresAt: tokenData.expiresAt
1473
- };
1474
- }
1475
- async disconnectProvider(provider, context) {
1476
- if (this.removeTokenCallback) {
1477
- try {
1478
- await this.removeTokenCallback(provider, context);
1479
- } catch (error) {
1480
- console.error(`Failed to delete token for ${provider} from database via removeProviderToken:`, error);
1481
- }
1482
- } else if (this.setTokenCallback) {
1483
- try {
1484
- const tokenData = await this.getProviderToken(provider, context);
1485
- if (tokenData) {
1486
- await this.setTokenCallback(provider, null, context);
1487
- }
1488
- } catch (error) {
1489
- console.error(`Failed to delete token for ${provider} from database via setProviderToken:`, error);
1490
- }
1491
- } else {
1492
- try {
1493
- const tokenData = await this.getProviderToken(provider);
1494
- if (tokenData?.accessToken) {
1495
- const url = this.apiBaseUrl ? `${this.apiBaseUrl}${this.oauthApiBase}/disconnect` : `${this.oauthApiBase}/disconnect`;
1496
- const response = await fetch(url, {
1497
- method: "POST",
1498
- headers: {
1499
- "Content-Type": "application/json",
1500
- Authorization: `Bearer ${tokenData.accessToken}`
1501
- },
1502
- body: JSON.stringify({
1503
- provider
1504
- })
1505
- });
1506
- if (!response.ok) {
1507
- if (response.status === 404) {
1508
- console.warn(`[Integrate SDK] OAuth disconnect route not found at ${url}. ` + `The route may not be set up on your server. ` + `Local token will still be cleared. ` + `To enable server-side disconnect, set up the route handler at ${this.oauthApiBase}/disconnect`);
1509
- } else {
1510
- const errorText = await response.text();
1511
- console.warn(`[Integrate SDK] Failed to disconnect ${provider} via API: ${response.status} ${errorText}. ` + `Local token will still be cleared.`);
1512
- }
1513
- }
1514
- }
1515
- } catch (error) {
1516
- const url = this.apiBaseUrl ? `${this.apiBaseUrl}${this.oauthApiBase}/disconnect` : `${this.oauthApiBase}/disconnect`;
1517
- if (error instanceof TypeError && error.message.includes("fetch")) {
1518
- console.warn(`[Integrate SDK] Could not reach disconnect route at ${url}. ` + `The route may not be set up on your server. ` + `Local token will still be cleared. ` + `To enable server-side disconnect, set up the route handler at ${this.oauthApiBase}/disconnect`);
1519
- } else {
1520
- console.warn(`[Integrate SDK] Failed to disconnect ${provider} via API: ${error}. ` + `Local token will still be cleared.`);
1521
- }
1522
- }
1523
- }
1524
- this.providerTokens.delete(provider);
1525
- this.clearProviderToken(provider);
1526
- }
1527
- async getProviderToken(provider, context) {
1528
- if (this.getTokenCallback) {
1529
- try {
1530
- const tokenData = await this.getTokenCallback(provider, context);
1531
- if (tokenData) {
1532
- this.providerTokens.set(provider, tokenData);
1533
- }
1534
- return tokenData;
1535
- } catch (error) {
1536
- console.error(`Failed to get token for ${provider} via callback:`, error);
1537
- return;
1538
- }
1539
- }
1540
- return this.providerTokens.get(provider);
1541
- }
1542
- getAllProviderTokens() {
1543
- return new Map(this.providerTokens);
1544
- }
1545
- getProviderTokenFromCache(provider) {
1546
- return this.providerTokens.get(provider);
1547
- }
1548
- async setProviderToken(provider, tokenData, context) {
1549
- if (tokenData === null) {
1550
- this.providerTokens.delete(provider);
1551
- } else {
1552
- this.providerTokens.set(provider, tokenData);
1553
- }
1554
- await this.saveProviderToken(provider, tokenData, context);
1555
- }
1556
- clearProviderToken(provider) {
1557
- this.providerTokens.delete(provider);
1558
- if (!this.skipLocalStorage && typeof window !== "undefined" && window.localStorage) {
1559
- try {
1560
- window.localStorage.removeItem(`integrate_token_${provider}`);
1561
- } catch (error) {
1562
- console.error(`Failed to clear token for ${provider} from localStorage:`, error);
1563
- }
1564
- }
1565
- }
1566
- clearAllProviderTokens() {
1567
- const providers = Array.from(this.providerTokens.keys());
1568
- this.providerTokens.clear();
1569
- if (!this.skipLocalStorage && typeof window !== "undefined" && window.localStorage) {
1570
- for (const provider of providers) {
1571
- try {
1572
- window.localStorage.removeItem(`integrate_token_${provider}`);
1573
- } catch (error) {
1574
- console.error(`Failed to clear token for ${provider} from localStorage:`, error);
1575
- }
1576
- }
1577
- }
1578
- }
1579
- clearAllPendingAuths() {
1580
- this.pendingAuths.clear();
1581
- if (typeof window !== "undefined" && window.localStorage) {
1582
- try {
1583
- const prefix = "integrate_oauth_pending_";
1584
- const keysToRemove = [];
1585
- for (let i = 0;i < window.localStorage.length; i++) {
1586
- const key = window.localStorage.key(i);
1587
- if (key && key.startsWith(prefix)) {
1588
- keysToRemove.push(key);
1589
- }
1590
- }
1591
- keysToRemove.forEach((key) => window.localStorage.removeItem(key));
1592
- } catch (error) {
1593
- console.error("Failed to clear pending auths from localStorage:", error);
1594
- }
1595
- }
1596
- }
1597
- async saveProviderToken(provider, tokenData, context) {
1598
- if (this.setTokenCallback) {
1599
- try {
1600
- await this.setTokenCallback(provider, tokenData, context);
1601
- } catch (error) {
1602
- console.error(`Failed to ${tokenData === null ? "delete" : "save"} token for ${provider} via callback:`, error);
1603
- throw error;
1604
- }
1605
- return;
1606
- }
1607
- if (tokenData === null) {
1608
- this.clearProviderToken(provider);
1609
- return;
1610
- }
1611
- if (this.skipLocalStorage) {
1612
- return;
1613
- }
1614
- if (typeof window !== "undefined" && window.localStorage) {
1615
- try {
1616
- const key = `integrate_token_${provider}`;
1617
- window.localStorage.setItem(key, JSON.stringify(tokenData));
1618
- } catch (error) {
1619
- console.error(`Failed to save token for ${provider} to localStorage:`, error);
1620
- }
1621
- }
1622
- }
1623
- async loadProviderToken(provider) {
1624
- if (this.getTokenCallback) {
1625
- try {
1626
- return await this.getTokenCallback(provider);
1627
- } catch (error) {
1628
- console.error(`Failed to load token for ${provider} via callback:`, error);
1629
- return;
1630
- }
1631
- }
1632
- if (typeof window !== "undefined" && window.localStorage) {
1633
- try {
1634
- const key = `integrate_token_${provider}`;
1635
- const stored = window.localStorage.getItem(key);
1636
- if (stored) {
1637
- return JSON.parse(stored);
1638
- }
1639
- } catch (error) {
1640
- console.error(`Failed to load token for ${provider} from localStorage:`, error);
1641
- }
1642
- }
1643
- return;
1644
- }
1645
- async loadAllProviderTokens(providers) {
1646
- for (const provider of providers) {
1647
- const tokenData = await this.loadProviderToken(provider);
1648
- if (tokenData) {
1649
- this.providerTokens.set(provider, tokenData);
1650
- }
1651
- }
1652
- }
1653
- loadProviderTokenSync(provider) {
1654
- if (this.getTokenCallback) {
1655
- return;
1656
- }
1657
- if (typeof window !== "undefined" && window.localStorage) {
1658
- try {
1659
- const key = `integrate_token_${provider}`;
1660
- const stored = window.localStorage.getItem(key);
1661
- if (stored) {
1662
- return JSON.parse(stored);
1663
- }
1664
- } catch (error) {
1665
- console.error(`Failed to load token for ${provider} from localStorage:`, error);
1666
- }
1667
- }
1668
- return;
1669
- }
1670
- loadAllProviderTokensSync(providers) {
1671
- if (this.getTokenCallback) {
1672
- return;
1673
- }
1674
- for (const provider of providers) {
1675
- const tokenData = this.loadProviderTokenSync(provider);
1676
- if (tokenData) {
1677
- this.providerTokens.set(provider, tokenData);
1678
- }
1679
- }
1680
- }
1681
- savePendingAuthToStorage(state, pendingAuth) {
1682
- if (this.skipLocalStorage) {
1683
- return;
1684
- }
1685
- if (typeof window !== "undefined" && window.localStorage) {
1686
- try {
1687
- const key = `integrate_oauth_pending_${state}`;
1688
- window.localStorage.setItem(key, JSON.stringify(pendingAuth));
1689
- } catch (error) {
1690
- console.error("Failed to save pending auth to localStorage:", error);
1691
- }
1692
- }
1693
- }
1694
- loadPendingAuthFromStorage(state) {
1695
- if (this.skipLocalStorage) {
1696
- return;
1697
- }
1698
- if (typeof window !== "undefined" && window.localStorage) {
1699
- try {
1700
- const key = `integrate_oauth_pending_${state}`;
1701
- const stored = window.localStorage.getItem(key);
1702
- if (stored) {
1703
- return JSON.parse(stored);
1704
- }
1705
- } catch (error) {
1706
- console.error("Failed to load pending auth from localStorage:", error);
1707
- }
1708
- }
1709
- return;
1710
- }
1711
- removePendingAuthFromStorage(state) {
1712
- if (this.skipLocalStorage) {
1713
- return;
1714
- }
1715
- if (typeof window !== "undefined" && window.localStorage) {
1716
- try {
1717
- const key = `integrate_oauth_pending_${state}`;
1718
- window.localStorage.removeItem(key);
1719
- } catch (error) {
1720
- console.error("Failed to remove pending auth from localStorage:", error);
1721
- }
1722
- }
1723
- }
1724
- cleanupExpiredPendingAuths() {
1725
- if (this.skipLocalStorage) {
1726
- return;
1727
- }
1728
- if (typeof window !== "undefined" && window.localStorage) {
1729
- try {
1730
- const prefix = "integrate_oauth_pending_";
1731
- const fiveMinutes = 5 * 60 * 1000;
1732
- const now = Date.now();
1733
- const keysToRemove = [];
1734
- for (let i = 0;i < window.localStorage.length; i++) {
1735
- const key = window.localStorage.key(i);
1736
- if (key && key.startsWith(prefix)) {
1737
- try {
1738
- const stored = window.localStorage.getItem(key);
1739
- if (stored) {
1740
- const pendingAuth = JSON.parse(stored);
1741
- if (now - pendingAuth.initiatedAt > fiveMinutes) {
1742
- keysToRemove.push(key);
1743
- }
1744
- }
1745
- } catch (error) {
1746
- keysToRemove.push(key);
1747
- }
1748
- }
1749
- }
1750
- keysToRemove.forEach((key) => window.localStorage.removeItem(key));
1751
- } catch (error) {
1752
- console.error("Failed to cleanup expired pending auths:", error);
1753
- }
1754
- }
1755
- }
1756
- async getAuthorizationUrl(provider, state, codeChallenge, redirectUri) {
1757
- const url = this.apiBaseUrl ? `${this.apiBaseUrl}${this.oauthApiBase}/authorize` : `${this.oauthApiBase}/authorize`;
1758
- const response = await fetch(url, {
1759
- method: "POST",
1760
- headers: {
1761
- "Content-Type": "application/json"
1762
- },
1763
- body: JSON.stringify({
1764
- provider,
1765
- state,
1766
- codeChallenge,
1767
- codeChallengeMethod: "S256",
1768
- redirectUri
1769
- })
1770
- });
1771
- if (!response.ok) {
1772
- const error = await response.text();
1773
- throw new Error(`Failed to get authorization URL: ${error}`);
1774
- }
1775
- const data = await response.json();
1776
- return data.authorizationUrl;
1777
- }
1778
- async exchangeCodeForToken(provider, code, codeVerifier, state) {
1779
- const url = this.apiBaseUrl ? `${this.apiBaseUrl}${this.oauthApiBase}/callback` : `${this.oauthApiBase}/callback`;
1780
- const response = await fetch(url, {
1781
- method: "POST",
1782
- headers: {
1783
- "Content-Type": "application/json"
1784
- },
1785
- body: JSON.stringify({
1786
- provider,
1787
- code,
1788
- codeVerifier,
1789
- state
1790
- })
1791
- });
1792
- if (!response.ok) {
1793
- const error = await response.text();
1794
- throw new Error(`Failed to exchange code for token: ${error}`);
1795
- }
1796
- const data = await response.json();
1797
- return data;
1798
- }
1799
- close() {
1800
- this.windowManager.close();
1801
- }
1802
- }
1803
-
1804
- // ../client.ts
1805
- class SimpleEventEmitter {
1806
- handlers = new Map;
1807
- on(event, handler) {
1808
- if (!this.handlers.has(event)) {
1809
- this.handlers.set(event, new Set);
1810
- }
1811
- this.handlers.get(event).add(handler);
1812
- }
1813
- off(event, handler) {
1814
- const handlers = this.handlers.get(event);
1815
- if (handlers) {
1816
- handlers.delete(handler);
1817
- }
1818
- }
1819
- emit(event, payload) {
1820
- const handlers = this.handlers.get(event);
1821
- if (handlers) {
1822
- handlers.forEach((handler) => {
1823
- try {
1824
- handler(payload);
1825
- } catch (error) {
1826
- console.error(`Error in event handler for ${event}:`, error);
1827
- }
1828
- });
1829
- }
1830
- }
1831
- removeAllListeners(event) {
1832
- if (event) {
1833
- this.handlers.delete(event);
1834
- } else {
1835
- this.handlers.clear();
1836
- }
1837
- }
1838
- }
1839
- var MCP_SERVER_URL2 = "https://mcp.integrate.dev/api/v1/mcp";
1840
- var clientCache = new Map;
1841
- var cleanupClients = new Set;
1842
- class MCPClientBase {
1843
- transport;
1844
- integrations;
1845
- availableTools = new Map;
1846
- enabledToolNames = new Set;
1847
- initialized = false;
1848
- clientInfo;
1849
- onReauthRequired;
1850
- maxReauthRetries;
1851
- authState = new Map;
1852
- oauthManager;
1853
- eventEmitter = new SimpleEventEmitter;
1854
- apiRouteBase;
1855
- apiBaseUrl;
1856
- oauthCallbackPromise;
1857
- server;
1858
- constructor(config) {
1859
- this.transport = new HttpSessionTransport({
1860
- url: config.serverUrl || MCP_SERVER_URL2,
1861
- headers: config.headers,
1862
- timeout: config.timeout
1863
- });
1864
- const oauthApiBase = config.oauthApiBase || "/api/integrate/oauth";
1865
- const defaultRedirectUri = this.getDefaultRedirectUri(oauthApiBase);
1866
- this.apiRouteBase = config.apiRouteBase || "/api/integrate";
1867
- this.apiBaseUrl = config.apiBaseUrl;
1868
- this.integrations = config.integrations.map((integration) => {
1869
- if (integration.oauth && !integration.oauth.redirectUri) {
1870
- return {
1871
- ...integration,
1872
- oauth: {
1873
- ...integration.oauth,
1874
- redirectUri: defaultRedirectUri
1875
- }
1876
- };
1877
- }
1878
- return integration;
1879
- });
1880
- this.clientInfo = config.clientInfo || {
1881
- name: "integrate-sdk",
1882
- version: "0.1.0"
1883
- };
1884
- this.onReauthRequired = config.onReauthRequired;
1885
- this.maxReauthRetries = config.maxReauthRetries ?? 1;
1886
- this.oauthManager = new OAuthManager(oauthApiBase, config.oauthFlow, this.apiBaseUrl, {
1887
- getProviderToken: config.getProviderToken,
1888
- setProviderToken: config.setProviderToken,
1889
- removeProviderToken: config.removeProviderToken,
1890
- skipLocalStorage: config.skipLocalStorage
1891
- });
1892
- for (const integration of this.integrations) {
1893
- for (const toolName of integration.tools) {
1894
- this.enabledToolNames.add(toolName);
1895
- }
1896
- if (integration.oauth) {
1897
- const provider = integration.oauth.provider;
1898
- this.authState.set(provider, { authenticated: false });
1899
- }
1900
- }
1901
- const providers = this.integrations.filter((p) => p.oauth).map((p) => p.oauth.provider);
1902
- const usingDatabaseCallbacks = !!config.getProviderToken;
1903
- if (usingDatabaseCallbacks) {
1904
- this.oauthManager.loadAllProviderTokens(providers).then(async () => {
1905
- for (const integration of this.integrations) {
1906
- if (integration.oauth) {
1907
- const provider = integration.oauth.provider;
1908
- try {
1909
- const tokenData = await this.oauthManager.getProviderToken(provider);
1910
- const currentState = this.authState.get(provider);
1911
- if (currentState && !currentState.authenticated && !currentState.lastError) {
1912
- this.authState.set(provider, { authenticated: !!tokenData });
1913
- }
1914
- } catch (error) {
1915
- console.error(`Failed to check token for ${provider}:`, error);
1916
- const currentState = this.authState.get(provider);
1917
- if (currentState && !currentState.authenticated && !currentState.lastError) {
1918
- this.authState.set(provider, { authenticated: false });
1919
- }
1920
- }
1921
- }
1922
- }
1923
- }).catch((error) => {
1924
- console.error("Failed to load provider tokens:", error);
1925
- });
1926
- } else {
1927
- this.oauthManager.loadAllProviderTokensSync(providers);
1928
- for (const integration of this.integrations) {
1929
- if (integration.oauth) {
1930
- const provider = integration.oauth.provider;
1931
- const tokenData = this.oauthManager.getProviderTokenFromCache(provider);
1932
- if (tokenData) {
1933
- this.authState.set(provider, { authenticated: true });
1934
- }
1935
- }
1936
- }
1937
- }
1938
- const integrationIds = this.integrations.map((i) => i.id);
1939
- if (integrationIds.includes("github")) {
1940
- this.github = this.createIntegrationProxy("github");
1941
- }
1942
- if (integrationIds.includes("gmail")) {
1943
- this.gmail = this.createIntegrationProxy("gmail");
1944
- }
1945
- if (integrationIds.includes("notion")) {
1946
- this.notion = this.createIntegrationProxy("notion");
1947
- }
1948
- this.server = this.createServerProxy();
1949
- this.initializeIntegrations();
1950
- }
1951
- getDefaultRedirectUri(oauthApiBase) {
1952
- if (typeof window === "undefined" || !window.location) {
1953
- return "http://localhost:3000/api/integrate/oauth/callback";
1954
- }
1955
- const origin = window.location.origin;
1956
- const normalizedPath = oauthApiBase.replace(/\/$/, "");
1957
- return `${origin}${normalizedPath}/callback`;
1958
- }
1959
- createIntegrationProxy(integrationId) {
1960
- const hasIntegration = this.integrations.some((integration) => integration.id === integrationId);
1961
- if (!hasIntegration) {
1962
- return;
1963
- }
1964
- return new Proxy({}, {
1965
- get: (_target, methodName) => {
1966
- return async (args, options) => {
1967
- const toolName = methodToToolName(methodName, integrationId);
1968
- return await this.callToolWithRetry(toolName, args, 0, options);
1969
- };
1970
- }
1971
- });
1972
- }
1973
- createServerProxy() {
1974
- return new Proxy({}, {
1975
- get: (_target, methodName) => {
1976
- return async (args, options) => {
1977
- const toolName = methodToToolName(methodName, "");
1978
- const finalToolName = toolName.startsWith("_") ? toolName.substring(1) : toolName;
1979
- return await this.callServerToolInternal(finalToolName, args, options);
1980
- };
1981
- }
1982
- });
1983
- }
1984
- async callServerToolInternal(name, args, options) {
1985
- try {
1986
- const response = await this.callToolThroughHandler(name, args, undefined, options);
1987
- return response;
1988
- } catch (error) {
1989
- const parsedError = parseServerError(error, { toolName: name });
1990
- throw parsedError;
1991
- }
1992
- }
1993
- async initializeIntegrations() {
1994
- for (const integration of this.integrations) {
1995
- if (integration.onInit) {
1996
- await integration.onInit(this);
1997
- }
1998
- }
1999
- }
2000
- async connect() {
2001
- for (const integration of this.integrations) {
2002
- if (integration.onBeforeConnect) {
2003
- await integration.onBeforeConnect(this);
2004
- }
2005
- }
2006
- await this.transport.connect();
2007
- await this.initialize();
2008
- await this.discoverTools();
2009
- for (const integration of this.integrations) {
2010
- if (integration.onAfterConnect) {
2011
- await integration.onAfterConnect(this);
2012
- }
2013
- }
2014
- }
2015
- async initialize() {
2016
- const params = {
2017
- protocolVersion: "2024-11-05",
2018
- capabilities: {
2019
- tools: {}
2020
- },
2021
- clientInfo: this.clientInfo
2022
- };
2023
- const response = await this.transport.sendRequest("initialize" /* INITIALIZE */, params);
2024
- this.initialized = true;
2025
- return response;
2026
- }
2027
- async discoverTools() {
2028
- const response = await this.transport.sendRequest("tools/list" /* TOOLS_LIST */);
2029
- for (const tool of response.tools) {
2030
- this.availableTools.set(tool.name, tool);
2031
- }
2032
- const enabledTools = response.tools.filter((tool) => this.enabledToolNames.has(tool.name));
2033
- console.log(`Discovered ${response.tools.length} tools, ${enabledTools.length} enabled by integrations`);
2034
- }
2035
- async _callToolByName(name, args, options) {
2036
- return await this.callToolWithRetry(name, args, 0, options);
2037
- }
2038
- async callServerTool(name, args) {
2039
- try {
2040
- const response = await this.callToolThroughHandler(name, args);
2041
- return response;
2042
- } catch (error) {
2043
- const parsedError = parseServerError(error, { toolName: name });
2044
- throw parsedError;
2045
- }
2046
- }
2047
- async callToolThroughHandler(name, args, provider, options) {
2048
- const transportHeaders = this.transport.headers || {};
2049
- const hasApiKey = !!transportHeaders["X-API-KEY"];
2050
- if (hasApiKey) {
2051
- if (provider) {
2052
- const tokenData = await this.oauthManager.getProviderToken(provider, options?.context);
2053
- if (tokenData && this.transport.setHeader) {
2054
- const previousAuthHeader = transportHeaders["Authorization"];
2055
- try {
2056
- this.transport.setHeader("Authorization", `Bearer ${tokenData.accessToken}`);
2057
- const result3 = await this.transport.sendRequest("tools/call", {
2058
- name,
2059
- arguments: args || {}
2060
- });
2061
- return result3;
2062
- } finally {
2063
- if (previousAuthHeader && this.transport.setHeader) {
2064
- this.transport.setHeader("Authorization", previousAuthHeader);
2065
- } else if (this.transport.removeHeader) {
2066
- this.transport.removeHeader("Authorization");
2067
- }
2068
- }
2069
- }
2070
- }
2071
- const result2 = await this.transport.sendRequest("tools/call", {
2072
- name,
2073
- arguments: args || {}
2074
- });
2075
- return result2;
2076
- }
2077
- const url = this.apiBaseUrl ? `${this.apiBaseUrl}${this.apiRouteBase}/mcp` : `${this.apiRouteBase}/mcp`;
2078
- const headers = {
2079
- "Content-Type": "application/json"
2080
- };
2081
- if (provider) {
2082
- const tokenData = await this.oauthManager.getProviderToken(provider, options?.context);
2083
- if (tokenData) {
2084
- headers["Authorization"] = `Bearer ${tokenData.accessToken}`;
2085
- }
2086
- }
2087
- const response = await fetch(url, {
2088
- method: "POST",
2089
- headers,
2090
- body: JSON.stringify({
2091
- name,
2092
- arguments: args
2093
- })
2094
- });
2095
- if (!response.ok) {
2096
- let errorMessage = `Request failed: ${response.statusText}`;
2097
- const error = new Error(errorMessage);
2098
- error.statusCode = response.status;
2099
- try {
2100
- const errorData = await response.json();
2101
- if (errorData.error) {
2102
- errorMessage = typeof errorData.error === "string" ? errorData.error : errorData.error.message || errorMessage;
2103
- error.message = errorMessage;
2104
- }
2105
- if (errorData.code) {
2106
- error.code = errorData.code;
2107
- }
2108
- if (errorData.data) {
2109
- error.data = errorData.data;
2110
- }
2111
- if (errorData.error && typeof errorData.error === "object") {
2112
- error.jsonrpcError = errorData.error;
2113
- }
2114
- } catch {}
2115
- throw error;
2116
- }
2117
- const result = await response.json();
2118
- return result;
2119
- }
2120
- async callToolWithRetry(name, args, retryCount = 0, options) {
2121
- if (!this.enabledToolNames.has(name)) {
2122
- throw new Error(`Tool "${name}" is not enabled. Enable it by adding the appropriate integration.`);
2123
- }
2124
- const provider = this.getProviderForTool(name);
2125
- try {
2126
- const response = await this.callToolThroughHandler(name, args, provider, options);
2127
- if (provider) {
2128
- this.authState.set(provider, { authenticated: true });
2129
- }
2130
- return response;
2131
- } catch (error) {
2132
- const parsedError = parseServerError(error, { toolName: name, provider });
2133
- if (isAuthError(parsedError) && retryCount < this.maxReauthRetries) {
2134
- if (provider) {
2135
- this.authState.set(provider, {
2136
- authenticated: false,
2137
- lastError: parsedError
2138
- });
2139
- }
2140
- if (this.onReauthRequired && provider) {
2141
- const reauthSuccess = await this.onReauthRequired({
2142
- provider,
2143
- error: parsedError,
2144
- toolName: name
2145
- });
2146
- if (reauthSuccess) {
2147
- return await this.callToolWithRetry(name, args, retryCount + 1);
2148
- }
2149
- }
2150
- }
2151
- throw parsedError;
2152
- }
2153
- }
2154
- getProviderForTool(toolName) {
2155
- for (const integration of this.integrations) {
2156
- if (integration.tools.includes(toolName) && integration.oauth) {
2157
- return integration.oauth.provider;
2158
- }
2159
- }
2160
- return;
2161
- }
2162
- getTool(name) {
2163
- return this.availableTools.get(name);
2164
- }
2165
- getAvailableTools() {
2166
- return Array.from(this.availableTools.values());
2167
- }
2168
- setRequestHeader(key, value) {
2169
- this.transport.setHeader(key, value);
2170
- }
2171
- getEnabledTools() {
2172
- return Array.from(this.availableTools.values()).filter((tool) => this.enabledToolNames.has(tool.name));
2173
- }
2174
- getOAuthConfig(integrationId) {
2175
- const integration = this.integrations.find((p) => p.id === integrationId);
2176
- return integration?.oauth;
2177
- }
2178
- getAllOAuthConfigs() {
2179
- const configs = new Map;
2180
- for (const integration of this.integrations) {
2181
- if (integration.oauth) {
2182
- configs.set(integration.id, integration.oauth);
2183
- }
2184
- }
2185
- return configs;
2186
- }
2187
- onMessage(handler) {
2188
- return this.transport.onMessage(handler);
2189
- }
2190
- on(event, handler) {
2191
- this.eventEmitter.on(event, handler);
2192
- }
2193
- off(event, handler) {
2194
- this.eventEmitter.off(event, handler);
2195
- }
2196
- clearSessionToken() {
2197
- this.oauthManager.clearAllProviderTokens();
2198
- for (const integration of this.integrations) {
2199
- if (integration.oauth) {
2200
- const provider = integration.oauth.provider;
2201
- this.authState.set(provider, { authenticated: false });
2202
- }
2203
- }
2204
- }
2205
- async disconnectProvider(provider, context) {
2206
- const integration = this.integrations.find((p) => p.oauth?.provider === provider);
2207
- if (!integration?.oauth) {
2208
- throw new Error(`No OAuth configuration found for provider: ${provider}`);
2209
- }
2210
- try {
2211
- await this.oauthManager.disconnectProvider(provider, context);
2212
- this.authState.set(provider, { authenticated: false });
2213
- this.eventEmitter.emit("auth:disconnect", { provider });
2214
- } catch (error) {
2215
- this.eventEmitter.emit("auth:error", {
2216
- provider,
2217
- error
2218
- });
2219
- throw error;
2220
- }
2221
- }
2222
- async logout() {
2223
- this.clearSessionToken();
2224
- this.oauthManager.clearAllPendingAuths();
2225
- this.authState.clear();
2226
- for (const integration of this.integrations) {
2227
- if (integration.oauth) {
2228
- this.authState.set(integration.oauth.provider, { authenticated: false });
2229
- }
2230
- }
2231
- this.eventEmitter.emit("auth:logout", {});
2232
- }
2233
- async disconnect() {
2234
- for (const integration of this.integrations) {
2235
- if (integration.onDisconnect) {
2236
- await integration.onDisconnect(this);
2237
- }
2238
- }
2239
- await this.transport.disconnect();
2240
- this.initialized = false;
2241
- }
2242
- isConnected() {
2243
- return this.transport.isConnected();
2244
- }
2245
- isInitialized() {
2246
- return this.initialized;
2247
- }
2248
- getAuthState(provider) {
2249
- return this.authState.get(provider);
2250
- }
2251
- isProviderAuthenticated(provider) {
2252
- return this.authState.get(provider)?.authenticated ?? false;
2253
- }
2254
- async isAuthorized(provider, context) {
2255
- if (this.oauthCallbackPromise) {
2256
- await this.oauthCallbackPromise;
2257
- this.oauthCallbackPromise = null;
2258
- }
2259
- try {
2260
- const tokenData = await this.oauthManager.getProviderToken(provider, context);
2261
- const isAuthenticated = !!tokenData;
2262
- const currentState = this.authState.get(provider);
2263
- if (currentState) {
2264
- currentState.authenticated = isAuthenticated;
2265
- if (isAuthenticated) {
2266
- currentState.lastError = undefined;
2267
- }
2268
- } else {
2269
- this.authState.set(provider, { authenticated: isAuthenticated });
2270
- }
2271
- return isAuthenticated;
2272
- } catch (error) {
2273
- const currentState = this.authState.get(provider);
2274
- if (currentState) {
2275
- currentState.authenticated = false;
2276
- } else {
2277
- this.authState.set(provider, { authenticated: false });
2278
- }
2279
- return false;
2280
- }
2281
- }
2282
- async authorizedProviders() {
2283
- if (this.oauthCallbackPromise) {
2284
- await this.oauthCallbackPromise;
2285
- this.oauthCallbackPromise = null;
2286
- }
2287
- const authorized = [];
2288
- for (const integration of this.integrations) {
2289
- if (integration.oauth) {
2290
- const provider = integration.oauth.provider;
2291
- if (this.authState.get(provider)?.authenticated) {
2292
- authorized.push(provider);
2293
- }
2294
- }
2295
- }
2296
- return authorized;
2297
- }
2298
- async getAuthorizationStatus(provider) {
2299
- return await this.oauthManager.checkAuthStatus(provider);
2300
- }
2301
- async authorize(provider, options) {
2302
- const integration = this.integrations.find((p) => p.oauth?.provider === provider);
2303
- if (!integration?.oauth) {
2304
- const error = new Error(`No OAuth configuration found for provider: ${provider}`);
2305
- this.eventEmitter.emit("auth:error", { provider, error });
2306
- throw error;
2307
- }
2308
- if (options?.useExistingConnection) {
2309
- const authStatus = await this.oauthManager.checkAuthStatus(provider);
2310
- if (authStatus.authorized) {
2311
- const tokenData = await this.oauthManager.getProviderToken(provider);
2312
- if (tokenData) {
2313
- this.eventEmitter.emit("auth:complete", {
2314
- provider,
2315
- accessToken: tokenData.accessToken,
2316
- expiresAt: tokenData.expiresAt
2317
- });
2318
- this.authState.set(provider, { authenticated: true });
2319
- }
2320
- return;
2321
- }
2322
- }
2323
- this.eventEmitter.emit("auth:started", { provider });
2324
- try {
2325
- await this.oauthManager.initiateFlow(provider, integration.oauth, options?.returnUrl);
2326
- const tokenData = await this.oauthManager.getProviderToken(provider);
2327
- if (tokenData) {
2328
- this.eventEmitter.emit("auth:complete", {
2329
- provider,
2330
- accessToken: tokenData.accessToken,
2331
- expiresAt: tokenData.expiresAt
2332
- });
2333
- }
2334
- this.authState.set(provider, { authenticated: true });
2335
- } catch (error) {
2336
- this.eventEmitter.emit("auth:error", { provider, error });
2337
- throw error;
2338
- }
2339
- }
2340
- async handleOAuthCallback(params) {
2341
- try {
2342
- const result = await this.oauthManager.handleCallback(params.code, params.state);
2343
- this.authState.set(result.provider, { authenticated: true });
2344
- this.eventEmitter.emit("auth:complete", {
2345
- provider: result.provider,
2346
- accessToken: result.accessToken,
2347
- expiresAt: result.expiresAt
2348
- });
2349
- } catch (error) {
2350
- this.eventEmitter.emit("auth:error", {
2351
- provider: "unknown",
2352
- error
2353
- });
2354
- throw error;
2355
- }
2356
- }
2357
- async getProviderToken(provider, context) {
2358
- return await this.oauthManager.getProviderToken(provider, context);
2359
- }
2360
- async setProviderToken(provider, tokenData, context) {
2361
- await this.oauthManager.setProviderToken(provider, tokenData, context);
2362
- if (tokenData === null) {
2363
- this.authState.set(provider, { authenticated: false });
2364
- } else {
2365
- this.authState.set(provider, { authenticated: true });
2366
- }
2367
- }
2368
- getAllProviderTokens() {
2369
- const tokens = {};
2370
- const allTokens = this.oauthManager.getAllProviderTokens();
2371
- for (const [provider, tokenData] of allTokens.entries()) {
2372
- tokens[provider] = tokenData.accessToken;
2373
- }
2374
- return tokens;
2375
- }
2376
- async reauthenticate(provider) {
2377
- const state = this.authState.get(provider);
2378
- if (!state) {
2379
- throw new Error(`Provider "${provider}" not found in configured integrations`);
2380
- }
2381
- if (!this.onReauthRequired) {
2382
- throw new Error("No re-authentication handler configured. Set onReauthRequired in client config.");
2383
- }
2384
- const lastError = state.lastError || new (await Promise.resolve().then(() => (init_errors(), exports_errors))).AuthenticationError("Manual re-authentication requested", undefined, provider);
2385
- const success = await this.onReauthRequired({
2386
- provider,
2387
- error: lastError
2388
- });
2389
- if (success) {
2390
- this.authState.set(provider, { authenticated: true });
2391
- }
2392
- return success;
2393
- }
2394
- }
2395
- // ../server.ts
2396
- function toSolidStartHandler(clientOrHandlerOrOptions, _redirectOptions) {
2397
- if (clientOrHandlerOrOptions && clientOrHandlerOrOptions.handler && typeof clientOrHandlerOrOptions.handler === "function") {
2398
- const baseHandler = clientOrHandlerOrOptions.handler;
2399
- const handler2 = async (event) => {
2400
- return baseHandler(event.request);
2401
- };
2402
- return {
2403
- GET: handler2,
2404
- POST: handler2,
2405
- PATCH: handler2,
2406
- PUT: handler2,
2407
- DELETE: handler2
2408
- };
2409
- }
2410
- if (typeof clientOrHandlerOrOptions === "function") {
2411
- const baseHandler = clientOrHandlerOrOptions;
2412
- const handler2 = async (event) => {
2413
- return baseHandler(event.request);
2414
- };
2415
- return {
2416
- GET: handler2,
2417
- POST: handler2,
2418
- PATCH: handler2,
2419
- PUT: handler2,
2420
- DELETE: handler2
2421
- };
2422
- }
2423
- const options = clientOrHandlerOrOptions;
2424
- if (!options.providers || Object.keys(options.providers).length === 0) {
2425
- throw new Error("toSolidStartHandler requires either a handler function or a providers config object");
2426
- }
2427
- const { providers, serverUrl, apiKey, redirectUrl, errorRedirectUrl } = options;
2428
- const nextHandler = createNextOAuthHandler({
2429
- providers,
2430
- serverUrl,
2431
- apiKey
2432
- });
2433
- const routes = nextHandler.toNextJsHandler({
2434
- redirectUrl: redirectUrl || "/",
2435
- errorRedirectUrl: errorRedirectUrl || "/auth-error"
2436
- });
2437
- const handler = async (event) => {
2438
- const method = event.request.method.toUpperCase();
2439
- const url = new URL(event.request.url);
2440
- const pathParts = url.pathname.split("/").filter(Boolean);
2441
- const integrateIndex = pathParts.indexOf("integrate");
2442
- const segments = integrateIndex >= 0 ? pathParts.slice(integrateIndex + 1) : [];
2443
- const context = {
2444
- params: segments
2445
- };
2446
- if (method === "POST") {
2447
- return routes.POST(event.request, { params: { all: context.params } });
2448
- } else if (method === "GET") {
2449
- return routes.GET(event.request, { params: { all: context.params } });
2450
- } else {
2451
- return Response.json({ error: `Method ${method} not allowed` }, { status: 405 });
2452
- }
2453
- };
2454
- return {
2455
- GET: handler,
2456
- POST: handler,
2457
- PATCH: handler,
2458
- PUT: handler,
2459
- DELETE: handler
2460
- };
2461
- }
2462
- function toSvelteKitHandler(clientOrHandlerOrOptions, _redirectOptions) {
2463
- if (clientOrHandlerOrOptions && clientOrHandlerOrOptions.handler && typeof clientOrHandlerOrOptions.handler === "function") {
2464
- const baseHandler = clientOrHandlerOrOptions.handler;
2465
- return async (event) => {
2466
- const all = event.params?.all;
2467
- return baseHandler(event.request, { params: { all } });
2468
- };
2469
- }
2470
- if (typeof clientOrHandlerOrOptions === "function") {
2471
- const baseHandler = clientOrHandlerOrOptions;
2472
- return async (event) => {
2473
- const all = event.params?.all;
2474
- return baseHandler(event.request, { params: { all } });
2475
- };
2476
- }
2477
- const options = clientOrHandlerOrOptions;
2478
- if (!options.providers || Object.keys(options.providers).length === 0) {
2479
- throw new Error("toSvelteKitHandler requires either a handler function or a providers config object");
2480
- }
2481
- const { providers, serverUrl, apiKey, redirectUrl, errorRedirectUrl } = options;
2482
- const nextHandler = createNextOAuthHandler({
2483
- providers,
2484
- serverUrl,
2485
- apiKey
2486
- });
2487
- const routes = nextHandler.toNextJsHandler({
2488
- redirectUrl: redirectUrl || "/",
2489
- errorRedirectUrl: errorRedirectUrl || "/auth-error"
2490
- });
2491
- return async (event) => {
2492
- const method = event.request.method.toUpperCase();
2493
- const all = event.params?.all;
2494
- const context = {
2495
- params: Array.isArray(all) ? all : all ? all.split("/").filter(Boolean) : []
2496
- };
2497
- if (method === "POST") {
2498
- return routes.POST(event.request, { params: { all: context.params } });
2499
- } else if (method === "GET") {
2500
- return routes.GET(event.request, { params: { all: context.params } });
2501
- } else {
2502
- return Response.json({ error: `Method ${method} not allowed` }, { status: 405 });
2503
- }
2504
- };
2505
- }
2506
171
  export {
2507
172
  toSolidStartHandler
2508
173
  };