integrate-sdk 0.9.43-dev.0 → 0.9.44-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js CHANGED
@@ -736,104 +736,267 @@ function base64UrlDecode(str) {
736
736
 
737
737
  // src/oauth/email-fetcher.ts
738
738
  async function fetchUserEmail(provider, tokenData) {
739
+ const fetcher = EMAIL_FETCHERS[provider.toLowerCase()];
740
+ if (!fetcher) {
741
+ return tokenData.email;
742
+ }
739
743
  try {
740
- switch (provider.toLowerCase()) {
741
- case "github":
742
- return await fetchGitHubEmail(tokenData.accessToken);
743
- case "gmail":
744
- case "google":
745
- return await fetchGoogleEmail(tokenData.accessToken);
746
- case "notion":
747
- return await fetchNotionEmail(tokenData.accessToken);
748
- default:
749
- return tokenData.email;
750
- }
744
+ const email = await fetcher(tokenData);
745
+ return email ?? tokenData.email;
751
746
  } catch (error) {
752
747
  logger3.error(`Failed to fetch email for ${provider}:`, error);
753
- return;
748
+ return tokenData.email;
754
749
  }
755
750
  }
756
- async function fetchGitHubEmail(accessToken) {
757
- try {
758
- const userResponse = await fetch("https://api.github.com/user", {
759
- headers: {
760
- Authorization: `Bearer ${accessToken}`,
761
- Accept: "application/vnd.github.v3+json"
762
- }
763
- });
764
- if (!userResponse.ok) {
765
- return;
766
- }
767
- const user = await userResponse.json();
768
- if (user.email) {
769
- return user.email;
770
- }
771
- const emailsResponse = await fetch("https://api.github.com/user/emails", {
772
- headers: {
773
- Authorization: `Bearer ${accessToken}`,
774
- Accept: "application/vnd.github.v3+json"
775
- }
776
- });
777
- if (!emailsResponse.ok) {
778
- return;
779
- }
780
- const emails = await emailsResponse.json();
781
- const primaryEmail = emails.find((e) => e.primary && e.verified);
782
- if (primaryEmail) {
783
- return primaryEmail.email;
751
+ async function fetchGitHubEmail(token) {
752
+ const headers = {
753
+ Authorization: `Bearer ${token.accessToken}`,
754
+ Accept: "application/vnd.github.v3+json"
755
+ };
756
+ const userResponse = await fetch("https://api.github.com/user", { headers });
757
+ if (!userResponse.ok)
758
+ return;
759
+ const user = await userResponse.json();
760
+ if (user.email)
761
+ return user.email;
762
+ const emailsResponse = await fetch("https://api.github.com/user/emails", { headers });
763
+ if (!emailsResponse.ok)
764
+ return;
765
+ const emails = await emailsResponse.json();
766
+ const primary = emails.find((e) => e.primary && e.verified);
767
+ if (primary)
768
+ return primary.email;
769
+ const verified = emails.find((e) => e.verified);
770
+ if (verified)
771
+ return verified.email;
772
+ return emails[0]?.email;
773
+ }
774
+ async function fetchGoogleEmail(token) {
775
+ const response = await fetch("https://www.googleapis.com/oauth2/v2/userinfo", {
776
+ headers: { Authorization: `Bearer ${token.accessToken}` }
777
+ });
778
+ if (!response.ok)
779
+ return;
780
+ const user = await response.json();
781
+ return user.email;
782
+ }
783
+ async function fetchNotionEmail(token) {
784
+ const response = await fetch("https://api.notion.com/v1/users/me", {
785
+ headers: {
786
+ Authorization: `Bearer ${token.accessToken}`,
787
+ "Notion-Version": "2022-06-28"
784
788
  }
785
- const verifiedEmail = emails.find((e) => e.verified);
786
- if (verifiedEmail) {
787
- return verifiedEmail.email;
789
+ });
790
+ if (!response.ok)
791
+ return;
792
+ const user = await response.json();
793
+ return user.person?.email ?? user.bot?.owner?.user?.person?.email;
794
+ }
795
+ async function fetchLinearEmail(token) {
796
+ const response = await fetch("https://api.linear.app/graphql", {
797
+ method: "POST",
798
+ headers: {
799
+ Authorization: `Bearer ${token.accessToken}`,
800
+ "Content-Type": "application/json"
801
+ },
802
+ body: JSON.stringify({ query: "{ viewer { email } }" })
803
+ });
804
+ if (!response.ok)
805
+ return;
806
+ const body = await response.json();
807
+ return body.data?.viewer?.email;
808
+ }
809
+ async function fetchHubSpotEmail(token) {
810
+ const url = `https://api.hubapi.com/oauth/v1/access-tokens/${encodeURIComponent(token.accessToken)}`;
811
+ const response = await fetch(url);
812
+ if (!response.ok)
813
+ return;
814
+ const body = await response.json();
815
+ return body.user;
816
+ }
817
+ async function fetchPolarEmail(token) {
818
+ const response = await fetch("https://api.polar.sh/v1/oauth2/userinfo", {
819
+ headers: { Authorization: `Bearer ${token.accessToken}` }
820
+ });
821
+ if (!response.ok)
822
+ return;
823
+ const body = await response.json();
824
+ return body.email;
825
+ }
826
+ async function fetchTodoistEmail(token) {
827
+ const response = await fetch("https://api.todoist.com/sync/v9/sync", {
828
+ method: "POST",
829
+ headers: {
830
+ Authorization: `Bearer ${token.accessToken}`,
831
+ "Content-Type": "application/x-www-form-urlencoded"
832
+ },
833
+ body: 'sync_token=*&resource_types=["user"]'
834
+ });
835
+ if (!response.ok)
836
+ return;
837
+ const body = await response.json();
838
+ return body.user?.email;
839
+ }
840
+ async function fetchVercelEmail(token) {
841
+ const response = await fetch("https://api.vercel.com/v2/user", {
842
+ headers: { Authorization: `Bearer ${token.accessToken}` }
843
+ });
844
+ if (!response.ok)
845
+ return;
846
+ const body = await response.json();
847
+ return body.user?.email ?? body.email;
848
+ }
849
+ async function fetchSlackEmail(token) {
850
+ const response = await fetch("https://slack.com/api/users.identity", {
851
+ headers: { Authorization: `Bearer ${token.accessToken}` }
852
+ });
853
+ if (!response.ok)
854
+ return;
855
+ const body = await response.json();
856
+ if (!body.ok)
857
+ return;
858
+ return body.user?.email;
859
+ }
860
+ async function fetchIntercomEmail(token) {
861
+ const response = await fetch("https://api.intercom.io/me", {
862
+ headers: {
863
+ Authorization: `Bearer ${token.accessToken}`,
864
+ Accept: "application/json"
788
865
  }
789
- if (emails.length > 0 && emails[0]?.email) {
790
- return emails[0].email;
866
+ });
867
+ if (!response.ok)
868
+ return;
869
+ const body = await response.json();
870
+ return body.email;
871
+ }
872
+ async function fetchAtlassianEmail(token) {
873
+ const response = await fetch("https://api.atlassian.com/me", {
874
+ headers: {
875
+ Authorization: `Bearer ${token.accessToken}`,
876
+ Accept: "application/json"
791
877
  }
878
+ });
879
+ if (!response.ok)
792
880
  return;
793
- } catch (error) {
794
- logger3.error("Failed to fetch GitHub email:", error);
881
+ const body = await response.json();
882
+ return body.email;
883
+ }
884
+ async function fetchZendeskEmail(token) {
885
+ const subdomain = token.providerConfig?.subdomain?.trim();
886
+ if (!subdomain)
795
887
  return;
796
- }
888
+ const response = await fetch(`https://${subdomain}.zendesk.com/api/v2/users/me.json`, {
889
+ headers: { Authorization: `Bearer ${token.accessToken}` }
890
+ });
891
+ if (!response.ok)
892
+ return;
893
+ const body = await response.json();
894
+ return body.user?.email;
797
895
  }
798
- async function fetchGoogleEmail(accessToken) {
799
- try {
800
- const response = await fetch("https://www.googleapis.com/oauth2/v2/userinfo", {
801
- headers: {
802
- Authorization: `Bearer ${accessToken}`
803
- }
804
- });
805
- if (!response.ok) {
806
- return;
807
- }
808
- const user = await response.json();
809
- return user.email;
810
- } catch (error) {
811
- logger3.error("Failed to fetch Google email:", error);
896
+ async function fetchAirtableEmail(token) {
897
+ const response = await fetch("https://api.airtable.com/v0/meta/whoami", {
898
+ headers: { Authorization: `Bearer ${token.accessToken}` }
899
+ });
900
+ if (!response.ok)
812
901
  return;
813
- }
902
+ const body = await response.json();
903
+ return body.email;
814
904
  }
815
- async function fetchNotionEmail(accessToken) {
816
- try {
817
- const response = await fetch("https://api.notion.com/v1/users/me", {
818
- headers: {
819
- Authorization: `Bearer ${accessToken}`,
820
- "Notion-Version": "2022-06-28"
821
- }
822
- });
823
- if (!response.ok) {
824
- return;
905
+ async function fetchDiscordEmail(token) {
906
+ const response = await fetch("https://discord.com/api/users/@me", {
907
+ headers: { Authorization: `Bearer ${token.accessToken}` }
908
+ });
909
+ if (!response.ok)
910
+ return;
911
+ const body = await response.json();
912
+ return body.email;
913
+ }
914
+ async function fetchDropboxEmail(token) {
915
+ const response = await fetch("https://api.dropboxapi.com/2/users/get_current_account", {
916
+ method: "POST",
917
+ headers: {
918
+ Authorization: `Bearer ${token.accessToken}`
919
+ },
920
+ body: "null"
921
+ });
922
+ if (!response.ok)
923
+ return;
924
+ const body = await response.json();
925
+ return body.email;
926
+ }
927
+ async function fetchGitLabEmail(token) {
928
+ const response = await fetch("https://gitlab.com/api/v4/user", {
929
+ headers: { Authorization: `Bearer ${token.accessToken}` }
930
+ });
931
+ if (!response.ok)
932
+ return;
933
+ const body = await response.json();
934
+ return body.email;
935
+ }
936
+ async function fetchRedditEmail(token) {
937
+ const response = await fetch("https://oauth.reddit.com/api/v1/me", {
938
+ headers: {
939
+ Authorization: `Bearer ${token.accessToken}`,
940
+ "User-Agent": "integrate-sdk"
825
941
  }
826
- const user = await response.json();
827
- return user.person?.email;
828
- } catch (error) {
829
- logger3.error("Failed to fetch Notion email:", error);
942
+ });
943
+ if (!response.ok)
830
944
  return;
831
- }
945
+ const body = await response.json();
946
+ return body.name;
947
+ }
948
+ async function fetchMicrosoftEmail(token) {
949
+ const response = await fetch("https://graph.microsoft.com/v1.0/me", {
950
+ headers: { Authorization: `Bearer ${token.accessToken}` }
951
+ });
952
+ if (!response.ok)
953
+ return;
954
+ const body = await response.json();
955
+ return body.mail ?? body.userPrincipalName;
832
956
  }
833
- var logger3;
957
+ var logger3, EMAIL_FETCHERS;
834
958
  var init_email_fetcher = __esm(() => {
835
959
  init_logger();
836
960
  logger3 = createLogger("EmailFetcher");
961
+ EMAIL_FETCHERS = {
962
+ github: fetchGitHubEmail,
963
+ gmail: fetchGoogleEmail,
964
+ google: fetchGoogleEmail,
965
+ gcal: fetchGoogleEmail,
966
+ gdrive: fetchGoogleEmail,
967
+ gdocs: fetchGoogleEmail,
968
+ gsheets: fetchGoogleEmail,
969
+ gslides: fetchGoogleEmail,
970
+ gcontacts: fetchGoogleEmail,
971
+ gmeet: fetchGoogleEmail,
972
+ gchat: fetchGoogleEmail,
973
+ gtasks: fetchGoogleEmail,
974
+ ga4: fetchGoogleEmail,
975
+ youtube: fetchGoogleEmail,
976
+ notion: fetchNotionEmail,
977
+ linear: fetchLinearEmail,
978
+ hubspot: fetchHubSpotEmail,
979
+ polar: fetchPolarEmail,
980
+ todoist: fetchTodoistEmail,
981
+ vercel: fetchVercelEmail,
982
+ slack: fetchSlackEmail,
983
+ intercom: fetchIntercomEmail,
984
+ jira: fetchAtlassianEmail,
985
+ zendesk: fetchZendeskEmail,
986
+ airtable: fetchAirtableEmail,
987
+ discord: fetchDiscordEmail,
988
+ dropbox: fetchDropboxEmail,
989
+ gitlab: fetchGitLabEmail,
990
+ reddit: fetchRedditEmail,
991
+ outlook: fetchMicrosoftEmail,
992
+ teams: fetchMicrosoftEmail,
993
+ onedrive: fetchMicrosoftEmail,
994
+ sharepoint: fetchMicrosoftEmail,
995
+ excel: fetchMicrosoftEmail,
996
+ word: fetchMicrosoftEmail,
997
+ powerpoint: fetchMicrosoftEmail,
998
+ planner: fetchMicrosoftEmail
999
+ };
837
1000
  });
838
1001
 
839
1002
  // src/utils/concurrency.ts
@@ -1,14 +1,25 @@
1
1
  /**
2
2
  * Email Fetcher
3
- * Fetches user email from OAuth provider APIs after token exchange
3
+ * Fetches user email from OAuth provider APIs after token exchange so the
4
+ * UI can label connected accounts.
5
+ *
6
+ * Implementations are registered in EMAIL_FETCHERS; unknown providers fall
7
+ * back to whatever email the OAuth response itself carried (e.g. Google's
8
+ * id_token JWT, which the MCP server extracts and surfaces on the callback
9
+ * response).
4
10
  */
5
11
  import type { ProviderTokenData } from "./types.js";
12
+ export type EmailFetcher = (token: ProviderTokenData) => Promise<string | undefined>;
6
13
  /**
7
- * Fetch user email from OAuth provider
8
- *
9
- * @param provider - Provider name (e.g., 'github', 'gmail')
10
- * @param tokenData - Token data with access token
11
- * @returns User email address or undefined if not available
14
+ * Register a custom email fetcher for a provider. Useful when downstream
15
+ * apps add integrations that aren't yet in the SDK's built-in registry.
16
+ */
17
+ export declare function registerEmailFetcher(provider: string, fetcher: EmailFetcher): void;
18
+ /**
19
+ * Fetch user email from the OAuth provider after a successful token
20
+ * exchange. Returns undefined if no fetcher is registered or the provider
21
+ * call fails. Caller should fall back to whatever tokenData.email already
22
+ * holds.
12
23
  */
13
24
  export declare function fetchUserEmail(provider: string, tokenData: ProviderTokenData): Promise<string | undefined>;
14
25
  //# sourceMappingURL=email-fetcher.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"email-fetcher.d.ts","sourceRoot":"","sources":["../../../src/oauth/email-fetcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAQpD;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,iBAAiB,GAC3B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAkB7B"}
1
+ {"version":3,"file":"email-fetcher.d.ts","sourceRoot":"","sources":["../../../src/oauth/email-fetcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAKpD,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;AA0CrF;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,CAElF;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,iBAAiB,GAC3B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAY7B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "integrate-sdk",
3
- "version": "0.9.43-dev.0",
3
+ "version": "0.9.44-dev.0",
4
4
  "description": "Type-safe 3rd party integration SDK for the Integrate MCP server",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",