integrate-sdk 0.7.48 → 0.7.49

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 (34) hide show
  1. package/dist/adapters/auto-routes.d.ts.map +1 -1
  2. package/dist/adapters/auto-routes.js +380 -24
  3. package/dist/adapters/base-handler.d.ts +50 -6
  4. package/dist/adapters/base-handler.d.ts.map +1 -1
  5. package/dist/adapters/base-handler.js +368 -18
  6. package/dist/adapters/context-cookie.d.ts +85 -0
  7. package/dist/adapters/context-cookie.d.ts.map +1 -0
  8. package/dist/adapters/context-cookie.js +152 -0
  9. package/dist/adapters/index.js +399 -37
  10. package/dist/adapters/nextjs.d.ts.map +1 -1
  11. package/dist/adapters/nextjs.js +387 -31
  12. package/dist/adapters/node.d.ts.map +1 -1
  13. package/dist/adapters/node.js +380 -24
  14. package/dist/adapters/session-detector.d.ts +37 -0
  15. package/dist/adapters/session-detector.d.ts.map +1 -0
  16. package/dist/adapters/session-detector.js +157 -0
  17. package/dist/adapters/solid-start.js +387 -31
  18. package/dist/adapters/svelte-kit.js +387 -31
  19. package/dist/index.js +392 -30
  20. package/dist/oauth.js +380 -24
  21. package/dist/server.js +401 -33
  22. package/dist/src/adapters/auto-routes.d.ts.map +1 -1
  23. package/dist/src/adapters/base-handler.d.ts +50 -6
  24. package/dist/src/adapters/base-handler.d.ts.map +1 -1
  25. package/dist/src/adapters/context-cookie.d.ts +85 -0
  26. package/dist/src/adapters/context-cookie.d.ts.map +1 -0
  27. package/dist/src/adapters/nextjs.d.ts.map +1 -1
  28. package/dist/src/adapters/node.d.ts.map +1 -1
  29. package/dist/src/adapters/session-detector.d.ts +37 -0
  30. package/dist/src/adapters/session-detector.d.ts.map +1 -0
  31. package/dist/src/config/types.d.ts +24 -0
  32. package/dist/src/config/types.d.ts.map +1 -1
  33. package/dist/src/server.d.ts.map +1 -1
  34. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -244,6 +244,280 @@ function base64UrlDecode(str) {
244
244
  }
245
245
  }
246
246
 
247
+ // src/adapters/session-detector.ts
248
+ var exports_session_detector = {};
249
+ __export(exports_session_detector, {
250
+ tryDecodeJWT: () => tryDecodeJWT,
251
+ detectSessionContext: () => detectSessionContext
252
+ });
253
+ function tryDecodeJWT(token) {
254
+ try {
255
+ const parts = token.split(".");
256
+ if (parts.length !== 3) {
257
+ return;
258
+ }
259
+ const payloadPart = parts[1];
260
+ if (!payloadPart) {
261
+ return;
262
+ }
263
+ const base64 = payloadPart.replace(/-/g, "+").replace(/_/g, "/");
264
+ const jsonPayload = decodeURIComponent(atob(base64).split("").map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2)).join(""));
265
+ return JSON.parse(jsonPayload);
266
+ } catch (error) {
267
+ return;
268
+ }
269
+ }
270
+ function getCookies(request) {
271
+ const cookies = new Map;
272
+ const cookieHeader = request.headers.get("cookie");
273
+ if (!cookieHeader) {
274
+ return cookies;
275
+ }
276
+ const pairs = cookieHeader.split(";");
277
+ for (const pair of pairs) {
278
+ const [name, ...valueParts] = pair.split("=");
279
+ if (name && valueParts.length > 0) {
280
+ const trimmedName = name.trim();
281
+ const value = valueParts.join("=").trim();
282
+ cookies.set(trimmedName, value);
283
+ }
284
+ }
285
+ return cookies;
286
+ }
287
+ function tryBetterAuth(cookies) {
288
+ const sessionToken = cookies.get("better-auth.session_token");
289
+ if (!sessionToken) {
290
+ return;
291
+ }
292
+ const payload = tryDecodeJWT(sessionToken);
293
+ if (!payload) {
294
+ return;
295
+ }
296
+ const userId = payload.sub || payload.userId || payload.user_id || payload.id;
297
+ if (!userId) {
298
+ return;
299
+ }
300
+ return {
301
+ userId,
302
+ sessionId: payload.jti || payload.sessionId
303
+ };
304
+ }
305
+ function tryNextAuth(cookies) {
306
+ const sessionToken = cookies.get("__Secure-next-auth.session-token") || cookies.get("next-auth.session-token");
307
+ if (!sessionToken) {
308
+ return;
309
+ }
310
+ if (sessionToken.includes(".")) {
311
+ const payload = tryDecodeJWT(sessionToken);
312
+ if (payload) {
313
+ return {
314
+ userId: payload.sub || payload.userId || payload.user_id || payload.id,
315
+ sessionId: payload.jti
316
+ };
317
+ }
318
+ }
319
+ return;
320
+ }
321
+ function tryClerk(cookies) {
322
+ const sessionToken = cookies.get("__session");
323
+ if (!sessionToken) {
324
+ return;
325
+ }
326
+ const payload = tryDecodeJWT(sessionToken);
327
+ if (!payload) {
328
+ return;
329
+ }
330
+ return {
331
+ userId: payload.sub || payload.userId,
332
+ organizationId: payload.org_id || payload.organizationId,
333
+ sessionId: payload.sid || payload.sessionId
334
+ };
335
+ }
336
+ function tryLucia(cookies) {
337
+ const sessionToken = cookies.get("lucia_session");
338
+ if (!sessionToken) {
339
+ return;
340
+ }
341
+ return {
342
+ sessionId: sessionToken
343
+ };
344
+ }
345
+ function tryGenericSession(cookies) {
346
+ const sessionToken = cookies.get("auth_session") || cookies.get("session");
347
+ if (!sessionToken) {
348
+ return;
349
+ }
350
+ if (sessionToken.includes(".")) {
351
+ const payload = tryDecodeJWT(sessionToken);
352
+ if (payload) {
353
+ return {
354
+ userId: payload.sub || payload.userId || payload.user_id || payload.id,
355
+ sessionId: payload.jti || payload.sessionId || payload.sid
356
+ };
357
+ }
358
+ }
359
+ return {
360
+ sessionId: sessionToken
361
+ };
362
+ }
363
+ async function detectSessionContext(request) {
364
+ const cookies = getCookies(request);
365
+ let context;
366
+ context = tryBetterAuth(cookies);
367
+ if (context?.userId) {
368
+ return context;
369
+ }
370
+ context = tryNextAuth(cookies);
371
+ if (context?.userId) {
372
+ return context;
373
+ }
374
+ context = tryClerk(cookies);
375
+ if (context?.userId) {
376
+ return context;
377
+ }
378
+ context = tryLucia(cookies);
379
+ if (context?.userId) {
380
+ return context;
381
+ }
382
+ context = tryGenericSession(cookies);
383
+ if (context?.userId) {
384
+ return context;
385
+ }
386
+ return;
387
+ }
388
+
389
+ // src/adapters/context-cookie.ts
390
+ var exports_context_cookie = {};
391
+ __export(exports_context_cookie, {
392
+ readContextCookie: () => readContextCookie,
393
+ getSetCookieHeader: () => getSetCookieHeader,
394
+ getContextCookieFromRequest: () => getContextCookieFromRequest,
395
+ getClearCookieHeader: () => getClearCookieHeader,
396
+ createContextCookie: () => createContextCookie,
397
+ CONTEXT_COOKIE_NAME: () => CONTEXT_COOKIE_NAME,
398
+ CONTEXT_COOKIE_MAX_AGE: () => CONTEXT_COOKIE_MAX_AGE
399
+ });
400
+ async function deriveKey(secret) {
401
+ const encoder = new TextEncoder;
402
+ const secretData = encoder.encode(secret);
403
+ const keyMaterial = await crypto.subtle.importKey("raw", secretData, { name: "PBKDF2" }, false, ["deriveBits", "deriveKey"]);
404
+ const salt = encoder.encode("integrate-oauth-context-v1");
405
+ return await crypto.subtle.deriveKey({
406
+ name: "PBKDF2",
407
+ salt,
408
+ iterations: 1e5,
409
+ hash: "SHA-256"
410
+ }, keyMaterial, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
411
+ }
412
+ async function encryptPayload(payload, secret) {
413
+ const key = await deriveKey(secret);
414
+ const iv = crypto.getRandomValues(new Uint8Array(12));
415
+ const encoder = new TextEncoder;
416
+ const data = encoder.encode(JSON.stringify(payload));
417
+ const encrypted = await crypto.subtle.encrypt({
418
+ name: "AES-GCM",
419
+ iv
420
+ }, key, data);
421
+ const combined = new Uint8Array(iv.length + encrypted.byteLength);
422
+ combined.set(iv, 0);
423
+ combined.set(new Uint8Array(encrypted), iv.length);
424
+ return base64UrlEncode2(combined);
425
+ }
426
+ async function decryptPayload(cookieValue, secret) {
427
+ try {
428
+ const combined = base64UrlDecode2(cookieValue);
429
+ const iv = combined.slice(0, 12);
430
+ const encrypted = combined.slice(12);
431
+ const key = await deriveKey(secret);
432
+ const decrypted = await crypto.subtle.decrypt({
433
+ name: "AES-GCM",
434
+ iv
435
+ }, key, encrypted);
436
+ const decoder = new TextDecoder;
437
+ const json = decoder.decode(decrypted);
438
+ const payload = JSON.parse(json);
439
+ const age = Date.now() - payload.timestamp;
440
+ if (age > CONTEXT_COOKIE_MAX_AGE * 1000) {
441
+ return;
442
+ }
443
+ return payload;
444
+ } catch (error) {
445
+ return;
446
+ }
447
+ }
448
+ function base64UrlEncode2(data) {
449
+ const base64 = btoa(String.fromCharCode(...data));
450
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
451
+ }
452
+ function base64UrlDecode2(str) {
453
+ let base64 = str.replace(/-/g, "+").replace(/_/g, "/");
454
+ const padding = base64.length % 4;
455
+ if (padding) {
456
+ base64 += "=".repeat(4 - padding);
457
+ }
458
+ const binary = atob(base64);
459
+ const bytes = new Uint8Array(binary.length);
460
+ for (let i = 0;i < binary.length; i++) {
461
+ bytes[i] = binary.charCodeAt(i);
462
+ }
463
+ return bytes;
464
+ }
465
+ async function createContextCookie(context, provider, secret) {
466
+ const payload = {
467
+ context,
468
+ provider,
469
+ timestamp: Date.now()
470
+ };
471
+ return await encryptPayload(payload, secret);
472
+ }
473
+ async function readContextCookie(cookieValue, secret) {
474
+ const payload = await decryptPayload(cookieValue, secret);
475
+ if (!payload) {
476
+ return;
477
+ }
478
+ return {
479
+ context: payload.context,
480
+ provider: payload.provider
481
+ };
482
+ }
483
+ function getSetCookieHeader(cookieValue, maxAge = CONTEXT_COOKIE_MAX_AGE) {
484
+ const attributes = [
485
+ `${CONTEXT_COOKIE_NAME}=${cookieValue}`,
486
+ `Max-Age=${maxAge}`,
487
+ "HttpOnly",
488
+ "Secure",
489
+ "SameSite=Lax",
490
+ "Path=/"
491
+ ];
492
+ return attributes.join("; ");
493
+ }
494
+ function getClearCookieHeader() {
495
+ const attributes = [
496
+ `${CONTEXT_COOKIE_NAME}=`,
497
+ "Max-Age=0",
498
+ "HttpOnly",
499
+ "Secure",
500
+ "SameSite=Lax",
501
+ "Path=/"
502
+ ];
503
+ return attributes.join("; ");
504
+ }
505
+ function getContextCookieFromRequest(request) {
506
+ const cookieHeader = request.headers.get("cookie");
507
+ if (!cookieHeader) {
508
+ return;
509
+ }
510
+ const cookies = cookieHeader.split(";");
511
+ for (const cookie of cookies) {
512
+ const [name, ...valueParts] = cookie.split("=");
513
+ if (name && name.trim() === CONTEXT_COOKIE_NAME) {
514
+ return valueParts.join("=").trim();
515
+ }
516
+ }
517
+ return;
518
+ }
519
+ var CONTEXT_COOKIE_NAME = "__integrate_oauth_ctx", CONTEXT_COOKIE_MAX_AGE = 300;
520
+
247
521
  // src/adapters/base-handler.ts
248
522
  class OAuthHandler {
249
523
  config;
@@ -267,25 +541,35 @@ class OAuthHandler {
267
541
  return headers;
268
542
  }
269
543
  async handleAuthorize(request) {
270
- const providerConfig = this.config.providers[request.provider];
544
+ let webRequest;
545
+ let authorizeRequest;
546
+ if (request instanceof Request) {
547
+ webRequest = request;
548
+ authorizeRequest = await request.json();
549
+ } else if (typeof request === "object" && "json" in request && typeof request.json === "function") {
550
+ authorizeRequest = await request.json();
551
+ } else {
552
+ authorizeRequest = request;
553
+ }
554
+ const providerConfig = this.config.providers[authorizeRequest.provider];
271
555
  if (!providerConfig) {
272
- throw new Error(`Provider ${request.provider} not configured. Add OAuth credentials to your API route configuration.`);
556
+ throw new Error(`Provider ${authorizeRequest.provider} not configured. Add OAuth credentials to your API route configuration.`);
273
557
  }
274
558
  if (!providerConfig.clientId || !providerConfig.clientSecret) {
275
- throw new Error(`Missing OAuth credentials for ${request.provider}. Check your environment variables.`);
559
+ throw new Error(`Missing OAuth credentials for ${authorizeRequest.provider}. Check your environment variables.`);
276
560
  }
277
561
  const url = new URL("/oauth/authorize", this.serverUrl);
278
- url.searchParams.set("provider", request.provider);
562
+ url.searchParams.set("provider", authorizeRequest.provider);
279
563
  url.searchParams.set("client_id", providerConfig.clientId);
280
564
  url.searchParams.set("client_secret", providerConfig.clientSecret);
281
- const scopes = request.scopes || providerConfig.scopes || [];
565
+ const scopes = authorizeRequest.scopes || providerConfig.scopes || [];
282
566
  if (scopes.length > 0) {
283
567
  url.searchParams.set("scope", scopes.join(","));
284
568
  }
285
- url.searchParams.set("state", request.state);
286
- url.searchParams.set("code_challenge", request.codeChallenge);
287
- url.searchParams.set("code_challenge_method", request.codeChallengeMethod);
288
- const redirectUri = request.redirectUri || providerConfig.redirectUri;
569
+ url.searchParams.set("state", authorizeRequest.state);
570
+ url.searchParams.set("code_challenge", authorizeRequest.codeChallenge);
571
+ url.searchParams.set("code_challenge_method", authorizeRequest.codeChallengeMethod);
572
+ const redirectUri = authorizeRequest.redirectUri || providerConfig.redirectUri;
289
573
  if (redirectUri) {
290
574
  url.searchParams.set("redirect_uri", redirectUri);
291
575
  }
@@ -298,15 +582,62 @@ class OAuthHandler {
298
582
  throw new Error(`MCP server failed to generate authorization URL: ${error}`);
299
583
  }
300
584
  const data = await response.json();
301
- return data;
585
+ const result = data;
586
+ if (webRequest) {
587
+ try {
588
+ const { detectSessionContext: detectSessionContext2 } = await Promise.resolve().then(() => exports_session_detector);
589
+ const { createContextCookie: createContextCookie2, getSetCookieHeader: getSetCookieHeader2 } = await Promise.resolve().then(() => exports_context_cookie);
590
+ let context;
591
+ if (this.config.getSessionContext) {
592
+ context = await this.config.getSessionContext(webRequest);
593
+ }
594
+ if (!context || !context.userId) {
595
+ context = await detectSessionContext2(webRequest);
596
+ }
597
+ if (context && context.userId) {
598
+ const secret = this.apiKey || providerConfig.clientSecret;
599
+ const cookieValue = await createContextCookie2(context, authorizeRequest.provider, secret);
600
+ result.setCookie = getSetCookieHeader2(cookieValue);
601
+ }
602
+ } catch (error) {
603
+ console.warn("[OAuth] Failed to capture user context:", error);
604
+ }
605
+ }
606
+ return result;
302
607
  }
303
608
  async handleCallback(request) {
304
- const providerConfig = this.config.providers[request.provider];
609
+ let webRequest;
610
+ let callbackRequest;
611
+ if (request instanceof Request) {
612
+ webRequest = request;
613
+ callbackRequest = await request.json();
614
+ } else if (typeof request === "object" && "json" in request && typeof request.json === "function") {
615
+ callbackRequest = await request.json();
616
+ } else {
617
+ callbackRequest = request;
618
+ }
619
+ const providerConfig = this.config.providers[callbackRequest.provider];
305
620
  if (!providerConfig) {
306
- throw new Error(`Provider ${request.provider} not configured. Add OAuth credentials to your API route configuration.`);
621
+ throw new Error(`Provider ${callbackRequest.provider} not configured. Add OAuth credentials to your API route configuration.`);
307
622
  }
308
623
  if (!providerConfig.clientId || !providerConfig.clientSecret) {
309
- throw new Error(`Missing OAuth credentials for ${request.provider}. Check your environment variables.`);
624
+ throw new Error(`Missing OAuth credentials for ${callbackRequest.provider}. Check your environment variables.`);
625
+ }
626
+ let context;
627
+ if (webRequest) {
628
+ try {
629
+ const { getContextCookieFromRequest: getContextCookieFromRequest2, readContextCookie: readContextCookie2 } = await Promise.resolve().then(() => exports_context_cookie);
630
+ const cookieValue = getContextCookieFromRequest2(webRequest);
631
+ if (cookieValue) {
632
+ const secret = this.apiKey || providerConfig.clientSecret;
633
+ const contextData = await readContextCookie2(cookieValue, secret);
634
+ if (contextData && contextData.provider === callbackRequest.provider) {
635
+ context = contextData.context;
636
+ }
637
+ }
638
+ } catch (error) {
639
+ console.warn("[OAuth] Failed to restore user context:", error);
640
+ }
310
641
  }
311
642
  const url = new URL("/oauth/callback", this.serverUrl);
312
643
  const response = await fetch(url.toString(), {
@@ -315,10 +646,10 @@ class OAuthHandler {
315
646
  "Content-Type": "application/json"
316
647
  }),
317
648
  body: JSON.stringify({
318
- provider: request.provider,
319
- code: request.code,
320
- code_verifier: request.codeVerifier,
321
- state: request.state,
649
+ provider: callbackRequest.provider,
650
+ code: callbackRequest.code,
651
+ code_verifier: callbackRequest.codeVerifier,
652
+ state: callbackRequest.state,
322
653
  client_id: providerConfig.clientId,
323
654
  client_secret: providerConfig.clientSecret,
324
655
  redirect_uri: providerConfig.redirectUri
@@ -329,7 +660,26 @@ class OAuthHandler {
329
660
  throw new Error(`MCP server failed to exchange authorization code: ${error}`);
330
661
  }
331
662
  const data = await response.json();
332
- return data;
663
+ const result = data;
664
+ if (this.config.setProviderToken && context) {
665
+ try {
666
+ const tokenData = {
667
+ accessToken: result.accessToken,
668
+ refreshToken: result.refreshToken,
669
+ tokenType: result.tokenType,
670
+ expiresIn: result.expiresIn,
671
+ expiresAt: result.expiresAt
672
+ };
673
+ await this.config.setProviderToken(callbackRequest.provider, tokenData, context);
674
+ } catch (error) {
675
+ console.error("[OAuth] Failed to save provider token:", error);
676
+ }
677
+ }
678
+ if (webRequest) {
679
+ const { getClearCookieHeader: getClearCookieHeader2 } = await Promise.resolve().then(() => exports_context_cookie);
680
+ result.clearCookie = getClearCookieHeader2();
681
+ }
682
+ return result;
333
683
  }
334
684
  async handleStatus(provider, accessToken) {
335
685
  const url = new URL("/oauth/status", this.serverUrl);
@@ -1819,9 +2169,12 @@ function createNextOAuthHandler(config) {
1819
2169
  const handlers = {
1820
2170
  async authorize(req) {
1821
2171
  try {
1822
- const body = await req.json();
1823
- const result = await handler.handleAuthorize(body);
1824
- return Response.json(result);
2172
+ const result = await handler.handleAuthorize(req);
2173
+ const response = Response.json(result);
2174
+ if (result.setCookie) {
2175
+ response.headers.set("Set-Cookie", result.setCookie);
2176
+ }
2177
+ return response;
1825
2178
  } catch (error) {
1826
2179
  console.error("[OAuth Authorize] Error:", error);
1827
2180
  return Response.json({ error: error.message || "Failed to get authorization URL" }, { status: 500 });
@@ -1829,9 +2182,12 @@ function createNextOAuthHandler(config) {
1829
2182
  },
1830
2183
  async callback(req) {
1831
2184
  try {
1832
- const body = await req.json();
1833
- const result = await handler.handleCallback(body);
1834
- return Response.json(result);
2185
+ const result = await handler.handleCallback(req);
2186
+ const response = Response.json(result);
2187
+ if (result.clearCookie) {
2188
+ response.headers.set("Set-Cookie", result.clearCookie);
2189
+ }
2190
+ return response;
1835
2191
  } catch (error) {
1836
2192
  console.error("[OAuth Callback] Error:", error);
1837
2193
  return Response.json({ error: error.message || "Failed to exchange authorization code" }, { status: 500 });
@@ -2089,18 +2445,24 @@ function toNodeHandler(config) {
2089
2445
  let webRes;
2090
2446
  if (req.method === "POST") {
2091
2447
  if (action === "authorize") {
2092
- const body = await webReq.json();
2093
- const result = await oauthHandler.handleAuthorize(body);
2448
+ const result = await oauthHandler.handleAuthorize(webReq);
2449
+ const headers = { "Content-Type": "application/json" };
2450
+ if (result.setCookie) {
2451
+ headers["Set-Cookie"] = result.setCookie;
2452
+ }
2094
2453
  webRes = new Response(JSON.stringify(result), {
2095
2454
  status: 200,
2096
- headers: { "Content-Type": "application/json" }
2455
+ headers
2097
2456
  });
2098
2457
  } else if (action === "callback") {
2099
- const body = await webReq.json();
2100
- const result = await oauthHandler.handleCallback(body);
2458
+ const result = await oauthHandler.handleCallback(webReq);
2459
+ const headers = { "Content-Type": "application/json" };
2460
+ if (result.clearCookie) {
2461
+ headers["Set-Cookie"] = result.clearCookie;
2462
+ }
2101
2463
  webRes = new Response(JSON.stringify(result), {
2102
2464
  status: 200,
2103
- headers: { "Content-Type": "application/json" }
2465
+ headers
2104
2466
  });
2105
2467
  } else if (action === "disconnect") {
2106
2468
  const authHeader = webReq.headers.get("authorization");