antarctic 0.2.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.
Files changed (145) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +155 -0
  3. package/dist/auth.d.ts +63 -0
  4. package/dist/auth.js +191 -0
  5. package/dist/client.d.ts +16 -0
  6. package/dist/client.js +105 -0
  7. package/dist/index.d.ts +70 -0
  8. package/dist/index.js +69 -0
  9. package/dist/oauth2.d.ts +16 -0
  10. package/dist/oauth2.js +67 -0
  11. package/dist/oidc.d.ts +1 -0
  12. package/dist/oidc.js +11 -0
  13. package/dist/providers/42.d.ts +16 -0
  14. package/dist/providers/42.js +75 -0
  15. package/dist/providers/amazon-cognito.d.ts +21 -0
  16. package/dist/providers/amazon-cognito.js +76 -0
  17. package/dist/providers/anilist.d.ts +14 -0
  18. package/dist/providers/anilist.js +91 -0
  19. package/dist/providers/apple.d.ts +22 -0
  20. package/dist/providers/apple.js +106 -0
  21. package/dist/providers/atlassian.d.ts +17 -0
  22. package/dist/providers/atlassian.js +83 -0
  23. package/dist/providers/auth0.d.ts +21 -0
  24. package/dist/providers/auth0.js +80 -0
  25. package/dist/providers/authentik.d.ts +21 -0
  26. package/dist/providers/authentik.js +75 -0
  27. package/dist/providers/autodesk.d.ts +16 -0
  28. package/dist/providers/autodesk.js +60 -0
  29. package/dist/providers/battlenet.d.ts +16 -0
  30. package/dist/providers/battlenet.js +69 -0
  31. package/dist/providers/bitbucket.d.ts +15 -0
  32. package/dist/providers/bitbucket.js +79 -0
  33. package/dist/providers/box.d.ts +18 -0
  34. package/dist/providers/box.js +90 -0
  35. package/dist/providers/bungie.d.ts +17 -0
  36. package/dist/providers/bungie.js +72 -0
  37. package/dist/providers/coinbase.d.ts +18 -0
  38. package/dist/providers/coinbase.js +95 -0
  39. package/dist/providers/discord.d.ts +16 -0
  40. package/dist/providers/discord.js +68 -0
  41. package/dist/providers/donation-alerts.d.ts +17 -0
  42. package/dist/providers/donation-alerts.js +86 -0
  43. package/dist/providers/dribbble.d.ts +16 -0
  44. package/dist/providers/dribbble.js +73 -0
  45. package/dist/providers/dropbox.d.ts +16 -0
  46. package/dist/providers/dropbox.js +96 -0
  47. package/dist/providers/epicgames.d.ts +16 -0
  48. package/dist/providers/epicgames.js +60 -0
  49. package/dist/providers/etsy.d.ts +15 -0
  50. package/dist/providers/etsy.js +68 -0
  51. package/dist/providers/facebook.d.ts +16 -0
  52. package/dist/providers/facebook.js +80 -0
  53. package/dist/providers/figma.d.ts +15 -0
  54. package/dist/providers/figma.js +56 -0
  55. package/dist/providers/gitea.d.ts +19 -0
  56. package/dist/providers/gitea.js +62 -0
  57. package/dist/providers/github.d.ts +17 -0
  58. package/dist/providers/github.js +142 -0
  59. package/dist/providers/gitlab.d.ts +21 -0
  60. package/dist/providers/gitlab.js +64 -0
  61. package/dist/providers/google.d.ts +16 -0
  62. package/dist/providers/google.js +70 -0
  63. package/dist/providers/intuit.d.ts +16 -0
  64. package/dist/providers/intuit.js +66 -0
  65. package/dist/providers/kakao.d.ts +17 -0
  66. package/dist/providers/kakao.js +95 -0
  67. package/dist/providers/keycloak.d.ts +21 -0
  68. package/dist/providers/keycloak.js +74 -0
  69. package/dist/providers/kick.d.ts +18 -0
  70. package/dist/providers/kick.js +103 -0
  71. package/dist/providers/lichess.d.ts +14 -0
  72. package/dist/providers/lichess.js +63 -0
  73. package/dist/providers/line.d.ts +17 -0
  74. package/dist/providers/line.js +98 -0
  75. package/dist/providers/linear.d.ts +16 -0
  76. package/dist/providers/linear.js +112 -0
  77. package/dist/providers/linkedin.d.ts +17 -0
  78. package/dist/providers/linkedin.js +89 -0
  79. package/dist/providers/mastodon.d.ts +20 -0
  80. package/dist/providers/mastodon.js +67 -0
  81. package/dist/providers/mercadolibre.d.ts +17 -0
  82. package/dist/providers/mercadolibre.js +95 -0
  83. package/dist/providers/mercadopago.d.ts +17 -0
  84. package/dist/providers/mercadopago.js +95 -0
  85. package/dist/providers/microsoft-entra-id.d.ts +20 -0
  86. package/dist/providers/microsoft-entra-id.js +120 -0
  87. package/dist/providers/myanimelist.d.ts +15 -0
  88. package/dist/providers/myanimelist.js +56 -0
  89. package/dist/providers/naver.d.ts +17 -0
  90. package/dist/providers/naver.js +83 -0
  91. package/dist/providers/notion.d.ts +14 -0
  92. package/dist/providers/notion.js +65 -0
  93. package/dist/providers/okta.d.ts +22 -0
  94. package/dist/providers/okta.js +85 -0
  95. package/dist/providers/osu.d.ts +17 -0
  96. package/dist/providers/osu.js +82 -0
  97. package/dist/providers/patreon.d.ts +17 -0
  98. package/dist/providers/patreon.js +89 -0
  99. package/dist/providers/polar.d.ts +18 -0
  100. package/dist/providers/polar.js +100 -0
  101. package/dist/providers/reddit.d.ts +15 -0
  102. package/dist/providers/reddit.js +55 -0
  103. package/dist/providers/roblox.d.ts +16 -0
  104. package/dist/providers/roblox.js +67 -0
  105. package/dist/providers/salesforce.d.ts +21 -0
  106. package/dist/providers/salesforce.js +74 -0
  107. package/dist/providers/shikimori.d.ts +17 -0
  108. package/dist/providers/shikimori.js +81 -0
  109. package/dist/providers/slack.d.ts +14 -0
  110. package/dist/providers/slack.js +59 -0
  111. package/dist/providers/spotify.d.ts +15 -0
  112. package/dist/providers/spotify.js +67 -0
  113. package/dist/providers/startgg.d.ts +17 -0
  114. package/dist/providers/startgg.js +143 -0
  115. package/dist/providers/strava.d.ts +17 -0
  116. package/dist/providers/strava.js +85 -0
  117. package/dist/providers/synology.d.ts +9 -0
  118. package/dist/providers/synology.js +20 -0
  119. package/dist/providers/tiktok.d.ts +18 -0
  120. package/dist/providers/tiktok.js +109 -0
  121. package/dist/providers/tiltify.d.ts +17 -0
  122. package/dist/providers/tiltify.js +90 -0
  123. package/dist/providers/tumblr.d.ts +15 -0
  124. package/dist/providers/tumblr.js +63 -0
  125. package/dist/providers/twitch.d.ts +17 -0
  126. package/dist/providers/twitch.js +91 -0
  127. package/dist/providers/twitter.d.ts +16 -0
  128. package/dist/providers/twitter.js +67 -0
  129. package/dist/providers/vk.d.ts +16 -0
  130. package/dist/providers/vk.js +82 -0
  131. package/dist/providers/withings.d.ts +16 -0
  132. package/dist/providers/withings.js +120 -0
  133. package/dist/providers/workos.d.ts +16 -0
  134. package/dist/providers/workos.js +82 -0
  135. package/dist/providers/yahoo.d.ts +15 -0
  136. package/dist/providers/yahoo.js +65 -0
  137. package/dist/providers/yandex.d.ts +15 -0
  138. package/dist/providers/yandex.js +66 -0
  139. package/dist/providers/zoom.d.ts +16 -0
  140. package/dist/providers/zoom.js +66 -0
  141. package/dist/request.d.ts +26 -0
  142. package/dist/request.js +182 -0
  143. package/dist/utils.d.ts +2 -0
  144. package/dist/utils.js +20 -0
  145. package/package.json +42 -0
@@ -0,0 +1,67 @@
1
+ import { CodeChallengeMethod, OAuth2Client } from "../client.js";
2
+ import { consumeOAuthState, fetchUserProfile, generateOAuthCodeVerifier, generateOAuthState, InvalidOAuthCallbackError, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveScopes, saveOAuthState } from "../auth.js";
3
+ const authorizationEndpoint = "https://accounts.spotify.com/authorize";
4
+ const tokenEndpoint = "https://accounts.spotify.com/api/token";
5
+ const userEndpoint = "https://api.spotify.com/v1/me";
6
+ const envPrefix = "SPOTIFY";
7
+ const defaultScopes = ["user-read-email", "user-read-private"];
8
+ export class Spotify {
9
+ client;
10
+ auth = null;
11
+ constructor(clientIdOrOptions, clientSecret, redirectURI) {
12
+ if (typeof clientIdOrOptions === "object") {
13
+ this.auth = resolveAuthConfig(envPrefix, clientIdOrOptions, { redirectURI: true });
14
+ this.client = new OAuth2Client(this.auth.clientId, this.auth.clientSecret, this.auth.redirectURI);
15
+ }
16
+ else {
17
+ this.client = new OAuth2Client(clientIdOrOptions, clientSecret ?? null, redirectURI ?? "");
18
+ }
19
+ }
20
+ createAuthorizationURL(state, codeVerifier, scopes) {
21
+ let url;
22
+ if (codeVerifier !== null) {
23
+ url = this.client.createAuthorizationURLWithPKCE(authorizationEndpoint, state, CodeChallengeMethod.S256, codeVerifier, scopes);
24
+ }
25
+ else {
26
+ url = this.client.createAuthorizationURL(authorizationEndpoint, state, scopes);
27
+ }
28
+ return url;
29
+ }
30
+ async validateAuthorizationCode(code, codeVerifier) {
31
+ const tokens = await this.client.validateAuthorizationCode(tokenEndpoint, code, codeVerifier);
32
+ return tokens;
33
+ }
34
+ async refreshAccessToken(refreshToken) {
35
+ const tokens = await this.client.refreshAccessToken(tokenEndpoint, refreshToken, []);
36
+ return tokens;
37
+ }
38
+ async getAuthorizationURL(scopes) {
39
+ const auth = requireAuthConfig(this.auth);
40
+ const state = generateOAuthState();
41
+ const codeVerifier = generateOAuthCodeVerifier();
42
+ const url = this.createAuthorizationURL(state, codeVerifier, resolveScopes(scopes, auth, defaultScopes));
43
+ await saveOAuthState(auth.store, state, { codeVerifier });
44
+ return url;
45
+ }
46
+ async getUser(query) {
47
+ const auth = requireAuthConfig(this.auth);
48
+ const { code, state } = parseCallbackQuery(query);
49
+ const stored = await consumeOAuthState(auth.store, state);
50
+ if (typeof stored.codeVerifier !== "string") {
51
+ throw new InvalidOAuthCallbackError("Missing PKCE code verifier for OAuth state");
52
+ }
53
+ const tokens = await this.validateAuthorizationCode(code, stored.codeVerifier);
54
+ const profile = await fetchUserProfile(userEndpoint, tokens.accessToken());
55
+ let image = null;
56
+ if (Array.isArray(profile.images) && profile.images.length > 0) {
57
+ const first = profile.images[0];
58
+ image = profileString(first.url);
59
+ }
60
+ return {
61
+ id: profileId(profile.id),
62
+ name: profileString(profile.display_name),
63
+ email: profileString(profile.email),
64
+ image
65
+ };
66
+ }
67
+ }
@@ -0,0 +1,17 @@
1
+ import type { OAuth2Tokens } from "../oauth2.js";
2
+ import type { OAuthCallbackQuery, OAuthUser, ProviderOptions } from "../auth.js";
3
+ export interface StartGGOptions extends ProviderOptions {
4
+ }
5
+ export declare class StartGG {
6
+ private clientId;
7
+ private clientSecret;
8
+ private redirectURI;
9
+ private auth;
10
+ constructor(options: StartGGOptions);
11
+ constructor(clientId: string, clientSecret: string, redirectURI: string);
12
+ createAuthorizationURL(state: string, scopes: string[]): URL;
13
+ validateAuthorizationCode(code: string, scopes: string[]): Promise<OAuth2Tokens>;
14
+ refreshAccessToken(refreshToken: string, scopes: string[]): Promise<OAuth2Tokens>;
15
+ getAuthorizationURL(scopes?: string[]): Promise<URL>;
16
+ getUser(query: OAuthCallbackQuery): Promise<OAuthUser>;
17
+ }
@@ -0,0 +1,143 @@
1
+ import { createOAuth2Request, sendTokenRequest } from "../request.js";
2
+ import { consumeOAuthState, generateOAuthState, OAuthProviderError, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveScopes, saveOAuthState } from "../auth.js";
3
+ const authorizationEndpoint = "https://start.gg/oauth/authorize";
4
+ const tokenEndpoint = "https://api.start.gg/oauth/access_token";
5
+ const refreshEndpoint = "https://api.start.gg/oauth/refresh";
6
+ const graphqlEndpoint = "https://api.start.gg/gql/alpha";
7
+ const envPrefix = "START_GG";
8
+ const defaultScopes = ["user.identity", "user.email"];
9
+ const currentUserQuery = "{ currentUser { id name email images { url } } }";
10
+ async function fetchCurrentUser(accessToken) {
11
+ const request = new Request(graphqlEndpoint, {
12
+ method: "POST",
13
+ body: JSON.stringify({ query: currentUserQuery })
14
+ });
15
+ request.headers.set("Authorization", `Bearer ${accessToken}`);
16
+ request.headers.set("Content-Type", "application/json");
17
+ request.headers.set("Accept", "application/json");
18
+ request.headers.set("User-Agent", "arctic");
19
+ let response;
20
+ try {
21
+ response = await fetch(request);
22
+ }
23
+ catch {
24
+ throw new OAuthProviderError("Failed to fetch user profile");
25
+ }
26
+ if (!response.ok) {
27
+ if (response.body !== null) {
28
+ await response.body.cancel();
29
+ }
30
+ throw new OAuthProviderError(`User profile request failed with status ${response.status}`);
31
+ }
32
+ let body;
33
+ try {
34
+ body = await response.json();
35
+ }
36
+ catch {
37
+ throw new OAuthProviderError("User profile response was not valid JSON");
38
+ }
39
+ if (typeof body !== "object" || body === null) {
40
+ throw new OAuthProviderError("Unexpected user profile response body");
41
+ }
42
+ const errors = body.errors;
43
+ if (Array.isArray(errors) && errors.length > 0) {
44
+ const first = errors[0];
45
+ throw new OAuthProviderError(`User profile request failed: ${profileString(first.message) ?? "unknown error"}`);
46
+ }
47
+ const data = body.data;
48
+ if (typeof data !== "object" || data === null) {
49
+ throw new OAuthProviderError("Unexpected user profile response body");
50
+ }
51
+ const currentUser = data.currentUser;
52
+ if (typeof currentUser !== "object" || currentUser === null) {
53
+ throw new OAuthProviderError("Unexpected user profile response body");
54
+ }
55
+ return currentUser;
56
+ }
57
+ export class StartGG {
58
+ clientId;
59
+ clientSecret;
60
+ redirectURI;
61
+ auth = null;
62
+ constructor(clientIdOrOptions, clientSecret, redirectURI) {
63
+ if (typeof clientIdOrOptions === "object") {
64
+ this.auth = resolveAuthConfig(envPrefix, clientIdOrOptions, {
65
+ clientSecret: true,
66
+ redirectURI: true
67
+ });
68
+ this.clientId = this.auth.clientId;
69
+ this.clientSecret = this.auth.clientSecret ?? "";
70
+ this.redirectURI = this.auth.redirectURI ?? "";
71
+ }
72
+ else {
73
+ this.clientId = clientIdOrOptions;
74
+ this.clientSecret = clientSecret ?? "";
75
+ this.redirectURI = redirectURI ?? "";
76
+ }
77
+ }
78
+ createAuthorizationURL(state, scopes) {
79
+ const url = new URL(authorizationEndpoint);
80
+ url.searchParams.set("response_type", "code");
81
+ url.searchParams.set("client_id", this.clientId);
82
+ url.searchParams.set("state", state);
83
+ if (scopes.length > 0) {
84
+ url.searchParams.set("scope", scopes.join(" "));
85
+ }
86
+ url.searchParams.set("redirect_uri", this.redirectURI);
87
+ return url;
88
+ }
89
+ async validateAuthorizationCode(code, scopes) {
90
+ const body = new URLSearchParams();
91
+ body.set("grant_type", "authorization_code");
92
+ body.set("code", code);
93
+ body.set("redirect_uri", this.redirectURI);
94
+ body.set("client_id", this.clientId);
95
+ body.set("client_secret", this.clientSecret);
96
+ if (scopes.length > 0) {
97
+ body.set("scope", scopes.join(" "));
98
+ }
99
+ const request = createOAuth2Request(tokenEndpoint, body);
100
+ const tokens = await sendTokenRequest(request);
101
+ return tokens;
102
+ }
103
+ async refreshAccessToken(refreshToken, scopes) {
104
+ const body = new URLSearchParams();
105
+ body.set("grant_type", "refresh_token");
106
+ body.set("refresh_token", refreshToken);
107
+ body.set("redirect_uri", this.redirectURI);
108
+ body.set("client_id", this.clientId);
109
+ body.set("client_secret", this.clientSecret);
110
+ if (scopes.length > 0) {
111
+ body.set("scope", scopes.join(" "));
112
+ }
113
+ const request = createOAuth2Request(refreshEndpoint, body);
114
+ const tokens = await sendTokenRequest(request);
115
+ return tokens;
116
+ }
117
+ async getAuthorizationURL(scopes) {
118
+ const auth = requireAuthConfig(this.auth);
119
+ const state = generateOAuthState();
120
+ const resolved = resolveScopes(scopes, auth, defaultScopes);
121
+ const url = this.createAuthorizationURL(state, resolved);
122
+ await saveOAuthState(auth.store, state, { scopes: resolved });
123
+ return url;
124
+ }
125
+ async getUser(query) {
126
+ const auth = requireAuthConfig(this.auth);
127
+ const { code, state } = parseCallbackQuery(query);
128
+ const stored = await consumeOAuthState(auth.store, state);
129
+ const tokens = await this.validateAuthorizationCode(code, stored.scopes ?? resolveScopes(undefined, auth, defaultScopes));
130
+ const profile = await fetchCurrentUser(tokens.accessToken());
131
+ let image = null;
132
+ if (Array.isArray(profile.images) && profile.images.length > 0) {
133
+ const first = profile.images[0];
134
+ image = profileString(first.url);
135
+ }
136
+ return {
137
+ id: profileId(profile.id),
138
+ name: profileString(profile.name),
139
+ email: profileString(profile.email),
140
+ image
141
+ };
142
+ }
143
+ }
@@ -0,0 +1,17 @@
1
+ import type { OAuth2Tokens } from "../oauth2.js";
2
+ import type { OAuthCallbackQuery, OAuthUser, ProviderOptions } from "../auth.js";
3
+ export interface StravaOptions extends ProviderOptions {
4
+ }
5
+ export declare class Strava {
6
+ private clientId;
7
+ private clientSecret;
8
+ private redirectURI;
9
+ private auth;
10
+ constructor(options: StravaOptions);
11
+ constructor(clientId: string, clientSecret: string, redirectURI: string);
12
+ createAuthorizationURL(state: string, scopes: string[]): URL;
13
+ validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
14
+ refreshAccessToken(refreshToken: string): Promise<OAuth2Tokens>;
15
+ getAuthorizationURL(scopes?: string[]): Promise<URL>;
16
+ getUser(query: OAuthCallbackQuery): Promise<OAuthUser>;
17
+ }
@@ -0,0 +1,85 @@
1
+ import { createOAuth2Request, sendTokenRequest } from "../request.js";
2
+ import { consumeOAuthState, fetchUserProfile, generateOAuthState, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveScopes, saveOAuthState } from "../auth.js";
3
+ const authorizationEndpoint = "https://www.strava.com/oauth/authorize";
4
+ const tokenEndpoint = "https://www.strava.com/api/v3/oauth/token";
5
+ const userEndpoint = "https://www.strava.com/api/v3/athlete";
6
+ const envPrefix = "STRAVA";
7
+ const defaultScopes = ["read"];
8
+ export class Strava {
9
+ clientId;
10
+ clientSecret;
11
+ redirectURI;
12
+ auth = null;
13
+ constructor(clientIdOrOptions, clientSecret, redirectURI) {
14
+ if (typeof clientIdOrOptions === "object") {
15
+ this.auth = resolveAuthConfig(envPrefix, clientIdOrOptions, {
16
+ clientSecret: true,
17
+ redirectURI: true
18
+ });
19
+ this.clientId = this.auth.clientId;
20
+ this.clientSecret = this.auth.clientSecret ?? "";
21
+ this.redirectURI = this.auth.redirectURI ?? "";
22
+ }
23
+ else {
24
+ this.clientId = clientIdOrOptions;
25
+ this.clientSecret = clientSecret ?? "";
26
+ this.redirectURI = redirectURI ?? "";
27
+ }
28
+ }
29
+ createAuthorizationURL(state, scopes) {
30
+ const url = new URL(authorizationEndpoint);
31
+ url.searchParams.set("response_type", "code");
32
+ url.searchParams.set("client_id", this.clientId);
33
+ url.searchParams.set("state", state);
34
+ // Strava deviates from the RFC and uses a comma-delimitated string instead of space.
35
+ if (scopes.length > 0) {
36
+ url.searchParams.set("scope", scopes.join(","));
37
+ }
38
+ url.searchParams.set("redirect_uri", this.redirectURI);
39
+ return url;
40
+ }
41
+ async validateAuthorizationCode(code) {
42
+ const body = new URLSearchParams();
43
+ body.set("grant_type", "authorization_code");
44
+ body.set("code", code);
45
+ body.set("redirect_uri", this.redirectURI);
46
+ body.set("client_id", this.clientId);
47
+ body.set("client_secret", this.clientSecret);
48
+ const request = createOAuth2Request(tokenEndpoint, body);
49
+ const tokens = await sendTokenRequest(request);
50
+ return tokens;
51
+ }
52
+ async refreshAccessToken(refreshToken) {
53
+ const body = new URLSearchParams();
54
+ body.set("grant_type", "refresh_token");
55
+ body.set("refresh_token", refreshToken);
56
+ body.set("client_id", this.clientId);
57
+ body.set("client_secret", this.clientSecret);
58
+ const request = createOAuth2Request(tokenEndpoint, body);
59
+ const tokens = await sendTokenRequest(request);
60
+ return tokens;
61
+ }
62
+ async getAuthorizationURL(scopes) {
63
+ const auth = requireAuthConfig(this.auth);
64
+ const state = generateOAuthState();
65
+ const url = this.createAuthorizationURL(state, resolveScopes(scopes, auth, defaultScopes));
66
+ await saveOAuthState(auth.store, state, {});
67
+ return url;
68
+ }
69
+ async getUser(query) {
70
+ const auth = requireAuthConfig(this.auth);
71
+ const { code, state } = parseCallbackQuery(query);
72
+ await consumeOAuthState(auth.store, state);
73
+ const tokens = await this.validateAuthorizationCode(code);
74
+ const profile = await fetchUserProfile(userEndpoint, tokens.accessToken());
75
+ const firstName = profileString(profile.firstname);
76
+ const lastName = profileString(profile.lastname);
77
+ const name = [firstName, lastName].filter((part) => part !== null).join(" ");
78
+ return {
79
+ id: profileId(profile.id),
80
+ name: name !== "" ? name : null,
81
+ email: null,
82
+ image: profileString(profile.profile)
83
+ };
84
+ }
85
+ }
@@ -0,0 +1,9 @@
1
+ import type { OAuth2Tokens } from "../oauth2.js";
2
+ export declare class Synology {
3
+ private authorizationEndpoint;
4
+ private tokenEndpoint;
5
+ private client;
6
+ constructor(baseURL: string, applicationId: string, applicationSecret: string, redirectURI: string);
7
+ createAuthorizationURL(state: string, codeVerifier: string, scopes: string[]): URL;
8
+ validateAuthorizationCode(code: string, codeVerifier: string): Promise<OAuth2Tokens>;
9
+ }
@@ -0,0 +1,20 @@
1
+ import { CodeChallengeMethod, OAuth2Client } from "../client.js";
2
+ import { joinURIAndPath } from "../request.js";
3
+ export class Synology {
4
+ authorizationEndpoint;
5
+ tokenEndpoint;
6
+ client;
7
+ constructor(baseURL, applicationId, applicationSecret, redirectURI) {
8
+ this.authorizationEndpoint = joinURIAndPath(baseURL, "/webman/sso/SSOOauth.cgi");
9
+ this.tokenEndpoint = joinURIAndPath(baseURL, "/webman/sso/SSOAccessToken.cgi");
10
+ this.client = new OAuth2Client(applicationId, applicationSecret, redirectURI);
11
+ }
12
+ createAuthorizationURL(state, codeVerifier, scopes) {
13
+ const url = this.client.createAuthorizationURLWithPKCE(this.authorizationEndpoint, state, CodeChallengeMethod.S256, codeVerifier, scopes);
14
+ return url;
15
+ }
16
+ async validateAuthorizationCode(code, codeVerifier) {
17
+ const tokens = await this.client.validateAuthorizationCode(this.tokenEndpoint, code, codeVerifier);
18
+ return tokens;
19
+ }
20
+ }
@@ -0,0 +1,18 @@
1
+ import type { OAuth2Tokens } from "../oauth2.js";
2
+ import type { OAuthCallbackQuery, OAuthUser, ProviderOptions } from "../auth.js";
3
+ export interface TikTokOptions extends ProviderOptions {
4
+ }
5
+ export declare class TikTok {
6
+ private clientKey;
7
+ private clientSecret;
8
+ private redirectURI;
9
+ private auth;
10
+ constructor(options: TikTokOptions);
11
+ constructor(clientKey: string, clientSecret: string, redirectURI: string);
12
+ createAuthorizationURL(state: string, codeVerifier: string, scopes: string[]): URL;
13
+ validateAuthorizationCode(code: string, codeVerifier: string): Promise<OAuth2Tokens>;
14
+ refreshAccessToken(refreshToken: string): Promise<OAuth2Tokens>;
15
+ revokeToken(token: string): Promise<void>;
16
+ getAuthorizationURL(scopes?: string[]): Promise<URL>;
17
+ getUser(query: OAuthCallbackQuery): Promise<OAuthUser>;
18
+ }
@@ -0,0 +1,109 @@
1
+ import { createS256CodeChallenge } from "../oauth2.js";
2
+ import { createOAuth2Request, sendTokenRequest, sendTokenRevocationRequest } from "../request.js";
3
+ import { consumeOAuthState, fetchUserProfile, generateOAuthCodeVerifier, generateOAuthState, InvalidOAuthCallbackError, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveScopes, saveOAuthState } from "../auth.js";
4
+ const authorizationEndpoint = "https://www.tiktok.com/v2/auth/authorize";
5
+ const tokenEndpoint = "https://open.tiktokapis.com/v2/oauth/token/";
6
+ const tokenRevocationEndpoint = "https://open.tiktokapis.com/v2/oauth/revoke/";
7
+ const userEndpoint = "https://open.tiktokapis.com/v2/user/info/";
8
+ const envPrefix = "TIKTOK";
9
+ const defaultScopes = ["user.info.basic"];
10
+ export class TikTok {
11
+ clientKey;
12
+ clientSecret;
13
+ redirectURI;
14
+ auth = null;
15
+ constructor(clientKeyOrOptions, clientSecret, redirectURI) {
16
+ if (typeof clientKeyOrOptions === "object") {
17
+ this.auth = resolveAuthConfig(envPrefix, clientKeyOrOptions, {
18
+ clientSecret: true,
19
+ redirectURI: true
20
+ });
21
+ this.clientKey = this.auth.clientId;
22
+ this.clientSecret = this.auth.clientSecret ?? "";
23
+ this.redirectURI = this.auth.redirectURI ?? "";
24
+ }
25
+ else {
26
+ this.clientKey = clientKeyOrOptions;
27
+ this.clientSecret = clientSecret ?? "";
28
+ this.redirectURI = redirectURI ?? "";
29
+ }
30
+ }
31
+ createAuthorizationURL(state, codeVerifier, scopes) {
32
+ const url = new URL(authorizationEndpoint);
33
+ url.searchParams.set("response_type", "code");
34
+ url.searchParams.set("client_key", this.clientKey);
35
+ url.searchParams.set("state", state);
36
+ const codeChallenge = createS256CodeChallenge(codeVerifier);
37
+ url.searchParams.set("code_challenge_method", "S256");
38
+ url.searchParams.set("code_challenge", codeChallenge);
39
+ if (scopes.length > 0) {
40
+ url.searchParams.set("scope", scopes.join(","));
41
+ }
42
+ url.searchParams.set("redirect_uri", this.redirectURI);
43
+ return url;
44
+ }
45
+ async validateAuthorizationCode(code, codeVerifier) {
46
+ const body = new URLSearchParams();
47
+ body.set("grant_type", "authorization_code");
48
+ body.set("code", code);
49
+ body.set("redirect_uri", this.redirectURI);
50
+ body.set("code_verifier", codeVerifier);
51
+ body.set("client_key", this.clientKey);
52
+ body.set("client_secret", this.clientSecret);
53
+ const request = createOAuth2Request(tokenEndpoint, body);
54
+ const tokens = await sendTokenRequest(request);
55
+ return tokens;
56
+ }
57
+ async refreshAccessToken(refreshToken) {
58
+ const body = new URLSearchParams();
59
+ body.set("grant_type", "refresh_token");
60
+ body.set("refresh_token", refreshToken);
61
+ body.set("client_key", this.clientKey);
62
+ body.set("client_secret", this.clientSecret);
63
+ const request = createOAuth2Request(tokenEndpoint, body);
64
+ const tokens = await sendTokenRequest(request);
65
+ return tokens;
66
+ }
67
+ async revokeToken(token) {
68
+ const body = new URLSearchParams();
69
+ body.set("token", token);
70
+ body.set("client_key", this.clientKey);
71
+ body.set("client_secret", this.clientSecret);
72
+ const request = createOAuth2Request(tokenRevocationEndpoint, body);
73
+ await sendTokenRevocationRequest(request);
74
+ }
75
+ async getAuthorizationURL(scopes) {
76
+ const auth = requireAuthConfig(this.auth);
77
+ const state = generateOAuthState();
78
+ const codeVerifier = generateOAuthCodeVerifier();
79
+ const url = this.createAuthorizationURL(state, codeVerifier, resolveScopes(scopes, auth, defaultScopes));
80
+ await saveOAuthState(auth.store, state, { codeVerifier });
81
+ return url;
82
+ }
83
+ async getUser(query) {
84
+ const auth = requireAuthConfig(this.auth);
85
+ const { code, state } = parseCallbackQuery(query);
86
+ const stored = await consumeOAuthState(auth.store, state);
87
+ if (typeof stored.codeVerifier !== "string") {
88
+ throw new InvalidOAuthCallbackError("Missing PKCE code verifier for OAuth state");
89
+ }
90
+ const tokens = await this.validateAuthorizationCode(code, stored.codeVerifier);
91
+ const url = new URL(userEndpoint);
92
+ url.searchParams.set("fields", "open_id,display_name,avatar_url");
93
+ const profile = await fetchUserProfile(url, tokens.accessToken());
94
+ let user = {};
95
+ if (typeof profile.data === "object" && profile.data !== null) {
96
+ const inner = profile.data.user;
97
+ if (typeof inner === "object" && inner !== null) {
98
+ user = inner;
99
+ }
100
+ }
101
+ // TikTok does not expose an email address.
102
+ return {
103
+ id: profileId(user.open_id),
104
+ name: profileString(user.display_name),
105
+ email: null,
106
+ image: profileString(user.avatar_url)
107
+ };
108
+ }
109
+ }
@@ -0,0 +1,17 @@
1
+ import type { OAuth2Tokens } from "../oauth2.js";
2
+ import type { OAuthCallbackQuery, OAuthUser, ProviderOptions } from "../auth.js";
3
+ export interface TiltifyOptions extends ProviderOptions {
4
+ }
5
+ export declare class Tiltify {
6
+ private clientId;
7
+ private clientSecret;
8
+ private redirectURI;
9
+ private auth;
10
+ constructor(options: TiltifyOptions);
11
+ constructor(clientId: string, clientSecret: string, redirectURI: string);
12
+ createAuthorizationURL(state: string, scopes: string[]): URL;
13
+ validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
14
+ refreshAccessToken(refreshToken: string): Promise<OAuth2Tokens>;
15
+ getAuthorizationURL(scopes?: string[]): Promise<URL>;
16
+ getUser(query: OAuthCallbackQuery): Promise<OAuthUser>;
17
+ }
@@ -0,0 +1,90 @@
1
+ import { createOAuth2Request, sendTokenRequest } from "../request.js";
2
+ import { consumeOAuthState, fetchUserProfile, generateOAuthState, parseCallbackQuery, profileId, profileString, requireAuthConfig, resolveAuthConfig, resolveScopes, saveOAuthState } from "../auth.js";
3
+ const authorizationEndpoint = "https://v5api.tiltify.com/oauth/authorize";
4
+ const tokenEndpoint = "https://v5api.tiltify.com/oauth/token";
5
+ const userEndpoint = "https://v5api.tiltify.com/api/public/current-user";
6
+ const envPrefix = "TILTIFY";
7
+ const defaultScopes = ["public"];
8
+ export class Tiltify {
9
+ clientId;
10
+ clientSecret;
11
+ redirectURI;
12
+ auth = null;
13
+ constructor(clientIdOrOptions, clientSecret, redirectURI) {
14
+ if (typeof clientIdOrOptions === "object") {
15
+ this.auth = resolveAuthConfig(envPrefix, clientIdOrOptions, {
16
+ clientSecret: true,
17
+ redirectURI: true
18
+ });
19
+ this.clientId = this.auth.clientId;
20
+ this.clientSecret = this.auth.clientSecret ?? "";
21
+ this.redirectURI = this.auth.redirectURI ?? "";
22
+ }
23
+ else {
24
+ this.clientId = clientIdOrOptions;
25
+ this.clientSecret = clientSecret ?? "";
26
+ this.redirectURI = redirectURI ?? "";
27
+ }
28
+ }
29
+ createAuthorizationURL(state, scopes) {
30
+ const url = new URL(authorizationEndpoint);
31
+ url.searchParams.set("response_type", "code");
32
+ url.searchParams.set("client_id", this.clientId);
33
+ url.searchParams.set("state", state);
34
+ if (scopes.length > 0) {
35
+ url.searchParams.set("scope", scopes.join(" "));
36
+ }
37
+ url.searchParams.set("redirect_uri", this.redirectURI);
38
+ return url;
39
+ }
40
+ async validateAuthorizationCode(code) {
41
+ const body = new URLSearchParams();
42
+ body.set("grant_type", "authorization_code");
43
+ body.set("code", code);
44
+ body.set("redirect_uri", this.redirectURI);
45
+ body.set("client_id", this.clientId);
46
+ body.set("client_secret", this.clientSecret);
47
+ const request = createOAuth2Request(tokenEndpoint, body);
48
+ const tokens = await sendTokenRequest(request);
49
+ return tokens;
50
+ }
51
+ async refreshAccessToken(refreshToken) {
52
+ const body = new URLSearchParams();
53
+ body.set("grant_type", "refresh_token");
54
+ body.set("refresh_token", refreshToken);
55
+ body.set("client_id", this.clientId);
56
+ body.set("client_secret", this.clientSecret);
57
+ const request = createOAuth2Request(tokenEndpoint, body);
58
+ const tokens = await sendTokenRequest(request);
59
+ return tokens;
60
+ }
61
+ async getAuthorizationURL(scopes) {
62
+ const auth = requireAuthConfig(this.auth);
63
+ const state = generateOAuthState();
64
+ const url = this.createAuthorizationURL(state, resolveScopes(scopes, auth, defaultScopes));
65
+ await saveOAuthState(auth.store, state, {});
66
+ return url;
67
+ }
68
+ async getUser(query) {
69
+ const auth = requireAuthConfig(this.auth);
70
+ const { code, state } = parseCallbackQuery(query);
71
+ await consumeOAuthState(auth.store, state);
72
+ const tokens = await this.validateAuthorizationCode(code);
73
+ const profile = await fetchUserProfile(userEndpoint, tokens.accessToken());
74
+ let user = {};
75
+ if (typeof profile.data === "object" && profile.data !== null) {
76
+ user = profile.data;
77
+ }
78
+ let image = null;
79
+ if (typeof user.avatar === "object" && user.avatar !== null) {
80
+ image = profileString(user.avatar.src);
81
+ }
82
+ // Tiltify does not expose an email address on the public current-user endpoint.
83
+ return {
84
+ id: profileId(user.id),
85
+ name: profileString(user.username),
86
+ email: null,
87
+ image
88
+ };
89
+ }
90
+ }
@@ -0,0 +1,15 @@
1
+ import type { OAuth2Tokens } from "../oauth2.js";
2
+ import type { OAuthCallbackQuery, OAuthUser, ProviderOptions } from "../auth.js";
3
+ export interface TumblrOptions extends ProviderOptions {
4
+ }
5
+ export declare class Tumblr {
6
+ private client;
7
+ private auth;
8
+ constructor(options: TumblrOptions);
9
+ constructor(clientId: string, clientSecret: string, redirectURI: string);
10
+ createAuthorizationURL(state: string, scopes: string[]): URL;
11
+ validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
12
+ refreshAccessToken(refreshToken: string): Promise<OAuth2Tokens>;
13
+ getAuthorizationURL(scopes?: string[]): Promise<URL>;
14
+ getUser(query: OAuthCallbackQuery): Promise<OAuthUser>;
15
+ }