@smarthivelabs-devs/auth-sdk 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/dist/index.cjs +137 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +113 -1
- package/dist/index.d.ts +113 -1
- package/dist/index.js +136 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -131,6 +131,44 @@ await client.login({ state: "my-custom-state" });
|
|
|
131
131
|
|
|
132
132
|
---
|
|
133
133
|
|
|
134
|
+
### `client.loginSocial(provider, options?)`
|
|
135
|
+
|
|
136
|
+
Initiates a per-project social OAuth flow. The browser is redirected to the provider's consent screen using **your project's own** Google/Apple/GitHub credentials — the consent screen shows your app name, not SmartHive's.
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
// Redirect to Google's consent screen
|
|
140
|
+
await client.loginSocial("google");
|
|
141
|
+
|
|
142
|
+
// Override the redirect_uri that receives the tokens
|
|
143
|
+
await client.loginSocial("github", { redirectUri: "https://myapp.com/auth/social/callback" });
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Supported providers:
|
|
147
|
+
`google` · `apple` · `github` · `facebook` · `twitter` · `linkedin` · `microsoft` · `discord` · `spotify` · `twitch` · `reddit` · `gitlab` · `slack` · `notion` · `zoom` · `figma`
|
|
148
|
+
|
|
149
|
+
Configure each provider's credentials in your SmartHive dashboard under **Project → OAuth Providers**.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
### `client.handleSocialCallback(options?)`
|
|
154
|
+
|
|
155
|
+
Called on the page/route that your `redirectUri` points to after a social OAuth flow. Reads `access_token` and `refresh_token` from the URL query params, persists the session, and returns it.
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
// On your /auth/social/callback page — reads window.location automatically
|
|
159
|
+
const session = await client.handleSocialCallback();
|
|
160
|
+
|
|
161
|
+
// Or pass the URL explicitly (SSR / React Native)
|
|
162
|
+
const session = await client.handleSocialCallback({ url: window.location.href });
|
|
163
|
+
|
|
164
|
+
console.log(session.accessToken); // short-lived JWT
|
|
165
|
+
console.log(session.refreshToken); // long-lived session token
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Throws `SmartHiveAuthError` with code `social_auth_failed` if the provider returned an error, or `callback_failed` if no `access_token` is present.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
134
172
|
### `client.handleCallback(options?)`
|
|
135
173
|
|
|
136
174
|
Completes the OAuth flow on your callback route. Exchanges the authorization code for tokens and persists the session.
|
|
@@ -382,6 +420,7 @@ import type {
|
|
|
382
420
|
SmartHiveAuthClient,
|
|
383
421
|
AuthSession,
|
|
384
422
|
AuthStorage,
|
|
423
|
+
SocialProvider,
|
|
385
424
|
} from "@smarthivelabs-devs/auth-sdk";
|
|
386
425
|
```
|
|
387
426
|
|
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
SmartHiveAuthError: () => SmartHiveAuthError,
|
|
24
|
+
envFromPublishableKey: () => envFromPublishableKey,
|
|
24
25
|
generateCodeChallenge: () => generateCodeChallenge,
|
|
25
26
|
generateCodeVerifier: () => generateCodeVerifier,
|
|
26
27
|
initAuth: () => initAuth,
|
|
@@ -73,11 +74,17 @@ function sessionStorageAdapter() {
|
|
|
73
74
|
function normalizeBaseUrl(baseUrl) {
|
|
74
75
|
return baseUrl.replace(/\/$/, "");
|
|
75
76
|
}
|
|
77
|
+
function envFromPublishableKey(publishableKey) {
|
|
78
|
+
const match = publishableKey.match(/^pk_(dev|staging|prod)_/);
|
|
79
|
+
return match ? match[1] : "prod";
|
|
80
|
+
}
|
|
76
81
|
function initAuth(config) {
|
|
77
82
|
const baseUrl = normalizeBaseUrl(config.baseUrl);
|
|
78
83
|
const authBase = normalizeBaseUrl(config.authDomain ?? config.baseUrl);
|
|
79
84
|
const storage = config.storage ?? browserStorage();
|
|
80
85
|
const tempStorage = config.temporaryStorage ?? sessionStorageAdapter();
|
|
86
|
+
const environment = envFromPublishableKey(config.publishableKey);
|
|
87
|
+
const headlessBase = `${baseUrl}/${environment}/api/auth/headless`;
|
|
81
88
|
async function saveSession(session) {
|
|
82
89
|
if (!session) {
|
|
83
90
|
await storage.removeItem(smartHiveAuthStorageKeys.session);
|
|
@@ -89,6 +96,106 @@ function initAuth(config) {
|
|
|
89
96
|
const raw = await storage.getItem(smartHiveAuthStorageKeys.session);
|
|
90
97
|
return raw ? JSON.parse(raw) : null;
|
|
91
98
|
}
|
|
99
|
+
function rawToSession(raw) {
|
|
100
|
+
return {
|
|
101
|
+
accessToken: raw.access_token,
|
|
102
|
+
refreshToken: raw.refresh_token,
|
|
103
|
+
expiresAt: Date.now() + raw.expires_in * 1e3,
|
|
104
|
+
user: raw.user
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
async function headlessPost(path, body) {
|
|
108
|
+
const res = await fetch(`${headlessBase}${path}`, {
|
|
109
|
+
method: "POST",
|
|
110
|
+
headers: { "content-type": "application/json" },
|
|
111
|
+
body: JSON.stringify(body)
|
|
112
|
+
});
|
|
113
|
+
if (!res.ok) {
|
|
114
|
+
const err = await res.json().catch(() => ({}));
|
|
115
|
+
throw new SmartHiveAuthError(
|
|
116
|
+
err.error ?? "request_failed",
|
|
117
|
+
err.message ?? `Request to ${path} failed.`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
return res.json();
|
|
121
|
+
}
|
|
122
|
+
async function headlessSignInAndSave(path, body) {
|
|
123
|
+
const raw = await headlessPost(path, body);
|
|
124
|
+
const result = rawToSession(raw);
|
|
125
|
+
await saveSession(result);
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
const headless = {
|
|
129
|
+
signIn: {
|
|
130
|
+
async email({ email, password }) {
|
|
131
|
+
return headlessSignInAndSave("/sign-in/email", { email, password });
|
|
132
|
+
},
|
|
133
|
+
phone: {
|
|
134
|
+
async sendOtp({ phoneNumber }) {
|
|
135
|
+
await headlessPost("/phone/send-otp", { phoneNumber });
|
|
136
|
+
},
|
|
137
|
+
async verify({ phoneNumber, code }) {
|
|
138
|
+
return headlessSignInAndSave("/phone/verify", { phoneNumber, code });
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
emailOtp: {
|
|
142
|
+
async send({ email }) {
|
|
143
|
+
await headlessPost("/email-otp/send", { email });
|
|
144
|
+
},
|
|
145
|
+
async verify({ email, code }) {
|
|
146
|
+
return headlessSignInAndSave("/email-otp/verify", { email, code });
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
magicLink: {
|
|
150
|
+
async send({ email, callbackURL }) {
|
|
151
|
+
await headlessPost("/magic-link/send", { email, ...callbackURL ? { callbackURL } : {} });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
signUp: {
|
|
156
|
+
async email({ email, password, name }) {
|
|
157
|
+
const res = await fetch(`${headlessBase}/sign-up/email`, {
|
|
158
|
+
method: "POST",
|
|
159
|
+
headers: { "content-type": "application/json" },
|
|
160
|
+
body: JSON.stringify({ email, password, name })
|
|
161
|
+
});
|
|
162
|
+
if (res.status === 202) {
|
|
163
|
+
return { accessToken: "", refreshToken: "", expiresAt: 0, requiresVerification: true };
|
|
164
|
+
}
|
|
165
|
+
if (!res.ok) {
|
|
166
|
+
const err = await res.json().catch(() => ({}));
|
|
167
|
+
throw new SmartHiveAuthError(err.error ?? "sign_up_failed", err.message ?? "Sign up failed.");
|
|
168
|
+
}
|
|
169
|
+
const raw = await res.json();
|
|
170
|
+
const result = { ...rawToSession(raw), requiresVerification: false };
|
|
171
|
+
await saveSession(result);
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
async refreshToken({ refreshToken }) {
|
|
176
|
+
const raw = await headlessPost("/token/refresh", { refresh_token: refreshToken });
|
|
177
|
+
const updated = {
|
|
178
|
+
...await readSession() ?? {},
|
|
179
|
+
accessToken: raw.access_token,
|
|
180
|
+
expiresAt: Date.now() + raw.expires_in * 1e3
|
|
181
|
+
};
|
|
182
|
+
await saveSession(updated);
|
|
183
|
+
return { accessToken: raw.access_token, expiresAt: updated.expiresAt };
|
|
184
|
+
},
|
|
185
|
+
async signOut({ refreshToken } = {}) {
|
|
186
|
+
const session = await readSession();
|
|
187
|
+
const token = refreshToken ?? session?.refreshToken;
|
|
188
|
+
await saveSession(null);
|
|
189
|
+
if (token) {
|
|
190
|
+
await fetch(`${headlessBase}/sign-out`, {
|
|
191
|
+
method: "POST",
|
|
192
|
+
headers: { "content-type": "application/json" },
|
|
193
|
+
body: JSON.stringify({ refresh_token: token })
|
|
194
|
+
}).catch(() => {
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
};
|
|
92
199
|
const client = {
|
|
93
200
|
async initialize() {
|
|
94
201
|
const response = await fetch(
|
|
@@ -156,6 +263,33 @@ function initAuth(config) {
|
|
|
156
263
|
await tempStorage.removeItem(smartHiveAuthStorageKeys.pkceState);
|
|
157
264
|
return session;
|
|
158
265
|
},
|
|
266
|
+
async loginSocial(provider, options) {
|
|
267
|
+
const redirectUri = options?.redirectUri ?? config.redirectUri ?? globalThis.location?.href;
|
|
268
|
+
if (!redirectUri) throw new SmartHiveAuthError("missing_redirect_uri", "redirectUri is required for social login.");
|
|
269
|
+
const url = new URL(`${authBase}/${environment}/api/auth/social/${provider}`);
|
|
270
|
+
url.searchParams.set("project_id", config.projectId);
|
|
271
|
+
url.searchParams.set("redirect_uri", redirectUri);
|
|
272
|
+
globalThis.location.assign(url.toString());
|
|
273
|
+
},
|
|
274
|
+
async handleSocialCallback(options) {
|
|
275
|
+
const href = options?.url ?? globalThis.location?.href;
|
|
276
|
+
if (!href) throw new SmartHiveAuthError("callback_failed", "No URL available for social callback.");
|
|
277
|
+
const url = new URL(href);
|
|
278
|
+
const error = url.searchParams.get("error");
|
|
279
|
+
if (error) {
|
|
280
|
+
throw new SmartHiveAuthError(error, url.searchParams.get("error_description") ?? error);
|
|
281
|
+
}
|
|
282
|
+
const accessToken = url.searchParams.get("access_token");
|
|
283
|
+
if (!accessToken) throw new SmartHiveAuthError("callback_failed", "No access token in social callback URL.");
|
|
284
|
+
const expiresIn = url.searchParams.get("expires_in");
|
|
285
|
+
const session = {
|
|
286
|
+
accessToken,
|
|
287
|
+
refreshToken: url.searchParams.get("refresh_token") ?? void 0,
|
|
288
|
+
expiresAt: expiresIn ? Date.now() + parseInt(expiresIn, 10) * 1e3 : void 0
|
|
289
|
+
};
|
|
290
|
+
await saveSession(session);
|
|
291
|
+
return session;
|
|
292
|
+
},
|
|
159
293
|
async logout() {
|
|
160
294
|
await saveSession(null);
|
|
161
295
|
await fetch(`${baseUrl}/api/auth/sign-out`, { method: "POST", credentials: "include" });
|
|
@@ -222,13 +356,15 @@ function initAuth(config) {
|
|
|
222
356
|
headers: { authorization: `Bearer ${token}` }
|
|
223
357
|
});
|
|
224
358
|
return response.ok ? response.json() : null;
|
|
225
|
-
}
|
|
359
|
+
},
|
|
360
|
+
headless
|
|
226
361
|
};
|
|
227
362
|
return client;
|
|
228
363
|
}
|
|
229
364
|
// Annotate the CommonJS export names for ESM import in node:
|
|
230
365
|
0 && (module.exports = {
|
|
231
366
|
SmartHiveAuthError,
|
|
367
|
+
envFromPublishableKey,
|
|
232
368
|
generateCodeChallenge,
|
|
233
369
|
generateCodeVerifier,
|
|
234
370
|
initAuth,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export interface SmartHiveAuthConfig {\n projectId: string;\n publishableKey: string;\n baseUrl: string;\n /** Custom branded auth domain, e.g. \"https://auth.myapp.com\". Used as the entry point for login/token flows. Falls back to baseUrl. */\n authDomain?: string;\n /** Fallback auth domain if authDomain is unreachable, e.g. \"https://auth.smarthivelabs.dev\". */\n fallbackAuthDomain?: string;\n redirectUri?: string;\n storage?: AuthStorage;\n temporaryStorage?: AuthStorage;\n}\n\nexport interface AuthStorage {\n getItem(key: string): string | null | Promise<string | null>;\n setItem(key: string, value: string): void | Promise<void>;\n removeItem(key: string): void | Promise<void>;\n}\n\nexport interface AuthSession {\n accessToken: string;\n refreshToken?: string;\n expiresAt?: number;\n user?: unknown;\n}\n\nexport interface SmartHiveAuthClient {\n initialize(): Promise<void>;\n login(options?: { redirectUri?: string; state?: string }): Promise<void>;\n handleCallback(options?: { url?: string }): Promise<AuthSession>;\n logout(): Promise<void>;\n getSession(): Promise<AuthSession | null>;\n getAccessToken(): Promise<string | null>;\n getAuthorizationHeader(): Promise<Record<string, string>>;\n fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;\n refreshSession(): Promise<AuthSession | null>;\n verifyToken(token: string): Promise<boolean>;\n getUser(): Promise<unknown>;\n}\n\nexport class SmartHiveAuthError extends Error {\n constructor(public code: string, message: string) {\n super(message);\n this.name = \"SmartHiveAuthError\";\n }\n}\n\n// ── PKCE helpers (Web Crypto — works in browser + Node 18+) ──────────────────\n\nexport async function generateCodeVerifier(): Promise<string> {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return base64urlEncode(array);\n}\n\nexport async function generateCodeChallenge(verifier: string): Promise<string> {\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const digest = await crypto.subtle.digest(\"SHA-256\", data);\n return base64urlEncode(new Uint8Array(digest));\n}\n\nfunction base64urlEncode(buffer: Uint8Array): string {\n let str = \"\";\n for (const byte of buffer) str += String.fromCharCode(byte);\n return btoa(str).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\n// ── Storage keys ─────────────────────────────────────────────────────────────\n\nexport const smartHiveAuthStorageKeys = {\n session: \"smarthive.auth.session\",\n pkceVerifier: \"smarthive.auth.pkce_verifier\",\n pkceState: \"smarthive.auth.pkce_state\"\n} as const;\n\nfunction browserStorage(): AuthStorage {\n return {\n getItem: (key) => globalThis.localStorage?.getItem(key) ?? null,\n setItem: (key, value) => globalThis.localStorage?.setItem(key, value),\n removeItem: (key) => globalThis.localStorage?.removeItem(key)\n };\n}\n\nfunction sessionStorageAdapter(): Pick<AuthStorage, \"getItem\" | \"setItem\" | \"removeItem\"> {\n return {\n getItem: (key) => globalThis.sessionStorage?.getItem(key) ?? null,\n setItem: (key, value) => globalThis.sessionStorage?.setItem(key, value),\n removeItem: (key) => globalThis.sessionStorage?.removeItem(key)\n };\n}\n\nfunction normalizeBaseUrl(baseUrl: string) {\n return baseUrl.replace(/\\/$/, \"\");\n}\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\nexport function initAuth(config: SmartHiveAuthConfig): SmartHiveAuthClient {\n const baseUrl = normalizeBaseUrl(config.baseUrl);\n const authBase = normalizeBaseUrl(config.authDomain ?? config.baseUrl);\n const storage = config.storage ?? browserStorage();\n const tempStorage = config.temporaryStorage ?? sessionStorageAdapter();\n\n async function saveSession(session: AuthSession | null) {\n if (!session) { await storage.removeItem(smartHiveAuthStorageKeys.session); return; }\n await storage.setItem(smartHiveAuthStorageKeys.session, JSON.stringify(session));\n }\n\n async function readSession(): Promise<AuthSession | null> {\n const raw = await storage.getItem(smartHiveAuthStorageKeys.session);\n return raw ? JSON.parse(raw) as AuthSession : null;\n }\n\n const client: SmartHiveAuthClient = {\n async initialize() {\n const response = await fetch(\n `${baseUrl}/sdk/config?projectId=${encodeURIComponent(config.projectId)}&publishableKey=${encodeURIComponent(config.publishableKey)}`\n );\n if (!response.ok) throw new SmartHiveAuthError(\"project_not_found\", \"Smart Hive Auth project configuration was not found.\");\n },\n\n async login(options) {\n const redirectUri = options?.redirectUri ?? config.redirectUri ?? globalThis.location?.href;\n const state = options?.state ?? crypto.randomUUID();\n const verifier = await generateCodeVerifier();\n const challenge = await generateCodeChallenge(verifier);\n\n await tempStorage.setItem(smartHiveAuthStorageKeys.pkceVerifier, verifier);\n await tempStorage.setItem(smartHiveAuthStorageKeys.pkceState, state);\n\n const url = new URL(`${authBase}/api/auth/oauth2/authorize`);\n url.searchParams.set(\"project_id\", config.projectId);\n url.searchParams.set(\"publishable_key\", config.publishableKey);\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"redirect_uri\", redirectUri);\n url.searchParams.set(\"state\", state);\n url.searchParams.set(\"code_challenge\", challenge);\n url.searchParams.set(\"code_challenge_method\", \"S256\");\n\n globalThis.location.assign(url.toString());\n },\n\n async handleCallback(options) {\n const href = options?.url ?? globalThis.location?.href;\n if (!href) throw new SmartHiveAuthError(\"callback_failed\", \"No URL provided for callback handling.\");\n\n const url = new URL(href);\n const code = url.searchParams.get(\"code\");\n const returnedState = url.searchParams.get(\"state\");\n\n if (!code) throw new SmartHiveAuthError(\"callback_failed\", \"No authorization code in callback URL.\");\n\n const storedState = await tempStorage.getItem(smartHiveAuthStorageKeys.pkceState);\n if (!storedState || !returnedState || storedState !== returnedState) {\n throw new SmartHiveAuthError(\"state_mismatch\", \"OAuth state mismatch — possible CSRF attack.\");\n }\n\n const verifier = await tempStorage.getItem(smartHiveAuthStorageKeys.pkceVerifier);\n if (!verifier) {\n throw new SmartHiveAuthError(\"pkce_missing\", \"Missing PKCE verifier for authorization code exchange.\");\n }\n const redirectUri = config.redirectUri ?? (url.origin + url.pathname);\n\n const body = new URLSearchParams({\n grant_type: \"authorization_code\",\n code,\n redirect_uri: redirectUri,\n client_id: config.publishableKey\n });\n body.set(\"code_verifier\", verifier);\n\n const response = await fetch(`${authBase}/api/auth/oauth2/token`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\" },\n body\n });\n\n if (!response.ok) {\n const err = await response.json().catch(() => ({})) as { error?: string; error_description?: string };\n throw new SmartHiveAuthError(err.error ?? \"token_error\", err.error_description ?? \"Token exchange failed.\");\n }\n\n const tokenBody = await response.json() as {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n token_type?: string;\n };\n\n const session: AuthSession = {\n accessToken: tokenBody.access_token,\n refreshToken: tokenBody.refresh_token,\n expiresAt: tokenBody.expires_in ? Date.now() + tokenBody.expires_in * 1000 : undefined\n };\n\n await saveSession(session);\n await tempStorage.removeItem(smartHiveAuthStorageKeys.pkceVerifier);\n await tempStorage.removeItem(smartHiveAuthStorageKeys.pkceState);\n\n return session;\n },\n\n async logout() {\n await saveSession(null);\n await fetch(`${baseUrl}/api/auth/sign-out`, { method: \"POST\", credentials: \"include\" });\n },\n\n getSession: readSession,\n\n async getAccessToken() {\n const session = await readSession();\n if (!session) return null;\n if (session.expiresAt && Date.now() > session.expiresAt - 30000) {\n return (await client.refreshSession())?.accessToken ?? null;\n }\n return session.accessToken;\n },\n\n async getAuthorizationHeader() {\n const token = await client.getAccessToken();\n const headers: Record<string, string> = {};\n if (token) headers.authorization = `Bearer ${token}`;\n return headers;\n },\n\n async fetch(input, init = {}) {\n const authHeader = await client.getAuthorizationHeader();\n const headers = new Headers(init.headers);\n for (const [key, value] of Object.entries(authHeader)) {\n headers.set(key, value);\n }\n return fetch(input, { ...init, headers });\n },\n\n async refreshSession() {\n const session = await readSession();\n if (!session?.refreshToken) return session;\n const response = await fetch(`${baseUrl}/api/auth/oauth2/token`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: session.refreshToken\n })\n });\n if (!response.ok) { await saveSession(null); return null; }\n const body = await response.json() as { access_token: string; refresh_token?: string; expires_in?: number };\n const nextSession: AuthSession = {\n ...session,\n accessToken: body.access_token,\n refreshToken: body.refresh_token ?? session.refreshToken,\n expiresAt: body.expires_in ? Date.now() + body.expires_in * 1000 : session.expiresAt\n };\n await saveSession(nextSession);\n return nextSession;\n },\n\n async verifyToken(token) {\n if (token.split(\".\").length !== 3) return false;\n const response = await fetch(`${authBase}/api/auth/oauth2/userinfo`, {\n headers: { authorization: `Bearer ${token}` }\n });\n return response.ok;\n },\n\n async getUser() {\n const token = await client.getAccessToken();\n if (!token) return null;\n const response = await fetch(`${baseUrl}/api/auth/oauth2/userinfo`, {\n headers: { authorization: `Bearer ${token}` }\n });\n return response.ok ? response.json() : null;\n }\n };\n\n return client;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export interface SmartHiveAuthConfig {\n projectId: string;\n publishableKey: string;\n baseUrl: string;\n /** Custom branded auth domain, e.g. \"https://auth.myapp.com\". Used as the entry point for login/token flows. Falls back to baseUrl. */\n authDomain?: string;\n /** Fallback auth domain if authDomain is unreachable, e.g. \"https://auth.smarthivelabs.dev\". */\n fallbackAuthDomain?: string;\n redirectUri?: string;\n storage?: AuthStorage;\n temporaryStorage?: AuthStorage;\n}\n\nexport interface AuthStorage {\n getItem(key: string): string | null | Promise<string | null>;\n setItem(key: string, value: string): void | Promise<void>;\n removeItem(key: string): void | Promise<void>;\n}\n\nexport interface AuthSession {\n accessToken: string;\n refreshToken?: string;\n expiresAt?: number;\n user?: unknown;\n}\n\n// ── Headless types ────────────────────────────────────────────────────────────\n\nexport interface HeadlessSignInResult {\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n user?: unknown;\n}\n\nexport interface HeadlessSignUpResult extends HeadlessSignInResult {\n /** True when email verification is required before the account can be used. */\n requiresVerification?: boolean;\n}\n\nexport interface HeadlessClient {\n signIn: {\n /**\n * Sign in with email and password. No browser redirect.\n * Returns tokens immediately on success.\n */\n email(params: { email: string; password: string }): Promise<HeadlessSignInResult>;\n\n phone: {\n /**\n * Send a one-time code to a phone number.\n * Call `verify` with the code the user receives.\n */\n sendOtp(params: { phoneNumber: string }): Promise<void>;\n /**\n * Verify the OTP sent to the phone number and return tokens on success.\n */\n verify(params: { phoneNumber: string; code: string }): Promise<HeadlessSignInResult>;\n };\n\n emailOtp: {\n /**\n * Send a one-time code to an email address.\n * Call `verify` with the code the user receives.\n */\n send(params: { email: string }): Promise<void>;\n /**\n * Verify the OTP sent to the email address and return tokens on success.\n */\n verify(params: { email: string; code: string }): Promise<HeadlessSignInResult>;\n };\n\n magicLink: {\n /**\n * Send a magic link to the given email address.\n * The user clicks the link — no token is returned here.\n */\n send(params: { email: string; callbackURL?: string }): Promise<void>;\n };\n };\n\n signUp: {\n /**\n * Create a new account with email and password. No browser redirect.\n * If email verification is required, `requiresVerification` will be true\n * and no tokens will be present — the user must verify before signing in.\n */\n email(params: { email: string; password: string; name?: string }): Promise<HeadlessSignUpResult>;\n };\n\n /** Refresh an expired access token using the refresh token. */\n refreshToken(params: { refreshToken: string }): Promise<{ accessToken: string; expiresAt: number }>;\n\n /** Sign the user out and invalidate their session on the server. */\n signOut(params?: { refreshToken?: string }): Promise<void>;\n}\n\nexport interface SmartHiveAuthClient {\n initialize(): Promise<void>;\n login(options?: { redirectUri?: string; state?: string }): Promise<void>;\n handleCallback(options?: { url?: string }): Promise<AuthSession>;\n /**\n * Initiate a social OAuth flow. Redirects the browser (or opens Linking URL\n * on mobile) to the provider's consent screen using the project's own credentials.\n * After the user approves, the provider redirects back with tokens in the redirect URI.\n */\n loginSocial(provider: SocialProvider, options?: { redirectUri?: string }): Promise<void>;\n /**\n * Parse social OAuth callback URL (contains access_token + refresh_token as query params),\n * persist the session, and return it. Call this when the app handles the redirect back from\n * the social flow (e.g. on the callback page, or in a deep link handler on mobile).\n */\n handleSocialCallback(options?: { url?: string }): Promise<AuthSession>;\n logout(): Promise<void>;\n getSession(): Promise<AuthSession | null>;\n getAccessToken(): Promise<string | null>;\n getAuthorizationHeader(): Promise<Record<string, string>>;\n fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;\n refreshSession(): Promise<AuthSession | null>;\n verifyToken(token: string): Promise<boolean>;\n getUser(): Promise<unknown>;\n /**\n * Direct credential-based authentication — no browser redirect.\n * Use these methods when you want full control of the sign-in UI\n * (e.g. native mobile apps with custom login screens).\n */\n headless: HeadlessClient;\n}\n\nexport type SocialProvider =\n | \"google\"\n | \"apple\"\n | \"github\"\n | \"facebook\"\n | \"twitter\"\n | \"linkedin\"\n | \"microsoft\"\n | \"discord\"\n | \"spotify\"\n | \"twitch\"\n | \"reddit\"\n | \"gitlab\"\n | \"slack\"\n | \"notion\"\n | \"zoom\"\n | \"figma\";\n\nexport class SmartHiveAuthError extends Error {\n constructor(public code: string, message: string) {\n super(message);\n this.name = \"SmartHiveAuthError\";\n }\n}\n\n// ── PKCE helpers (Web Crypto — works in browser + Node 18+) ──────────────────\n\nexport async function generateCodeVerifier(): Promise<string> {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return base64urlEncode(array);\n}\n\nexport async function generateCodeChallenge(verifier: string): Promise<string> {\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const digest = await crypto.subtle.digest(\"SHA-256\", data);\n return base64urlEncode(new Uint8Array(digest));\n}\n\nfunction base64urlEncode(buffer: Uint8Array): string {\n let str = \"\";\n for (const byte of buffer) str += String.fromCharCode(byte);\n return btoa(str).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\n// ── Storage keys ─────────────────────────────────────────────────────────────\n\nexport const smartHiveAuthStorageKeys = {\n session: \"smarthive.auth.session\",\n pkceVerifier: \"smarthive.auth.pkce_verifier\",\n pkceState: \"smarthive.auth.pkce_state\"\n} as const;\n\nfunction browserStorage(): AuthStorage {\n return {\n getItem: (key) => globalThis.localStorage?.getItem(key) ?? null,\n setItem: (key, value) => globalThis.localStorage?.setItem(key, value),\n removeItem: (key) => globalThis.localStorage?.removeItem(key)\n };\n}\n\nfunction sessionStorageAdapter(): Pick<AuthStorage, \"getItem\" | \"setItem\" | \"removeItem\"> {\n return {\n getItem: (key) => globalThis.sessionStorage?.getItem(key) ?? null,\n setItem: (key, value) => globalThis.sessionStorage?.setItem(key, value),\n removeItem: (key) => globalThis.sessionStorage?.removeItem(key)\n };\n}\n\nfunction normalizeBaseUrl(baseUrl: string) {\n return baseUrl.replace(/\\/$/, \"\");\n}\n\n/** Extract the environment prefix from a publishable key (pk_dev_*, pk_staging_*, pk_prod_*). */\nexport function envFromPublishableKey(publishableKey: string): string {\n const match = publishableKey.match(/^pk_(dev|staging|prod)_/);\n return match ? match[1] : \"prod\";\n}\n\n// ── Headless response shape from the backend ──────────────────────────────────\n\ninterface RawHeadlessResponse {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n token_type: string;\n user?: unknown;\n requires_verification?: boolean;\n message?: string;\n}\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\nexport function initAuth(config: SmartHiveAuthConfig): SmartHiveAuthClient {\n const baseUrl = normalizeBaseUrl(config.baseUrl);\n const authBase = normalizeBaseUrl(config.authDomain ?? config.baseUrl);\n const storage = config.storage ?? browserStorage();\n const tempStorage = config.temporaryStorage ?? sessionStorageAdapter();\n const environment = envFromPublishableKey(config.publishableKey);\n const headlessBase = `${baseUrl}/${environment}/api/auth/headless`;\n\n async function saveSession(session: AuthSession | null) {\n if (!session) { await storage.removeItem(smartHiveAuthStorageKeys.session); return; }\n await storage.setItem(smartHiveAuthStorageKeys.session, JSON.stringify(session));\n }\n\n async function readSession(): Promise<AuthSession | null> {\n const raw = await storage.getItem(smartHiveAuthStorageKeys.session);\n return raw ? JSON.parse(raw) as AuthSession : null;\n }\n\n function rawToSession(raw: RawHeadlessResponse): HeadlessSignInResult {\n return {\n accessToken: raw.access_token,\n refreshToken: raw.refresh_token,\n expiresAt: Date.now() + raw.expires_in * 1000,\n user: raw.user,\n };\n }\n\n async function headlessPost(path: string, body: Record<string, unknown>): Promise<RawHeadlessResponse> {\n const res = await fetch(`${headlessBase}${path}`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as { error?: string; message?: string };\n throw new SmartHiveAuthError(\n err.error ?? \"request_failed\",\n err.message ?? `Request to ${path} failed.`\n );\n }\n\n return res.json() as Promise<RawHeadlessResponse>;\n }\n\n async function headlessSignInAndSave(path: string, body: Record<string, unknown>): Promise<HeadlessSignInResult> {\n const raw = await headlessPost(path, body);\n const result = rawToSession(raw);\n await saveSession(result);\n return result;\n }\n\n const headless: HeadlessClient = {\n signIn: {\n async email({ email, password }) {\n return headlessSignInAndSave(\"/sign-in/email\", { email, password });\n },\n\n phone: {\n async sendOtp({ phoneNumber }) {\n await headlessPost(\"/phone/send-otp\", { phoneNumber });\n },\n async verify({ phoneNumber, code }) {\n return headlessSignInAndSave(\"/phone/verify\", { phoneNumber, code });\n },\n },\n\n emailOtp: {\n async send({ email }) {\n await headlessPost(\"/email-otp/send\", { email });\n },\n async verify({ email, code }) {\n return headlessSignInAndSave(\"/email-otp/verify\", { email, code });\n },\n },\n\n magicLink: {\n async send({ email, callbackURL }) {\n await headlessPost(\"/magic-link/send\", { email, ...(callbackURL ? { callbackURL } : {}) });\n },\n },\n },\n\n signUp: {\n async email({ email, password, name }) {\n const res = await fetch(`${headlessBase}/sign-up/email`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ email, password, name }),\n });\n\n // 202 = account created but email verification required\n if (res.status === 202) {\n return { accessToken: \"\", refreshToken: \"\", expiresAt: 0, requiresVerification: true };\n }\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as { error?: string; message?: string };\n throw new SmartHiveAuthError(err.error ?? \"sign_up_failed\", err.message ?? \"Sign up failed.\");\n }\n\n const raw = await res.json() as RawHeadlessResponse;\n const result: HeadlessSignUpResult = { ...rawToSession(raw), requiresVerification: false };\n await saveSession(result);\n return result;\n },\n },\n\n async refreshToken({ refreshToken }) {\n const raw = await headlessPost(\"/token/refresh\", { refresh_token: refreshToken });\n const updated: AuthSession = {\n ...(await readSession() ?? {}),\n accessToken: raw.access_token,\n expiresAt: Date.now() + raw.expires_in * 1000,\n };\n await saveSession(updated);\n return { accessToken: raw.access_token, expiresAt: updated.expiresAt! };\n },\n\n async signOut({ refreshToken } = {}) {\n const session = await readSession();\n const token = refreshToken ?? session?.refreshToken;\n await saveSession(null);\n if (token) {\n await fetch(`${headlessBase}/sign-out`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ refresh_token: token }),\n }).catch(() => {});\n }\n },\n };\n\n const client: SmartHiveAuthClient = {\n async initialize() {\n const response = await fetch(\n `${baseUrl}/sdk/config?projectId=${encodeURIComponent(config.projectId)}&publishableKey=${encodeURIComponent(config.publishableKey)}`\n );\n if (!response.ok) throw new SmartHiveAuthError(\"project_not_found\", \"Smart Hive Auth project configuration was not found.\");\n },\n\n async login(options) {\n const redirectUri = options?.redirectUri ?? config.redirectUri ?? globalThis.location?.href;\n const state = options?.state ?? crypto.randomUUID();\n const verifier = await generateCodeVerifier();\n const challenge = await generateCodeChallenge(verifier);\n\n await tempStorage.setItem(smartHiveAuthStorageKeys.pkceVerifier, verifier);\n await tempStorage.setItem(smartHiveAuthStorageKeys.pkceState, state);\n\n const url = new URL(`${authBase}/api/auth/oauth2/authorize`);\n url.searchParams.set(\"project_id\", config.projectId);\n url.searchParams.set(\"publishable_key\", config.publishableKey);\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"redirect_uri\", redirectUri);\n url.searchParams.set(\"state\", state);\n url.searchParams.set(\"code_challenge\", challenge);\n url.searchParams.set(\"code_challenge_method\", \"S256\");\n\n globalThis.location.assign(url.toString());\n },\n\n async handleCallback(options) {\n const href = options?.url ?? globalThis.location?.href;\n if (!href) throw new SmartHiveAuthError(\"callback_failed\", \"No URL provided for callback handling.\");\n\n const url = new URL(href);\n const code = url.searchParams.get(\"code\");\n const returnedState = url.searchParams.get(\"state\");\n\n if (!code) throw new SmartHiveAuthError(\"callback_failed\", \"No authorization code in callback URL.\");\n\n const storedState = await tempStorage.getItem(smartHiveAuthStorageKeys.pkceState);\n if (!storedState || !returnedState || storedState !== returnedState) {\n throw new SmartHiveAuthError(\"state_mismatch\", \"OAuth state mismatch — possible CSRF attack.\");\n }\n\n const verifier = await tempStorage.getItem(smartHiveAuthStorageKeys.pkceVerifier);\n if (!verifier) {\n throw new SmartHiveAuthError(\"pkce_missing\", \"Missing PKCE verifier for authorization code exchange.\");\n }\n const redirectUri = config.redirectUri ?? (url.origin + url.pathname);\n\n const body = new URLSearchParams({\n grant_type: \"authorization_code\",\n code,\n redirect_uri: redirectUri,\n client_id: config.publishableKey\n });\n body.set(\"code_verifier\", verifier);\n\n const response = await fetch(`${authBase}/api/auth/oauth2/token`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\" },\n body\n });\n\n if (!response.ok) {\n const err = await response.json().catch(() => ({})) as { error?: string; error_description?: string };\n throw new SmartHiveAuthError(err.error ?? \"token_error\", err.error_description ?? \"Token exchange failed.\");\n }\n\n const tokenBody = await response.json() as {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n token_type?: string;\n };\n\n const session: AuthSession = {\n accessToken: tokenBody.access_token,\n refreshToken: tokenBody.refresh_token,\n expiresAt: tokenBody.expires_in ? Date.now() + tokenBody.expires_in * 1000 : undefined\n };\n\n await saveSession(session);\n await tempStorage.removeItem(smartHiveAuthStorageKeys.pkceVerifier);\n await tempStorage.removeItem(smartHiveAuthStorageKeys.pkceState);\n\n return session;\n },\n\n async loginSocial(provider, options) {\n const redirectUri = options?.redirectUri ?? config.redirectUri ?? globalThis.location?.href;\n if (!redirectUri) throw new SmartHiveAuthError(\"missing_redirect_uri\", \"redirectUri is required for social login.\");\n const url = new URL(`${authBase}/${environment}/api/auth/social/${provider}`);\n url.searchParams.set(\"project_id\", config.projectId);\n url.searchParams.set(\"redirect_uri\", redirectUri);\n globalThis.location.assign(url.toString());\n },\n\n async handleSocialCallback(options) {\n const href = options?.url ?? globalThis.location?.href;\n if (!href) throw new SmartHiveAuthError(\"callback_failed\", \"No URL available for social callback.\");\n const url = new URL(href);\n const error = url.searchParams.get(\"error\");\n if (error) {\n throw new SmartHiveAuthError(error, url.searchParams.get(\"error_description\") ?? error);\n }\n const accessToken = url.searchParams.get(\"access_token\");\n if (!accessToken) throw new SmartHiveAuthError(\"callback_failed\", \"No access token in social callback URL.\");\n const expiresIn = url.searchParams.get(\"expires_in\");\n const session: AuthSession = {\n accessToken,\n refreshToken: url.searchParams.get(\"refresh_token\") ?? undefined,\n expiresAt: expiresIn ? Date.now() + parseInt(expiresIn, 10) * 1000 : undefined,\n };\n await saveSession(session);\n return session;\n },\n\n async logout() {\n await saveSession(null);\n await fetch(`${baseUrl}/api/auth/sign-out`, { method: \"POST\", credentials: \"include\" });\n },\n\n getSession: readSession,\n\n async getAccessToken() {\n const session = await readSession();\n if (!session) return null;\n if (session.expiresAt && Date.now() > session.expiresAt - 30000) {\n return (await client.refreshSession())?.accessToken ?? null;\n }\n return session.accessToken;\n },\n\n async getAuthorizationHeader() {\n const token = await client.getAccessToken();\n const headers: Record<string, string> = {};\n if (token) headers.authorization = `Bearer ${token}`;\n return headers;\n },\n\n async fetch(input, init = {}) {\n const authHeader = await client.getAuthorizationHeader();\n const headers = new Headers(init.headers);\n for (const [key, value] of Object.entries(authHeader)) {\n headers.set(key, value);\n }\n return fetch(input, { ...init, headers });\n },\n\n async refreshSession() {\n const session = await readSession();\n if (!session?.refreshToken) return session;\n const response = await fetch(`${baseUrl}/api/auth/oauth2/token`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: session.refreshToken\n })\n });\n if (!response.ok) { await saveSession(null); return null; }\n const body = await response.json() as { access_token: string; refresh_token?: string; expires_in?: number };\n const nextSession: AuthSession = {\n ...session,\n accessToken: body.access_token,\n refreshToken: body.refresh_token ?? session.refreshToken,\n expiresAt: body.expires_in ? Date.now() + body.expires_in * 1000 : session.expiresAt\n };\n await saveSession(nextSession);\n return nextSession;\n },\n\n async verifyToken(token) {\n if (token.split(\".\").length !== 3) return false;\n const response = await fetch(`${authBase}/api/auth/oauth2/userinfo`, {\n headers: { authorization: `Bearer ${token}` }\n });\n return response.ok;\n },\n\n async getUser() {\n const token = await client.getAccessToken();\n if (!token) return null;\n const response = await fetch(`${baseUrl}/api/auth/oauth2/userinfo`, {\n headers: { authorization: `Bearer ${token}` }\n });\n return response.ok ? response.json() : null;\n },\n\n headless,\n };\n\n return client;\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -21,6 +21,93 @@ interface AuthSession {
|
|
|
21
21
|
expiresAt?: number;
|
|
22
22
|
user?: unknown;
|
|
23
23
|
}
|
|
24
|
+
interface HeadlessSignInResult {
|
|
25
|
+
accessToken: string;
|
|
26
|
+
refreshToken: string;
|
|
27
|
+
expiresAt: number;
|
|
28
|
+
user?: unknown;
|
|
29
|
+
}
|
|
30
|
+
interface HeadlessSignUpResult extends HeadlessSignInResult {
|
|
31
|
+
/** True when email verification is required before the account can be used. */
|
|
32
|
+
requiresVerification?: boolean;
|
|
33
|
+
}
|
|
34
|
+
interface HeadlessClient {
|
|
35
|
+
signIn: {
|
|
36
|
+
/**
|
|
37
|
+
* Sign in with email and password. No browser redirect.
|
|
38
|
+
* Returns tokens immediately on success.
|
|
39
|
+
*/
|
|
40
|
+
email(params: {
|
|
41
|
+
email: string;
|
|
42
|
+
password: string;
|
|
43
|
+
}): Promise<HeadlessSignInResult>;
|
|
44
|
+
phone: {
|
|
45
|
+
/**
|
|
46
|
+
* Send a one-time code to a phone number.
|
|
47
|
+
* Call `verify` with the code the user receives.
|
|
48
|
+
*/
|
|
49
|
+
sendOtp(params: {
|
|
50
|
+
phoneNumber: string;
|
|
51
|
+
}): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Verify the OTP sent to the phone number and return tokens on success.
|
|
54
|
+
*/
|
|
55
|
+
verify(params: {
|
|
56
|
+
phoneNumber: string;
|
|
57
|
+
code: string;
|
|
58
|
+
}): Promise<HeadlessSignInResult>;
|
|
59
|
+
};
|
|
60
|
+
emailOtp: {
|
|
61
|
+
/**
|
|
62
|
+
* Send a one-time code to an email address.
|
|
63
|
+
* Call `verify` with the code the user receives.
|
|
64
|
+
*/
|
|
65
|
+
send(params: {
|
|
66
|
+
email: string;
|
|
67
|
+
}): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Verify the OTP sent to the email address and return tokens on success.
|
|
70
|
+
*/
|
|
71
|
+
verify(params: {
|
|
72
|
+
email: string;
|
|
73
|
+
code: string;
|
|
74
|
+
}): Promise<HeadlessSignInResult>;
|
|
75
|
+
};
|
|
76
|
+
magicLink: {
|
|
77
|
+
/**
|
|
78
|
+
* Send a magic link to the given email address.
|
|
79
|
+
* The user clicks the link — no token is returned here.
|
|
80
|
+
*/
|
|
81
|
+
send(params: {
|
|
82
|
+
email: string;
|
|
83
|
+
callbackURL?: string;
|
|
84
|
+
}): Promise<void>;
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
signUp: {
|
|
88
|
+
/**
|
|
89
|
+
* Create a new account with email and password. No browser redirect.
|
|
90
|
+
* If email verification is required, `requiresVerification` will be true
|
|
91
|
+
* and no tokens will be present — the user must verify before signing in.
|
|
92
|
+
*/
|
|
93
|
+
email(params: {
|
|
94
|
+
email: string;
|
|
95
|
+
password: string;
|
|
96
|
+
name?: string;
|
|
97
|
+
}): Promise<HeadlessSignUpResult>;
|
|
98
|
+
};
|
|
99
|
+
/** Refresh an expired access token using the refresh token. */
|
|
100
|
+
refreshToken(params: {
|
|
101
|
+
refreshToken: string;
|
|
102
|
+
}): Promise<{
|
|
103
|
+
accessToken: string;
|
|
104
|
+
expiresAt: number;
|
|
105
|
+
}>;
|
|
106
|
+
/** Sign the user out and invalidate their session on the server. */
|
|
107
|
+
signOut(params?: {
|
|
108
|
+
refreshToken?: string;
|
|
109
|
+
}): Promise<void>;
|
|
110
|
+
}
|
|
24
111
|
interface SmartHiveAuthClient {
|
|
25
112
|
initialize(): Promise<void>;
|
|
26
113
|
login(options?: {
|
|
@@ -30,6 +117,22 @@ interface SmartHiveAuthClient {
|
|
|
30
117
|
handleCallback(options?: {
|
|
31
118
|
url?: string;
|
|
32
119
|
}): Promise<AuthSession>;
|
|
120
|
+
/**
|
|
121
|
+
* Initiate a social OAuth flow. Redirects the browser (or opens Linking URL
|
|
122
|
+
* on mobile) to the provider's consent screen using the project's own credentials.
|
|
123
|
+
* After the user approves, the provider redirects back with tokens in the redirect URI.
|
|
124
|
+
*/
|
|
125
|
+
loginSocial(provider: SocialProvider, options?: {
|
|
126
|
+
redirectUri?: string;
|
|
127
|
+
}): Promise<void>;
|
|
128
|
+
/**
|
|
129
|
+
* Parse social OAuth callback URL (contains access_token + refresh_token as query params),
|
|
130
|
+
* persist the session, and return it. Call this when the app handles the redirect back from
|
|
131
|
+
* the social flow (e.g. on the callback page, or in a deep link handler on mobile).
|
|
132
|
+
*/
|
|
133
|
+
handleSocialCallback(options?: {
|
|
134
|
+
url?: string;
|
|
135
|
+
}): Promise<AuthSession>;
|
|
33
136
|
logout(): Promise<void>;
|
|
34
137
|
getSession(): Promise<AuthSession | null>;
|
|
35
138
|
getAccessToken(): Promise<string | null>;
|
|
@@ -38,7 +141,14 @@ interface SmartHiveAuthClient {
|
|
|
38
141
|
refreshSession(): Promise<AuthSession | null>;
|
|
39
142
|
verifyToken(token: string): Promise<boolean>;
|
|
40
143
|
getUser(): Promise<unknown>;
|
|
144
|
+
/**
|
|
145
|
+
* Direct credential-based authentication — no browser redirect.
|
|
146
|
+
* Use these methods when you want full control of the sign-in UI
|
|
147
|
+
* (e.g. native mobile apps with custom login screens).
|
|
148
|
+
*/
|
|
149
|
+
headless: HeadlessClient;
|
|
41
150
|
}
|
|
151
|
+
type SocialProvider = "google" | "apple" | "github" | "facebook" | "twitter" | "linkedin" | "microsoft" | "discord" | "spotify" | "twitch" | "reddit" | "gitlab" | "slack" | "notion" | "zoom" | "figma";
|
|
42
152
|
declare class SmartHiveAuthError extends Error {
|
|
43
153
|
code: string;
|
|
44
154
|
constructor(code: string, message: string);
|
|
@@ -50,6 +160,8 @@ declare const smartHiveAuthStorageKeys: {
|
|
|
50
160
|
readonly pkceVerifier: "smarthive.auth.pkce_verifier";
|
|
51
161
|
readonly pkceState: "smarthive.auth.pkce_state";
|
|
52
162
|
};
|
|
163
|
+
/** Extract the environment prefix from a publishable key (pk_dev_*, pk_staging_*, pk_prod_*). */
|
|
164
|
+
declare function envFromPublishableKey(publishableKey: string): string;
|
|
53
165
|
declare function initAuth(config: SmartHiveAuthConfig): SmartHiveAuthClient;
|
|
54
166
|
|
|
55
|
-
export { type AuthSession, type AuthStorage, type SmartHiveAuthClient, type SmartHiveAuthConfig, SmartHiveAuthError, generateCodeChallenge, generateCodeVerifier, initAuth, smartHiveAuthStorageKeys };
|
|
167
|
+
export { type AuthSession, type AuthStorage, type HeadlessClient, type HeadlessSignInResult, type HeadlessSignUpResult, type SmartHiveAuthClient, type SmartHiveAuthConfig, SmartHiveAuthError, type SocialProvider, envFromPublishableKey, generateCodeChallenge, generateCodeVerifier, initAuth, smartHiveAuthStorageKeys };
|
package/dist/index.d.ts
CHANGED
|
@@ -21,6 +21,93 @@ interface AuthSession {
|
|
|
21
21
|
expiresAt?: number;
|
|
22
22
|
user?: unknown;
|
|
23
23
|
}
|
|
24
|
+
interface HeadlessSignInResult {
|
|
25
|
+
accessToken: string;
|
|
26
|
+
refreshToken: string;
|
|
27
|
+
expiresAt: number;
|
|
28
|
+
user?: unknown;
|
|
29
|
+
}
|
|
30
|
+
interface HeadlessSignUpResult extends HeadlessSignInResult {
|
|
31
|
+
/** True when email verification is required before the account can be used. */
|
|
32
|
+
requiresVerification?: boolean;
|
|
33
|
+
}
|
|
34
|
+
interface HeadlessClient {
|
|
35
|
+
signIn: {
|
|
36
|
+
/**
|
|
37
|
+
* Sign in with email and password. No browser redirect.
|
|
38
|
+
* Returns tokens immediately on success.
|
|
39
|
+
*/
|
|
40
|
+
email(params: {
|
|
41
|
+
email: string;
|
|
42
|
+
password: string;
|
|
43
|
+
}): Promise<HeadlessSignInResult>;
|
|
44
|
+
phone: {
|
|
45
|
+
/**
|
|
46
|
+
* Send a one-time code to a phone number.
|
|
47
|
+
* Call `verify` with the code the user receives.
|
|
48
|
+
*/
|
|
49
|
+
sendOtp(params: {
|
|
50
|
+
phoneNumber: string;
|
|
51
|
+
}): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Verify the OTP sent to the phone number and return tokens on success.
|
|
54
|
+
*/
|
|
55
|
+
verify(params: {
|
|
56
|
+
phoneNumber: string;
|
|
57
|
+
code: string;
|
|
58
|
+
}): Promise<HeadlessSignInResult>;
|
|
59
|
+
};
|
|
60
|
+
emailOtp: {
|
|
61
|
+
/**
|
|
62
|
+
* Send a one-time code to an email address.
|
|
63
|
+
* Call `verify` with the code the user receives.
|
|
64
|
+
*/
|
|
65
|
+
send(params: {
|
|
66
|
+
email: string;
|
|
67
|
+
}): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Verify the OTP sent to the email address and return tokens on success.
|
|
70
|
+
*/
|
|
71
|
+
verify(params: {
|
|
72
|
+
email: string;
|
|
73
|
+
code: string;
|
|
74
|
+
}): Promise<HeadlessSignInResult>;
|
|
75
|
+
};
|
|
76
|
+
magicLink: {
|
|
77
|
+
/**
|
|
78
|
+
* Send a magic link to the given email address.
|
|
79
|
+
* The user clicks the link — no token is returned here.
|
|
80
|
+
*/
|
|
81
|
+
send(params: {
|
|
82
|
+
email: string;
|
|
83
|
+
callbackURL?: string;
|
|
84
|
+
}): Promise<void>;
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
signUp: {
|
|
88
|
+
/**
|
|
89
|
+
* Create a new account with email and password. No browser redirect.
|
|
90
|
+
* If email verification is required, `requiresVerification` will be true
|
|
91
|
+
* and no tokens will be present — the user must verify before signing in.
|
|
92
|
+
*/
|
|
93
|
+
email(params: {
|
|
94
|
+
email: string;
|
|
95
|
+
password: string;
|
|
96
|
+
name?: string;
|
|
97
|
+
}): Promise<HeadlessSignUpResult>;
|
|
98
|
+
};
|
|
99
|
+
/** Refresh an expired access token using the refresh token. */
|
|
100
|
+
refreshToken(params: {
|
|
101
|
+
refreshToken: string;
|
|
102
|
+
}): Promise<{
|
|
103
|
+
accessToken: string;
|
|
104
|
+
expiresAt: number;
|
|
105
|
+
}>;
|
|
106
|
+
/** Sign the user out and invalidate their session on the server. */
|
|
107
|
+
signOut(params?: {
|
|
108
|
+
refreshToken?: string;
|
|
109
|
+
}): Promise<void>;
|
|
110
|
+
}
|
|
24
111
|
interface SmartHiveAuthClient {
|
|
25
112
|
initialize(): Promise<void>;
|
|
26
113
|
login(options?: {
|
|
@@ -30,6 +117,22 @@ interface SmartHiveAuthClient {
|
|
|
30
117
|
handleCallback(options?: {
|
|
31
118
|
url?: string;
|
|
32
119
|
}): Promise<AuthSession>;
|
|
120
|
+
/**
|
|
121
|
+
* Initiate a social OAuth flow. Redirects the browser (or opens Linking URL
|
|
122
|
+
* on mobile) to the provider's consent screen using the project's own credentials.
|
|
123
|
+
* After the user approves, the provider redirects back with tokens in the redirect URI.
|
|
124
|
+
*/
|
|
125
|
+
loginSocial(provider: SocialProvider, options?: {
|
|
126
|
+
redirectUri?: string;
|
|
127
|
+
}): Promise<void>;
|
|
128
|
+
/**
|
|
129
|
+
* Parse social OAuth callback URL (contains access_token + refresh_token as query params),
|
|
130
|
+
* persist the session, and return it. Call this when the app handles the redirect back from
|
|
131
|
+
* the social flow (e.g. on the callback page, or in a deep link handler on mobile).
|
|
132
|
+
*/
|
|
133
|
+
handleSocialCallback(options?: {
|
|
134
|
+
url?: string;
|
|
135
|
+
}): Promise<AuthSession>;
|
|
33
136
|
logout(): Promise<void>;
|
|
34
137
|
getSession(): Promise<AuthSession | null>;
|
|
35
138
|
getAccessToken(): Promise<string | null>;
|
|
@@ -38,7 +141,14 @@ interface SmartHiveAuthClient {
|
|
|
38
141
|
refreshSession(): Promise<AuthSession | null>;
|
|
39
142
|
verifyToken(token: string): Promise<boolean>;
|
|
40
143
|
getUser(): Promise<unknown>;
|
|
144
|
+
/**
|
|
145
|
+
* Direct credential-based authentication — no browser redirect.
|
|
146
|
+
* Use these methods when you want full control of the sign-in UI
|
|
147
|
+
* (e.g. native mobile apps with custom login screens).
|
|
148
|
+
*/
|
|
149
|
+
headless: HeadlessClient;
|
|
41
150
|
}
|
|
151
|
+
type SocialProvider = "google" | "apple" | "github" | "facebook" | "twitter" | "linkedin" | "microsoft" | "discord" | "spotify" | "twitch" | "reddit" | "gitlab" | "slack" | "notion" | "zoom" | "figma";
|
|
42
152
|
declare class SmartHiveAuthError extends Error {
|
|
43
153
|
code: string;
|
|
44
154
|
constructor(code: string, message: string);
|
|
@@ -50,6 +160,8 @@ declare const smartHiveAuthStorageKeys: {
|
|
|
50
160
|
readonly pkceVerifier: "smarthive.auth.pkce_verifier";
|
|
51
161
|
readonly pkceState: "smarthive.auth.pkce_state";
|
|
52
162
|
};
|
|
163
|
+
/** Extract the environment prefix from a publishable key (pk_dev_*, pk_staging_*, pk_prod_*). */
|
|
164
|
+
declare function envFromPublishableKey(publishableKey: string): string;
|
|
53
165
|
declare function initAuth(config: SmartHiveAuthConfig): SmartHiveAuthClient;
|
|
54
166
|
|
|
55
|
-
export { type AuthSession, type AuthStorage, type SmartHiveAuthClient, type SmartHiveAuthConfig, SmartHiveAuthError, generateCodeChallenge, generateCodeVerifier, initAuth, smartHiveAuthStorageKeys };
|
|
167
|
+
export { type AuthSession, type AuthStorage, type HeadlessClient, type HeadlessSignInResult, type HeadlessSignUpResult, type SmartHiveAuthClient, type SmartHiveAuthConfig, SmartHiveAuthError, type SocialProvider, envFromPublishableKey, generateCodeChallenge, generateCodeVerifier, initAuth, smartHiveAuthStorageKeys };
|
package/dist/index.js
CHANGED
|
@@ -45,11 +45,17 @@ function sessionStorageAdapter() {
|
|
|
45
45
|
function normalizeBaseUrl(baseUrl) {
|
|
46
46
|
return baseUrl.replace(/\/$/, "");
|
|
47
47
|
}
|
|
48
|
+
function envFromPublishableKey(publishableKey) {
|
|
49
|
+
const match = publishableKey.match(/^pk_(dev|staging|prod)_/);
|
|
50
|
+
return match ? match[1] : "prod";
|
|
51
|
+
}
|
|
48
52
|
function initAuth(config) {
|
|
49
53
|
const baseUrl = normalizeBaseUrl(config.baseUrl);
|
|
50
54
|
const authBase = normalizeBaseUrl(config.authDomain ?? config.baseUrl);
|
|
51
55
|
const storage = config.storage ?? browserStorage();
|
|
52
56
|
const tempStorage = config.temporaryStorage ?? sessionStorageAdapter();
|
|
57
|
+
const environment = envFromPublishableKey(config.publishableKey);
|
|
58
|
+
const headlessBase = `${baseUrl}/${environment}/api/auth/headless`;
|
|
53
59
|
async function saveSession(session) {
|
|
54
60
|
if (!session) {
|
|
55
61
|
await storage.removeItem(smartHiveAuthStorageKeys.session);
|
|
@@ -61,6 +67,106 @@ function initAuth(config) {
|
|
|
61
67
|
const raw = await storage.getItem(smartHiveAuthStorageKeys.session);
|
|
62
68
|
return raw ? JSON.parse(raw) : null;
|
|
63
69
|
}
|
|
70
|
+
function rawToSession(raw) {
|
|
71
|
+
return {
|
|
72
|
+
accessToken: raw.access_token,
|
|
73
|
+
refreshToken: raw.refresh_token,
|
|
74
|
+
expiresAt: Date.now() + raw.expires_in * 1e3,
|
|
75
|
+
user: raw.user
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
async function headlessPost(path, body) {
|
|
79
|
+
const res = await fetch(`${headlessBase}${path}`, {
|
|
80
|
+
method: "POST",
|
|
81
|
+
headers: { "content-type": "application/json" },
|
|
82
|
+
body: JSON.stringify(body)
|
|
83
|
+
});
|
|
84
|
+
if (!res.ok) {
|
|
85
|
+
const err = await res.json().catch(() => ({}));
|
|
86
|
+
throw new SmartHiveAuthError(
|
|
87
|
+
err.error ?? "request_failed",
|
|
88
|
+
err.message ?? `Request to ${path} failed.`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
return res.json();
|
|
92
|
+
}
|
|
93
|
+
async function headlessSignInAndSave(path, body) {
|
|
94
|
+
const raw = await headlessPost(path, body);
|
|
95
|
+
const result = rawToSession(raw);
|
|
96
|
+
await saveSession(result);
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
const headless = {
|
|
100
|
+
signIn: {
|
|
101
|
+
async email({ email, password }) {
|
|
102
|
+
return headlessSignInAndSave("/sign-in/email", { email, password });
|
|
103
|
+
},
|
|
104
|
+
phone: {
|
|
105
|
+
async sendOtp({ phoneNumber }) {
|
|
106
|
+
await headlessPost("/phone/send-otp", { phoneNumber });
|
|
107
|
+
},
|
|
108
|
+
async verify({ phoneNumber, code }) {
|
|
109
|
+
return headlessSignInAndSave("/phone/verify", { phoneNumber, code });
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
emailOtp: {
|
|
113
|
+
async send({ email }) {
|
|
114
|
+
await headlessPost("/email-otp/send", { email });
|
|
115
|
+
},
|
|
116
|
+
async verify({ email, code }) {
|
|
117
|
+
return headlessSignInAndSave("/email-otp/verify", { email, code });
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
magicLink: {
|
|
121
|
+
async send({ email, callbackURL }) {
|
|
122
|
+
await headlessPost("/magic-link/send", { email, ...callbackURL ? { callbackURL } : {} });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
signUp: {
|
|
127
|
+
async email({ email, password, name }) {
|
|
128
|
+
const res = await fetch(`${headlessBase}/sign-up/email`, {
|
|
129
|
+
method: "POST",
|
|
130
|
+
headers: { "content-type": "application/json" },
|
|
131
|
+
body: JSON.stringify({ email, password, name })
|
|
132
|
+
});
|
|
133
|
+
if (res.status === 202) {
|
|
134
|
+
return { accessToken: "", refreshToken: "", expiresAt: 0, requiresVerification: true };
|
|
135
|
+
}
|
|
136
|
+
if (!res.ok) {
|
|
137
|
+
const err = await res.json().catch(() => ({}));
|
|
138
|
+
throw new SmartHiveAuthError(err.error ?? "sign_up_failed", err.message ?? "Sign up failed.");
|
|
139
|
+
}
|
|
140
|
+
const raw = await res.json();
|
|
141
|
+
const result = { ...rawToSession(raw), requiresVerification: false };
|
|
142
|
+
await saveSession(result);
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
async refreshToken({ refreshToken }) {
|
|
147
|
+
const raw = await headlessPost("/token/refresh", { refresh_token: refreshToken });
|
|
148
|
+
const updated = {
|
|
149
|
+
...await readSession() ?? {},
|
|
150
|
+
accessToken: raw.access_token,
|
|
151
|
+
expiresAt: Date.now() + raw.expires_in * 1e3
|
|
152
|
+
};
|
|
153
|
+
await saveSession(updated);
|
|
154
|
+
return { accessToken: raw.access_token, expiresAt: updated.expiresAt };
|
|
155
|
+
},
|
|
156
|
+
async signOut({ refreshToken } = {}) {
|
|
157
|
+
const session = await readSession();
|
|
158
|
+
const token = refreshToken ?? session?.refreshToken;
|
|
159
|
+
await saveSession(null);
|
|
160
|
+
if (token) {
|
|
161
|
+
await fetch(`${headlessBase}/sign-out`, {
|
|
162
|
+
method: "POST",
|
|
163
|
+
headers: { "content-type": "application/json" },
|
|
164
|
+
body: JSON.stringify({ refresh_token: token })
|
|
165
|
+
}).catch(() => {
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
};
|
|
64
170
|
const client = {
|
|
65
171
|
async initialize() {
|
|
66
172
|
const response = await fetch(
|
|
@@ -128,6 +234,33 @@ function initAuth(config) {
|
|
|
128
234
|
await tempStorage.removeItem(smartHiveAuthStorageKeys.pkceState);
|
|
129
235
|
return session;
|
|
130
236
|
},
|
|
237
|
+
async loginSocial(provider, options) {
|
|
238
|
+
const redirectUri = options?.redirectUri ?? config.redirectUri ?? globalThis.location?.href;
|
|
239
|
+
if (!redirectUri) throw new SmartHiveAuthError("missing_redirect_uri", "redirectUri is required for social login.");
|
|
240
|
+
const url = new URL(`${authBase}/${environment}/api/auth/social/${provider}`);
|
|
241
|
+
url.searchParams.set("project_id", config.projectId);
|
|
242
|
+
url.searchParams.set("redirect_uri", redirectUri);
|
|
243
|
+
globalThis.location.assign(url.toString());
|
|
244
|
+
},
|
|
245
|
+
async handleSocialCallback(options) {
|
|
246
|
+
const href = options?.url ?? globalThis.location?.href;
|
|
247
|
+
if (!href) throw new SmartHiveAuthError("callback_failed", "No URL available for social callback.");
|
|
248
|
+
const url = new URL(href);
|
|
249
|
+
const error = url.searchParams.get("error");
|
|
250
|
+
if (error) {
|
|
251
|
+
throw new SmartHiveAuthError(error, url.searchParams.get("error_description") ?? error);
|
|
252
|
+
}
|
|
253
|
+
const accessToken = url.searchParams.get("access_token");
|
|
254
|
+
if (!accessToken) throw new SmartHiveAuthError("callback_failed", "No access token in social callback URL.");
|
|
255
|
+
const expiresIn = url.searchParams.get("expires_in");
|
|
256
|
+
const session = {
|
|
257
|
+
accessToken,
|
|
258
|
+
refreshToken: url.searchParams.get("refresh_token") ?? void 0,
|
|
259
|
+
expiresAt: expiresIn ? Date.now() + parseInt(expiresIn, 10) * 1e3 : void 0
|
|
260
|
+
};
|
|
261
|
+
await saveSession(session);
|
|
262
|
+
return session;
|
|
263
|
+
},
|
|
131
264
|
async logout() {
|
|
132
265
|
await saveSession(null);
|
|
133
266
|
await fetch(`${baseUrl}/api/auth/sign-out`, { method: "POST", credentials: "include" });
|
|
@@ -194,12 +327,14 @@ function initAuth(config) {
|
|
|
194
327
|
headers: { authorization: `Bearer ${token}` }
|
|
195
328
|
});
|
|
196
329
|
return response.ok ? response.json() : null;
|
|
197
|
-
}
|
|
330
|
+
},
|
|
331
|
+
headless
|
|
198
332
|
};
|
|
199
333
|
return client;
|
|
200
334
|
}
|
|
201
335
|
export {
|
|
202
336
|
SmartHiveAuthError,
|
|
337
|
+
envFromPublishableKey,
|
|
203
338
|
generateCodeChallenge,
|
|
204
339
|
generateCodeVerifier,
|
|
205
340
|
initAuth,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export interface SmartHiveAuthConfig {\n projectId: string;\n publishableKey: string;\n baseUrl: string;\n /** Custom branded auth domain, e.g. \"https://auth.myapp.com\". Used as the entry point for login/token flows. Falls back to baseUrl. */\n authDomain?: string;\n /** Fallback auth domain if authDomain is unreachable, e.g. \"https://auth.smarthivelabs.dev\". */\n fallbackAuthDomain?: string;\n redirectUri?: string;\n storage?: AuthStorage;\n temporaryStorage?: AuthStorage;\n}\n\nexport interface AuthStorage {\n getItem(key: string): string | null | Promise<string | null>;\n setItem(key: string, value: string): void | Promise<void>;\n removeItem(key: string): void | Promise<void>;\n}\n\nexport interface AuthSession {\n accessToken: string;\n refreshToken?: string;\n expiresAt?: number;\n user?: unknown;\n}\n\nexport interface SmartHiveAuthClient {\n initialize(): Promise<void>;\n login(options?: { redirectUri?: string; state?: string }): Promise<void>;\n handleCallback(options?: { url?: string }): Promise<AuthSession>;\n logout(): Promise<void>;\n getSession(): Promise<AuthSession | null>;\n getAccessToken(): Promise<string | null>;\n getAuthorizationHeader(): Promise<Record<string, string>>;\n fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;\n refreshSession(): Promise<AuthSession | null>;\n verifyToken(token: string): Promise<boolean>;\n getUser(): Promise<unknown>;\n}\n\nexport class SmartHiveAuthError extends Error {\n constructor(public code: string, message: string) {\n super(message);\n this.name = \"SmartHiveAuthError\";\n }\n}\n\n// ── PKCE helpers (Web Crypto — works in browser + Node 18+) ──────────────────\n\nexport async function generateCodeVerifier(): Promise<string> {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return base64urlEncode(array);\n}\n\nexport async function generateCodeChallenge(verifier: string): Promise<string> {\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const digest = await crypto.subtle.digest(\"SHA-256\", data);\n return base64urlEncode(new Uint8Array(digest));\n}\n\nfunction base64urlEncode(buffer: Uint8Array): string {\n let str = \"\";\n for (const byte of buffer) str += String.fromCharCode(byte);\n return btoa(str).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\n// ── Storage keys ─────────────────────────────────────────────────────────────\n\nexport const smartHiveAuthStorageKeys = {\n session: \"smarthive.auth.session\",\n pkceVerifier: \"smarthive.auth.pkce_verifier\",\n pkceState: \"smarthive.auth.pkce_state\"\n} as const;\n\nfunction browserStorage(): AuthStorage {\n return {\n getItem: (key) => globalThis.localStorage?.getItem(key) ?? null,\n setItem: (key, value) => globalThis.localStorage?.setItem(key, value),\n removeItem: (key) => globalThis.localStorage?.removeItem(key)\n };\n}\n\nfunction sessionStorageAdapter(): Pick<AuthStorage, \"getItem\" | \"setItem\" | \"removeItem\"> {\n return {\n getItem: (key) => globalThis.sessionStorage?.getItem(key) ?? null,\n setItem: (key, value) => globalThis.sessionStorage?.setItem(key, value),\n removeItem: (key) => globalThis.sessionStorage?.removeItem(key)\n };\n}\n\nfunction normalizeBaseUrl(baseUrl: string) {\n return baseUrl.replace(/\\/$/, \"\");\n}\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\nexport function initAuth(config: SmartHiveAuthConfig): SmartHiveAuthClient {\n const baseUrl = normalizeBaseUrl(config.baseUrl);\n const authBase = normalizeBaseUrl(config.authDomain ?? config.baseUrl);\n const storage = config.storage ?? browserStorage();\n const tempStorage = config.temporaryStorage ?? sessionStorageAdapter();\n\n async function saveSession(session: AuthSession | null) {\n if (!session) { await storage.removeItem(smartHiveAuthStorageKeys.session); return; }\n await storage.setItem(smartHiveAuthStorageKeys.session, JSON.stringify(session));\n }\n\n async function readSession(): Promise<AuthSession | null> {\n const raw = await storage.getItem(smartHiveAuthStorageKeys.session);\n return raw ? JSON.parse(raw) as AuthSession : null;\n }\n\n const client: SmartHiveAuthClient = {\n async initialize() {\n const response = await fetch(\n `${baseUrl}/sdk/config?projectId=${encodeURIComponent(config.projectId)}&publishableKey=${encodeURIComponent(config.publishableKey)}`\n );\n if (!response.ok) throw new SmartHiveAuthError(\"project_not_found\", \"Smart Hive Auth project configuration was not found.\");\n },\n\n async login(options) {\n const redirectUri = options?.redirectUri ?? config.redirectUri ?? globalThis.location?.href;\n const state = options?.state ?? crypto.randomUUID();\n const verifier = await generateCodeVerifier();\n const challenge = await generateCodeChallenge(verifier);\n\n await tempStorage.setItem(smartHiveAuthStorageKeys.pkceVerifier, verifier);\n await tempStorage.setItem(smartHiveAuthStorageKeys.pkceState, state);\n\n const url = new URL(`${authBase}/api/auth/oauth2/authorize`);\n url.searchParams.set(\"project_id\", config.projectId);\n url.searchParams.set(\"publishable_key\", config.publishableKey);\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"redirect_uri\", redirectUri);\n url.searchParams.set(\"state\", state);\n url.searchParams.set(\"code_challenge\", challenge);\n url.searchParams.set(\"code_challenge_method\", \"S256\");\n\n globalThis.location.assign(url.toString());\n },\n\n async handleCallback(options) {\n const href = options?.url ?? globalThis.location?.href;\n if (!href) throw new SmartHiveAuthError(\"callback_failed\", \"No URL provided for callback handling.\");\n\n const url = new URL(href);\n const code = url.searchParams.get(\"code\");\n const returnedState = url.searchParams.get(\"state\");\n\n if (!code) throw new SmartHiveAuthError(\"callback_failed\", \"No authorization code in callback URL.\");\n\n const storedState = await tempStorage.getItem(smartHiveAuthStorageKeys.pkceState);\n if (!storedState || !returnedState || storedState !== returnedState) {\n throw new SmartHiveAuthError(\"state_mismatch\", \"OAuth state mismatch — possible CSRF attack.\");\n }\n\n const verifier = await tempStorage.getItem(smartHiveAuthStorageKeys.pkceVerifier);\n if (!verifier) {\n throw new SmartHiveAuthError(\"pkce_missing\", \"Missing PKCE verifier for authorization code exchange.\");\n }\n const redirectUri = config.redirectUri ?? (url.origin + url.pathname);\n\n const body = new URLSearchParams({\n grant_type: \"authorization_code\",\n code,\n redirect_uri: redirectUri,\n client_id: config.publishableKey\n });\n body.set(\"code_verifier\", verifier);\n\n const response = await fetch(`${authBase}/api/auth/oauth2/token`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\" },\n body\n });\n\n if (!response.ok) {\n const err = await response.json().catch(() => ({})) as { error?: string; error_description?: string };\n throw new SmartHiveAuthError(err.error ?? \"token_error\", err.error_description ?? \"Token exchange failed.\");\n }\n\n const tokenBody = await response.json() as {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n token_type?: string;\n };\n\n const session: AuthSession = {\n accessToken: tokenBody.access_token,\n refreshToken: tokenBody.refresh_token,\n expiresAt: tokenBody.expires_in ? Date.now() + tokenBody.expires_in * 1000 : undefined\n };\n\n await saveSession(session);\n await tempStorage.removeItem(smartHiveAuthStorageKeys.pkceVerifier);\n await tempStorage.removeItem(smartHiveAuthStorageKeys.pkceState);\n\n return session;\n },\n\n async logout() {\n await saveSession(null);\n await fetch(`${baseUrl}/api/auth/sign-out`, { method: \"POST\", credentials: \"include\" });\n },\n\n getSession: readSession,\n\n async getAccessToken() {\n const session = await readSession();\n if (!session) return null;\n if (session.expiresAt && Date.now() > session.expiresAt - 30000) {\n return (await client.refreshSession())?.accessToken ?? null;\n }\n return session.accessToken;\n },\n\n async getAuthorizationHeader() {\n const token = await client.getAccessToken();\n const headers: Record<string, string> = {};\n if (token) headers.authorization = `Bearer ${token}`;\n return headers;\n },\n\n async fetch(input, init = {}) {\n const authHeader = await client.getAuthorizationHeader();\n const headers = new Headers(init.headers);\n for (const [key, value] of Object.entries(authHeader)) {\n headers.set(key, value);\n }\n return fetch(input, { ...init, headers });\n },\n\n async refreshSession() {\n const session = await readSession();\n if (!session?.refreshToken) return session;\n const response = await fetch(`${baseUrl}/api/auth/oauth2/token`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: session.refreshToken\n })\n });\n if (!response.ok) { await saveSession(null); return null; }\n const body = await response.json() as { access_token: string; refresh_token?: string; expires_in?: number };\n const nextSession: AuthSession = {\n ...session,\n accessToken: body.access_token,\n refreshToken: body.refresh_token ?? session.refreshToken,\n expiresAt: body.expires_in ? Date.now() + body.expires_in * 1000 : session.expiresAt\n };\n await saveSession(nextSession);\n return nextSession;\n },\n\n async verifyToken(token) {\n if (token.split(\".\").length !== 3) return false;\n const response = await fetch(`${authBase}/api/auth/oauth2/userinfo`, {\n headers: { authorization: `Bearer ${token}` }\n });\n return response.ok;\n },\n\n async getUser() {\n const token = await client.getAccessToken();\n if (!token) return null;\n const response = await fetch(`${baseUrl}/api/auth/oauth2/userinfo`, {\n headers: { authorization: `Bearer ${token}` }\n });\n return response.ok ? response.json() : null;\n }\n };\n\n return client;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export interface SmartHiveAuthConfig {\n projectId: string;\n publishableKey: string;\n baseUrl: string;\n /** Custom branded auth domain, e.g. \"https://auth.myapp.com\". Used as the entry point for login/token flows. Falls back to baseUrl. */\n authDomain?: string;\n /** Fallback auth domain if authDomain is unreachable, e.g. \"https://auth.smarthivelabs.dev\". */\n fallbackAuthDomain?: string;\n redirectUri?: string;\n storage?: AuthStorage;\n temporaryStorage?: AuthStorage;\n}\n\nexport interface AuthStorage {\n getItem(key: string): string | null | Promise<string | null>;\n setItem(key: string, value: string): void | Promise<void>;\n removeItem(key: string): void | Promise<void>;\n}\n\nexport interface AuthSession {\n accessToken: string;\n refreshToken?: string;\n expiresAt?: number;\n user?: unknown;\n}\n\n// ── Headless types ────────────────────────────────────────────────────────────\n\nexport interface HeadlessSignInResult {\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n user?: unknown;\n}\n\nexport interface HeadlessSignUpResult extends HeadlessSignInResult {\n /** True when email verification is required before the account can be used. */\n requiresVerification?: boolean;\n}\n\nexport interface HeadlessClient {\n signIn: {\n /**\n * Sign in with email and password. No browser redirect.\n * Returns tokens immediately on success.\n */\n email(params: { email: string; password: string }): Promise<HeadlessSignInResult>;\n\n phone: {\n /**\n * Send a one-time code to a phone number.\n * Call `verify` with the code the user receives.\n */\n sendOtp(params: { phoneNumber: string }): Promise<void>;\n /**\n * Verify the OTP sent to the phone number and return tokens on success.\n */\n verify(params: { phoneNumber: string; code: string }): Promise<HeadlessSignInResult>;\n };\n\n emailOtp: {\n /**\n * Send a one-time code to an email address.\n * Call `verify` with the code the user receives.\n */\n send(params: { email: string }): Promise<void>;\n /**\n * Verify the OTP sent to the email address and return tokens on success.\n */\n verify(params: { email: string; code: string }): Promise<HeadlessSignInResult>;\n };\n\n magicLink: {\n /**\n * Send a magic link to the given email address.\n * The user clicks the link — no token is returned here.\n */\n send(params: { email: string; callbackURL?: string }): Promise<void>;\n };\n };\n\n signUp: {\n /**\n * Create a new account with email and password. No browser redirect.\n * If email verification is required, `requiresVerification` will be true\n * and no tokens will be present — the user must verify before signing in.\n */\n email(params: { email: string; password: string; name?: string }): Promise<HeadlessSignUpResult>;\n };\n\n /** Refresh an expired access token using the refresh token. */\n refreshToken(params: { refreshToken: string }): Promise<{ accessToken: string; expiresAt: number }>;\n\n /** Sign the user out and invalidate their session on the server. */\n signOut(params?: { refreshToken?: string }): Promise<void>;\n}\n\nexport interface SmartHiveAuthClient {\n initialize(): Promise<void>;\n login(options?: { redirectUri?: string; state?: string }): Promise<void>;\n handleCallback(options?: { url?: string }): Promise<AuthSession>;\n /**\n * Initiate a social OAuth flow. Redirects the browser (or opens Linking URL\n * on mobile) to the provider's consent screen using the project's own credentials.\n * After the user approves, the provider redirects back with tokens in the redirect URI.\n */\n loginSocial(provider: SocialProvider, options?: { redirectUri?: string }): Promise<void>;\n /**\n * Parse social OAuth callback URL (contains access_token + refresh_token as query params),\n * persist the session, and return it. Call this when the app handles the redirect back from\n * the social flow (e.g. on the callback page, or in a deep link handler on mobile).\n */\n handleSocialCallback(options?: { url?: string }): Promise<AuthSession>;\n logout(): Promise<void>;\n getSession(): Promise<AuthSession | null>;\n getAccessToken(): Promise<string | null>;\n getAuthorizationHeader(): Promise<Record<string, string>>;\n fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;\n refreshSession(): Promise<AuthSession | null>;\n verifyToken(token: string): Promise<boolean>;\n getUser(): Promise<unknown>;\n /**\n * Direct credential-based authentication — no browser redirect.\n * Use these methods when you want full control of the sign-in UI\n * (e.g. native mobile apps with custom login screens).\n */\n headless: HeadlessClient;\n}\n\nexport type SocialProvider =\n | \"google\"\n | \"apple\"\n | \"github\"\n | \"facebook\"\n | \"twitter\"\n | \"linkedin\"\n | \"microsoft\"\n | \"discord\"\n | \"spotify\"\n | \"twitch\"\n | \"reddit\"\n | \"gitlab\"\n | \"slack\"\n | \"notion\"\n | \"zoom\"\n | \"figma\";\n\nexport class SmartHiveAuthError extends Error {\n constructor(public code: string, message: string) {\n super(message);\n this.name = \"SmartHiveAuthError\";\n }\n}\n\n// ── PKCE helpers (Web Crypto — works in browser + Node 18+) ──────────────────\n\nexport async function generateCodeVerifier(): Promise<string> {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return base64urlEncode(array);\n}\n\nexport async function generateCodeChallenge(verifier: string): Promise<string> {\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const digest = await crypto.subtle.digest(\"SHA-256\", data);\n return base64urlEncode(new Uint8Array(digest));\n}\n\nfunction base64urlEncode(buffer: Uint8Array): string {\n let str = \"\";\n for (const byte of buffer) str += String.fromCharCode(byte);\n return btoa(str).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\n// ── Storage keys ─────────────────────────────────────────────────────────────\n\nexport const smartHiveAuthStorageKeys = {\n session: \"smarthive.auth.session\",\n pkceVerifier: \"smarthive.auth.pkce_verifier\",\n pkceState: \"smarthive.auth.pkce_state\"\n} as const;\n\nfunction browserStorage(): AuthStorage {\n return {\n getItem: (key) => globalThis.localStorage?.getItem(key) ?? null,\n setItem: (key, value) => globalThis.localStorage?.setItem(key, value),\n removeItem: (key) => globalThis.localStorage?.removeItem(key)\n };\n}\n\nfunction sessionStorageAdapter(): Pick<AuthStorage, \"getItem\" | \"setItem\" | \"removeItem\"> {\n return {\n getItem: (key) => globalThis.sessionStorage?.getItem(key) ?? null,\n setItem: (key, value) => globalThis.sessionStorage?.setItem(key, value),\n removeItem: (key) => globalThis.sessionStorage?.removeItem(key)\n };\n}\n\nfunction normalizeBaseUrl(baseUrl: string) {\n return baseUrl.replace(/\\/$/, \"\");\n}\n\n/** Extract the environment prefix from a publishable key (pk_dev_*, pk_staging_*, pk_prod_*). */\nexport function envFromPublishableKey(publishableKey: string): string {\n const match = publishableKey.match(/^pk_(dev|staging|prod)_/);\n return match ? match[1] : \"prod\";\n}\n\n// ── Headless response shape from the backend ──────────────────────────────────\n\ninterface RawHeadlessResponse {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n token_type: string;\n user?: unknown;\n requires_verification?: boolean;\n message?: string;\n}\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\nexport function initAuth(config: SmartHiveAuthConfig): SmartHiveAuthClient {\n const baseUrl = normalizeBaseUrl(config.baseUrl);\n const authBase = normalizeBaseUrl(config.authDomain ?? config.baseUrl);\n const storage = config.storage ?? browserStorage();\n const tempStorage = config.temporaryStorage ?? sessionStorageAdapter();\n const environment = envFromPublishableKey(config.publishableKey);\n const headlessBase = `${baseUrl}/${environment}/api/auth/headless`;\n\n async function saveSession(session: AuthSession | null) {\n if (!session) { await storage.removeItem(smartHiveAuthStorageKeys.session); return; }\n await storage.setItem(smartHiveAuthStorageKeys.session, JSON.stringify(session));\n }\n\n async function readSession(): Promise<AuthSession | null> {\n const raw = await storage.getItem(smartHiveAuthStorageKeys.session);\n return raw ? JSON.parse(raw) as AuthSession : null;\n }\n\n function rawToSession(raw: RawHeadlessResponse): HeadlessSignInResult {\n return {\n accessToken: raw.access_token,\n refreshToken: raw.refresh_token,\n expiresAt: Date.now() + raw.expires_in * 1000,\n user: raw.user,\n };\n }\n\n async function headlessPost(path: string, body: Record<string, unknown>): Promise<RawHeadlessResponse> {\n const res = await fetch(`${headlessBase}${path}`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as { error?: string; message?: string };\n throw new SmartHiveAuthError(\n err.error ?? \"request_failed\",\n err.message ?? `Request to ${path} failed.`\n );\n }\n\n return res.json() as Promise<RawHeadlessResponse>;\n }\n\n async function headlessSignInAndSave(path: string, body: Record<string, unknown>): Promise<HeadlessSignInResult> {\n const raw = await headlessPost(path, body);\n const result = rawToSession(raw);\n await saveSession(result);\n return result;\n }\n\n const headless: HeadlessClient = {\n signIn: {\n async email({ email, password }) {\n return headlessSignInAndSave(\"/sign-in/email\", { email, password });\n },\n\n phone: {\n async sendOtp({ phoneNumber }) {\n await headlessPost(\"/phone/send-otp\", { phoneNumber });\n },\n async verify({ phoneNumber, code }) {\n return headlessSignInAndSave(\"/phone/verify\", { phoneNumber, code });\n },\n },\n\n emailOtp: {\n async send({ email }) {\n await headlessPost(\"/email-otp/send\", { email });\n },\n async verify({ email, code }) {\n return headlessSignInAndSave(\"/email-otp/verify\", { email, code });\n },\n },\n\n magicLink: {\n async send({ email, callbackURL }) {\n await headlessPost(\"/magic-link/send\", { email, ...(callbackURL ? { callbackURL } : {}) });\n },\n },\n },\n\n signUp: {\n async email({ email, password, name }) {\n const res = await fetch(`${headlessBase}/sign-up/email`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ email, password, name }),\n });\n\n // 202 = account created but email verification required\n if (res.status === 202) {\n return { accessToken: \"\", refreshToken: \"\", expiresAt: 0, requiresVerification: true };\n }\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as { error?: string; message?: string };\n throw new SmartHiveAuthError(err.error ?? \"sign_up_failed\", err.message ?? \"Sign up failed.\");\n }\n\n const raw = await res.json() as RawHeadlessResponse;\n const result: HeadlessSignUpResult = { ...rawToSession(raw), requiresVerification: false };\n await saveSession(result);\n return result;\n },\n },\n\n async refreshToken({ refreshToken }) {\n const raw = await headlessPost(\"/token/refresh\", { refresh_token: refreshToken });\n const updated: AuthSession = {\n ...(await readSession() ?? {}),\n accessToken: raw.access_token,\n expiresAt: Date.now() + raw.expires_in * 1000,\n };\n await saveSession(updated);\n return { accessToken: raw.access_token, expiresAt: updated.expiresAt! };\n },\n\n async signOut({ refreshToken } = {}) {\n const session = await readSession();\n const token = refreshToken ?? session?.refreshToken;\n await saveSession(null);\n if (token) {\n await fetch(`${headlessBase}/sign-out`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ refresh_token: token }),\n }).catch(() => {});\n }\n },\n };\n\n const client: SmartHiveAuthClient = {\n async initialize() {\n const response = await fetch(\n `${baseUrl}/sdk/config?projectId=${encodeURIComponent(config.projectId)}&publishableKey=${encodeURIComponent(config.publishableKey)}`\n );\n if (!response.ok) throw new SmartHiveAuthError(\"project_not_found\", \"Smart Hive Auth project configuration was not found.\");\n },\n\n async login(options) {\n const redirectUri = options?.redirectUri ?? config.redirectUri ?? globalThis.location?.href;\n const state = options?.state ?? crypto.randomUUID();\n const verifier = await generateCodeVerifier();\n const challenge = await generateCodeChallenge(verifier);\n\n await tempStorage.setItem(smartHiveAuthStorageKeys.pkceVerifier, verifier);\n await tempStorage.setItem(smartHiveAuthStorageKeys.pkceState, state);\n\n const url = new URL(`${authBase}/api/auth/oauth2/authorize`);\n url.searchParams.set(\"project_id\", config.projectId);\n url.searchParams.set(\"publishable_key\", config.publishableKey);\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"redirect_uri\", redirectUri);\n url.searchParams.set(\"state\", state);\n url.searchParams.set(\"code_challenge\", challenge);\n url.searchParams.set(\"code_challenge_method\", \"S256\");\n\n globalThis.location.assign(url.toString());\n },\n\n async handleCallback(options) {\n const href = options?.url ?? globalThis.location?.href;\n if (!href) throw new SmartHiveAuthError(\"callback_failed\", \"No URL provided for callback handling.\");\n\n const url = new URL(href);\n const code = url.searchParams.get(\"code\");\n const returnedState = url.searchParams.get(\"state\");\n\n if (!code) throw new SmartHiveAuthError(\"callback_failed\", \"No authorization code in callback URL.\");\n\n const storedState = await tempStorage.getItem(smartHiveAuthStorageKeys.pkceState);\n if (!storedState || !returnedState || storedState !== returnedState) {\n throw new SmartHiveAuthError(\"state_mismatch\", \"OAuth state mismatch — possible CSRF attack.\");\n }\n\n const verifier = await tempStorage.getItem(smartHiveAuthStorageKeys.pkceVerifier);\n if (!verifier) {\n throw new SmartHiveAuthError(\"pkce_missing\", \"Missing PKCE verifier for authorization code exchange.\");\n }\n const redirectUri = config.redirectUri ?? (url.origin + url.pathname);\n\n const body = new URLSearchParams({\n grant_type: \"authorization_code\",\n code,\n redirect_uri: redirectUri,\n client_id: config.publishableKey\n });\n body.set(\"code_verifier\", verifier);\n\n const response = await fetch(`${authBase}/api/auth/oauth2/token`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\" },\n body\n });\n\n if (!response.ok) {\n const err = await response.json().catch(() => ({})) as { error?: string; error_description?: string };\n throw new SmartHiveAuthError(err.error ?? \"token_error\", err.error_description ?? \"Token exchange failed.\");\n }\n\n const tokenBody = await response.json() as {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n token_type?: string;\n };\n\n const session: AuthSession = {\n accessToken: tokenBody.access_token,\n refreshToken: tokenBody.refresh_token,\n expiresAt: tokenBody.expires_in ? Date.now() + tokenBody.expires_in * 1000 : undefined\n };\n\n await saveSession(session);\n await tempStorage.removeItem(smartHiveAuthStorageKeys.pkceVerifier);\n await tempStorage.removeItem(smartHiveAuthStorageKeys.pkceState);\n\n return session;\n },\n\n async loginSocial(provider, options) {\n const redirectUri = options?.redirectUri ?? config.redirectUri ?? globalThis.location?.href;\n if (!redirectUri) throw new SmartHiveAuthError(\"missing_redirect_uri\", \"redirectUri is required for social login.\");\n const url = new URL(`${authBase}/${environment}/api/auth/social/${provider}`);\n url.searchParams.set(\"project_id\", config.projectId);\n url.searchParams.set(\"redirect_uri\", redirectUri);\n globalThis.location.assign(url.toString());\n },\n\n async handleSocialCallback(options) {\n const href = options?.url ?? globalThis.location?.href;\n if (!href) throw new SmartHiveAuthError(\"callback_failed\", \"No URL available for social callback.\");\n const url = new URL(href);\n const error = url.searchParams.get(\"error\");\n if (error) {\n throw new SmartHiveAuthError(error, url.searchParams.get(\"error_description\") ?? error);\n }\n const accessToken = url.searchParams.get(\"access_token\");\n if (!accessToken) throw new SmartHiveAuthError(\"callback_failed\", \"No access token in social callback URL.\");\n const expiresIn = url.searchParams.get(\"expires_in\");\n const session: AuthSession = {\n accessToken,\n refreshToken: url.searchParams.get(\"refresh_token\") ?? undefined,\n expiresAt: expiresIn ? Date.now() + parseInt(expiresIn, 10) * 1000 : undefined,\n };\n await saveSession(session);\n return session;\n },\n\n async logout() {\n await saveSession(null);\n await fetch(`${baseUrl}/api/auth/sign-out`, { method: \"POST\", credentials: \"include\" });\n },\n\n getSession: readSession,\n\n async getAccessToken() {\n const session = await readSession();\n if (!session) return null;\n if (session.expiresAt && Date.now() > session.expiresAt - 30000) {\n return (await client.refreshSession())?.accessToken ?? null;\n }\n return session.accessToken;\n },\n\n async getAuthorizationHeader() {\n const token = await client.getAccessToken();\n const headers: Record<string, string> = {};\n if (token) headers.authorization = `Bearer ${token}`;\n return headers;\n },\n\n async fetch(input, init = {}) {\n const authHeader = await client.getAuthorizationHeader();\n const headers = new Headers(init.headers);\n for (const [key, value] of Object.entries(authHeader)) {\n headers.set(key, value);\n }\n return fetch(input, { ...init, headers });\n },\n\n async refreshSession() {\n const session = await readSession();\n if (!session?.refreshToken) return session;\n const response = await fetch(`${baseUrl}/api/auth/oauth2/token`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: session.refreshToken\n })\n });\n if (!response.ok) { await saveSession(null); return null; }\n const body = await response.json() as { access_token: string; refresh_token?: string; expires_in?: number };\n const nextSession: AuthSession = {\n ...session,\n accessToken: body.access_token,\n refreshToken: body.refresh_token ?? session.refreshToken,\n expiresAt: body.expires_in ? Date.now() + body.expires_in * 1000 : session.expiresAt\n };\n await saveSession(nextSession);\n return nextSession;\n },\n\n async verifyToken(token) {\n if (token.split(\".\").length !== 3) return false;\n const response = await fetch(`${authBase}/api/auth/oauth2/userinfo`, {\n headers: { authorization: `Bearer ${token}` }\n });\n return response.ok;\n },\n\n async getUser() {\n const token = await client.getAccessToken();\n if (!token) return null;\n const response = await fetch(`${baseUrl}/api/auth/oauth2/userinfo`, {\n headers: { authorization: `Bearer ${token}` }\n });\n return response.ok ? response.json() : null;\n },\n\n headless,\n };\n\n return client;\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED