@smarthivelabs-devs/auth-sdk 1.2.0 → 1.4.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 CHANGED
@@ -81,6 +81,14 @@ interface SmartHiveAuthConfig {
81
81
 
82
82
  /** Custom temporary storage for PKCE values (default: sessionStorage in browser) */
83
83
  temporaryStorage?: AuthStorage;
84
+
85
+ /**
86
+ * URL of your own backend's social auth proxy (e.g. "https://api.myapp.com").
87
+ * When set, social OAuth initiations route through your domain so Google/Apple
88
+ * consent screens show your domain instead of SmartHive's.
89
+ * See auth-expo README → "Social Auth Proxy" for the full setup guide.
90
+ */
91
+ socialProxyUrl?: string;
84
92
  }
85
93
  ```
86
94
 
package/dist/index.cjs CHANGED
@@ -266,9 +266,15 @@ function initAuth(config) {
266
266
  async loginSocial(provider, options) {
267
267
  const redirectUri = options?.redirectUri ?? config.redirectUri ?? globalThis.location?.href;
268
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);
269
+ let url;
270
+ if (config.socialProxyUrl) {
271
+ url = new URL(`${normalizeBaseUrl(config.socialProxyUrl)}/api/auth/social/${provider}`);
272
+ url.searchParams.set("redirect_uri", redirectUri);
273
+ } else {
274
+ url = new URL(`${authBase}/${environment}/api/auth/social/${provider}`);
275
+ url.searchParams.set("project_id", config.projectId);
276
+ url.searchParams.set("redirect_uri", redirectUri);
277
+ }
272
278
  globalThis.location.assign(url.toString());
273
279
  },
274
280
  async handleSocialCallback(options) {
@@ -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\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":[]}
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 * URL of your own backend's social auth proxy (e.g. \"https://api.myapp.com\").\n * When set, social OAuth initiations route through your domain so Google/Apple\n * consent screens show your domain instead of SmartHive's.\n * Your backend must implement GET /api/auth/social/:provider and\n * GET /api/auth/social/:provider/callback.\n */\n socialProxyUrl?: string;\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 let url: URL;\n if (config.socialProxyUrl) {\n // Route through the app's own backend proxy — provider shows app's domain\n url = new URL(`${normalizeBaseUrl(config.socialProxyUrl)}/api/auth/social/${provider}`);\n url.searchParams.set(\"redirect_uri\", redirectUri);\n // project_id is injected server-side by the backend proxy\n } else {\n 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 }\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
@@ -9,6 +9,14 @@ interface SmartHiveAuthConfig {
9
9
  redirectUri?: string;
10
10
  storage?: AuthStorage;
11
11
  temporaryStorage?: AuthStorage;
12
+ /**
13
+ * URL of your own backend's social auth proxy (e.g. "https://api.myapp.com").
14
+ * When set, social OAuth initiations route through your domain so Google/Apple
15
+ * consent screens show your domain instead of SmartHive's.
16
+ * Your backend must implement GET /api/auth/social/:provider and
17
+ * GET /api/auth/social/:provider/callback.
18
+ */
19
+ socialProxyUrl?: string;
12
20
  }
13
21
  interface AuthStorage {
14
22
  getItem(key: string): string | null | Promise<string | null>;
package/dist/index.d.ts CHANGED
@@ -9,6 +9,14 @@ interface SmartHiveAuthConfig {
9
9
  redirectUri?: string;
10
10
  storage?: AuthStorage;
11
11
  temporaryStorage?: AuthStorage;
12
+ /**
13
+ * URL of your own backend's social auth proxy (e.g. "https://api.myapp.com").
14
+ * When set, social OAuth initiations route through your domain so Google/Apple
15
+ * consent screens show your domain instead of SmartHive's.
16
+ * Your backend must implement GET /api/auth/social/:provider and
17
+ * GET /api/auth/social/:provider/callback.
18
+ */
19
+ socialProxyUrl?: string;
12
20
  }
13
21
  interface AuthStorage {
14
22
  getItem(key: string): string | null | Promise<string | null>;
package/dist/index.js CHANGED
@@ -237,9 +237,15 @@ function initAuth(config) {
237
237
  async loginSocial(provider, options) {
238
238
  const redirectUri = options?.redirectUri ?? config.redirectUri ?? globalThis.location?.href;
239
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);
240
+ let url;
241
+ if (config.socialProxyUrl) {
242
+ url = new URL(`${normalizeBaseUrl(config.socialProxyUrl)}/api/auth/social/${provider}`);
243
+ url.searchParams.set("redirect_uri", redirectUri);
244
+ } else {
245
+ url = new URL(`${authBase}/${environment}/api/auth/social/${provider}`);
246
+ url.searchParams.set("project_id", config.projectId);
247
+ url.searchParams.set("redirect_uri", redirectUri);
248
+ }
243
249
  globalThis.location.assign(url.toString());
244
250
  },
245
251
  async handleSocialCallback(options) {
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\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":[]}
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 * URL of your own backend's social auth proxy (e.g. \"https://api.myapp.com\").\n * When set, social OAuth initiations route through your domain so Google/Apple\n * consent screens show your domain instead of SmartHive's.\n * Your backend must implement GET /api/auth/social/:provider and\n * GET /api/auth/social/:provider/callback.\n */\n socialProxyUrl?: string;\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 let url: URL;\n if (config.socialProxyUrl) {\n // Route through the app's own backend proxy — provider shows app's domain\n url = new URL(`${normalizeBaseUrl(config.socialProxyUrl)}/api/auth/social/${provider}`);\n url.searchParams.set(\"redirect_uri\", redirectUri);\n // project_id is injected server-side by the backend proxy\n } else {\n 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 }\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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smarthivelabs-devs/auth-sdk",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "SmartHive Auth JavaScript/TypeScript SDK — core client for browser, Node.js, and React Native",
5
5
  "license": "MIT",
6
6
  "repository": {