@rudderjs/socialite 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Suleiman Shahbari
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # @rudderjs/socialite
2
+
3
+ OAuth authentication for RudderJS. Built-in providers: GitHub, Google, Facebook, Apple. Extensible with custom providers.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @rudderjs/socialite
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ ```ts
14
+ // config/socialite.ts
15
+ import { Env } from '@rudderjs/core'
16
+
17
+ export default {
18
+ github: {
19
+ clientId: Env.get('GITHUB_CLIENT_ID', ''),
20
+ clientSecret: Env.get('GITHUB_CLIENT_SECRET', ''),
21
+ redirectUrl: Env.get('GITHUB_REDIRECT_URL', 'http://localhost:3000/auth/github/callback'),
22
+ },
23
+ google: {
24
+ clientId: Env.get('GOOGLE_CLIENT_ID', ''),
25
+ clientSecret: Env.get('GOOGLE_CLIENT_SECRET', ''),
26
+ redirectUrl: Env.get('GOOGLE_REDIRECT_URL', 'http://localhost:3000/auth/google/callback'),
27
+ },
28
+ }
29
+
30
+ // bootstrap/providers.ts
31
+ import { socialite } from '@rudderjs/socialite'
32
+ export default [..., socialite(configs.socialite)]
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ ```ts
38
+ import { Socialite } from '@rudderjs/socialite'
39
+ import { Auth } from '@rudderjs/auth'
40
+
41
+ // Redirect to provider
42
+ Route.get('/auth/github', () => {
43
+ return Socialite.driver('github').redirect()
44
+ })
45
+
46
+ // Handle callback
47
+ Route.get('/auth/github/callback', async (req) => {
48
+ const socialUser = await Socialite.driver('github').user(req)
49
+
50
+ socialUser.getId() // "12345"
51
+ socialUser.getName() // "John Doe"
52
+ socialUser.getEmail() // "john@example.com"
53
+ socialUser.getAvatar() // "https://..."
54
+ socialUser.getNickname() // "johnd"
55
+ socialUser.token // "gho_abc123..."
56
+
57
+ // Find or create local user, then login
58
+ const user = await User.firstOrCreate(
59
+ { githubId: socialUser.getId() },
60
+ { name: socialUser.getName(), email: socialUser.getEmail() },
61
+ )
62
+ await Auth.login(user)
63
+ return Response.redirect('/')
64
+ })
65
+ ```
66
+
67
+ ## Providers
68
+
69
+ | Provider | Driver | Auth URL |
70
+ |----------|--------|----------|
71
+ | GitHub | `github` | `github.com/login/oauth/authorize` |
72
+ | Google | `google` | `accounts.google.com/o/oauth2/v2/auth` |
73
+ | Facebook | `facebook` | `facebook.com/v19.0/dialog/oauth` |
74
+ | Apple | `apple` | `appleid.apple.com/auth/authorize` |
75
+
76
+ ## Custom Providers
77
+
78
+ ```ts
79
+ import { SocialiteProvider, SocialUser, Socialite } from '@rudderjs/socialite'
80
+
81
+ class GitLabProvider extends SocialiteProvider {
82
+ protected defaultScopes() { return ['read_user'] }
83
+ protected authUrl() { return 'https://gitlab.com/oauth/authorize' }
84
+ protected tokenUrl() { return 'https://gitlab.com/oauth/token' }
85
+ protected userUrl() { return 'https://gitlab.com/api/v4/user' }
86
+
87
+ protected mapToUser(data: Record<string, unknown>, token: string, refreshToken: string | null) {
88
+ return new SocialUser({
89
+ id: String(data['id']), name: data['name'] as string,
90
+ email: data['email'] as string, avatar: data['avatar_url'] as string,
91
+ nickname: data['username'] as string, token, refreshToken, raw: data,
92
+ })
93
+ }
94
+ }
95
+
96
+ Socialite.extend('gitlab', (config) => new GitLabProvider(config))
97
+ ```
98
+
99
+ ## Scopes
100
+
101
+ ```ts
102
+ // Add scopes
103
+ Socialite.driver('github').withScopes(['repo'])
104
+
105
+ // Replace scopes entirely
106
+ Socialite.driver('github').setScopes(['read:user'])
107
+ ```
@@ -0,0 +1,17 @@
1
+ import { SocialiteProvider } from '../provider.js';
2
+ import { SocialUser } from '../social-user.js';
3
+ export declare class AppleProvider extends SocialiteProvider {
4
+ protected defaultScopes(): string[];
5
+ protected authUrl(): string;
6
+ protected tokenUrl(): string;
7
+ protected userUrl(): string;
8
+ getRedirectUrl(state?: string): string;
9
+ protected mapToUser(data: Record<string, unknown>, token: string, refreshToken: string | null): SocialUser;
10
+ /** Apple sends user data as form POST on callback. Parse the id_token JWT for user info. */
11
+ user(codeOrRequest: string | {
12
+ query: Record<string, string>;
13
+ body?: unknown;
14
+ }): Promise<SocialUser>;
15
+ private getIdToken;
16
+ }
17
+ //# sourceMappingURL=apple.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apple.d.ts","sourceRoot":"","sources":["../../src/drivers/apple.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,qBAAa,aAAc,SAAQ,iBAAiB;IAClD,SAAS,CAAC,aAAa,IAAI,MAAM,EAAE;IACnC,SAAS,CAAC,OAAO,IAAK,MAAM;IAC5B,SAAS,CAAC,QAAQ,IAAI,MAAM;IAC5B,SAAS,CAAC,OAAO,IAAK,MAAM;IAE5B,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;IAYtC,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,UAAU;IAkB1G,4FAA4F;IACtF,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;YA0B5F,UAAU;CAwBzB"}
@@ -0,0 +1,86 @@
1
+ import { SocialiteProvider } from '../provider.js';
2
+ import { SocialUser } from '../social-user.js';
3
+ export class AppleProvider extends SocialiteProvider {
4
+ defaultScopes() { return ['name', 'email']; }
5
+ authUrl() { return 'https://appleid.apple.com/auth/authorize'; }
6
+ tokenUrl() { return 'https://appleid.apple.com/auth/token'; }
7
+ userUrl() { return ''; } // Apple sends user data in the callback, not a separate endpoint
8
+ getRedirectUrl(state) {
9
+ const params = new URLSearchParams({
10
+ client_id: this.config.clientId,
11
+ redirect_uri: this.config.redirectUrl,
12
+ response_type: 'code',
13
+ response_mode: 'form_post',
14
+ scope: this.scopes.join(' '),
15
+ ...(state ? { state } : {}),
16
+ });
17
+ return `${this.authUrl()}?${params.toString()}`;
18
+ }
19
+ mapToUser(data, token, refreshToken) {
20
+ // Apple's id_token contains the user info as a JWT
21
+ const sub = data['sub'] ?? '';
22
+ const email = data['email'] ?? null;
23
+ const name = data['name'];
24
+ return new SocialUser({
25
+ id: sub,
26
+ name: name ? [name.firstName, name.lastName].filter(Boolean).join(' ') || null : null,
27
+ email,
28
+ avatar: null, // Apple doesn't provide avatars
29
+ nickname: null,
30
+ token,
31
+ refreshToken,
32
+ raw: data,
33
+ });
34
+ }
35
+ /** Apple sends user data as form POST on callback. Parse the id_token JWT for user info. */
36
+ async user(codeOrRequest) {
37
+ const code = typeof codeOrRequest === 'string'
38
+ ? codeOrRequest
39
+ : (codeOrRequest.query['code'] ?? codeOrRequest.body?.['code']);
40
+ if (!code)
41
+ throw new Error('[RudderJS Socialite] Missing authorization code.');
42
+ const { accessToken, refreshToken } = await this.getAccessToken(code);
43
+ // Decode id_token (JWT) for user info — no verification needed here,
44
+ // Apple's token endpoint is trusted.
45
+ const idToken = (await this.getIdToken(code)) ?? {};
46
+ const userData = { ...idToken };
47
+ // Apple sends user name only on first authorization (as form POST body)
48
+ if (typeof codeOrRequest !== 'string' && codeOrRequest.body) {
49
+ const body = codeOrRequest.body;
50
+ if (body['user']) {
51
+ const user = typeof body['user'] === 'string' ? JSON.parse(body['user']) : body['user'];
52
+ userData['name'] = user;
53
+ }
54
+ }
55
+ return this.mapToUser(userData, accessToken, refreshToken);
56
+ }
57
+ async getIdToken(code) {
58
+ try {
59
+ const res = await fetch(this.tokenUrl(), {
60
+ method: 'POST',
61
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
62
+ body: new URLSearchParams({
63
+ client_id: this.config.clientId,
64
+ client_secret: this.config.clientSecret,
65
+ code,
66
+ redirect_uri: this.config.redirectUrl,
67
+ grant_type: 'authorization_code',
68
+ }),
69
+ });
70
+ if (!res.ok)
71
+ return null;
72
+ const data = await res.json();
73
+ if (!data.id_token)
74
+ return null;
75
+ // Decode JWT payload (base64url)
76
+ const payload = data.id_token.split('.')[1];
77
+ if (!payload)
78
+ return null;
79
+ return JSON.parse(Buffer.from(payload, 'base64url').toString('utf8'));
80
+ }
81
+ catch {
82
+ return null;
83
+ }
84
+ }
85
+ }
86
+ //# sourceMappingURL=apple.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apple.js","sourceRoot":"","sources":["../../src/drivers/apple.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { SocialiteProvider } from '../provider.js';
2
+ import { SocialUser } from '../social-user.js';
3
+ export declare class FacebookProvider extends SocialiteProvider {
4
+ protected defaultScopes(): string[];
5
+ protected authUrl(): string;
6
+ protected tokenUrl(): string;
7
+ protected userUrl(): string;
8
+ protected mapToUser(data: Record<string, unknown>, token: string, refreshToken: string | null): SocialUser;
9
+ }
10
+ //# sourceMappingURL=facebook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"facebook.d.ts","sourceRoot":"","sources":["../../src/drivers/facebook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,qBAAa,gBAAiB,SAAQ,iBAAiB;IACrD,SAAS,CAAC,aAAa,IAAI,MAAM,EAAE;IACnC,SAAS,CAAC,OAAO,IAAK,MAAM;IAC5B,SAAS,CAAC,QAAQ,IAAI,MAAM;IAC5B,SAAS,CAAC,OAAO,IAAK,MAAM;IAE5B,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,UAAU;CAa3G"}
@@ -0,0 +1,22 @@
1
+ import { SocialiteProvider } from '../provider.js';
2
+ import { SocialUser } from '../social-user.js';
3
+ export class FacebookProvider extends SocialiteProvider {
4
+ defaultScopes() { return ['email', 'public_profile']; }
5
+ authUrl() { return 'https://www.facebook.com/v19.0/dialog/oauth'; }
6
+ tokenUrl() { return 'https://graph.facebook.com/v19.0/oauth/access_token'; }
7
+ userUrl() { return 'https://graph.facebook.com/v19.0/me?fields=id,name,email,picture.type(large)'; }
8
+ mapToUser(data, token, refreshToken) {
9
+ const picture = data['picture'];
10
+ return new SocialUser({
11
+ id: String(data['id'] ?? ''),
12
+ name: data['name'] ?? null,
13
+ email: data['email'] ?? null,
14
+ avatar: picture?.data?.url ?? null,
15
+ nickname: null,
16
+ token,
17
+ refreshToken,
18
+ raw: data,
19
+ });
20
+ }
21
+ }
22
+ //# sourceMappingURL=facebook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"facebook.js","sourceRoot":"","sources":["../../src/drivers/facebook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,MAAM,OAAO,gBAAiB,SAAQ,iBAAiB;IAC3C,aAAa,KAAe,OAAO,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAA,CAAC,CAAC;IAChE,OAAO,KAAc,OAAO,6CAA6C,CAAA,CAAC,CAAC;IAC3E,QAAQ,KAAa,OAAO,qDAAqD,CAAA,CAAC,CAAC;IACnF,OAAO,KAAc,OAAO,8EAA8E,CAAA,CAAC,CAAC;IAE5G,SAAS,CAAC,IAA6B,EAAE,KAAa,EAAE,YAA2B;QAC3F,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAA4C,CAAA;QAC1E,OAAO,IAAI,UAAU,CAAC;YACpB,EAAE,EAAQ,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAClC,IAAI,EAAO,IAAI,CAAC,MAAM,CAAmB,IAAI,IAAI;YACjD,KAAK,EAAM,IAAI,CAAC,OAAO,CAAmB,IAAI,IAAI;YAClD,MAAM,EAAI,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,IAAI;YACpC,QAAQ,EAAE,IAAI;YACd,KAAK;YACL,YAAY;YACZ,GAAG,EAAE,IAAI;SACV,CAAC,CAAA;IACJ,CAAC;CACF"}
@@ -0,0 +1,15 @@
1
+ import { SocialiteProvider } from '../provider.js';
2
+ import { SocialUser } from '../social-user.js';
3
+ export declare class GitHubProvider extends SocialiteProvider {
4
+ protected defaultScopes(): string[];
5
+ protected authUrl(): string;
6
+ protected tokenUrl(): string;
7
+ protected userUrl(): string;
8
+ protected mapToUser(data: Record<string, unknown>, token: string, refreshToken: string | null): SocialUser;
9
+ /** GitHub may not return email in the user endpoint if it's private. Fetch from /user/emails. */
10
+ user(codeOrRequest: string | {
11
+ query: Record<string, string>;
12
+ }): Promise<SocialUser>;
13
+ private fetchPrimaryEmail;
14
+ }
15
+ //# sourceMappingURL=github.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/drivers/github.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,qBAAa,cAAe,SAAQ,iBAAiB;IACnD,SAAS,CAAC,aAAa,IAAI,MAAM,EAAE;IACnC,SAAS,CAAC,OAAO,IAAK,MAAM;IAC5B,SAAS,CAAC,QAAQ,IAAI,MAAM;IAC5B,SAAS,CAAC,OAAO,IAAK,MAAM;IAE5B,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,UAAU;IAa1G,iGAAiG;IAC3F,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;YAoB5E,iBAAiB;CAahC"}
@@ -0,0 +1,56 @@
1
+ import { SocialiteProvider } from '../provider.js';
2
+ import { SocialUser } from '../social-user.js';
3
+ export class GitHubProvider extends SocialiteProvider {
4
+ defaultScopes() { return ['read:user', 'user:email']; }
5
+ authUrl() { return 'https://github.com/login/oauth/authorize'; }
6
+ tokenUrl() { return 'https://github.com/login/oauth/access_token'; }
7
+ userUrl() { return 'https://api.github.com/user'; }
8
+ mapToUser(data, token, refreshToken) {
9
+ return new SocialUser({
10
+ id: String(data['id'] ?? ''),
11
+ name: data['name'] ?? null,
12
+ email: data['email'] ?? null,
13
+ avatar: data['avatar_url'] ?? null,
14
+ nickname: data['login'] ?? null,
15
+ token,
16
+ refreshToken,
17
+ raw: data,
18
+ });
19
+ }
20
+ /** GitHub may not return email in the user endpoint if it's private. Fetch from /user/emails. */
21
+ async user(codeOrRequest) {
22
+ const socialUser = await super.user(codeOrRequest);
23
+ if (!socialUser.getEmail()) {
24
+ const email = await this.fetchPrimaryEmail(socialUser.token);
25
+ if (email) {
26
+ return new SocialUser({
27
+ id: socialUser.getId(),
28
+ name: socialUser.getName(),
29
+ email,
30
+ avatar: socialUser.getAvatar(),
31
+ nickname: socialUser.getNickname(),
32
+ token: socialUser.token,
33
+ refreshToken: socialUser.refreshToken,
34
+ raw: { ...socialUser.getRaw(), email },
35
+ });
36
+ }
37
+ }
38
+ return socialUser;
39
+ }
40
+ async fetchPrimaryEmail(token) {
41
+ try {
42
+ const res = await fetch('https://api.github.com/user/emails', {
43
+ headers: { 'Authorization': `Bearer ${token}`, 'Accept': 'application/json' },
44
+ });
45
+ if (!res.ok)
46
+ return null;
47
+ const emails = await res.json();
48
+ const primary = emails.find(e => e.primary && e.verified);
49
+ return primary?.email ?? emails[0]?.email ?? null;
50
+ }
51
+ catch {
52
+ return null;
53
+ }
54
+ }
55
+ }
56
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/drivers/github.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,MAAM,OAAO,cAAe,SAAQ,iBAAiB;IACzC,aAAa,KAAe,OAAO,CAAC,WAAW,EAAE,YAAY,CAAC,CAAA,CAAC,CAAC;IAChE,OAAO,KAAc,OAAO,0CAA0C,CAAA,CAAC,CAAC;IACxE,QAAQ,KAAa,OAAO,6CAA6C,CAAA,CAAC,CAAC;IAC3E,OAAO,KAAc,OAAO,6BAA6B,CAAA,CAAC,CAAC;IAE3D,SAAS,CAAC,IAA6B,EAAE,KAAa,EAAE,YAA2B;QAC3F,OAAO,IAAI,UAAU,CAAC;YACpB,EAAE,EAAQ,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAClC,IAAI,EAAO,IAAI,CAAC,MAAM,CAAmB,IAAI,IAAI;YACjD,KAAK,EAAM,IAAI,CAAC,OAAO,CAAmB,IAAI,IAAI;YAClD,MAAM,EAAK,IAAI,CAAC,YAAY,CAAmB,IAAI,IAAI;YACvD,QAAQ,EAAG,IAAI,CAAC,OAAO,CAAmB,IAAI,IAAI;YAClD,KAAK;YACL,YAAY;YACZ,GAAG,EAAE,IAAI;SACV,CAAC,CAAA;IACJ,CAAC;IAED,iGAAiG;IACjG,KAAK,CAAC,IAAI,CAAC,aAAyD;QAClE,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;QAClD,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;YAC5D,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,IAAI,UAAU,CAAC;oBACpB,EAAE,EAAQ,UAAU,CAAC,KAAK,EAAE;oBAC5B,IAAI,EAAM,UAAU,CAAC,OAAO,EAAE;oBAC9B,KAAK;oBACL,MAAM,EAAI,UAAU,CAAC,SAAS,EAAE;oBAChC,QAAQ,EAAE,UAAU,CAAC,WAAW,EAAE;oBAClC,KAAK,EAAK,UAAU,CAAC,KAAK;oBAC1B,YAAY,EAAE,UAAU,CAAC,YAAY;oBACrC,GAAG,EAAE,EAAE,GAAG,UAAU,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE;iBACvC,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;QACD,OAAO,UAAU,CAAA;IACnB,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,KAAa;QAC3C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,oCAAoC,EAAE;gBAC5D,OAAO,EAAE,EAAE,eAAe,EAAE,UAAU,KAAK,EAAE,EAAE,QAAQ,EAAE,kBAAkB,EAAE;aAC9E,CAAC,CAAA;YACF,IAAI,CAAC,GAAG,CAAC,EAAE;gBAAE,OAAO,IAAI,CAAA;YACxB,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,EAA8D,CAAA;YAC3F,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAA;YACzD,OAAO,OAAO,EAAE,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,IAAI,CAAA;QACnD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ import { SocialiteProvider } from '../provider.js';
2
+ import { SocialUser } from '../social-user.js';
3
+ export declare class GoogleProvider extends SocialiteProvider {
4
+ protected defaultScopes(): string[];
5
+ protected authUrl(): string;
6
+ protected tokenUrl(): string;
7
+ protected userUrl(): string;
8
+ protected mapToUser(data: Record<string, unknown>, token: string, refreshToken: string | null): SocialUser;
9
+ }
10
+ //# sourceMappingURL=google.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../src/drivers/google.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,qBAAa,cAAe,SAAQ,iBAAiB;IACnD,SAAS,CAAC,aAAa,IAAI,MAAM,EAAE;IACnC,SAAS,CAAC,OAAO,IAAK,MAAM;IAC5B,SAAS,CAAC,QAAQ,IAAI,MAAM;IAC5B,SAAS,CAAC,OAAO,IAAK,MAAM;IAE5B,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,UAAU;CAY3G"}
@@ -0,0 +1,21 @@
1
+ import { SocialiteProvider } from '../provider.js';
2
+ import { SocialUser } from '../social-user.js';
3
+ export class GoogleProvider extends SocialiteProvider {
4
+ defaultScopes() { return ['openid', 'profile', 'email']; }
5
+ authUrl() { return 'https://accounts.google.com/o/oauth2/v2/auth'; }
6
+ tokenUrl() { return 'https://oauth2.googleapis.com/token'; }
7
+ userUrl() { return 'https://www.googleapis.com/oauth2/v3/userinfo'; }
8
+ mapToUser(data, token, refreshToken) {
9
+ return new SocialUser({
10
+ id: String(data['sub'] ?? ''),
11
+ name: data['name'] ?? null,
12
+ email: data['email'] ?? null,
13
+ avatar: data['picture'] ?? null,
14
+ nickname: null,
15
+ token,
16
+ refreshToken,
17
+ raw: data,
18
+ });
19
+ }
20
+ }
21
+ //# sourceMappingURL=google.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google.js","sourceRoot":"","sources":["../../src/drivers/google.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,MAAM,OAAO,cAAe,SAAQ,iBAAiB;IACzC,aAAa,KAAe,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,CAAA,CAAC,CAAC;IACnE,OAAO,KAAc,OAAO,8CAA8C,CAAA,CAAC,CAAC;IAC5E,QAAQ,KAAa,OAAO,qCAAqC,CAAA,CAAC,CAAC;IACnE,OAAO,KAAc,OAAO,+CAA+C,CAAA,CAAC,CAAC;IAE7E,SAAS,CAAC,IAA6B,EAAE,KAAa,EAAE,YAA2B;QAC3F,OAAO,IAAI,UAAU,CAAC;YACpB,EAAE,EAAQ,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,EAAO,IAAI,CAAC,MAAM,CAAmB,IAAI,IAAI;YACjD,KAAK,EAAM,IAAI,CAAC,OAAO,CAAmB,IAAI,IAAI;YAClD,MAAM,EAAK,IAAI,CAAC,SAAS,CAAmB,IAAI,IAAI;YACpD,QAAQ,EAAE,IAAI;YACd,KAAK;YACL,YAAY;YACZ,GAAG,EAAE,IAAI;SACV,CAAC,CAAA;IACJ,CAAC;CACF"}
@@ -0,0 +1,35 @@
1
+ import { ServiceProvider, type Application } from '@rudderjs/core';
2
+ import { SocialiteProvider, type SocialiteProviderConfig } from './provider.js';
3
+ export { SocialUser } from './social-user.js';
4
+ export { SocialiteProvider } from './provider.js';
5
+ export { GitHubProvider } from './drivers/github.js';
6
+ export { GoogleProvider } from './drivers/google.js';
7
+ export { FacebookProvider } from './drivers/facebook.js';
8
+ export { AppleProvider } from './drivers/apple.js';
9
+ export type { SocialiteProviderConfig } from './provider.js';
10
+ type ProviderFactory = (config: SocialiteProviderConfig) => SocialiteProvider;
11
+ export declare class Socialite {
12
+ private static _config;
13
+ private static _custom;
14
+ private static _instances;
15
+ /** Get or create a provider instance by name. */
16
+ static driver(name: string): SocialiteProvider;
17
+ /** Register a custom provider driver. */
18
+ static extend(name: string, factory: ProviderFactory): void;
19
+ /** @internal — set config from the service provider. */
20
+ static configure(config: SocialiteConfig): void;
21
+ /** @internal — reset for testing. */
22
+ static reset(): void;
23
+ }
24
+ export type SocialiteConfig = Record<string, SocialiteProviderConfig>;
25
+ /**
26
+ * Returns a SocialiteServiceProvider configured for OAuth.
27
+ *
28
+ * Built-in providers: github, google, facebook, apple
29
+ *
30
+ * Usage in bootstrap/providers.ts:
31
+ * import { socialite } from '@rudderjs/socialite'
32
+ * export default [..., socialite(configs.socialite), ...]
33
+ */
34
+ export declare function socialite(config: SocialiteConfig): new (app: Application) => ServiceProvider;
35
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAClE,OAAO,EAAE,iBAAiB,EAAE,KAAK,uBAAuB,EAAE,MAAM,eAAe,CAAA;AAQ/E,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD,YAAY,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAA;AAI5D,KAAK,eAAe,GAAG,CAAC,MAAM,EAAE,uBAAuB,KAAK,iBAAiB,CAAA;AAW7E,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAC,OAAO,CAAsB;IAC5C,OAAO,CAAC,MAAM,CAAC,OAAO,CAAqC;IAC3D,OAAO,CAAC,MAAM,CAAC,UAAU,CAAuC;IAEhE,iDAAiD;IACjD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB;IAe9C,yCAAyC;IACzC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI;IAI3D,wDAAwD;IACxD,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI;IAK/C,qCAAqC;IACrC,MAAM,CAAC,KAAK,IAAI,IAAI;CAKrB;AAID,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAA;AAIrE;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,KAAK,GAAG,EAAE,WAAW,KAAK,eAAe,CAW5F"}
package/dist/index.js ADDED
@@ -0,0 +1,75 @@
1
+ import { ServiceProvider } from '@rudderjs/core';
2
+ import { GitHubProvider } from './drivers/github.js';
3
+ import { GoogleProvider } from './drivers/google.js';
4
+ import { FacebookProvider } from './drivers/facebook.js';
5
+ import { AppleProvider } from './drivers/apple.js';
6
+ // ─── Re-exports ───────────────────────────────────────────
7
+ export { SocialUser } from './social-user.js';
8
+ export { SocialiteProvider } from './provider.js';
9
+ export { GitHubProvider } from './drivers/github.js';
10
+ export { GoogleProvider } from './drivers/google.js';
11
+ export { FacebookProvider } from './drivers/facebook.js';
12
+ export { AppleProvider } from './drivers/apple.js';
13
+ const builtInDrivers = {
14
+ github: (c) => new GitHubProvider(c),
15
+ google: (c) => new GoogleProvider(c),
16
+ facebook: (c) => new FacebookProvider(c),
17
+ apple: (c) => new AppleProvider(c),
18
+ };
19
+ // ─── Socialite Facade ─────────────────────────────────────
20
+ export class Socialite {
21
+ static _config = {};
22
+ static _custom = new Map();
23
+ static _instances = new Map();
24
+ /** Get or create a provider instance by name. */
25
+ static driver(name) {
26
+ const existing = this._instances.get(name);
27
+ if (existing)
28
+ return existing;
29
+ const config = this._config[name];
30
+ if (!config)
31
+ throw new Error(`[RudderJS Socialite] Provider "${name}" is not configured.`);
32
+ const factory = this._custom.get(name) ?? builtInDrivers[name];
33
+ if (!factory)
34
+ throw new Error(`[RudderJS Socialite] Unknown provider "${name}". Use Socialite.extend() to register custom providers.`);
35
+ const instance = factory(config);
36
+ this._instances.set(name, instance);
37
+ return instance;
38
+ }
39
+ /** Register a custom provider driver. */
40
+ static extend(name, factory) {
41
+ this._custom.set(name, factory);
42
+ }
43
+ /** @internal — set config from the service provider. */
44
+ static configure(config) {
45
+ this._config = config;
46
+ this._instances.clear();
47
+ }
48
+ /** @internal — reset for testing. */
49
+ static reset() {
50
+ this._config = {};
51
+ this._custom.clear();
52
+ this._instances.clear();
53
+ }
54
+ }
55
+ // ─── Service Provider Factory ─────────────────────────────
56
+ /**
57
+ * Returns a SocialiteServiceProvider configured for OAuth.
58
+ *
59
+ * Built-in providers: github, google, facebook, apple
60
+ *
61
+ * Usage in bootstrap/providers.ts:
62
+ * import { socialite } from '@rudderjs/socialite'
63
+ * export default [..., socialite(configs.socialite), ...]
64
+ */
65
+ export function socialite(config) {
66
+ class SocialiteServiceProvider extends ServiceProvider {
67
+ register() { }
68
+ async boot() {
69
+ Socialite.configure(config);
70
+ this.app.instance('socialite', Socialite);
71
+ }
72
+ }
73
+ return SocialiteServiceProvider;
74
+ }
75
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { SocialUser } from './social-user.js';
2
+ export interface SocialiteProviderConfig {
3
+ clientId: string;
4
+ clientSecret: string;
5
+ redirectUrl: string;
6
+ scopes?: string[];
7
+ }
8
+ export declare abstract class SocialiteProvider {
9
+ protected readonly config: SocialiteProviderConfig;
10
+ protected scopes: string[];
11
+ constructor(config: SocialiteProviderConfig);
12
+ /** Default scopes for this provider. */
13
+ protected abstract defaultScopes(): string[];
14
+ /** OAuth authorize URL (e.g. https://github.com/login/oauth/authorize). */
15
+ protected abstract authUrl(): string;
16
+ /** OAuth token URL (e.g. https://github.com/login/oauth/access_token). */
17
+ protected abstract tokenUrl(): string;
18
+ /** User info URL (e.g. https://api.github.com/user). */
19
+ protected abstract userUrl(): string;
20
+ /** Parse the provider's user API response into a SocialUser. */
21
+ protected abstract mapToUser(data: Record<string, unknown>, token: string, refreshToken: string | null): SocialUser;
22
+ /** Add extra scopes. */
23
+ withScopes(scopes: string[]): this;
24
+ /** Set scopes (replacing defaults). */
25
+ setScopes(scopes: string[]): this;
26
+ /** Get the redirect URL to the OAuth provider. */
27
+ getRedirectUrl(state?: string): string;
28
+ /** Redirect the response to the OAuth provider. */
29
+ redirect(state?: string): Response;
30
+ /** Exchange the authorization code for an access token. */
31
+ getAccessToken(code: string): Promise<{
32
+ accessToken: string;
33
+ refreshToken: string | null;
34
+ expiresIn: number | null;
35
+ }>;
36
+ /** Get the authenticated user from the OAuth callback. */
37
+ user(codeOrRequest: string | {
38
+ query: Record<string, string>;
39
+ }): Promise<SocialUser>;
40
+ /** Get the user directly from an access token (e.g. for mobile apps). */
41
+ getUserByToken(token: string, refreshToken?: string | null): Promise<SocialUser>;
42
+ }
43
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAI7C,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAM,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAG,MAAM,CAAA;IACpB,MAAM,CAAC,EAAO,MAAM,EAAE,CAAA;CACvB;AAED,8BAAsB,iBAAiB;IAGzB,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,uBAAuB;IAF9D,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,CAAA;gBAEK,MAAM,EAAE,uBAAuB;IAI9D,wCAAwC;IACxC,SAAS,CAAC,QAAQ,CAAC,aAAa,IAAI,MAAM,EAAE;IAE5C,2EAA2E;IAC3E,SAAS,CAAC,QAAQ,CAAC,OAAO,IAAI,MAAM;IAEpC,0EAA0E;IAC1E,SAAS,CAAC,QAAQ,CAAC,QAAQ,IAAI,MAAM;IAErC,wDAAwD;IACxD,SAAS,CAAC,QAAQ,CAAC,OAAO,IAAI,MAAM;IAEpC,gEAAgE;IAChE,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,UAAU;IAEnH,wBAAwB;IACxB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI;IAKlC,uCAAuC;IACvC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI;IAKjC,kDAAkD;IAClD,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;IAWtC,mDAAmD;IACnD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ;IAIlC,2DAA2D;IACrD,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAmC3H,0DAA0D;IACpD,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAW1F,yEAAyE;IACnE,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC;CAgBvF"}
@@ -0,0 +1,89 @@
1
+ export class SocialiteProvider {
2
+ config;
3
+ scopes;
4
+ constructor(config) {
5
+ this.config = config;
6
+ this.scopes = config.scopes ?? this.defaultScopes();
7
+ }
8
+ /** Add extra scopes. */
9
+ withScopes(scopes) {
10
+ this.scopes = [...new Set([...this.scopes, ...scopes])];
11
+ return this;
12
+ }
13
+ /** Set scopes (replacing defaults). */
14
+ setScopes(scopes) {
15
+ this.scopes = scopes;
16
+ return this;
17
+ }
18
+ /** Get the redirect URL to the OAuth provider. */
19
+ getRedirectUrl(state) {
20
+ const params = new URLSearchParams({
21
+ client_id: this.config.clientId,
22
+ redirect_uri: this.config.redirectUrl,
23
+ response_type: 'code',
24
+ scope: this.scopes.join(' '),
25
+ ...(state ? { state } : {}),
26
+ });
27
+ return `${this.authUrl()}?${params.toString()}`;
28
+ }
29
+ /** Redirect the response to the OAuth provider. */
30
+ redirect(state) {
31
+ return Response.redirect(this.getRedirectUrl(state), 302);
32
+ }
33
+ /** Exchange the authorization code for an access token. */
34
+ async getAccessToken(code) {
35
+ const res = await fetch(this.tokenUrl(), {
36
+ method: 'POST',
37
+ headers: {
38
+ 'Content-Type': 'application/json',
39
+ 'Accept': 'application/json',
40
+ },
41
+ body: JSON.stringify({
42
+ client_id: this.config.clientId,
43
+ client_secret: this.config.clientSecret,
44
+ code,
45
+ redirect_uri: this.config.redirectUrl,
46
+ grant_type: 'authorization_code',
47
+ }),
48
+ });
49
+ if (!res.ok) {
50
+ const text = await res.text();
51
+ throw new Error(`[RudderJS Socialite] Token exchange failed: ${res.status} ${text}`);
52
+ }
53
+ const data = await res.json();
54
+ // Some providers return access_token, others return it in different shapes
55
+ const accessToken = (data['access_token'] ?? data['accessToken']);
56
+ const refreshToken = (data['refresh_token'] ?? data['refreshToken']);
57
+ const expiresIn = (data['expires_in'] ?? data['expiresIn']);
58
+ if (!accessToken) {
59
+ throw new Error(`[RudderJS Socialite] No access_token in response: ${JSON.stringify(data)}`);
60
+ }
61
+ return { accessToken, refreshToken: refreshToken ?? null, expiresIn: expiresIn ?? null };
62
+ }
63
+ /** Get the authenticated user from the OAuth callback. */
64
+ async user(codeOrRequest) {
65
+ const code = typeof codeOrRequest === 'string'
66
+ ? codeOrRequest
67
+ : codeOrRequest.query['code'];
68
+ if (!code)
69
+ throw new Error('[RudderJS Socialite] Missing authorization code.');
70
+ const { accessToken, refreshToken } = await this.getAccessToken(code);
71
+ return this.getUserByToken(accessToken, refreshToken);
72
+ }
73
+ /** Get the user directly from an access token (e.g. for mobile apps). */
74
+ async getUserByToken(token, refreshToken) {
75
+ const res = await fetch(this.userUrl(), {
76
+ headers: {
77
+ 'Authorization': `Bearer ${token}`,
78
+ 'Accept': 'application/json',
79
+ },
80
+ });
81
+ if (!res.ok) {
82
+ const text = await res.text();
83
+ throw new Error(`[RudderJS Socialite] User info request failed: ${res.status} ${text}`);
84
+ }
85
+ const data = await res.json();
86
+ return this.mapToUser(data, token, refreshToken ?? null);
87
+ }
88
+ }
89
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export declare class SocialUser {
2
+ private readonly data;
3
+ constructor(data: {
4
+ id: string;
5
+ name: string | null;
6
+ email: string | null;
7
+ avatar: string | null;
8
+ nickname: string | null;
9
+ token: string;
10
+ refreshToken?: string | null;
11
+ expiresIn?: number | null;
12
+ raw: Record<string, unknown>;
13
+ });
14
+ getId(): string;
15
+ getName(): string | null;
16
+ getEmail(): string | null;
17
+ getAvatar(): string | null;
18
+ getNickname(): string | null;
19
+ /** The access token from the OAuth provider. */
20
+ get token(): string;
21
+ get refreshToken(): string | null;
22
+ get expiresIn(): number | null;
23
+ /** Raw user data from the provider's API. */
24
+ getRaw(): Record<string, unknown>;
25
+ }
26
+ //# sourceMappingURL=social-user.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"social-user.d.ts","sourceRoot":"","sources":["../src/social-user.ts"],"names":[],"mappings":"AAGA,qBAAa,UAAU;IAEnB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE;QACrB,EAAE,EAAQ,MAAM,CAAA;QAChB,IAAI,EAAM,MAAM,GAAG,IAAI,CAAA;QACvB,KAAK,EAAK,MAAM,GAAG,IAAI,CAAA;QACvB,MAAM,EAAI,MAAM,GAAG,IAAI,CAAA;QACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;QACvB,KAAK,EAAK,MAAM,CAAA;QAChB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QACzB,GAAG,EAAO,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAClC;IAGH,KAAK,IAAU,MAAM;IACrB,OAAO,IAAQ,MAAM,GAAG,IAAI;IAC5B,QAAQ,IAAO,MAAM,GAAG,IAAI;IAC5B,SAAS,IAAM,MAAM,GAAG,IAAI;IAC5B,WAAW,IAAI,MAAM,GAAG,IAAI;IAE5B,gDAAgD;IAChD,IAAI,KAAK,IAAW,MAAM,CAAuC;IACjE,IAAI,YAAY,IAAI,MAAM,GAAG,IAAI,CAA+C;IAChF,IAAI,SAAS,IAAO,MAAM,GAAG,IAAI,CAA4C;IAE7E,6CAA6C;IAC7C,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAClC"}
@@ -0,0 +1,20 @@
1
+ // ─── Social User ──────────────────────────────────────────
2
+ // Normalized user returned by all OAuth providers.
3
+ export class SocialUser {
4
+ data;
5
+ constructor(data) {
6
+ this.data = data;
7
+ }
8
+ getId() { return this.data.id; }
9
+ getName() { return this.data.name; }
10
+ getEmail() { return this.data.email; }
11
+ getAvatar() { return this.data.avatar; }
12
+ getNickname() { return this.data.nickname; }
13
+ /** The access token from the OAuth provider. */
14
+ get token() { return this.data.token; }
15
+ get refreshToken() { return this.data.refreshToken ?? null; }
16
+ get expiresIn() { return this.data.expiresIn ?? null; }
17
+ /** Raw user data from the provider's API. */
18
+ getRaw() { return this.data.raw; }
19
+ }
20
+ //# sourceMappingURL=social-user.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"social-user.js","sourceRoot":"","sources":["../src/social-user.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,mDAAmD;AAEnD,MAAM,OAAO,UAAU;IAEF;IADnB,YACmB,IAUhB;QAVgB,SAAI,GAAJ,IAAI,CAUpB;IACA,CAAC;IAEJ,KAAK,KAAyB,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAA,CAAC,CAAC;IACnD,OAAO,KAAwB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAA,CAAC,CAAC;IACtD,QAAQ,KAAuB,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAA,CAAC,CAAC;IACvD,SAAS,KAAsB,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAA,CAAC,CAAC;IACxD,WAAW,KAAoB,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAA,CAAC,CAAC;IAE1D,gDAAgD;IAChD,IAAI,KAAK,KAAgC,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAA,CAAC,CAAC;IACjE,IAAI,YAAY,KAAyB,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,CAAA,CAAC,CAAC;IAChF,IAAI,SAAS,KAA4B,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAA,CAAC,CAAC;IAE7E,6CAA6C;IAC7C,MAAM,KAA8B,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAA,CAAC,CAAC;CAC3D"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@rudderjs/socialite",
3
+ "version": "0.0.1",
4
+ "license": "MIT",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/rudderjs/rudder",
8
+ "directory": "packages/socialite"
9
+ },
10
+ "type": "module",
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "import": "./dist/index.js",
19
+ "types": "./dist/index.d.ts"
20
+ }
21
+ },
22
+ "dependencies": {
23
+ "@rudderjs/core": "0.0.8"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^20.0.0",
27
+ "typescript": "^5.4.0"
28
+ },
29
+ "author": "Suleiman Shahbari",
30
+ "scripts": {
31
+ "build": "tsc -p tsconfig.build.json",
32
+ "dev": "tsc -p tsconfig.build.json --watch",
33
+ "typecheck": "tsc --noEmit",
34
+ "lint": "eslint src",
35
+ "clean": "rm -rf dist",
36
+ "test": "tsc -p tsconfig.test.json && node --test dist-test/index.test.js; EXIT=$?; rm -rf dist-test; exit $EXIT"
37
+ }
38
+ }