@rudderjs/socialite 1.0.1 → 2.0.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/README.md +82 -5
- package/boost/guidelines.md +45 -26
- package/dist/driver.d.ts +76 -3
- package/dist/driver.d.ts.map +1 -1
- package/dist/driver.js +159 -16
- package/dist/driver.js.map +1 -1
- package/dist/drivers/apple.d.ts +46 -8
- package/dist/drivers/apple.d.ts.map +1 -1
- package/dist/drivers/apple.js +214 -45
- package/dist/drivers/apple.js.map +1 -1
- package/dist/drivers/github.js +1 -1
- package/dist/drivers/github.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/package.json +12 -3
package/README.md
CHANGED
|
@@ -27,11 +27,10 @@ export default {
|
|
|
27
27
|
},
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
// bootstrap/providers.ts
|
|
31
|
-
import { SocialiteProvider } from '@rudderjs/socialite'
|
|
32
|
-
export default [SocialiteProvider]
|
|
33
30
|
```
|
|
34
31
|
|
|
32
|
+
`SocialiteProvider` is picked up by [auto-discovery](https://github.com/rudderjs/rudder/blob/main/docs/guide/service-providers.md#auto-discovery) — `pnpm rudder providers:discover` is all that's needed.
|
|
33
|
+
|
|
35
34
|
## Usage
|
|
36
35
|
|
|
37
36
|
```ts
|
|
@@ -64,6 +63,50 @@ Route.get('/auth/github/callback', async (req) => {
|
|
|
64
63
|
})
|
|
65
64
|
```
|
|
66
65
|
|
|
66
|
+
## CSRF state — stateful by default
|
|
67
|
+
|
|
68
|
+
Socialite mints a CSPRNG `state` parameter on every redirect, persists it
|
|
69
|
+
on the session, and validates the `state` returned in the callback before
|
|
70
|
+
exchanging the code. A mismatch (or a missing session) throws
|
|
71
|
+
`InvalidStateException` — same defense Laravel Socialite ships out of the
|
|
72
|
+
box. No code changes needed: the routes above are already protected, as
|
|
73
|
+
long as `@rudderjs/session`'s middleware is mounted (auto-installed on
|
|
74
|
+
the `web` group).
|
|
75
|
+
|
|
76
|
+
For flows that legitimately can't reach the session — mobile clients,
|
|
77
|
+
machine-to-machine token grants, server-side OAuth where the round-trip
|
|
78
|
+
happens entirely off-browser — opt out per call:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
Route.get('/auth/github', () => {
|
|
82
|
+
return Socialite.driver('github').stateless().redirect()
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
Route.get('/auth/github/callback', async (req) => {
|
|
86
|
+
const user = await Socialite.driver('github').stateless().user(req)
|
|
87
|
+
// …
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`InvalidStateException` is exported for `instanceof`-checks in your
|
|
92
|
+
exception handler:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { InvalidStateException } from '@rudderjs/socialite'
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
await Socialite.driver('github').user(req)
|
|
99
|
+
} catch (err) {
|
|
100
|
+
if (err instanceof InvalidStateException) return abort(403, 'Auth failed.')
|
|
101
|
+
throw err
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
State is namespaced per provider (`socialite_state:github`,
|
|
106
|
+
`socialite_state:google`, …) so concurrent OAuth flows on the same
|
|
107
|
+
session don't collide. State is one-time use — successful or failed
|
|
108
|
+
validation clears the slot, so a leaked value can't be replayed.
|
|
109
|
+
|
|
67
110
|
## Providers
|
|
68
111
|
|
|
69
112
|
| Provider | Driver | Auth URL |
|
|
@@ -73,12 +116,46 @@ Route.get('/auth/github/callback', async (req) => {
|
|
|
73
116
|
| Facebook | `facebook` | `facebook.com/v19.0/dialog/oauth` |
|
|
74
117
|
| Apple | `apple` | `appleid.apple.com/auth/authorize` |
|
|
75
118
|
|
|
119
|
+
### Sign-in-with-Apple — extra config
|
|
120
|
+
|
|
121
|
+
Apple's OAuth flow requires a freshly-signed ES256 JWT as `client_secret`
|
|
122
|
+
on every token exchange (a raw string is rejected with `invalid_client`).
|
|
123
|
+
Add three Apple-specific fields to your config:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
// config/socialite.ts
|
|
127
|
+
import { readFileSync } from 'node:fs'
|
|
128
|
+
import type { AppleSocialiteConfig } from '@rudderjs/socialite'
|
|
129
|
+
|
|
130
|
+
export default {
|
|
131
|
+
apple: {
|
|
132
|
+
clientId: Env.get('APPLE_CLIENT_ID', ''), // Service ID, e.g. com.example.app
|
|
133
|
+
redirectUrl: Env.get('APPLE_REDIRECT_URL', ''),
|
|
134
|
+
teamId: Env.get('APPLE_TEAM_ID', ''), // 10-char Team ID from developer.apple.com
|
|
135
|
+
keyId: Env.get('APPLE_KEY_ID', ''), // 10-char Key ID for the .p8
|
|
136
|
+
privateKey: readFileSync(Env.get('APPLE_PRIVATE_KEY_PATH', ''), 'utf8'),
|
|
137
|
+
clientSecret: '', // unused; left for type compat
|
|
138
|
+
} satisfies AppleSocialiteConfig,
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Download the `.p8` file once from the Apple Developer portal and either
|
|
143
|
+
read it from disk (as above) or pass its PEM contents directly. The
|
|
144
|
+
driver verifies returned `id_token`s against Apple's JWKS
|
|
145
|
+
(`https://appleid.apple.com/auth/keys`, cached for 1h) — signature, `iss`,
|
|
146
|
+
`aud`, and `exp` are all checked before any user data is trusted.
|
|
147
|
+
|
|
148
|
+
Apple's first-authorization callback POSTs the user's `name` once in the
|
|
149
|
+
form-post body. RudderJS reads it automatically when you pass the request
|
|
150
|
+
object to `user(req)`. Your route handler must include the `body` in the
|
|
151
|
+
request shape — `@rudderjs/server-hono` already does this.
|
|
152
|
+
|
|
76
153
|
## Custom Providers
|
|
77
154
|
|
|
78
155
|
```ts
|
|
79
|
-
import {
|
|
156
|
+
import { SocialiteDriver, SocialUser, Socialite } from '@rudderjs/socialite'
|
|
80
157
|
|
|
81
|
-
class GitLabProvider extends
|
|
158
|
+
class GitLabProvider extends SocialiteDriver {
|
|
82
159
|
protected defaultScopes() { return ['read_user'] }
|
|
83
160
|
protected authUrl() { return 'https://gitlab.com/oauth/authorize' }
|
|
84
161
|
protected tokenUrl() { return 'https://gitlab.com/oauth/token' }
|
package/boost/guidelines.md
CHANGED
|
@@ -39,9 +39,11 @@ Route.get('/auth/github', () => {
|
|
|
39
39
|
Route.get('/auth/github/callback', async (req) => {
|
|
40
40
|
const socialUser = await Socialite.driver('github').user(req)
|
|
41
41
|
|
|
42
|
-
// socialUser
|
|
43
|
-
|
|
44
|
-
const
|
|
42
|
+
// socialUser methods: getId(), getName(), getEmail(), getAvatar(), getNickname(), getRaw()
|
|
43
|
+
// socialUser getters: .token, .refreshToken, .expiresIn
|
|
44
|
+
const id = socialUser.getId()
|
|
45
|
+
const email = socialUser.getEmail()
|
|
46
|
+
const accessToken = socialUser.token
|
|
45
47
|
|
|
46
48
|
// Find or create a local user
|
|
47
49
|
let user = await User.where('email', email).first()
|
|
@@ -58,31 +60,42 @@ Route.get('/auth/github/callback', async (req) => {
|
|
|
58
60
|
### Scopes + state
|
|
59
61
|
|
|
60
62
|
```ts
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
// Replace defaults
|
|
64
|
+
Socialite.driver('github').setScopes(['user:email', 'read:org']).redirect()
|
|
65
|
+
|
|
66
|
+
// Or extend defaults — withScopes() merges, deduped
|
|
67
|
+
Socialite.driver('github').withScopes(['read:org']).redirect()
|
|
68
|
+
|
|
69
|
+
// Skip CSRF state (mobile / machine-to-machine flows that can't reach the session)
|
|
70
|
+
Socialite.driver('github').stateless().redirect()
|
|
65
71
|
```
|
|
66
72
|
|
|
67
|
-
State (CSRF) is handled automatically — stored in the session and verified on callback.
|
|
73
|
+
State (CSRF) is handled automatically — stored in the session and verified on callback. To inject extra provider-specific query parameters (`prompt=consent`, Apple's `response_mode=form_post`, etc.), override `extraAuthParams()` on a custom driver subclass — there is no fluent `.with({...})` method.
|
|
68
74
|
|
|
69
75
|
### Custom providers
|
|
70
76
|
|
|
77
|
+
`SocialiteDriver` declares `authUrl`, `tokenUrl`, `userUrl`, `defaultScopes`, and `mapToUser` as abstract **methods** (not properties). Override each:
|
|
78
|
+
|
|
71
79
|
```ts
|
|
72
|
-
import { Socialite, SocialiteDriver } from '@rudderjs/socialite'
|
|
80
|
+
import { Socialite, SocialiteDriver, SocialUser } from '@rudderjs/socialite'
|
|
73
81
|
|
|
74
82
|
class DiscordDriver extends SocialiteDriver {
|
|
75
|
-
protected
|
|
76
|
-
protected
|
|
77
|
-
protected
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
protected defaultScopes() { return ['identify', 'email'] }
|
|
84
|
+
protected authUrl() { return 'https://discord.com/api/oauth2/authorize' }
|
|
85
|
+
protected tokenUrl() { return 'https://discord.com/api/oauth2/token' }
|
|
86
|
+
protected userUrl() { return 'https://discord.com/api/users/@me' }
|
|
87
|
+
|
|
88
|
+
protected mapToUser(raw: Record<string, unknown>, token: string, refreshToken: string | null): SocialUser {
|
|
89
|
+
return new SocialUser({
|
|
90
|
+
id: String(raw['id']),
|
|
91
|
+
name: (raw['username'] as string) ?? null,
|
|
92
|
+
email: (raw['email'] as string) ?? null,
|
|
93
|
+
avatar: raw['avatar'] ? `https://cdn.discordapp.com/avatars/${raw['id']}/${raw['avatar']}.png` : null,
|
|
94
|
+
nickname: null,
|
|
95
|
+
token,
|
|
96
|
+
refreshToken,
|
|
97
|
+
raw,
|
|
98
|
+
})
|
|
86
99
|
}
|
|
87
100
|
}
|
|
88
101
|
|
|
@@ -92,12 +105,18 @@ Socialite.extend('discord', (cfg) => new DiscordDriver(cfg))
|
|
|
92
105
|
### SocialUser interface
|
|
93
106
|
|
|
94
107
|
```ts
|
|
95
|
-
|
|
96
|
-
socialUser.
|
|
97
|
-
socialUser.
|
|
98
|
-
socialUser.
|
|
99
|
-
socialUser.
|
|
100
|
-
socialUser.
|
|
108
|
+
// Methods
|
|
109
|
+
socialUser.getId() // provider's user id (always string)
|
|
110
|
+
socialUser.getName() // string | null
|
|
111
|
+
socialUser.getEmail() // string | null
|
|
112
|
+
socialUser.getAvatar() // string | null
|
|
113
|
+
socialUser.getNickname() // string | null
|
|
114
|
+
socialUser.getRaw() // Record<string, unknown> — full raw provider response
|
|
115
|
+
|
|
116
|
+
// Getters (not methods)
|
|
117
|
+
socialUser.token // access token
|
|
118
|
+
socialUser.refreshToken // string | null
|
|
119
|
+
socialUser.expiresIn // number | null
|
|
101
120
|
```
|
|
102
121
|
|
|
103
122
|
## Common Pitfalls
|
package/dist/driver.d.ts
CHANGED
|
@@ -4,10 +4,32 @@ export interface SocialiteDriverConfig {
|
|
|
4
4
|
clientSecret: string;
|
|
5
5
|
redirectUrl: string;
|
|
6
6
|
scopes?: string[];
|
|
7
|
+
/** Per-request HTTP timeout in milliseconds (default 10_000). */
|
|
8
|
+
timeout?: number;
|
|
9
|
+
}
|
|
10
|
+
/** Detail attached to OAuth provider errors via `Error.cause`. */
|
|
11
|
+
export interface SocialiteHttpErrorCause {
|
|
12
|
+
status: number;
|
|
13
|
+
body: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Thrown when an OAuth callback's `state` parameter is missing, doesn't
|
|
17
|
+
* match the value the framework stored before redirect, or arrives without
|
|
18
|
+
* a session in context. Indicates a CSRF / state-fixation attempt — apps
|
|
19
|
+
* should treat as auth failure.
|
|
20
|
+
*/
|
|
21
|
+
export declare class InvalidStateException extends Error {
|
|
22
|
+
constructor(message?: string);
|
|
23
|
+
}
|
|
24
|
+
/** Shape of the request object accepted by `user()` and `validateRequestState`. */
|
|
25
|
+
export interface SocialiteCallbackRequest {
|
|
26
|
+
query: Record<string, string>;
|
|
27
|
+
body?: unknown;
|
|
7
28
|
}
|
|
8
29
|
export declare abstract class SocialiteDriver {
|
|
9
30
|
protected readonly config: SocialiteDriverConfig;
|
|
10
31
|
protected scopes: string[];
|
|
32
|
+
private _stateless;
|
|
11
33
|
constructor(config: SocialiteDriverConfig);
|
|
12
34
|
/** Default scopes for this provider. */
|
|
13
35
|
protected abstract defaultScopes(): string[];
|
|
@@ -19,14 +41,43 @@ export declare abstract class SocialiteDriver {
|
|
|
19
41
|
protected abstract userUrl(): string;
|
|
20
42
|
/** Parse the provider's user API response into a SocialUser. */
|
|
21
43
|
protected abstract mapToUser(data: Record<string, unknown>, token: string, refreshToken: string | null): SocialUser;
|
|
44
|
+
/**
|
|
45
|
+
* Provider key used to namespace the session state slot. Defaults to the
|
|
46
|
+
* lowercase class name with a trailing `provider` stripped (e.g. `GitHubProvider`
|
|
47
|
+
* → `github`). Override on a subclass if a custom key is preferred.
|
|
48
|
+
*/
|
|
49
|
+
protected providerName(): string;
|
|
22
50
|
/** Add extra scopes. */
|
|
23
51
|
withScopes(scopes: string[]): this;
|
|
24
52
|
/** Set scopes (replacing defaults). */
|
|
25
53
|
setScopes(scopes: string[]): this;
|
|
54
|
+
/**
|
|
55
|
+
* Disable state generation + validation (Laravel `->stateless()`).
|
|
56
|
+
*
|
|
57
|
+
* Use for OAuth flows that can't reach the session — e.g. mobile clients,
|
|
58
|
+
* machine-to-machine auth, or token grants where the round-trip happens
|
|
59
|
+
* entirely server-to-server. The default (stateful) generates a CSPRNG
|
|
60
|
+
* `state` on redirect, stores it in the session, and validates it on
|
|
61
|
+
* callback to prevent CSRF / state-fixation.
|
|
62
|
+
*/
|
|
63
|
+
stateless(): this;
|
|
64
|
+
isStateless(): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Provider-specific extra params to merge into the authorize URL. Apple
|
|
67
|
+
* needs `response_mode=form_post`; other drivers may want `prompt=consent`
|
|
68
|
+
* etc. Override on subclasses — base returns `{}`.
|
|
69
|
+
*/
|
|
70
|
+
protected extraAuthParams(): Record<string, string>;
|
|
26
71
|
/** Get the redirect URL to the OAuth provider. */
|
|
27
72
|
getRedirectUrl(state?: string): string;
|
|
28
73
|
/** Redirect the response to the OAuth provider. */
|
|
29
74
|
redirect(state?: string): Response;
|
|
75
|
+
/**
|
|
76
|
+
* Wrapper around `fetch` that injects an `AbortSignal.timeout` so a hung
|
|
77
|
+
* provider endpoint can't keep the request handler alive indefinitely.
|
|
78
|
+
* Subclasses (Apple, GitHub) call this for their own provider fetches.
|
|
79
|
+
*/
|
|
80
|
+
protected fetchWithTimeout(input: Parameters<typeof fetch>[0], init?: RequestInit): Promise<Response>;
|
|
30
81
|
/** Exchange the authorization code for an access token. */
|
|
31
82
|
getAccessToken(code: string): Promise<{
|
|
32
83
|
accessToken: string;
|
|
@@ -34,10 +85,32 @@ export declare abstract class SocialiteDriver {
|
|
|
34
85
|
expiresIn: number | null;
|
|
35
86
|
}>;
|
|
36
87
|
/** Get the authenticated user from the OAuth callback. */
|
|
37
|
-
user(codeOrRequest: string |
|
|
38
|
-
query: Record<string, string>;
|
|
39
|
-
}): Promise<SocialUser>;
|
|
88
|
+
user(codeOrRequest: string | SocialiteCallbackRequest): Promise<SocialUser>;
|
|
40
89
|
/** Get the user directly from an access token (e.g. for mobile apps). */
|
|
41
90
|
getUserByToken(token: string, refreshToken?: string | null): Promise<SocialUser>;
|
|
91
|
+
private get stateKey();
|
|
92
|
+
/**
|
|
93
|
+
* Generate a CSPRNG state token, store it on the session, and return the
|
|
94
|
+
* value to embed in the authorize URL. Throws when no session is in
|
|
95
|
+
* context — the caller can opt out via `.stateless()`.
|
|
96
|
+
*/
|
|
97
|
+
private generateAndStoreState;
|
|
98
|
+
/**
|
|
99
|
+
* Validate the `state` carried in a callback request against what was
|
|
100
|
+
* stored at redirect time. Pulls from `query.state` first, falling back
|
|
101
|
+
* to the request body's `state` (used by Apple's `form_post` callback).
|
|
102
|
+
* Always forgets the stored value after validation — the state is
|
|
103
|
+
* one-time use, so a leaked state can't be replayed.
|
|
104
|
+
*/
|
|
105
|
+
protected validateRequestState(req: SocialiteCallbackRequest): void;
|
|
106
|
+
private extractState;
|
|
107
|
+
private constantTimeStringEqual;
|
|
108
|
+
/**
|
|
109
|
+
* Build an Error whose `message` carries only status + statusText (safe to
|
|
110
|
+
* surface in logs), with the response body attached on `cause` so callers
|
|
111
|
+
* that need it can still inspect — without leaking provider-echoed
|
|
112
|
+
* client_id / hints / PII into top-level error tracking.
|
|
113
|
+
*/
|
|
114
|
+
protected httpError(prefix: string, res: Response): Promise<Error>;
|
|
42
115
|
}
|
|
43
116
|
//# sourceMappingURL=driver.d.ts.map
|
package/dist/driver.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../src/driver.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../src/driver.ts"],"names":[],"mappings":"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"}
|
package/dist/driver.js
CHANGED
|
@@ -1,10 +1,35 @@
|
|
|
1
|
+
import { randomBytes, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
import { Session } from '@rudderjs/session';
|
|
3
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
4
|
+
const STATE_BYTES = 20;
|
|
5
|
+
/**
|
|
6
|
+
* Thrown when an OAuth callback's `state` parameter is missing, doesn't
|
|
7
|
+
* match the value the framework stored before redirect, or arrives without
|
|
8
|
+
* a session in context. Indicates a CSRF / state-fixation attempt — apps
|
|
9
|
+
* should treat as auth failure.
|
|
10
|
+
*/
|
|
11
|
+
export class InvalidStateException extends Error {
|
|
12
|
+
constructor(message = 'OAuth state mismatch — possible CSRF attack.') {
|
|
13
|
+
super(`[RudderJS Socialite] ${message}`);
|
|
14
|
+
this.name = 'InvalidStateException';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
1
17
|
export class SocialiteDriver {
|
|
2
18
|
config;
|
|
3
19
|
scopes;
|
|
20
|
+
_stateless = false;
|
|
4
21
|
constructor(config) {
|
|
5
22
|
this.config = config;
|
|
6
23
|
this.scopes = config.scopes ?? this.defaultScopes();
|
|
7
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Provider key used to namespace the session state slot. Defaults to the
|
|
27
|
+
* lowercase class name with a trailing `provider` stripped (e.g. `GitHubProvider`
|
|
28
|
+
* → `github`). Override on a subclass if a custom key is preferred.
|
|
29
|
+
*/
|
|
30
|
+
providerName() {
|
|
31
|
+
return this.constructor.name.toLowerCase().replace(/provider$/, '');
|
|
32
|
+
}
|
|
8
33
|
/** Add extra scopes. */
|
|
9
34
|
withScopes(scopes) {
|
|
10
35
|
this.scopes = [...new Set([...this.scopes, ...scopes])];
|
|
@@ -15,14 +40,42 @@ export class SocialiteDriver {
|
|
|
15
40
|
this.scopes = scopes;
|
|
16
41
|
return this;
|
|
17
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Disable state generation + validation (Laravel `->stateless()`).
|
|
45
|
+
*
|
|
46
|
+
* Use for OAuth flows that can't reach the session — e.g. mobile clients,
|
|
47
|
+
* machine-to-machine auth, or token grants where the round-trip happens
|
|
48
|
+
* entirely server-to-server. The default (stateful) generates a CSPRNG
|
|
49
|
+
* `state` on redirect, stores it in the session, and validates it on
|
|
50
|
+
* callback to prevent CSRF / state-fixation.
|
|
51
|
+
*/
|
|
52
|
+
stateless() {
|
|
53
|
+
this._stateless = true;
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
isStateless() {
|
|
57
|
+
return this._stateless;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Provider-specific extra params to merge into the authorize URL. Apple
|
|
61
|
+
* needs `response_mode=form_post`; other drivers may want `prompt=consent`
|
|
62
|
+
* etc. Override on subclasses — base returns `{}`.
|
|
63
|
+
*/
|
|
64
|
+
extraAuthParams() {
|
|
65
|
+
return {};
|
|
66
|
+
}
|
|
18
67
|
/** Get the redirect URL to the OAuth provider. */
|
|
19
68
|
getRedirectUrl(state) {
|
|
69
|
+
// Caller-supplied state always wins (test-friendly + advanced override).
|
|
70
|
+
// When stateful and no state is supplied, generate + persist one.
|
|
71
|
+
const stateValue = state ?? (this._stateless ? undefined : this.generateAndStoreState());
|
|
20
72
|
const params = new URLSearchParams({
|
|
21
73
|
client_id: this.config.clientId,
|
|
22
74
|
redirect_uri: this.config.redirectUrl,
|
|
23
75
|
response_type: 'code',
|
|
24
76
|
scope: this.scopes.join(' '),
|
|
25
|
-
...(
|
|
77
|
+
...(stateValue ? { state: stateValue } : {}),
|
|
78
|
+
...this.extraAuthParams(),
|
|
26
79
|
});
|
|
27
80
|
return `${this.authUrl()}?${params.toString()}`;
|
|
28
81
|
}
|
|
@@ -30,15 +83,27 @@ export class SocialiteDriver {
|
|
|
30
83
|
redirect(state) {
|
|
31
84
|
return Response.redirect(this.getRedirectUrl(state), 302);
|
|
32
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Wrapper around `fetch` that injects an `AbortSignal.timeout` so a hung
|
|
88
|
+
* provider endpoint can't keep the request handler alive indefinitely.
|
|
89
|
+
* Subclasses (Apple, GitHub) call this for their own provider fetches.
|
|
90
|
+
*/
|
|
91
|
+
fetchWithTimeout(input, init = {}) {
|
|
92
|
+
const timeoutMs = this.config.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
93
|
+
return fetch(input, { ...init, signal: init.signal ?? AbortSignal.timeout(timeoutMs) });
|
|
94
|
+
}
|
|
33
95
|
/** Exchange the authorization code for an access token. */
|
|
34
96
|
async getAccessToken(code) {
|
|
35
|
-
|
|
97
|
+
// RFC 6749 §4.1.3 mandates `application/x-www-form-urlencoded` for the
|
|
98
|
+
// token endpoint. GitHub, Google, and Facebook all reject JSON bodies
|
|
99
|
+
// (or accept them inconsistently); Apple's override already form-encodes.
|
|
100
|
+
const res = await this.fetchWithTimeout(this.tokenUrl(), {
|
|
36
101
|
method: 'POST',
|
|
37
102
|
headers: {
|
|
38
|
-
'Content-Type': 'application/
|
|
103
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
39
104
|
'Accept': 'application/json',
|
|
40
105
|
},
|
|
41
|
-
body:
|
|
106
|
+
body: new URLSearchParams({
|
|
42
107
|
client_id: this.config.clientId,
|
|
43
108
|
client_secret: this.config.clientSecret,
|
|
44
109
|
code,
|
|
@@ -47,21 +112,28 @@ export class SocialiteDriver {
|
|
|
47
112
|
}),
|
|
48
113
|
});
|
|
49
114
|
if (!res.ok) {
|
|
50
|
-
|
|
51
|
-
throw new Error(`[RudderJS Socialite] Token exchange failed: ${res.status} ${text}`);
|
|
115
|
+
throw await this.httpError('Token exchange failed', res);
|
|
52
116
|
}
|
|
53
117
|
const data = await res.json();
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
118
|
+
// Provider response is JSON of unknown shape — type-check before trusting.
|
|
119
|
+
// Some providers use snake_case, some camelCase; either is fine, but the
|
|
120
|
+
// value must be a non-empty string. Anything else (number, null, object,
|
|
121
|
+
// empty string) is treated as a missing token.
|
|
122
|
+
const rawToken = data['access_token'] ?? data['accessToken'];
|
|
123
|
+
const rawRefresh = data['refresh_token'] ?? data['refreshToken'];
|
|
124
|
+
const rawExpiresIn = data['expires_in'] ?? data['expiresIn'];
|
|
125
|
+
if (typeof rawToken !== 'string' || rawToken.length === 0) {
|
|
126
|
+
throw new Error('[RudderJS Socialite] No access_token in token-exchange response.');
|
|
60
127
|
}
|
|
61
|
-
|
|
128
|
+
const refreshToken = typeof rawRefresh === 'string' && rawRefresh.length > 0 ? rawRefresh : null;
|
|
129
|
+
const expiresIn = typeof rawExpiresIn === 'number' && Number.isFinite(rawExpiresIn) ? rawExpiresIn : null;
|
|
130
|
+
return { accessToken: rawToken, refreshToken, expiresIn };
|
|
62
131
|
}
|
|
63
132
|
/** Get the authenticated user from the OAuth callback. */
|
|
64
133
|
async user(codeOrRequest) {
|
|
134
|
+
if (typeof codeOrRequest !== 'string') {
|
|
135
|
+
this.validateRequestState(codeOrRequest);
|
|
136
|
+
}
|
|
65
137
|
const code = typeof codeOrRequest === 'string'
|
|
66
138
|
? codeOrRequest
|
|
67
139
|
: codeOrRequest.query['code'];
|
|
@@ -72,18 +144,89 @@ export class SocialiteDriver {
|
|
|
72
144
|
}
|
|
73
145
|
/** Get the user directly from an access token (e.g. for mobile apps). */
|
|
74
146
|
async getUserByToken(token, refreshToken) {
|
|
75
|
-
const res = await
|
|
147
|
+
const res = await this.fetchWithTimeout(this.userUrl(), {
|
|
76
148
|
headers: {
|
|
77
149
|
'Authorization': `Bearer ${token}`,
|
|
78
150
|
'Accept': 'application/json',
|
|
79
151
|
},
|
|
80
152
|
});
|
|
81
153
|
if (!res.ok) {
|
|
82
|
-
|
|
83
|
-
throw new Error(`[RudderJS Socialite] User info request failed: ${res.status} ${text}`);
|
|
154
|
+
throw await this.httpError('User info request failed', res);
|
|
84
155
|
}
|
|
85
156
|
const data = await res.json();
|
|
86
157
|
return this.mapToUser(data, token, refreshToken ?? null);
|
|
87
158
|
}
|
|
159
|
+
// ─── State (CSRF defense) ───────────────────────────────
|
|
160
|
+
get stateKey() {
|
|
161
|
+
return `socialite_state:${this.providerName()}`;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Generate a CSPRNG state token, store it on the session, and return the
|
|
165
|
+
* value to embed in the authorize URL. Throws when no session is in
|
|
166
|
+
* context — the caller can opt out via `.stateless()`.
|
|
167
|
+
*/
|
|
168
|
+
generateAndStoreState() {
|
|
169
|
+
if (!Session.active()) {
|
|
170
|
+
throw new Error('[RudderJS Socialite] Cannot generate OAuth state: no session in context. ' +
|
|
171
|
+
'Register session middleware (auto-installed on the web group), or call ' +
|
|
172
|
+
'`.stateless()` on the driver if state validation is intentionally skipped.');
|
|
173
|
+
}
|
|
174
|
+
const value = randomBytes(STATE_BYTES).toString('hex');
|
|
175
|
+
Session.put(this.stateKey, value);
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Validate the `state` carried in a callback request against what was
|
|
180
|
+
* stored at redirect time. Pulls from `query.state` first, falling back
|
|
181
|
+
* to the request body's `state` (used by Apple's `form_post` callback).
|
|
182
|
+
* Always forgets the stored value after validation — the state is
|
|
183
|
+
* one-time use, so a leaked state can't be replayed.
|
|
184
|
+
*/
|
|
185
|
+
validateRequestState(req) {
|
|
186
|
+
if (this._stateless)
|
|
187
|
+
return;
|
|
188
|
+
if (!Session.active()) {
|
|
189
|
+
throw new InvalidStateException('No session in context for state validation. Register session middleware ' +
|
|
190
|
+
'or use `.stateless()` if state validation is intentionally skipped.');
|
|
191
|
+
}
|
|
192
|
+
const stored = Session.get(this.stateKey);
|
|
193
|
+
Session.forget(this.stateKey);
|
|
194
|
+
const provided = this.extractState(req);
|
|
195
|
+
if (typeof stored !== 'string' || stored.length === 0 ||
|
|
196
|
+
typeof provided !== 'string' || provided.length === 0 ||
|
|
197
|
+
!this.constantTimeStringEqual(stored, provided)) {
|
|
198
|
+
throw new InvalidStateException();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
extractState(req) {
|
|
202
|
+
const fromQuery = req.query['state'];
|
|
203
|
+
if (typeof fromQuery === 'string' && fromQuery.length > 0)
|
|
204
|
+
return fromQuery;
|
|
205
|
+
const body = req.body;
|
|
206
|
+
if (body && typeof body === 'object') {
|
|
207
|
+
const fromBody = body['state'];
|
|
208
|
+
if (typeof fromBody === 'string' && fromBody.length > 0)
|
|
209
|
+
return fromBody;
|
|
210
|
+
}
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
213
|
+
constantTimeStringEqual(a, b) {
|
|
214
|
+
if (a.length !== b.length)
|
|
215
|
+
return false;
|
|
216
|
+
const ab = Buffer.from(a, 'utf8');
|
|
217
|
+
const bb = Buffer.from(b, 'utf8');
|
|
218
|
+
return timingSafeEqual(ab, bb);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Build an Error whose `message` carries only status + statusText (safe to
|
|
222
|
+
* surface in logs), with the response body attached on `cause` so callers
|
|
223
|
+
* that need it can still inspect — without leaking provider-echoed
|
|
224
|
+
* client_id / hints / PII into top-level error tracking.
|
|
225
|
+
*/
|
|
226
|
+
async httpError(prefix, res) {
|
|
227
|
+
const body = await res.text().catch(() => '');
|
|
228
|
+
const cause = { status: res.status, body };
|
|
229
|
+
return new Error(`[RudderJS Socialite] ${prefix}: ${res.status} ${res.statusText}`.trimEnd(), { cause });
|
|
230
|
+
}
|
|
88
231
|
}
|
|
89
232
|
//# sourceMappingURL=driver.js.map
|
package/dist/driver.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver.js","sourceRoot":"","sources":["../src/driver.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"driver.js","sourceRoot":"","sources":["../src/driver.ts"],"names":[],"mappings":"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"}
|
package/dist/drivers/apple.d.ts
CHANGED
|
@@ -1,17 +1,55 @@
|
|
|
1
|
-
import { SocialiteDriver } from '../driver.js';
|
|
1
|
+
import { SocialiteDriver, type SocialiteDriverConfig, type SocialiteCallbackRequest } from '../driver.js';
|
|
2
2
|
import { SocialUser } from '../social-user.js';
|
|
3
|
+
/**
|
|
4
|
+
* Apple-specific config. The base `clientSecret` field is unused — Apple
|
|
5
|
+
* requires a freshly-signed ES256 JWT as `client_secret` on each token
|
|
6
|
+
* exchange. Provide `teamId`, `keyId`, and `privateKey` (PEM contents of the
|
|
7
|
+
* `.p8` file downloaded from the Apple Developer portal); the driver mints
|
|
8
|
+
* the JWT just-in-time.
|
|
9
|
+
*/
|
|
10
|
+
export interface AppleSocialiteConfig extends SocialiteDriverConfig {
|
|
11
|
+
/** Apple Developer Team ID (10 chars). Used as the `iss` claim. */
|
|
12
|
+
teamId?: string;
|
|
13
|
+
/** Sign-in-with-Apple Key ID (10 chars). Embedded in the JWT header as `kid`. */
|
|
14
|
+
keyId?: string;
|
|
15
|
+
/** PEM-encoded EC P-256 private key (the `.p8` file contents). */
|
|
16
|
+
privateKey?: string;
|
|
17
|
+
/** Override the JWT lifetime in seconds. Apple max is 6 months; default 5 minutes. */
|
|
18
|
+
clientSecretTtl?: number;
|
|
19
|
+
}
|
|
3
20
|
export declare class AppleProvider extends SocialiteDriver {
|
|
21
|
+
private static _jwksCache;
|
|
22
|
+
constructor(config: AppleSocialiteConfig);
|
|
4
23
|
protected defaultScopes(): string[];
|
|
5
24
|
protected authUrl(): string;
|
|
6
25
|
protected tokenUrl(): string;
|
|
7
26
|
protected userUrl(): string;
|
|
8
|
-
|
|
27
|
+
protected extraAuthParams(): Record<string, string>;
|
|
9
28
|
protected mapToUser(data: Record<string, unknown>, token: string, refreshToken: string | null): SocialUser;
|
|
10
|
-
/**
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Exchange the auth code with Apple in a single POST, verify the returned
|
|
31
|
+
* id_token, and merge any first-authorization user details from the
|
|
32
|
+
* form_post body. Apple's auth codes are single-use, so this driver does
|
|
33
|
+
* NOT call the inherited `getAccessToken` — the token endpoint is hit
|
|
34
|
+
* exactly once per callback.
|
|
35
|
+
*/
|
|
36
|
+
user(codeOrRequest: string | SocialiteCallbackRequest): Promise<SocialUser>;
|
|
37
|
+
private _exchange;
|
|
38
|
+
/**
|
|
39
|
+
* Build a freshly-signed ES256 JWT to use as `client_secret` for Apple's
|
|
40
|
+
* token endpoint. Apple requires JWS spec signatures — IEEE P-1363 raw
|
|
41
|
+
* (r||s, 64 bytes), NOT DER. node:crypto's `createSign` defaults to DER
|
|
42
|
+
* for EC keys, so `dsaEncoding: 'ieee-p1363'` is mandatory.
|
|
43
|
+
*/
|
|
44
|
+
private _buildClientSecret;
|
|
45
|
+
/**
|
|
46
|
+
* Verify Apple's id_token: signature against the JWKS-resolved public key,
|
|
47
|
+
* then issuer / audience / expiration claims. Throws on any failure —
|
|
48
|
+
* never returns unverified data.
|
|
49
|
+
*/
|
|
50
|
+
private _verifyIdToken;
|
|
51
|
+
private _resolveAppleJwk;
|
|
52
|
+
/** @internal — testing only. */
|
|
53
|
+
static _resetJwksCache(): void;
|
|
16
54
|
}
|
|
17
55
|
//# sourceMappingURL=apple.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apple.d.ts","sourceRoot":"","sources":["../../src/drivers/apple.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"apple.d.ts","sourceRoot":"","sources":["../../src/drivers/apple.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,qBAAqB,EAAE,KAAK,wBAAwB,EAAE,MAAM,cAAc,CAAA;AACzG,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C;;;;;;GAMG;AACH,MAAM,WAAW,oBAAqB,SAAQ,qBAAqB;IACjE,mEAAmE;IACnE,MAAM,CAAC,EAAM,MAAM,CAAA;IACnB,iFAAiF;IACjF,KAAK,CAAC,EAAO,MAAM,CAAA;IACnB,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sFAAsF;IACtF,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AA+BD,qBAAa,aAAc,SAAQ,eAAe;IAGhD,OAAO,CAAC,MAAM,CAAC,UAAU,CAA8B;gBAE3C,MAAM,EAAE,oBAAoB;IAIxC,SAAS,CAAC,aAAa,IAAI,MAAM,EAAE;IACnC,SAAS,CAAC,OAAO,IAAK,MAAM;IAC5B,SAAS,CAAC,QAAQ,IAAI,MAAM;IAE5B,SAAS,CAAC,OAAO,IAAK,MAAM;cAET,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAO5D,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,UAAU;IAiB1G;;;;;;OAMG;IACY,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,wBAAwB,GAAG,OAAO,CAAC,UAAU,CAAC;YAuC5E,SAAS;IA4CvB;;;;;OAKG;YACW,kBAAkB;IAoDhC;;;;OAIG;YACW,cAAc;YA0Ed,gBAAgB;IAwB9B,gCAAgC;IAChC,MAAM,CAAC,eAAe,IAAI,IAAI;CAG/B"}
|
package/dist/drivers/apple.js
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
import { SocialiteDriver } from '../driver.js';
|
|
2
2
|
import { SocialUser } from '../social-user.js';
|
|
3
|
+
const APPLE_ISSUER = 'https://appleid.apple.com';
|
|
4
|
+
const APPLE_JWKS = 'https://appleid.apple.com/auth/keys';
|
|
5
|
+
const JWKS_TTL_MS = 60 * 60 * 1000; // 1 hour
|
|
6
|
+
const DEFAULT_JWT_TTL_SECONDS = 5 * 60;
|
|
3
7
|
export class AppleProvider extends SocialiteDriver {
|
|
8
|
+
// Process-wide cache shared across AppleProvider instances. JWKS is small
|
|
9
|
+
// and Apple's keys rotate slowly, so a 1h cache is well within their guidance.
|
|
10
|
+
static _jwksCache = null;
|
|
11
|
+
constructor(config) {
|
|
12
|
+
super(config);
|
|
13
|
+
}
|
|
4
14
|
defaultScopes() { return ['name', 'email']; }
|
|
5
15
|
authUrl() { return 'https://appleid.apple.com/auth/authorize'; }
|
|
6
16
|
tokenUrl() { return 'https://appleid.apple.com/auth/token'; }
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
scope: this.scopes.join(' '),
|
|
15
|
-
...(state ? { state } : {}),
|
|
16
|
-
});
|
|
17
|
-
return `${this.authUrl()}?${params.toString()}`;
|
|
17
|
+
// Apple sends user data in the id_token + first-auth form_post body, never a separate user endpoint.
|
|
18
|
+
userUrl() { return ''; }
|
|
19
|
+
extraAuthParams() {
|
|
20
|
+
// Apple requires form_post when the requested scopes include `name` or
|
|
21
|
+
// `email` (anything beyond `openid`) — the user-info payload is sent as
|
|
22
|
+
// a POST body, not a query.
|
|
23
|
+
return { response_mode: 'form_post' };
|
|
18
24
|
}
|
|
19
25
|
mapToUser(data, token, refreshToken) {
|
|
20
|
-
// Apple's id_token contains the user info as a JWT
|
|
21
26
|
const sub = data['sub'] ?? '';
|
|
22
27
|
const email = data['email'] ?? null;
|
|
23
28
|
const name = data['name'];
|
|
@@ -32,55 +37,219 @@ export class AppleProvider extends SocialiteDriver {
|
|
|
32
37
|
raw: data,
|
|
33
38
|
});
|
|
34
39
|
}
|
|
35
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* Exchange the auth code with Apple in a single POST, verify the returned
|
|
42
|
+
* id_token, and merge any first-authorization user details from the
|
|
43
|
+
* form_post body. Apple's auth codes are single-use, so this driver does
|
|
44
|
+
* NOT call the inherited `getAccessToken` — the token endpoint is hit
|
|
45
|
+
* exactly once per callback.
|
|
46
|
+
*/
|
|
36
47
|
async user(codeOrRequest) {
|
|
48
|
+
if (typeof codeOrRequest !== 'string') {
|
|
49
|
+
// Apple's `state` arrives in the form_post body, not the query — the
|
|
50
|
+
// base validator already checks both, no Apple-specific override needed.
|
|
51
|
+
this.validateRequestState(codeOrRequest);
|
|
52
|
+
}
|
|
37
53
|
const code = typeof codeOrRequest === 'string'
|
|
38
54
|
? codeOrRequest
|
|
39
55
|
: (codeOrRequest.query['code'] ?? codeOrRequest.body?.['code']);
|
|
40
56
|
if (!code)
|
|
41
57
|
throw new Error('[RudderJS Socialite] Missing authorization code.');
|
|
42
|
-
const { accessToken, refreshToken } = await this.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const userData = { ...idToken };
|
|
47
|
-
// Apple sends user name only on first authorization (as form POST body)
|
|
58
|
+
const { accessToken, refreshToken, idToken } = await this._exchange(code);
|
|
59
|
+
const claims = await this._verifyIdToken(idToken);
|
|
60
|
+
const userData = { ...claims };
|
|
61
|
+
// First authorization only — Apple sends `name` once, in the form_post body.
|
|
48
62
|
if (typeof codeOrRequest !== 'string' && codeOrRequest.body) {
|
|
49
63
|
const body = codeOrRequest.body;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
64
|
+
const userField = body['user'];
|
|
65
|
+
if (userField !== undefined) {
|
|
66
|
+
try {
|
|
67
|
+
const parsed = typeof userField === 'string' ? JSON.parse(userField) : userField;
|
|
68
|
+
if (parsed && typeof parsed === 'object' && 'name' in parsed) {
|
|
69
|
+
userData['name'] = parsed['name'];
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Malformed body.user — ignore, name simply won't be set.
|
|
74
|
+
}
|
|
53
75
|
}
|
|
54
76
|
}
|
|
55
77
|
return this.mapToUser(userData, accessToken, refreshToken);
|
|
56
78
|
}
|
|
57
|
-
|
|
79
|
+
// ─── Token exchange ────────────────────────────────────
|
|
80
|
+
async _exchange(code) {
|
|
81
|
+
const clientSecret = await this._buildClientSecret();
|
|
82
|
+
const res = await this.fetchWithTimeout(this.tokenUrl(), {
|
|
83
|
+
method: 'POST',
|
|
84
|
+
headers: {
|
|
85
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
86
|
+
'Accept': 'application/json',
|
|
87
|
+
},
|
|
88
|
+
body: new URLSearchParams({
|
|
89
|
+
client_id: this.config.clientId,
|
|
90
|
+
client_secret: clientSecret,
|
|
91
|
+
code,
|
|
92
|
+
redirect_uri: this.config.redirectUrl,
|
|
93
|
+
grant_type: 'authorization_code',
|
|
94
|
+
}),
|
|
95
|
+
});
|
|
96
|
+
if (!res.ok) {
|
|
97
|
+
throw await this.httpError('Apple token exchange failed', res);
|
|
98
|
+
}
|
|
99
|
+
const data = await res.json();
|
|
100
|
+
const accessToken = data['access_token'];
|
|
101
|
+
const refreshToken = data['refresh_token'];
|
|
102
|
+
const idToken = data['id_token'];
|
|
103
|
+
if (typeof accessToken !== 'string' || accessToken.length === 0) {
|
|
104
|
+
throw new Error('[RudderJS Socialite] Apple token-exchange response missing access_token.');
|
|
105
|
+
}
|
|
106
|
+
if (typeof idToken !== 'string' || idToken.length === 0) {
|
|
107
|
+
throw new Error('[RudderJS Socialite] Apple token-exchange response missing id_token.');
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
accessToken,
|
|
111
|
+
refreshToken: typeof refreshToken === 'string' && refreshToken.length > 0 ? refreshToken : null,
|
|
112
|
+
idToken,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// ─── O2: ES256 client_secret JWT ───────────────────────
|
|
116
|
+
/**
|
|
117
|
+
* Build a freshly-signed ES256 JWT to use as `client_secret` for Apple's
|
|
118
|
+
* token endpoint. Apple requires JWS spec signatures — IEEE P-1363 raw
|
|
119
|
+
* (r||s, 64 bytes), NOT DER. node:crypto's `createSign` defaults to DER
|
|
120
|
+
* for EC keys, so `dsaEncoding: 'ieee-p1363'` is mandatory.
|
|
121
|
+
*/
|
|
122
|
+
async _buildClientSecret() {
|
|
123
|
+
const cfg = this.config;
|
|
124
|
+
if (!cfg.teamId || !cfg.keyId || !cfg.privateKey) {
|
|
125
|
+
throw new Error('[RudderJS Socialite] Apple requires `teamId`, `keyId`, and `privateKey` ' +
|
|
126
|
+
'in config to sign the client_secret JWT. See https://developer.apple.com/sign-in-with-apple/.');
|
|
127
|
+
}
|
|
128
|
+
const { createPrivateKey, createSign } = await import('node:crypto');
|
|
129
|
+
const now = Math.floor(Date.now() / 1000);
|
|
130
|
+
const ttl = cfg.clientSecretTtl ?? DEFAULT_JWT_TTL_SECONDS;
|
|
131
|
+
const header = { alg: 'ES256', kid: cfg.keyId, typ: 'JWT' };
|
|
132
|
+
const payload = {
|
|
133
|
+
iss: cfg.teamId,
|
|
134
|
+
iat: now,
|
|
135
|
+
exp: now + ttl,
|
|
136
|
+
aud: APPLE_ISSUER,
|
|
137
|
+
sub: this.config.clientId,
|
|
138
|
+
};
|
|
139
|
+
const headerB64 = Buffer.from(JSON.stringify(header)).toString('base64url');
|
|
140
|
+
const payloadB64 = Buffer.from(JSON.stringify(payload)).toString('base64url');
|
|
141
|
+
const signingInput = `${headerB64}.${payloadB64}`;
|
|
142
|
+
let key;
|
|
143
|
+
try {
|
|
144
|
+
key = createPrivateKey({ key: cfg.privateKey, format: 'pem' });
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
throw new Error('[RudderJS Socialite] Apple `privateKey` is not a valid PEM-encoded EC private key. ' +
|
|
148
|
+
'(See `.p8` file from Apple Developer portal.)', { cause: err });
|
|
149
|
+
}
|
|
150
|
+
if (key.asymmetricKeyType !== 'ec') {
|
|
151
|
+
throw new Error(`[RudderJS Socialite] Apple expects an EC P-256 private key; got ${key.asymmetricKeyType ?? 'unknown'}.`);
|
|
152
|
+
}
|
|
153
|
+
const signer = createSign('SHA256');
|
|
154
|
+
signer.update(signingInput);
|
|
155
|
+
const signature = signer.sign({ key, dsaEncoding: 'ieee-p1363' }, 'base64url');
|
|
156
|
+
return `${signingInput}.${signature}`;
|
|
157
|
+
}
|
|
158
|
+
// ─── O3: id_token verification ─────────────────────────
|
|
159
|
+
/**
|
|
160
|
+
* Verify Apple's id_token: signature against the JWKS-resolved public key,
|
|
161
|
+
* then issuer / audience / expiration claims. Throws on any failure —
|
|
162
|
+
* never returns unverified data.
|
|
163
|
+
*/
|
|
164
|
+
async _verifyIdToken(idToken) {
|
|
165
|
+
const parts = idToken.split('.');
|
|
166
|
+
if (parts.length !== 3) {
|
|
167
|
+
throw new Error('[RudderJS Socialite] Apple id_token: malformed (expected 3 segments).');
|
|
168
|
+
}
|
|
169
|
+
const [headerB64, payloadB64, signatureB64] = parts;
|
|
170
|
+
let header;
|
|
58
171
|
try {
|
|
59
|
-
|
|
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'));
|
|
172
|
+
header = JSON.parse(Buffer.from(headerB64, 'base64url').toString('utf8'));
|
|
80
173
|
}
|
|
81
174
|
catch {
|
|
82
|
-
|
|
175
|
+
throw new Error('[RudderJS Socialite] Apple id_token: header is not valid JSON.');
|
|
176
|
+
}
|
|
177
|
+
if (header.alg !== 'RS256') {
|
|
178
|
+
throw new Error(`[RudderJS Socialite] Apple id_token: unexpected alg "${header.alg ?? ''}" (expected RS256).`);
|
|
179
|
+
}
|
|
180
|
+
if (typeof header.kid !== 'string' || header.kid.length === 0) {
|
|
181
|
+
throw new Error('[RudderJS Socialite] Apple id_token: header missing `kid`.');
|
|
182
|
+
}
|
|
183
|
+
const jwk = await this._resolveAppleJwk(header.kid);
|
|
184
|
+
if (!jwk) {
|
|
185
|
+
throw new Error(`[RudderJS Socialite] Apple id_token: no signing key for kid "${header.kid}".`);
|
|
83
186
|
}
|
|
187
|
+
const { createPublicKey, createVerify } = await import('node:crypto');
|
|
188
|
+
let publicKey;
|
|
189
|
+
try {
|
|
190
|
+
// node:crypto's createPublicKey accepts a JsonWebKey from lib.dom; this
|
|
191
|
+
// package targets Node and doesn't include DOM lib, so widen via
|
|
192
|
+
// `as never` (bottom type, assignable to the parameter's expected type).
|
|
193
|
+
publicKey = createPublicKey({ key: jwk, format: 'jwk' });
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
throw new Error('[RudderJS Socialite] Apple id_token: failed to import JWKS public key.', { cause: err });
|
|
197
|
+
}
|
|
198
|
+
const verifier = createVerify('SHA256');
|
|
199
|
+
verifier.update(`${headerB64}.${payloadB64}`);
|
|
200
|
+
if (!verifier.verify(publicKey, signatureB64, 'base64url')) {
|
|
201
|
+
throw new Error('[RudderJS Socialite] Apple id_token: signature verification failed.');
|
|
202
|
+
}
|
|
203
|
+
let claims;
|
|
204
|
+
try {
|
|
205
|
+
claims = JSON.parse(Buffer.from(payloadB64, 'base64url').toString('utf8'));
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
throw new Error('[RudderJS Socialite] Apple id_token: payload is not valid JSON.');
|
|
209
|
+
}
|
|
210
|
+
if (claims.iss !== APPLE_ISSUER) {
|
|
211
|
+
throw new Error(`[RudderJS Socialite] Apple id_token: iss "${claims.iss ?? ''}" does not match "${APPLE_ISSUER}".`);
|
|
212
|
+
}
|
|
213
|
+
const expectedAud = this.config.clientId;
|
|
214
|
+
const audMatches = Array.isArray(claims.aud)
|
|
215
|
+
? claims.aud.includes(expectedAud)
|
|
216
|
+
: claims.aud === expectedAud;
|
|
217
|
+
if (!audMatches) {
|
|
218
|
+
throw new Error('[RudderJS Socialite] Apple id_token: aud does not match clientId.');
|
|
219
|
+
}
|
|
220
|
+
if (typeof claims.exp !== 'number' || claims.exp * 1000 <= Date.now()) {
|
|
221
|
+
throw new Error('[RudderJS Socialite] Apple id_token: token expired or missing exp.');
|
|
222
|
+
}
|
|
223
|
+
if (typeof claims.sub !== 'string' || claims.sub.length === 0) {
|
|
224
|
+
throw new Error('[RudderJS Socialite] Apple id_token: missing sub.');
|
|
225
|
+
}
|
|
226
|
+
return claims;
|
|
227
|
+
}
|
|
228
|
+
async _resolveAppleJwk(kid) {
|
|
229
|
+
const cache = AppleProvider._jwksCache;
|
|
230
|
+
if (cache && Date.now() - cache.fetchedAt < JWKS_TTL_MS) {
|
|
231
|
+
const hit = cache.keys.get(kid);
|
|
232
|
+
if (hit)
|
|
233
|
+
return hit;
|
|
234
|
+
// Fall through — kid not in cache. Apple may have rotated; refetch.
|
|
235
|
+
}
|
|
236
|
+
const res = await this.fetchWithTimeout(APPLE_JWKS, { headers: { Accept: 'application/json' } });
|
|
237
|
+
if (!res.ok) {
|
|
238
|
+
throw await this.httpError('Apple JWKS fetch failed', res);
|
|
239
|
+
}
|
|
240
|
+
const body = await res.json();
|
|
241
|
+
const keys = Array.isArray(body.keys) ? body.keys : [];
|
|
242
|
+
const map = new Map();
|
|
243
|
+
for (const k of keys) {
|
|
244
|
+
if (typeof k.kid === 'string')
|
|
245
|
+
map.set(k.kid, k);
|
|
246
|
+
}
|
|
247
|
+
AppleProvider._jwksCache = { fetchedAt: Date.now(), keys: map };
|
|
248
|
+
return map.get(kid);
|
|
249
|
+
}
|
|
250
|
+
/** @internal — testing only. */
|
|
251
|
+
static _resetJwksCache() {
|
|
252
|
+
AppleProvider._jwksCache = null;
|
|
84
253
|
}
|
|
85
254
|
}
|
|
86
255
|
//# sourceMappingURL=apple.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apple.js","sourceRoot":"","sources":["../../src/drivers/apple.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"apple.js","sourceRoot":"","sources":["../../src/drivers/apple.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAA6D,MAAM,cAAc,CAAA;AACzG,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAuC9C,MAAM,YAAY,GAAG,2BAA2B,CAAA;AAChD,MAAM,UAAU,GAAK,qCAAqC,CAAA;AAC1D,MAAM,WAAW,GAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA,CAAE,SAAS;AAC9C,MAAM,uBAAuB,GAAG,CAAC,GAAG,EAAE,CAAA;AAOtC,MAAM,OAAO,aAAc,SAAQ,eAAe;IAChD,0EAA0E;IAC1E,+EAA+E;IACvE,MAAM,CAAC,UAAU,GAA0B,IAAI,CAAA;IAEvD,YAAY,MAA4B;QACtC,KAAK,CAAC,MAAM,CAAC,CAAA;IACf,CAAC;IAES,aAAa,KAAe,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA,CAAC,CAAC;IACtD,OAAO,KAAc,OAAO,0CAA0C,CAAA,CAAC,CAAC;IACxE,QAAQ,KAAa,OAAO,sCAAsC,CAAA,CAAC,CAAC;IAC9E,qGAAqG;IAC3F,OAAO,KAAc,OAAO,EAAE,CAAA,CAAC,CAAC;IAEvB,eAAe;QAChC,uEAAuE;QACvE,wEAAwE;QACxE,4BAA4B;QAC5B,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,CAAA;IACvC,CAAC;IAES,SAAS,CAAC,IAA6B,EAAE,KAAa,EAAE,YAA2B;QAC3F,MAAM,GAAG,GAAM,IAAI,CAAC,KAAK,CAAwB,IAAI,EAAE,CAAA;QACvD,MAAM,KAAK,GAAI,IAAI,CAAC,OAAO,CAAwB,IAAI,IAAI,CAAA;QAC3D,MAAM,IAAI,GAAI,IAAI,CAAC,MAAM,CAA0D,CAAA;QAEnF,OAAO,IAAI,UAAU,CAAC;YACpB,EAAE,EAAQ,GAAG;YACb,IAAI,EAAM,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI;YACzF,KAAK;YACL,MAAM,EAAI,IAAI,EAAG,gCAAgC;YACjD,QAAQ,EAAE,IAAI;YACd,KAAK;YACL,YAAY;YACZ,GAAG,EAAE,IAAI;SACV,CAAC,CAAA;IACJ,CAAC;IAED;;;;;;OAMG;IACM,KAAK,CAAC,IAAI,CAAC,aAAgD;QAClE,IAAI,OAAO,aAAa,KAAK,QAAQ,EAAE,CAAC;YACtC,qEAAqE;YACrE,yEAAyE;YACzE,IAAI,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAA;QAC1C,CAAC;QAED,MAAM,IAAI,GAAG,OAAO,aAAa,KAAK,QAAQ;YAC5C,CAAC,CAAC,aAAa;YACf,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,IAAK,aAAa,CAAC,IAA2C,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;QAEzG,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAA;QAE9E,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QACzE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAA;QAEjD,MAAM,QAAQ,GAA4B,EAAE,GAAG,MAAM,EAAE,CAAA;QAEvD,6EAA6E;QAC7E,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,CAAC,IAAI,EAAE,CAAC;YAC5D,MAAM,IAAI,GAAG,aAAa,CAAC,IAA+B,CAAA;YAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;YAC9B,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC5B,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;oBAChF,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,IAAK,MAAkC,EAAE,CAAC;wBAC1F,QAAQ,CAAC,MAAM,CAAC,GAAI,MAAkC,CAAC,MAAM,CAAC,CAAA;oBAChE,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,0DAA0D;gBAC5D,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,WAAW,EAAE,YAAY,CAAC,CAAA;IAC5D,CAAC;IAED,0DAA0D;IAElD,KAAK,CAAC,SAAS,CAAC,IAAY;QAClC,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAA;QAEpD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE;YACvD,MAAM,EAAG,MAAM;YACf,OAAO,EAAE;gBACP,cAAc,EAAE,mCAAmC;gBACnD,QAAQ,EAAQ,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,eAAe,CAAC;gBACxB,SAAS,EAAM,IAAI,CAAC,MAAM,CAAC,QAAQ;gBACnC,aAAa,EAAE,YAAY;gBAC3B,IAAI;gBACJ,YAAY,EAAG,IAAI,CAAC,MAAM,CAAC,WAAW;gBACtC,UAAU,EAAK,oBAAoB;aACpC,CAAC;SACH,CAAC,CAAA;QAEF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,MAAM,IAAI,CAAC,SAAS,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAA;QAChE,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAA6B,CAAA;QAExD,MAAM,WAAW,GAAI,IAAI,CAAC,cAAc,CAAC,CAAA;QACzC,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,CAAA;QAC1C,MAAM,OAAO,GAAQ,IAAI,CAAC,UAAU,CAAC,CAAA;QAErC,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChE,MAAM,IAAI,KAAK,CAAC,0EAA0E,CAAC,CAAA;QAC7F,CAAC;QACD,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxD,MAAM,IAAI,KAAK,CAAC,sEAAsE,CAAC,CAAA;QACzF,CAAC;QAED,OAAO;YACL,WAAW;YACX,YAAY,EAAE,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI;YAC/F,OAAO;SACR,CAAA;IACH,CAAC;IAED,0DAA0D;IAE1D;;;;;OAKG;IACK,KAAK,CAAC,kBAAkB;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,MAA8B,CAAA;QAC/C,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;YACjD,MAAM,IAAI,KAAK,CACb,0EAA0E;gBAC1E,+FAA+F,CAChG,CAAA;QACH,CAAC;QAED,MAAM,EAAE,gBAAgB,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;QAEpE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;QACzC,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,IAAI,uBAAuB,CAAA;QAE1D,MAAM,MAAM,GAAI,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAA;QAC5D,MAAM,OAAO,GAAG;YACd,GAAG,EAAE,GAAG,CAAC,MAAM;YACf,GAAG,EAAE,GAAG;YACR,GAAG,EAAE,GAAG,GAAG,GAAG;YACd,GAAG,EAAE,YAAY;YACjB,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;SAC1B,CAAA;QAED,MAAM,SAAS,GAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;QAC9E,MAAM,UAAU,GAAK,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;QAC/E,MAAM,YAAY,GAAG,GAAG,SAAS,IAAI,UAAU,EAAE,CAAA;QAEjD,IAAI,GAAG,CAAA;QACP,IAAI,CAAC;YACH,GAAG,GAAG,gBAAgB,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;QAChE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,qFAAqF;gBACrF,+CAA+C,EAC/C,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAA;QACH,CAAC;QACD,IAAI,GAAG,CAAC,iBAAiB,KAAK,IAAI,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CACb,mEAAmE,GAAG,CAAC,iBAAiB,IAAI,SAAS,GAAG,CACzG,CAAA;QACH,CAAC;QAED,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAA;QACnC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;QAC3B,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,YAAY,EAAE,EAAE,WAAW,CAAC,CAAA;QAE9E,OAAO,GAAG,YAAY,IAAI,SAAS,EAAE,CAAA;IACvC,CAAC;IAED,0DAA0D;IAE1D;;;;OAIG;IACK,KAAK,CAAC,cAAc,CAAC,OAAe;QAC1C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAChC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAA;QAC1F,CAAC;QACD,MAAM,CAAC,SAAS,EAAE,UAAU,EAAE,YAAY,CAAC,GAAG,KAAiC,CAAA;QAE/E,IAAI,MAAsC,CAAA;QAC1C,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAmC,CAAA;QAC7G,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAA;QACnF,CAAC;QAED,IAAI,MAAM,CAAC,GAAG,KAAK,OAAO,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,wDAAwD,MAAM,CAAC,GAAG,IAAI,EAAE,qBAAqB,CAAC,CAAA;QAChH,CAAC;QACD,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9D,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAA;QAC/E,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACnD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,gEAAgE,MAAM,CAAC,GAAG,IAAI,CAAC,CAAA;QACjG,CAAC;QAED,MAAM,EAAE,eAAe,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;QAErE,IAAI,SAAS,CAAA;QACb,IAAI,CAAC;YACH,wEAAwE;YACxE,iEAAiE;YACjE,yEAAyE;YACzE,SAAS,GAAG,eAAe,CAAC,EAAE,GAAG,EAAE,GAAY,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;QACnE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,wEAAwE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAA;QAC3G,CAAC;QAED,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAA;QACvC,QAAQ,CAAC,MAAM,CAAC,GAAG,SAAS,IAAI,UAAU,EAAE,CAAC,CAAA;QAC7C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,YAAY,EAAE,WAAW,CAAC,EAAE,CAAC;YAC3D,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAA;QACxF,CAAC;QAED,IAAI,MAA0B,CAAA;QAC9B,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAuB,CAAA;QAClG,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAA;QACpF,CAAC;QAED,IAAI,MAAM,CAAC,GAAG,KAAK,YAAY,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,6CAA6C,MAAM,CAAC,GAAG,IAAI,EAAE,qBAAqB,YAAY,IAAI,CAAC,CAAA;QACrH,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAA;QACxC,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC;YAC1C,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC;YAClC,CAAC,CAAC,MAAM,CAAC,GAAG,KAAK,WAAW,CAAA;QAC9B,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAA;QACtF,CAAC;QAED,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,GAAG,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YACtE,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAA;QACvF,CAAC;QAED,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9D,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;QACtE,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,GAAW;QACxC,MAAM,KAAK,GAAG,aAAa,CAAC,UAAU,CAAA;QACtC,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,WAAW,EAAE,CAAC;YACxD,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAC/B,IAAI,GAAG;gBAAE,OAAO,GAAG,CAAA;YACnB,oEAAoE;QACtE,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAA;QAChG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,MAAM,IAAI,CAAC,SAAS,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAA;QAC5D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAA2B,CAAA;QACtD,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;QACtD,MAAM,GAAG,GAAI,IAAI,GAAG,EAAoB,CAAA;QACxC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,IAAI,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ;gBAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;QAClD,CAAC;QAED,aAAa,CAAC,UAAU,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAA;QAC/D,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACrB,CAAC;IAED,gCAAgC;IAChC,MAAM,CAAC,eAAe;QACpB,aAAa,CAAC,UAAU,GAAG,IAAI,CAAA;IACjC,CAAC"}
|
package/dist/drivers/github.js
CHANGED
|
@@ -39,7 +39,7 @@ export class GitHubProvider extends SocialiteDriver {
|
|
|
39
39
|
}
|
|
40
40
|
async fetchPrimaryEmail(token) {
|
|
41
41
|
try {
|
|
42
|
-
const res = await
|
|
42
|
+
const res = await this.fetchWithTimeout('https://api.github.com/user/emails', {
|
|
43
43
|
headers: { 'Authorization': `Bearer ${token}`, 'Accept': 'application/json' },
|
|
44
44
|
});
|
|
45
45
|
if (!res.ok)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/drivers/github.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,MAAM,OAAO,cAAe,SAAQ,eAAe;IACvC,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,
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/drivers/github.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,MAAM,OAAO,cAAe,SAAQ,eAAe;IACvC,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,IAAI,CAAC,gBAAgB,CAAC,oCAAoC,EAAE;gBAC5E,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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { ServiceProvider } from '@rudderjs/core';
|
|
2
2
|
import { SocialiteDriver, type SocialiteDriverConfig } from './driver.js';
|
|
3
3
|
export { SocialUser } from './social-user.js';
|
|
4
|
-
export { SocialiteDriver } from './driver.js';
|
|
4
|
+
export { SocialiteDriver, InvalidStateException } from './driver.js';
|
|
5
5
|
export { GitHubProvider } from './drivers/github.js';
|
|
6
6
|
export { GoogleProvider } from './drivers/google.js';
|
|
7
7
|
export { FacebookProvider } from './drivers/facebook.js';
|
|
8
8
|
export { AppleProvider } from './drivers/apple.js';
|
|
9
|
-
export type { SocialiteDriverConfig } from './driver.js';
|
|
9
|
+
export type { SocialiteDriverConfig, SocialiteCallbackRequest, SocialiteHttpErrorCause } from './driver.js';
|
|
10
|
+
export type { AppleSocialiteConfig } from './drivers/apple.js';
|
|
10
11
|
type DriverFactory = (config: SocialiteDriverConfig) => SocialiteDriver;
|
|
11
12
|
export declare class Socialite {
|
|
12
13
|
private static _config;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAU,MAAM,gBAAgB,CAAA;AACxD,OAAO,EAAE,eAAe,EAAE,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAQzE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAU,MAAM,gBAAgB,CAAA;AACxD,OAAO,EAAE,eAAe,EAAE,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAQzE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACpE,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,qBAAqB,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAC3G,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAI9D,KAAK,aAAa,GAAG,CAAC,MAAM,EAAE,qBAAqB,KAAK,eAAe,CAAA;AAWvE,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAC,OAAO,CAAsB;IAC5C,OAAO,CAAC,MAAM,CAAC,OAAO,CAAmC;IACzD,OAAO,CAAC,MAAM,CAAC,UAAU,CAAqC;IAE9D,+CAA+C;IAC/C,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe;IAe5C,sCAAsC;IACtC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI;IAQzD,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,qBAAqB,CAAC,CAAA;AAInE;;;;;;;;;;GAUG;AACH,qBAAa,iBAAkB,SAAQ,eAAe;IACpD,QAAQ,IAAI,IAAI;IAEV,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAK5B"}
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { FacebookProvider } from './drivers/facebook.js';
|
|
|
5
5
|
import { AppleProvider } from './drivers/apple.js';
|
|
6
6
|
// ─── Re-exports ───────────────────────────────────────────
|
|
7
7
|
export { SocialUser } from './social-user.js';
|
|
8
|
-
export { SocialiteDriver } from './driver.js';
|
|
8
|
+
export { SocialiteDriver, InvalidStateException } from './driver.js';
|
|
9
9
|
export { GitHubProvider } from './drivers/github.js';
|
|
10
10
|
export { GoogleProvider } from './drivers/google.js';
|
|
11
11
|
export { FacebookProvider } from './drivers/facebook.js';
|
|
@@ -39,6 +39,10 @@ export class Socialite {
|
|
|
39
39
|
/** Register a custom OAuth driver. */
|
|
40
40
|
static extend(name, factory) {
|
|
41
41
|
this._custom.set(name, factory);
|
|
42
|
+
// Drop any previously cached instance so the next driver(name) call uses
|
|
43
|
+
// the new factory. Without this, calling extend() after driver() is silent
|
|
44
|
+
// no-op and the old driver lingers (bites hot-reload + runtime override).
|
|
45
|
+
this._instances.delete(name);
|
|
42
46
|
}
|
|
43
47
|
/** @internal — set config from the service provider. */
|
|
44
48
|
static configure(config) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAExD,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,6DAA6D;AAE7D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rudderjs/socialite",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"rudderjs": {
|
|
5
5
|
"provider": "SocialiteProvider",
|
|
6
6
|
"stage": "feature"
|
|
@@ -25,11 +25,20 @@
|
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@rudderjs/core": "^1.1.
|
|
28
|
+
"@rudderjs/core": "^1.1.4"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"@rudderjs/session": "^2.0.0"
|
|
32
|
+
},
|
|
33
|
+
"peerDependenciesMeta": {
|
|
34
|
+
"@rudderjs/session": {
|
|
35
|
+
"optional": false
|
|
36
|
+
}
|
|
29
37
|
},
|
|
30
38
|
"devDependencies": {
|
|
31
39
|
"@types/node": "^20.0.0",
|
|
32
|
-
"typescript": "^5.4.0"
|
|
40
|
+
"typescript": "^5.4.0",
|
|
41
|
+
"@rudderjs/session": "^2.0.0"
|
|
33
42
|
},
|
|
34
43
|
"author": "Suleiman Shahbari",
|
|
35
44
|
"scripts": {
|