{"version":3,"file":"twitter.mjs","names":[],"sources":["../../src/social-providers/twitter.ts"],"sourcesContent":["import { betterFetch } from \"@better-fetch/fetch\";\nimport type { OAuthProvider, ProviderOptions } from \"../oauth2\";\nimport {\n\tcreateAuthorizationURL,\n\trefreshAccessToken,\n\tvalidateAuthorizationCode,\n} from \"../oauth2\";\n\nexport interface TwitterProfile {\n\tdata: {\n\t\t/**\n\t\t * Unique identifier of this user. This is returned as a string in order to avoid complications with languages and tools\n\t\t * that cannot handle large integers.\n\t\t */\n\t\tid: string;\n\t\t/** The friendly name of this user, as shown on their profile. */\n\t\tname: string;\n\t\t/** The email address of this user. */\n\t\temail?: string | undefined;\n\t\t/** The Twitter handle (screen name) of this user. */\n\t\tusername: string;\n\t\t/**\n\t\t * The location specified in the user's profile, if the user provided one.\n\t\t * As this is a freeform value, it may not indicate a valid location, but it may be fuzzily evaluated when performing searches with location queries.\n\t\t *\n\t\t * To return this field, add `user.fields=location` in the authorization request's query parameter.\n\t\t */\n\t\tlocation?: string | undefined;\n\t\t/**\n\t\t * This object and its children fields contain details about text that has a special meaning in the user's description.\n\t\t *\n\t\t *To return this field, add `user.fields=entities` in the authorization request's query parameter.\n\t\t */\n\t\tentities?:\n\t\t\t| {\n\t\t\t\t\t/** Contains details about the user's profile website. */\n\t\t\t\t\turl: {\n\t\t\t\t\t\t/** Contains details about the user's profile website. */\n\t\t\t\t\t\turls: Array<{\n\t\t\t\t\t\t\t/** The start position (zero-based) of the recognized user's profile website. All start indices are inclusive. */\n\t\t\t\t\t\t\tstart: number;\n\t\t\t\t\t\t\t/** The end position (zero-based) of the recognized user's profile website. This end index is exclusive. */\n\t\t\t\t\t\t\tend: number;\n\t\t\t\t\t\t\t/** The URL in the format entered by the user. */\n\t\t\t\t\t\t\turl: string;\n\t\t\t\t\t\t\t/** The fully resolved URL. */\n\t\t\t\t\t\t\texpanded_url: string;\n\t\t\t\t\t\t\t/** The URL as displayed in the user's profile. */\n\t\t\t\t\t\t\tdisplay_url: string;\n\t\t\t\t\t\t}>;\n\t\t\t\t\t};\n\t\t\t\t\t/** Contains details about URLs, Hashtags, Cashtags, or mentions located within a user's description. */\n\t\t\t\t\tdescription: {\n\t\t\t\t\t\thashtags: Array<{\n\t\t\t\t\t\t\tstart: number;\n\t\t\t\t\t\t\tend: number;\n\t\t\t\t\t\t\ttag: string;\n\t\t\t\t\t\t}>;\n\t\t\t\t\t};\n\t\t\t }\n\t\t\t| undefined;\n\t\t/**\n\t\t * Indicate if this user is a verified Twitter user.\n\t\t *\n\t\t * To return this field, add `user.fields=verified` in the authorization request's query parameter.\n\t\t */\n\t\tverified?: boolean | undefined;\n\t\t/**\n\t\t * The text of this user's profile description (also known as bio), if the user provided one.\n\t\t *\n\t\t * To return this field, add `user.fields=description` in the authorization request's query parameter.\n\t\t */\n\t\tdescription?: string | undefined;\n\t\t/**\n\t\t * The URL specified in the user's profile, if present.\n\t\t *\n\t\t * To return this field, add `user.fields=url` in the authorization request's query parameter.\n\t\t */\n\t\turl?: string | undefined;\n\t\t/** The URL to the profile image for this user, as shown on the user's profile. */\n\t\tprofile_image_url?: string | undefined;\n\t\tprotected?: boolean | undefined;\n\t\t/**\n\t\t * Unique identifier of this user's pinned Tweet.\n\t\t *\n\t\t * You can obtain the expanded object in `includes.tweets` by adding `expansions=pinned_tweet_id` in the authorization request's query parameter.\n\t\t */\n\t\tpinned_tweet_id?: string | undefined;\n\t\tcreated_at?: string | undefined;\n\t};\n\tincludes?:\n\t\t| {\n\t\t\t\ttweets?: Array<{\n\t\t\t\t\tid: string;\n\t\t\t\t\ttext: string;\n\t\t\t\t}>;\n\t\t }\n\t\t| undefined;\n\t[claims: string]: unknown;\n}\n\nexport interface TwitterOption extends ProviderOptions {\n\tclientId: string;\n}\n\nexport const twitter = (options: TwitterOption) => {\n\treturn {\n\t\tid: \"twitter\",\n\t\tname: \"Twitter\",\n\t\tcreateAuthorizationURL(data) {\n\t\t\tconst _scopes = options.disableDefaultScope\n\t\t\t\t? []\n\t\t\t\t: [\"users.read\", \"tweet.read\", \"offline.access\", \"users.email\"];\n\t\t\tif (options.scope) _scopes.push(...options.scope);\n\t\t\tif (data.scopes) _scopes.push(...data.scopes);\n\t\t\treturn createAuthorizationURL({\n\t\t\t\tid: \"twitter\",\n\t\t\t\toptions,\n\t\t\t\tauthorizationEndpoint: \"https://x.com/i/oauth2/authorize\",\n\t\t\t\tscopes: _scopes,\n\t\t\t\tstate: data.state,\n\t\t\t\tcodeVerifier: data.codeVerifier,\n\t\t\t\tredirectURI: data.redirectURI,\n\t\t\t});\n\t\t},\n\t\tvalidateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {\n\t\t\treturn validateAuthorizationCode({\n\t\t\t\tcode,\n\t\t\t\tcodeVerifier,\n\t\t\t\tauthentication: \"basic\",\n\t\t\t\tredirectURI,\n\t\t\t\toptions,\n\t\t\t\ttokenEndpoint: \"https://api.x.com/2/oauth2/token\",\n\t\t\t});\n\t\t},\n\n\t\trefreshAccessToken: options.refreshAccessToken\n\t\t\t? options.refreshAccessToken\n\t\t\t: async (refreshToken) => {\n\t\t\t\t\treturn refreshAccessToken({\n\t\t\t\t\t\trefreshToken,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tclientId: options.clientId,\n\t\t\t\t\t\t\tclientKey: options.clientKey,\n\t\t\t\t\t\t\tclientSecret: options.clientSecret,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tauthentication: \"basic\",\n\t\t\t\t\t\ttokenEndpoint: \"https://api.x.com/2/oauth2/token\",\n\t\t\t\t\t});\n\t\t\t\t},\n\t\tasync getUserInfo(token) {\n\t\t\tif (options.getUserInfo) {\n\t\t\t\treturn options.getUserInfo(token);\n\t\t\t}\n\t\t\tconst { data: profile, error: profileError } =\n\t\t\t\tawait betterFetch(\n\t\t\t\t\t\"https://api.x.com/2/users/me?user.fields=profile_image_url\",\n\t\t\t\t\t{\n\t\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\tAuthorization: `Bearer ${token.accessToken}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\tif (profileError) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst { data: emailData, error: emailError } = await betterFetch<{\n\t\t\t\tdata: { confirmed_email: string };\n\t\t\t}>(\"https://api.x.com/2/users/me?user.fields=confirmed_email\", {\n\t\t\t\tmethod: \"GET\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${token.accessToken}`,\n\t\t\t\t},\n\t\t\t});\n\t\t\tlet emailVerified = false;\n\t\t\tif (!emailError && emailData?.data?.confirmed_email) {\n\t\t\t\tprofile.data.email = emailData.data.confirmed_email;\n\t\t\t\temailVerified = true;\n\t\t\t}\n\t\t\tconst userMap = await options.mapProfileToUser?.(profile);\n\t\t\treturn {\n\t\t\t\tuser: {\n\t\t\t\t\tid: profile.data.id,\n\t\t\t\t\tname: profile.data.name,\n\t\t\t\t\temail: profile.data.email || profile.data.username || null,\n\t\t\t\t\timage: profile.data.profile_image_url,\n\t\t\t\t\temailVerified: emailVerified,\n\t\t\t\t\t...userMap,\n\t\t\t\t},\n\t\t\t\tdata: profile,\n\t\t\t};\n\t\t},\n\t\toptions,\n\t} satisfies OAuthProvider;\n};\n"],"mappings":";;;;;;;AAyGA,MAAa,WAAW,YAA2B;AAClD,QAAO;EACN,IAAI;EACJ,MAAM;EACN,uBAAuB,MAAM;GAC5B,MAAM,UAAU,QAAQ,sBACrB,EAAE,GACF;IAAC;IAAc;IAAc;IAAkB;IAAc;AAChE,OAAI,QAAQ,MAAO,SAAQ,KAAK,GAAG,QAAQ,MAAM;AACjD,OAAI,KAAK,OAAQ,SAAQ,KAAK,GAAG,KAAK,OAAO;AAC7C,UAAO,uBAAuB;IAC7B,IAAI;IACJ;IACA,uBAAuB;IACvB,QAAQ;IACR,OAAO,KAAK;IACZ,cAAc,KAAK;IACnB,aAAa,KAAK;IAClB,CAAC;;EAEH,2BAA2B,OAAO,EAAE,MAAM,cAAc,kBAAkB;AACzE,UAAO,0BAA0B;IAChC;IACA;IACA,gBAAgB;IAChB;IACA;IACA,eAAe;IACf,CAAC;;EAGH,oBAAoB,QAAQ,qBACzB,QAAQ,qBACR,OAAO,iBAAiB;AACxB,UAAO,mBAAmB;IACzB;IACA,SAAS;KACR,UAAU,QAAQ;KAClB,WAAW,QAAQ;KACnB,cAAc,QAAQ;KACtB;IACD,gBAAgB;IAChB,eAAe;IACf,CAAC;;EAEL,MAAM,YAAY,OAAO;AACxB,OAAI,QAAQ,YACX,QAAO,QAAQ,YAAY,MAAM;GAElC,MAAM,EAAE,MAAM,SAAS,OAAO,iBAC7B,MAAM,YACL,8DACA;IACC,QAAQ;IACR,SAAS,EACR,eAAe,UAAU,MAAM,eAC/B;IACD,CACD;AAEF,OAAI,aACH,QAAO;GAGR,MAAM,EAAE,MAAM,WAAW,OAAO,eAAe,MAAM,YAElD,4DAA4D;IAC9D,QAAQ;IACR,SAAS,EACR,eAAe,UAAU,MAAM,eAC/B;IACD,CAAC;GACF,IAAI,gBAAgB;AACpB,OAAI,CAAC,cAAc,WAAW,MAAM,iBAAiB;AACpD,YAAQ,KAAK,QAAQ,UAAU,KAAK;AACpC,oBAAgB;;GAEjB,MAAM,UAAU,MAAM,QAAQ,mBAAmB,QAAQ;AACzD,UAAO;IACN,MAAM;KACL,IAAI,QAAQ,KAAK;KACjB,MAAM,QAAQ,KAAK;KACnB,OAAO,QAAQ,KAAK,SAAS,QAAQ,KAAK,YAAY;KACtD,OAAO,QAAQ,KAAK;KACL;KACf,GAAG;KACH;IACD,MAAM;IACN;;EAEF;EACA"}