@smarthivelabs-devs/auth-sdk 0.1.0 → 1.1.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 ADDED
@@ -0,0 +1,402 @@
1
+ # @smarthivelabs-devs/auth-sdk
2
+
3
+ Core JavaScript/TypeScript SDK for SmartHive Auth. Framework-agnostic — works in the browser, Node.js 18+, and React Native. This is the foundation that `auth-react`, `auth-expo`, and `auth-server` are all built on.
4
+
5
+ ---
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @smarthivelabs-devs/auth-sdk
11
+ # or
12
+ pnpm add @smarthivelabs-devs/auth-sdk
13
+ # or
14
+ yarn add @smarthivelabs-devs/auth-sdk
15
+ ```
16
+
17
+ ---
18
+
19
+ ## Prerequisites
20
+
21
+ You need a SmartHive Auth project. From your SmartHive dashboard grab:
22
+
23
+ - `projectId` — e.g. `proj_abc123`
24
+ - `publishableKey` — e.g. `pk_live_abc123`
25
+ - `baseUrl` — the URL of your SmartHive Auth service instance
26
+
27
+ ---
28
+
29
+ ## Quick Start
30
+
31
+ ```ts
32
+ import { initAuth } from "@smarthivelabs-devs/auth-sdk";
33
+
34
+ const client = initAuth({
35
+ projectId: "proj_abc123",
36
+ publishableKey: "pk_live_abc123",
37
+ baseUrl: "https://auth.myapp.com",
38
+ redirectUri: "https://myapp.com/auth/callback",
39
+ });
40
+
41
+ // Initialize (validates your project config against the server)
42
+ await client.initialize();
43
+
44
+ // Redirect the user to the SmartHive login page
45
+ await client.login();
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Configuration
51
+
52
+ ```ts
53
+ interface SmartHiveAuthConfig {
54
+ /** Your SmartHive project ID */
55
+ projectId: string;
56
+
57
+ /** Your publishable (public) key */
58
+ publishableKey: string;
59
+
60
+ /** Base URL of your SmartHive Auth service */
61
+ baseUrl: string;
62
+
63
+ /**
64
+ * Custom branded auth domain (e.g. "https://auth.myapp.com").
65
+ * Used as the entry point for login/token flows.
66
+ * Falls back to baseUrl if not set.
67
+ */
68
+ authDomain?: string;
69
+
70
+ /**
71
+ * Fallback auth domain if authDomain is unreachable.
72
+ * Useful for high-availability setups.
73
+ */
74
+ fallbackAuthDomain?: string;
75
+
76
+ /** Default OAuth redirect URI after login */
77
+ redirectUri?: string;
78
+
79
+ /** Custom persistent storage adapter (default: localStorage in browser) */
80
+ storage?: AuthStorage;
81
+
82
+ /** Custom temporary storage for PKCE values (default: sessionStorage in browser) */
83
+ temporaryStorage?: AuthStorage;
84
+ }
85
+ ```
86
+
87
+ ---
88
+
89
+ ## API Reference
90
+
91
+ ### `initAuth(config)`
92
+
93
+ Creates and returns a `SmartHiveAuthClient`. Call this once at your app's entry point.
94
+
95
+ ```ts
96
+ const client = initAuth({
97
+ projectId: "proj_abc123",
98
+ publishableKey: "pk_live_abc123",
99
+ baseUrl: "https://auth.myapp.com",
100
+ });
101
+ ```
102
+
103
+ ---
104
+
105
+ ### `client.initialize()`
106
+
107
+ Validates your project configuration with the SmartHive server. Call this before any auth operations.
108
+
109
+ ```ts
110
+ await client.initialize();
111
+ ```
112
+
113
+ Throws `SmartHiveAuthError` with code `project_not_found` if the project or key is invalid.
114
+
115
+ ---
116
+
117
+ ### `client.login(options?)`
118
+
119
+ Starts the OAuth 2.0 + PKCE login flow by redirecting the user to the SmartHive login page.
120
+
121
+ ```ts
122
+ // Basic login (uses redirectUri from config)
123
+ await client.login();
124
+
125
+ // Override the redirect URI for this login attempt
126
+ await client.login({ redirectUri: "https://myapp.com/auth/callback" });
127
+
128
+ // Pass custom state (returned in the callback URL)
129
+ await client.login({ state: "my-custom-state" });
130
+ ```
131
+
132
+ ---
133
+
134
+ ### `client.handleCallback(options?)`
135
+
136
+ Completes the OAuth flow on your callback route. Exchanges the authorization code for tokens and persists the session.
137
+
138
+ ```ts
139
+ // In your /auth/callback page — reads from window.location automatically
140
+ const session = await client.handleCallback();
141
+
142
+ // Or pass the URL explicitly (useful in SSR or React Native)
143
+ const session = await client.handleCallback({ url: "https://myapp.com/auth/callback?code=...&state=..." });
144
+
145
+ console.log(session.accessToken);
146
+ console.log(session.refreshToken);
147
+ console.log(session.expiresAt); // Unix timestamp in ms
148
+ ```
149
+
150
+ Throws `SmartHiveAuthError` with codes:
151
+ - `callback_failed` — missing code or URL
152
+ - `state_mismatch` — possible CSRF attack
153
+ - `pkce_missing` — PKCE verifier not found (session expired between steps)
154
+ - `token_error` — server rejected the code exchange
155
+
156
+ ---
157
+
158
+ ### `client.getSession()`
159
+
160
+ Returns the current session from storage, or `null` if not signed in. Does not refresh expired tokens automatically.
161
+
162
+ ```ts
163
+ const session = await client.getSession();
164
+ if (session) {
165
+ console.log("Signed in:", session.accessToken);
166
+ } else {
167
+ console.log("Not signed in");
168
+ }
169
+ ```
170
+
171
+ ---
172
+
173
+ ### `client.getAccessToken()`
174
+
175
+ Returns a valid access token. Automatically refreshes using the refresh token if the access token is within 30 seconds of expiry.
176
+
177
+ ```ts
178
+ const token = await client.getAccessToken();
179
+ if (token) {
180
+ // token is always fresh when truthy
181
+ }
182
+ ```
183
+
184
+ ---
185
+
186
+ ### `client.getAuthorizationHeader()`
187
+
188
+ Returns a `{ authorization: "Bearer <token>" }` header object ready to spread into fetch options. Returns an empty object if not signed in.
189
+
190
+ ```ts
191
+ const headers = await client.getAuthorizationHeader();
192
+ const res = await fetch("/api/protected", { headers });
193
+ ```
194
+
195
+ ---
196
+
197
+ ### `client.fetch(input, init?)`
198
+
199
+ Drop-in replacement for `fetch` that automatically injects the `Authorization` header.
200
+
201
+ ```ts
202
+ // Identical to native fetch, but auth is handled automatically
203
+ const res = await client.fetch("/api/user/profile");
204
+ const res2 = await client.fetch("https://api.myapp.com/data", {
205
+ method: "POST",
206
+ body: JSON.stringify({ name: "Alice" }),
207
+ headers: { "content-type": "application/json" },
208
+ });
209
+ ```
210
+
211
+ ---
212
+
213
+ ### `client.refreshSession()`
214
+
215
+ Explicitly refreshes the session using the stored refresh token. Returns the new session, or `null` if the refresh token is missing or expired (which also clears the stored session).
216
+
217
+ ```ts
218
+ const newSession = await client.refreshSession();
219
+ if (!newSession) {
220
+ // Refresh token expired — user must log in again
221
+ await client.login();
222
+ }
223
+ ```
224
+
225
+ ---
226
+
227
+ ### `client.logout()`
228
+
229
+ Clears the local session and calls the server-side sign-out endpoint.
230
+
231
+ ```ts
232
+ await client.logout();
233
+ // User is now signed out — redirect them to your home/login page
234
+ ```
235
+
236
+ ---
237
+
238
+ ### `client.getUser()`
239
+
240
+ Fetches the current user's profile from the SmartHive userinfo endpoint. Returns `null` if not signed in.
241
+
242
+ ```ts
243
+ const user = await client.getUser();
244
+ console.log(user); // { sub: "user_123", email: "alice@example.com", ... }
245
+ ```
246
+
247
+ ---
248
+
249
+ ### `client.verifyToken(token)`
250
+
251
+ Verifies a raw access token against the SmartHive userinfo endpoint. Returns `true` if the token is valid and accepted by the server.
252
+
253
+ ```ts
254
+ const isValid = await client.verifyToken(rawToken);
255
+ ```
256
+
257
+ ---
258
+
259
+ ## Custom Storage Adapter
260
+
261
+ By default the SDK uses `localStorage` for persistent storage and `sessionStorage` for PKCE state. Provide your own adapter to use any other storage backend (IndexedDB, AsyncStorage, SecureStore, Redis, etc.).
262
+
263
+ ```ts
264
+ import { initAuth, type AuthStorage } from "@smarthivelabs-devs/auth-sdk";
265
+
266
+ const myStorage: AuthStorage = {
267
+ getItem: async (key) => {
268
+ return await myDatabase.get(key);
269
+ },
270
+ setItem: async (key, value) => {
271
+ await myDatabase.set(key, value);
272
+ },
273
+ removeItem: async (key) => {
274
+ await myDatabase.delete(key);
275
+ },
276
+ };
277
+
278
+ const client = initAuth({
279
+ projectId: "proj_abc123",
280
+ publishableKey: "pk_live_abc123",
281
+ baseUrl: "https://auth.myapp.com",
282
+ storage: myStorage,
283
+ });
284
+ ```
285
+
286
+ ---
287
+
288
+ ## PKCE Helpers
289
+
290
+ Low-level PKCE utilities exported for advanced use cases (e.g. building your own auth client on top of this SDK).
291
+
292
+ ```ts
293
+ import {
294
+ generateCodeVerifier,
295
+ generateCodeChallenge,
296
+ } from "@smarthivelabs-devs/auth-sdk";
297
+
298
+ const verifier = await generateCodeVerifier(); // random 32-byte base64url string
299
+ const challenge = await generateCodeChallenge(verifier); // SHA-256(verifier), base64url encoded
300
+ ```
301
+
302
+ Uses the Web Crypto API — works in browsers and Node.js 18+.
303
+
304
+ ---
305
+
306
+ ## Error Handling
307
+
308
+ All async methods throw `SmartHiveAuthError` on failure.
309
+
310
+ ```ts
311
+ import { SmartHiveAuthError } from "@smarthivelabs-devs/auth-sdk";
312
+
313
+ try {
314
+ await client.login();
315
+ } catch (err) {
316
+ if (err instanceof SmartHiveAuthError) {
317
+ console.error(err.code); // e.g. "project_not_found"
318
+ console.error(err.message); // human-readable description
319
+ }
320
+ }
321
+ ```
322
+
323
+ Common error codes:
324
+
325
+ | Code | When |
326
+ |---|---|
327
+ | `project_not_found` | `initialize()` — invalid projectId or publishableKey |
328
+ | `callback_failed` | `handleCallback()` — no code in URL |
329
+ | `state_mismatch` | `handleCallback()` — OAuth state doesn't match (CSRF) |
330
+ | `pkce_missing` | `handleCallback()` — PKCE verifier not in storage |
331
+ | `token_error` | `handleCallback()` — server rejected code exchange |
332
+
333
+ ---
334
+
335
+ ## Vanilla JS/TS Example (Full Flow)
336
+
337
+ ```ts
338
+ import { initAuth, SmartHiveAuthError } from "@smarthivelabs-devs/auth-sdk";
339
+
340
+ const client = initAuth({
341
+ projectId: import.meta.env.VITE_AUTH_PROJECT_ID,
342
+ publishableKey: import.meta.env.VITE_AUTH_PUBLISHABLE_KEY,
343
+ baseUrl: import.meta.env.VITE_AUTH_BASE_URL,
344
+ redirectUri: `${window.location.origin}/auth/callback`,
345
+ });
346
+
347
+ // Entry point — runs on every page load
348
+ await client.initialize();
349
+ const session = await client.getSession();
350
+
351
+ // Login button
352
+ document.getElementById("login-btn")?.addEventListener("click", () => {
353
+ client.login();
354
+ });
355
+
356
+ // Logout button
357
+ document.getElementById("logout-btn")?.addEventListener("click", async () => {
358
+ await client.logout();
359
+ window.location.href = "/";
360
+ });
361
+
362
+ // Callback page (e.g. /auth/callback)
363
+ if (window.location.pathname === "/auth/callback") {
364
+ try {
365
+ await client.handleCallback();
366
+ window.location.href = "/dashboard";
367
+ } catch (err) {
368
+ if (err instanceof SmartHiveAuthError) {
369
+ console.error("Auth failed:", err.code, err.message);
370
+ }
371
+ }
372
+ }
373
+ ```
374
+
375
+ ---
376
+
377
+ ## TypeScript Types
378
+
379
+ ```ts
380
+ import type {
381
+ SmartHiveAuthConfig,
382
+ SmartHiveAuthClient,
383
+ AuthSession,
384
+ AuthStorage,
385
+ } from "@smarthivelabs-devs/auth-sdk";
386
+ ```
387
+
388
+ ---
389
+
390
+ ## Related Packages
391
+
392
+ | Package | Use case |
393
+ |---|---|
394
+ | [`@smarthivelabs-devs/auth-react`](https://www.npmjs.com/package/@smarthivelabs-devs/auth-react) | React web apps — provider, hooks, components |
395
+ | [`@smarthivelabs-devs/auth-expo`](https://www.npmjs.com/package/@smarthivelabs-devs/auth-expo) | React Native / Expo apps |
396
+ | [`@smarthivelabs-devs/auth-server`](https://www.npmjs.com/package/@smarthivelabs-devs/auth-server) | Express / Next.js server-side JWT verification |
397
+
398
+ ---
399
+
400
+ ## License
401
+
402
+ MIT © SmartHive Labs
package/dist/index.cjs CHANGED
@@ -73,11 +73,17 @@ function sessionStorageAdapter() {
73
73
  function normalizeBaseUrl(baseUrl) {
74
74
  return baseUrl.replace(/\/$/, "");
75
75
  }
76
+ function envFromPublishableKey(publishableKey) {
77
+ const match = publishableKey.match(/^pk_(dev|staging|prod)_/);
78
+ return match ? match[1] : "prod";
79
+ }
76
80
  function initAuth(config) {
77
81
  const baseUrl = normalizeBaseUrl(config.baseUrl);
78
82
  const authBase = normalizeBaseUrl(config.authDomain ?? config.baseUrl);
79
83
  const storage = config.storage ?? browserStorage();
80
84
  const tempStorage = config.temporaryStorage ?? sessionStorageAdapter();
85
+ const environment = envFromPublishableKey(config.publishableKey);
86
+ const headlessBase = `${baseUrl}/${environment}/api/auth/headless`;
81
87
  async function saveSession(session) {
82
88
  if (!session) {
83
89
  await storage.removeItem(smartHiveAuthStorageKeys.session);
@@ -89,6 +95,106 @@ function initAuth(config) {
89
95
  const raw = await storage.getItem(smartHiveAuthStorageKeys.session);
90
96
  return raw ? JSON.parse(raw) : null;
91
97
  }
98
+ function rawToSession(raw) {
99
+ return {
100
+ accessToken: raw.access_token,
101
+ refreshToken: raw.refresh_token,
102
+ expiresAt: Date.now() + raw.expires_in * 1e3,
103
+ user: raw.user
104
+ };
105
+ }
106
+ async function headlessPost(path, body) {
107
+ const res = await fetch(`${headlessBase}${path}`, {
108
+ method: "POST",
109
+ headers: { "content-type": "application/json" },
110
+ body: JSON.stringify(body)
111
+ });
112
+ if (!res.ok) {
113
+ const err = await res.json().catch(() => ({}));
114
+ throw new SmartHiveAuthError(
115
+ err.error ?? "request_failed",
116
+ err.message ?? `Request to ${path} failed.`
117
+ );
118
+ }
119
+ return res.json();
120
+ }
121
+ async function headlessSignInAndSave(path, body) {
122
+ const raw = await headlessPost(path, body);
123
+ const result = rawToSession(raw);
124
+ await saveSession(result);
125
+ return result;
126
+ }
127
+ const headless = {
128
+ signIn: {
129
+ async email({ email, password }) {
130
+ return headlessSignInAndSave("/sign-in/email", { email, password });
131
+ },
132
+ phone: {
133
+ async sendOtp({ phoneNumber }) {
134
+ await headlessPost("/phone/send-otp", { phoneNumber });
135
+ },
136
+ async verify({ phoneNumber, code }) {
137
+ return headlessSignInAndSave("/phone/verify", { phoneNumber, code });
138
+ }
139
+ },
140
+ emailOtp: {
141
+ async send({ email }) {
142
+ await headlessPost("/email-otp/send", { email });
143
+ },
144
+ async verify({ email, code }) {
145
+ return headlessSignInAndSave("/email-otp/verify", { email, code });
146
+ }
147
+ },
148
+ magicLink: {
149
+ async send({ email, callbackURL }) {
150
+ await headlessPost("/magic-link/send", { email, ...callbackURL ? { callbackURL } : {} });
151
+ }
152
+ }
153
+ },
154
+ signUp: {
155
+ async email({ email, password, name }) {
156
+ const res = await fetch(`${headlessBase}/sign-up/email`, {
157
+ method: "POST",
158
+ headers: { "content-type": "application/json" },
159
+ body: JSON.stringify({ email, password, name })
160
+ });
161
+ if (res.status === 202) {
162
+ return { accessToken: "", refreshToken: "", expiresAt: 0, requiresVerification: true };
163
+ }
164
+ if (!res.ok) {
165
+ const err = await res.json().catch(() => ({}));
166
+ throw new SmartHiveAuthError(err.error ?? "sign_up_failed", err.message ?? "Sign up failed.");
167
+ }
168
+ const raw = await res.json();
169
+ const result = { ...rawToSession(raw), requiresVerification: false };
170
+ await saveSession(result);
171
+ return result;
172
+ }
173
+ },
174
+ async refreshToken({ refreshToken }) {
175
+ const raw = await headlessPost("/token/refresh", { refresh_token: refreshToken });
176
+ const updated = {
177
+ ...await readSession() ?? {},
178
+ accessToken: raw.access_token,
179
+ expiresAt: Date.now() + raw.expires_in * 1e3
180
+ };
181
+ await saveSession(updated);
182
+ return { accessToken: raw.access_token, expiresAt: updated.expiresAt };
183
+ },
184
+ async signOut({ refreshToken } = {}) {
185
+ const session = await readSession();
186
+ const token = refreshToken ?? session?.refreshToken;
187
+ await saveSession(null);
188
+ if (token) {
189
+ await fetch(`${headlessBase}/sign-out`, {
190
+ method: "POST",
191
+ headers: { "content-type": "application/json" },
192
+ body: JSON.stringify({ refresh_token: token })
193
+ }).catch(() => {
194
+ });
195
+ }
196
+ }
197
+ };
92
198
  const client = {
93
199
  async initialize() {
94
200
  const response = await fetch(
@@ -222,7 +328,8 @@ function initAuth(config) {
222
328
  headers: { authorization: `Bearer ${token}` }
223
329
  });
224
330
  return response.ok ? response.json() : null;
225
- }
331
+ },
332
+ headless
226
333
  };
227
334
  return client;
228
335
  }
@@ -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 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 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_*). */\nfunction 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 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?: {
@@ -38,6 +125,12 @@ interface SmartHiveAuthClient {
38
125
  refreshSession(): Promise<AuthSession | null>;
39
126
  verifyToken(token: string): Promise<boolean>;
40
127
  getUser(): Promise<unknown>;
128
+ /**
129
+ * Direct credential-based authentication — no browser redirect.
130
+ * Use these methods when you want full control of the sign-in UI
131
+ * (e.g. native mobile apps with custom login screens).
132
+ */
133
+ headless: HeadlessClient;
41
134
  }
42
135
  declare class SmartHiveAuthError extends Error {
43
136
  code: string;
@@ -52,4 +145,4 @@ declare const smartHiveAuthStorageKeys: {
52
145
  };
53
146
  declare function initAuth(config: SmartHiveAuthConfig): SmartHiveAuthClient;
54
147
 
55
- export { type AuthSession, type AuthStorage, type SmartHiveAuthClient, type SmartHiveAuthConfig, SmartHiveAuthError, generateCodeChallenge, generateCodeVerifier, initAuth, smartHiveAuthStorageKeys };
148
+ export { type AuthSession, type AuthStorage, type HeadlessClient, type HeadlessSignInResult, type HeadlessSignUpResult, type SmartHiveAuthClient, type SmartHiveAuthConfig, SmartHiveAuthError, 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?: {
@@ -38,6 +125,12 @@ interface SmartHiveAuthClient {
38
125
  refreshSession(): Promise<AuthSession | null>;
39
126
  verifyToken(token: string): Promise<boolean>;
40
127
  getUser(): Promise<unknown>;
128
+ /**
129
+ * Direct credential-based authentication — no browser redirect.
130
+ * Use these methods when you want full control of the sign-in UI
131
+ * (e.g. native mobile apps with custom login screens).
132
+ */
133
+ headless: HeadlessClient;
41
134
  }
42
135
  declare class SmartHiveAuthError extends Error {
43
136
  code: string;
@@ -52,4 +145,4 @@ declare const smartHiveAuthStorageKeys: {
52
145
  };
53
146
  declare function initAuth(config: SmartHiveAuthConfig): SmartHiveAuthClient;
54
147
 
55
- export { type AuthSession, type AuthStorage, type SmartHiveAuthClient, type SmartHiveAuthConfig, SmartHiveAuthError, generateCodeChallenge, generateCodeVerifier, initAuth, smartHiveAuthStorageKeys };
148
+ export { type AuthSession, type AuthStorage, type HeadlessClient, type HeadlessSignInResult, type HeadlessSignUpResult, type SmartHiveAuthClient, type SmartHiveAuthConfig, SmartHiveAuthError, 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(
@@ -194,7 +300,8 @@ function initAuth(config) {
194
300
  headers: { authorization: `Bearer ${token}` }
195
301
  });
196
302
  return response.ok ? response.json() : null;
197
- }
303
+ },
304
+ headless
198
305
  };
199
306
  return client;
200
307
  }
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 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 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_*). */\nfunction 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 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": "0.1.0",
3
+ "version": "1.1.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": {