integrate-sdk 0.3.10 → 0.3.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -608,6 +608,7 @@ class OAuthWindowManager {
608
608
  const left = window.screenX + (window.outerWidth - width) / 2;
609
609
  const top = window.screenY + (window.outerHeight - height) / 2;
610
610
  const features = [
611
+ `popup=yes`,
611
612
  `width=${width}`,
612
613
  `height=${height}`,
613
614
  `left=${left}`,
@@ -619,9 +620,11 @@ class OAuthWindowManager {
619
620
  "menubar=no",
620
621
  "scrollbars=yes",
621
622
  "resizable=yes",
622
- "copyhistory=no"
623
+ "copyhistory=no",
624
+ "noopener=no"
623
625
  ].join(",");
624
- this.popupWindow = window.open(url, "oauth_popup", features);
626
+ const windowName = `oauth_popup_${Date.now()}`;
627
+ this.popupWindow = window.open(url, windowName, features);
625
628
  if (!this.popupWindow) {
626
629
  console.warn("Popup was blocked by the browser. Please allow popups for this site.");
627
630
  return null;
@@ -790,6 +793,7 @@ class OAuthManager {
790
793
  popupOptions: flowConfig?.popupOptions,
791
794
  onAuthCallback: flowConfig?.onAuthCallback
792
795
  };
796
+ this.cleanupExpiredPendingAuths();
793
797
  }
794
798
  async initiateFlow(provider, config) {
795
799
  const codeVerifier = generateCodeVerifier();
@@ -805,6 +809,7 @@ class OAuthManager {
805
809
  initiatedAt: Date.now()
806
810
  };
807
811
  this.pendingAuths.set(state, pendingAuth);
812
+ this.savePendingAuthToStorage(state, pendingAuth);
808
813
  const authUrl = await this.getAuthorizationUrl(provider, config.scopes, state, codeChallenge, config.redirectUri);
809
814
  if (this.flowConfig.mode === "popup") {
810
815
  this.windowManager.openPopup(authUrl, this.flowConfig.popupOptions);
@@ -820,13 +825,17 @@ class OAuthManager {
820
825
  }
821
826
  }
822
827
  async handleCallback(code, state) {
823
- const pendingAuth = this.pendingAuths.get(state);
828
+ let pendingAuth = this.pendingAuths.get(state);
829
+ if (!pendingAuth) {
830
+ pendingAuth = this.loadPendingAuthFromStorage(state);
831
+ }
824
832
  if (!pendingAuth) {
825
833
  throw new Error("Invalid state parameter: no matching OAuth flow found");
826
834
  }
827
835
  const fiveMinutes = 5 * 60 * 1000;
828
836
  if (Date.now() - pendingAuth.initiatedAt > fiveMinutes) {
829
837
  this.pendingAuths.delete(state);
838
+ this.removePendingAuthFromStorage(state);
830
839
  throw new Error("OAuth flow expired: please try again");
831
840
  }
832
841
  if (this.flowConfig.onAuthCallback) {
@@ -841,9 +850,11 @@ class OAuthManager {
841
850
  this.sessionToken = response.sessionToken;
842
851
  this.saveSessionToken(response.sessionToken);
843
852
  this.pendingAuths.delete(state);
853
+ this.removePendingAuthFromStorage(state);
844
854
  return response.sessionToken;
845
855
  } catch (error) {
846
856
  this.pendingAuths.delete(state);
857
+ this.removePendingAuthFromStorage(state);
847
858
  throw error;
848
859
  }
849
860
  }
@@ -904,6 +915,69 @@ class OAuthManager {
904
915
  }
905
916
  }
906
917
  }
918
+ savePendingAuthToStorage(state, pendingAuth) {
919
+ if (typeof window !== "undefined" && window.localStorage) {
920
+ try {
921
+ const key = `integrate_oauth_pending_${state}`;
922
+ window.localStorage.setItem(key, JSON.stringify(pendingAuth));
923
+ } catch (error) {
924
+ console.error("Failed to save pending auth to localStorage:", error);
925
+ }
926
+ }
927
+ }
928
+ loadPendingAuthFromStorage(state) {
929
+ if (typeof window !== "undefined" && window.localStorage) {
930
+ try {
931
+ const key = `integrate_oauth_pending_${state}`;
932
+ const stored = window.localStorage.getItem(key);
933
+ if (stored) {
934
+ return JSON.parse(stored);
935
+ }
936
+ } catch (error) {
937
+ console.error("Failed to load pending auth from localStorage:", error);
938
+ }
939
+ }
940
+ return;
941
+ }
942
+ removePendingAuthFromStorage(state) {
943
+ if (typeof window !== "undefined" && window.localStorage) {
944
+ try {
945
+ const key = `integrate_oauth_pending_${state}`;
946
+ window.localStorage.removeItem(key);
947
+ } catch (error) {
948
+ console.error("Failed to remove pending auth from localStorage:", error);
949
+ }
950
+ }
951
+ }
952
+ cleanupExpiredPendingAuths() {
953
+ if (typeof window !== "undefined" && window.localStorage) {
954
+ try {
955
+ const prefix = "integrate_oauth_pending_";
956
+ const fiveMinutes = 5 * 60 * 1000;
957
+ const now = Date.now();
958
+ const keysToRemove = [];
959
+ for (let i = 0;i < window.localStorage.length; i++) {
960
+ const key = window.localStorage.key(i);
961
+ if (key && key.startsWith(prefix)) {
962
+ try {
963
+ const stored = window.localStorage.getItem(key);
964
+ if (stored) {
965
+ const pendingAuth = JSON.parse(stored);
966
+ if (now - pendingAuth.initiatedAt > fiveMinutes) {
967
+ keysToRemove.push(key);
968
+ }
969
+ }
970
+ } catch (error) {
971
+ keysToRemove.push(key);
972
+ }
973
+ }
974
+ }
975
+ keysToRemove.forEach((key) => window.localStorage.removeItem(key));
976
+ } catch (error) {
977
+ console.error("Failed to cleanup expired pending auths:", error);
978
+ }
979
+ }
980
+ }
907
981
  async getAuthorizationUrl(provider, scopes, state, codeChallenge, redirectUri) {
908
982
  const url = `${this.oauthApiBase}/authorize`;
909
983
  const response = await fetch(url, {
package/dist/server.js CHANGED
@@ -608,6 +608,7 @@ class OAuthWindowManager {
608
608
  const left = window.screenX + (window.outerWidth - width) / 2;
609
609
  const top = window.screenY + (window.outerHeight - height) / 2;
610
610
  const features = [
611
+ `popup=yes`,
611
612
  `width=${width}`,
612
613
  `height=${height}`,
613
614
  `left=${left}`,
@@ -619,9 +620,11 @@ class OAuthWindowManager {
619
620
  "menubar=no",
620
621
  "scrollbars=yes",
621
622
  "resizable=yes",
622
- "copyhistory=no"
623
+ "copyhistory=no",
624
+ "noopener=no"
623
625
  ].join(",");
624
- this.popupWindow = window.open(url, "oauth_popup", features);
626
+ const windowName = `oauth_popup_${Date.now()}`;
627
+ this.popupWindow = window.open(url, windowName, features);
625
628
  if (!this.popupWindow) {
626
629
  console.warn("Popup was blocked by the browser. Please allow popups for this site.");
627
630
  return null;
@@ -790,6 +793,7 @@ class OAuthManager {
790
793
  popupOptions: flowConfig?.popupOptions,
791
794
  onAuthCallback: flowConfig?.onAuthCallback
792
795
  };
796
+ this.cleanupExpiredPendingAuths();
793
797
  }
794
798
  async initiateFlow(provider, config) {
795
799
  const codeVerifier = generateCodeVerifier();
@@ -805,6 +809,7 @@ class OAuthManager {
805
809
  initiatedAt: Date.now()
806
810
  };
807
811
  this.pendingAuths.set(state, pendingAuth);
812
+ this.savePendingAuthToStorage(state, pendingAuth);
808
813
  const authUrl = await this.getAuthorizationUrl(provider, config.scopes, state, codeChallenge, config.redirectUri);
809
814
  if (this.flowConfig.mode === "popup") {
810
815
  this.windowManager.openPopup(authUrl, this.flowConfig.popupOptions);
@@ -820,13 +825,17 @@ class OAuthManager {
820
825
  }
821
826
  }
822
827
  async handleCallback(code, state) {
823
- const pendingAuth = this.pendingAuths.get(state);
828
+ let pendingAuth = this.pendingAuths.get(state);
829
+ if (!pendingAuth) {
830
+ pendingAuth = this.loadPendingAuthFromStorage(state);
831
+ }
824
832
  if (!pendingAuth) {
825
833
  throw new Error("Invalid state parameter: no matching OAuth flow found");
826
834
  }
827
835
  const fiveMinutes = 5 * 60 * 1000;
828
836
  if (Date.now() - pendingAuth.initiatedAt > fiveMinutes) {
829
837
  this.pendingAuths.delete(state);
838
+ this.removePendingAuthFromStorage(state);
830
839
  throw new Error("OAuth flow expired: please try again");
831
840
  }
832
841
  if (this.flowConfig.onAuthCallback) {
@@ -841,9 +850,11 @@ class OAuthManager {
841
850
  this.sessionToken = response.sessionToken;
842
851
  this.saveSessionToken(response.sessionToken);
843
852
  this.pendingAuths.delete(state);
853
+ this.removePendingAuthFromStorage(state);
844
854
  return response.sessionToken;
845
855
  } catch (error) {
846
856
  this.pendingAuths.delete(state);
857
+ this.removePendingAuthFromStorage(state);
847
858
  throw error;
848
859
  }
849
860
  }
@@ -904,6 +915,69 @@ class OAuthManager {
904
915
  }
905
916
  }
906
917
  }
918
+ savePendingAuthToStorage(state, pendingAuth) {
919
+ if (typeof window !== "undefined" && window.localStorage) {
920
+ try {
921
+ const key = `integrate_oauth_pending_${state}`;
922
+ window.localStorage.setItem(key, JSON.stringify(pendingAuth));
923
+ } catch (error) {
924
+ console.error("Failed to save pending auth to localStorage:", error);
925
+ }
926
+ }
927
+ }
928
+ loadPendingAuthFromStorage(state) {
929
+ if (typeof window !== "undefined" && window.localStorage) {
930
+ try {
931
+ const key = `integrate_oauth_pending_${state}`;
932
+ const stored = window.localStorage.getItem(key);
933
+ if (stored) {
934
+ return JSON.parse(stored);
935
+ }
936
+ } catch (error) {
937
+ console.error("Failed to load pending auth from localStorage:", error);
938
+ }
939
+ }
940
+ return;
941
+ }
942
+ removePendingAuthFromStorage(state) {
943
+ if (typeof window !== "undefined" && window.localStorage) {
944
+ try {
945
+ const key = `integrate_oauth_pending_${state}`;
946
+ window.localStorage.removeItem(key);
947
+ } catch (error) {
948
+ console.error("Failed to remove pending auth from localStorage:", error);
949
+ }
950
+ }
951
+ }
952
+ cleanupExpiredPendingAuths() {
953
+ if (typeof window !== "undefined" && window.localStorage) {
954
+ try {
955
+ const prefix = "integrate_oauth_pending_";
956
+ const fiveMinutes = 5 * 60 * 1000;
957
+ const now = Date.now();
958
+ const keysToRemove = [];
959
+ for (let i = 0;i < window.localStorage.length; i++) {
960
+ const key = window.localStorage.key(i);
961
+ if (key && key.startsWith(prefix)) {
962
+ try {
963
+ const stored = window.localStorage.getItem(key);
964
+ if (stored) {
965
+ const pendingAuth = JSON.parse(stored);
966
+ if (now - pendingAuth.initiatedAt > fiveMinutes) {
967
+ keysToRemove.push(key);
968
+ }
969
+ }
970
+ } catch (error) {
971
+ keysToRemove.push(key);
972
+ }
973
+ }
974
+ }
975
+ keysToRemove.forEach((key) => window.localStorage.removeItem(key));
976
+ } catch (error) {
977
+ console.error("Failed to cleanup expired pending auths:", error);
978
+ }
979
+ }
980
+ }
907
981
  async getAuthorizationUrl(provider, scopes, state, codeChallenge, redirectUri) {
908
982
  const url = `${this.oauthApiBase}/authorize`;
909
983
  const response = await fetch(url, {
@@ -79,6 +79,27 @@ export declare class OAuthManager {
79
79
  * Save session token to sessionStorage
80
80
  */
81
81
  private saveSessionToken;
82
+ /**
83
+ * Save pending auth to localStorage (for redirect flows)
84
+ * Uses localStorage instead of sessionStorage because OAuth may open in a new tab,
85
+ * and sessionStorage is isolated per tab. localStorage is shared across tabs.
86
+ * Keyed by state parameter for security and retrieval.
87
+ */
88
+ private savePendingAuthToStorage;
89
+ /**
90
+ * Load pending auth from localStorage (after redirect)
91
+ * Returns undefined if not found or invalid
92
+ */
93
+ private loadPendingAuthFromStorage;
94
+ /**
95
+ * Remove pending auth from localStorage
96
+ */
97
+ private removePendingAuthFromStorage;
98
+ /**
99
+ * Clean up expired pending auth entries from localStorage
100
+ * Removes any entries older than 5 minutes
101
+ */
102
+ private cleanupExpiredPendingAuths;
82
103
  /**
83
104
  * Request authorization URL from user's API route
84
105
  * The API route will add OAuth secrets and forward to MCP server
@@ -1 +1 @@
1
- {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/oauth/manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EACV,eAAe,EAEf,UAAU,EAGX,MAAM,YAAY,CAAC;AAIpB;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,YAAY,CAAuC;IAC3D,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,YAAY,CAAS;gBAG3B,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC;IAWvC;;;;;;;;;;;;;;;;OAgBG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAwCxE;;;;;;;;;;;;;OAaG;IACG,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAiDlE;;;;;;;;;;;;;OAaG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAoC5D;;OAEG;IACH,eAAe,IAAI,MAAM,GAAG,SAAS;IAIrC;;OAEG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKpC;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAWzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAUxB;;;OAGG;YACW,mBAAmB;IAiCjC;;;OAGG;YACW,oBAAoB;IA8BlC;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd"}
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/oauth/manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EACV,eAAe,EAEf,UAAU,EAGX,MAAM,YAAY,CAAC;AAIpB;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,YAAY,CAAuC;IAC3D,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,YAAY,CAAS;gBAG3B,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC;IAcvC;;;;;;;;;;;;;;;;OAgBG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IA4CxE;;;;;;;;;;;;;OAaG;IACG,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAyDlE;;;;;;;;;;;;;OAaG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAoC5D;;OAEG;IACH,eAAe,IAAI,MAAM,GAAG,SAAS;IAIrC;;OAEG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKpC;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAWzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAUxB;;;;;OAKG;IACH,OAAO,CAAC,wBAAwB;IAWhC;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAelC;;OAEG;IACH,OAAO,CAAC,4BAA4B;IAWpC;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAoClC;;;OAGG;YACW,mBAAmB;IAiCjC;;;OAGG;YACW,oBAAoB;IA8BlC;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd"}
@@ -1 +1 @@
1
- {"version":3,"file":"window-manager.d.ts","sourceRoot":"","sources":["../../../src/oauth/window-manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AASpE;;;;;;GAMG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,kBAAkB,CAA+C;IACzE,OAAO,CAAC,iBAAiB,CAA8C;IAEvE;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI;IAwC7D;;;;;;;;;;OAUG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAQ/B;;;;;;;;;;;;;;;;;OAiBG;IACH,iBAAiB,CACf,IAAI,EAAE,OAAO,GAAG,UAAU,EAC1B,SAAS,GAAE,MAAsB,GAChC,OAAO,CAAC,mBAAmB,CAAC;IAQ/B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAkE9B;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAiEjC;;OAEG;IACH,OAAO,CAAC,OAAO;IAiBf;;;OAGG;IACH,KAAK,IAAI,IAAI;CAGd;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC3C,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,GAAG,IAAI,CAwBP"}
1
+ {"version":3,"file":"window-manager.d.ts","sourceRoot":"","sources":["../../../src/oauth/window-manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AASpE;;;;;;GAMG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,kBAAkB,CAA+C;IACzE,OAAO,CAAC,iBAAiB,CAA8C;IAEvE;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI;IA6C7D;;;;;;;;;;OAUG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAQ/B;;;;;;;;;;;;;;;;;OAiBG;IACH,iBAAiB,CACf,IAAI,EAAE,OAAO,GAAG,UAAU,EAC1B,SAAS,GAAE,MAAsB,GAChC,OAAO,CAAC,mBAAmB,CAAC;IAQ/B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAkE9B;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAiEjC;;OAEG;IACH,OAAO,CAAC,OAAO;IAiBf;;;OAGG;IACH,KAAK,IAAI,IAAI;CAGd;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC3C,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,GAAG,IAAI,CAwBP"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "integrate-sdk",
3
- "version": "0.3.10",
3
+ "version": "0.3.11",
4
4
  "description": "Type-safe TypeScript SDK for MCP Client with plugin-based OAuth provider configuration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",