@deepkey/sdk 1.0.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 CHANGED
@@ -180,6 +180,46 @@ await fetch('/api/things', {
180
180
  })
181
181
  ```
182
182
 
183
+ ## Provider connections (durable provider access)
184
+
185
+ Login discards provider tokens. When your product needs to act on a provider on the user's behalf (for example manage several X accounts), the signed-in user **connects** accounts. DeepKey keeps the provider refresh token; browsers only see metadata and your server receives short-lived provider access tokens.
186
+
187
+ ```ts
188
+ // Browser — the user is already signed in (any method: email, Google, X).
189
+ await deepkey.connections.connect({
190
+ provider: 'x',
191
+ options: { redirectTo: `${window.location.origin}/settings` }, // must be allow-listed
192
+ })
193
+ // Full-page redirect to the provider. DeepKey returns to redirectTo with
194
+ // ?connection_id=...&provider=x (or ?error=access_denied&error_code=...).
195
+
196
+ const { data, error } = await deepkey.connections.list()
197
+ // data.connections: [{ id, provider, provider_user_id, identity_data, scope, status, created_at, updated_at }]
198
+
199
+ await deepkey.connections.revoke(connectionId) // revokes at the provider and deletes the connection
200
+ ```
201
+
202
+ ```ts
203
+ // Server — secret key only.
204
+ const { data: token, error } = await deepkey.connections.issueAccessToken(connectionId)
205
+ // token: { access_token, token_type: 'bearer', expires_at, scope } — no refresh token, ever.
206
+ // error?.code === 'connection_reauthorization_required' → the user must connect again.
207
+
208
+ const { data } = await deepkey.connections.list({ userId })
209
+ await deepkey.connections.revoke(connectionId)
210
+ ```
211
+
212
+ **How a connection is tied to the user.** `connections.connect()` sends the current DeepKey session as the bearer, so DeepKey binds the new connection to the signed-in `user.id` (the id is signed into the OAuth state and re-checked on the callback; nothing from the browser chooses the user). On your server, correlate with the same id you get from `getUser(jwt)`:
213
+
214
+ ```ts
215
+ const { data: { user } } = await deepkey.auth.getUser(jwt) // your authenticated user
216
+ const { data: { connections } } = await deepkey.connections.list({ userId: user!.id })
217
+ // Only trust a connection_id from your frontend if it is in this list
218
+ // (every item also carries user_id === user.id).
219
+ ```
220
+
221
+ Scopes are a project policy: the adapter's minimum plus the `connectScopes` configured for the provider on the DeepKey console. They are requested only by `connections.connect()`, never during login. Each connection's `scope` reports what the provider actually granted.
222
+
183
223
  ## Server client (validating tokens in your backend)
184
224
 
185
225
  ```ts
@@ -211,7 +251,7 @@ Use `getUser()` when you need revocation-awareness (a signed-out session fails i
211
251
  ```ts
212
252
  // '@deepkey/sdk'
213
253
  const DEEPKEY_API_URL: 'https://deepkey.dev/api'
214
- function createAuthClient(publishableKey: string, options?: AuthClientOptions): { auth: Auth }
254
+ function createAuthClient(publishableKey: string, options?: AuthClientOptions): { auth: Auth; connections: Connections }
215
255
 
216
256
  class Auth {
217
257
  signInWithOtp(credentials: SignInWithOtpCredentials): Promise<AuthResponse<{ user: null; session: null }>>
@@ -224,6 +264,26 @@ class Auth {
224
264
  signOut(): Promise<{ error: AuthError | null }>
225
265
  }
226
266
 
267
+ class Connections {
268
+ connect(credentials: ConnectProviderCredentials): Promise<AuthResponse<{ provider: string; url: string | null }>>
269
+ list(): Promise<AuthResponse<{ connections: ProviderConnection[] }>>
270
+ revoke(connectionId: string): Promise<{ error: AuthError | null }>
271
+ }
272
+
273
+ interface ConnectProviderCredentials { provider: string; options?: { redirectTo?: string; skipBrowserRedirect?: boolean } }
274
+ interface ProviderConnection {
275
+ id: string // stable reference for your own tables
276
+ user_id: string // the DeepKey user that granted it (same id as getUser(jwt).user.id)
277
+ provider: string
278
+ provider_user_id: string // immutable provider subject
279
+ identity_data: Record<string, unknown>
280
+ scope: string | null // what the provider granted
281
+ status: 'active' | 'reauthorization_required'
282
+ created_at: string
283
+ updated_at: string
284
+ }
285
+ interface ProviderAccessToken { access_token: string; token_type: 'bearer'; expires_at: number | null; scope: string | null }
286
+
227
287
  interface AuthClientOptions {
228
288
  persistSession?: boolean
229
289
  autoRefreshToken?: boolean
@@ -261,7 +321,12 @@ interface User {
261
321
  // '@deepkey/sdk/server'
262
322
  const DEEPKEY_API_URL: 'https://deepkey.dev/api'
263
323
  function createServerClient(secretKey: string, options?: ServerClientOptions): {
264
- auth: { getUser(jwt: string): Promise<{ data: { user: User | null }; error: AuthError | null }> }
324
+ auth: { getUser(jwt: string): Promise<AuthResponse<{ user: User | null }>> }
325
+ connections: {
326
+ list(params: { userId: string }): Promise<AuthResponse<{ connections: ProviderConnection[] }>>
327
+ issueAccessToken(connectionId: string): Promise<AuthResponse<ProviderAccessToken | null>>
328
+ revoke(connectionId: string): Promise<{ error: AuthError | null }>
329
+ }
265
330
  }
266
331
  interface ServerClientOptions { fetch?: typeof fetch }
267
332
  ```
@@ -279,6 +344,10 @@ All calls send the API key as the `apikey` header against `https://deepkey.dev/a
279
344
  | token refresh | `POST /token?grant_type=refresh_token` |
280
345
  | `getUser` | `GET /user` (with `Authorization: Bearer`) |
281
346
  | `signOut` | `POST /logout` |
347
+ | `connections.connect` | `POST /connections/authorize` (bearer) → navigate to `data.url`; provider returns to `redirectTo?connection_id=…` |
348
+ | `connections.list` | `GET /connections` (bearer) or `GET /connections?user_id=…` (secret key) |
349
+ | server `connections.issueAccessToken` | `POST /connections/:id/token` (secret key) |
350
+ | `connections.revoke` | `DELETE /connections/:id` |
282
351
 
283
352
  ## Gotchas & troubleshooting
284
353
 
@@ -0,0 +1,61 @@
1
+ // src/types.ts
2
+ var AuthError = class extends Error {
3
+ constructor(message, status, code) {
4
+ super(message);
5
+ this.name = "AuthError";
6
+ this.status = status;
7
+ this.code = code;
8
+ }
9
+ };
10
+
11
+ // src/fetch.ts
12
+ var request = async (options) => {
13
+ const fetchImpl = options.fetchImpl ?? fetch;
14
+ try {
15
+ const headers = { apikey: options.apikey };
16
+ if (options.body !== void 0) headers["Content-Type"] = "application/json";
17
+ if (options.accessToken) headers.Authorization = `Bearer ${options.accessToken}`;
18
+ const response = await fetchImpl(`${options.baseUrl}${options.path}`, {
19
+ method: options.method,
20
+ headers,
21
+ body: options.body !== void 0 ? JSON.stringify(options.body) : void 0
22
+ });
23
+ if (response.status === 204) return { data: {}, error: null };
24
+ let payload;
25
+ try {
26
+ payload = await response.json();
27
+ } catch {
28
+ payload = null;
29
+ }
30
+ if (!response.ok) {
31
+ const errorBody = payload?.error;
32
+ return {
33
+ data: null,
34
+ error: new AuthError(
35
+ errorBody?.message ?? `Request failed with status ${response.status}`,
36
+ response.status,
37
+ errorBody?.code
38
+ )
39
+ };
40
+ }
41
+ return { data: payload, error: null };
42
+ } catch (err) {
43
+ const message = err instanceof Error ? err.message : "Network request failed";
44
+ return { data: null, error: new AuthError(message, 0, "network_error") };
45
+ }
46
+ };
47
+
48
+ // src/constants.ts
49
+ var DEEPKEY_API_URL = "https://deepkey.dev/api";
50
+ var resolveBaseUrl = (url) => {
51
+ const candidate = typeof url === "string" ? url.trim() : "";
52
+ return (candidate || DEEPKEY_API_URL).replace(/\/+$/, "");
53
+ };
54
+
55
+ export {
56
+ AuthError,
57
+ request,
58
+ DEEPKEY_API_URL,
59
+ resolveBaseUrl
60
+ };
61
+ //# sourceMappingURL=chunk-A2CRUXTA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/fetch.ts","../src/constants.ts"],"sourcesContent":["export interface UserIdentity {\n identity_id: string\n id: string\n user_id: string\n provider: string\n identity_data: Record<string, unknown>\n last_sign_in_at: string | null\n created_at: string\n updated_at: string\n}\n\nexport interface User {\n id: string\n aud: string\n role: string\n email: string | null\n email_confirmed_at: string | null\n app_metadata: { provider?: string | null; providers?: string[]; [key: string]: unknown }\n user_metadata: {\n name?: string\n full_name?: string\n avatar_url?: string\n picture?: string\n email?: string\n [key: string]: unknown\n }\n identities?: UserIdentity[]\n created_at: string\n updated_at?: string\n last_sign_in_at?: string | null\n}\n\nexport interface Session {\n access_token: string\n refresh_token: string\n token_type: 'bearer'\n expires_in: number\n expires_at: number\n user: User\n}\n\nexport class AuthError extends Error {\n status?: number\n code?: string\n\n constructor(message: string, status?: number, code?: string) {\n super(message)\n this.name = 'AuthError'\n this.status = status\n this.code = code\n }\n}\n\nexport type AuthChangeEvent = 'INITIAL_SESSION' | 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED'\n\nexport interface Subscription {\n id: string\n unsubscribe: () => void\n}\n\nexport interface StorageAdapter {\n getItem(key: string): string | null\n setItem(key: string, value: string): void\n removeItem(key: string): void\n}\n\nexport interface AuthClientOptions {\n /**\n * @internal Replaces the hosted DeepKey API origin. Used only by DeepKey's own\n * console and test suites; not supported for consumers and stripped from the\n * published type declarations.\n */\n __internalBaseUrl?: string\n storageKey?: string\n autoRefreshToken?: boolean\n detectSessionInUrl?: boolean\n persistSession?: boolean\n storage?: StorageAdapter\n fetch?: typeof fetch\n}\n\nexport interface ServerClientOptions {\n /**\n * @internal Replaces the hosted DeepKey API origin. Used only by DeepKey's own\n * console and test suites; not supported for consumers and stripped from the\n * published type declarations.\n */\n __internalBaseUrl?: string\n fetch?: typeof fetch\n}\n\nexport interface SignInWithOtpCredentials {\n email: string\n options?: {\n emailRedirectTo?: string\n shouldCreateUser?: boolean\n data?: Record<string, unknown>\n }\n}\n\nexport interface VerifyOtpParams {\n email: string\n token: string\n type: 'email' | 'magiclink'\n}\n\nexport interface ConnectProviderCredentials {\n provider: string\n options?: {\n redirectTo?: string\n skipBrowserRedirect?: boolean\n }\n}\n\n// Metadata only: provider tokens never appear in browser responses.\nexport interface ProviderConnection {\n id: string\n // The DeepKey user that granted the connection: the same `user.id` your server gets from getUser(jwt).\n user_id: string\n provider: string\n provider_user_id: string\n identity_data: Record<string, unknown>\n scope: string | null\n status: 'active' | 'reauthorization_required'\n created_at: string\n updated_at: string\n}\n\n// Issued to consumer servers through the secret key; short-lived and refreshed by DeepKey.\nexport interface ProviderAccessToken {\n access_token: string\n token_type: 'bearer'\n expires_at: number | null\n scope: string | null\n}\n\nexport interface SignInWithOAuthCredentials {\n provider: string\n options?: {\n redirectTo?: string\n scopes?: string\n queryParams?: Record<string, string>\n skipBrowserRedirect?: boolean\n }\n}\n\nexport interface AuthResponse<T> {\n data: T\n error: AuthError | null\n}\n","import { AuthError } from './types'\n\nexport interface RequestOptions {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE'\n path: string\n apikey: string\n baseUrl: string\n accessToken?: string\n body?: unknown\n fetchImpl?: typeof fetch\n}\n\nexport interface RequestResult<T> {\n data: T | null\n error: AuthError | null\n}\n\n// All service errors are shaped { error: { code, message } }.\nexport const request = async <T>(options: RequestOptions): Promise<RequestResult<T>> => {\n const fetchImpl = options.fetchImpl ?? fetch\n try {\n const headers: Record<string, string> = { apikey: options.apikey }\n if (options.body !== undefined) headers['Content-Type'] = 'application/json'\n if (options.accessToken) headers.Authorization = `Bearer ${options.accessToken}`\n\n const response = await fetchImpl(`${options.baseUrl}${options.path}`, {\n method: options.method,\n headers,\n body: options.body !== undefined ? JSON.stringify(options.body) : undefined,\n })\n\n if (response.status === 204) return { data: {} as T, error: null }\n\n let payload: unknown\n try {\n payload = await response.json()\n } catch {\n payload = null\n }\n\n if (!response.ok) {\n const errorBody = (payload as { error?: { code?: string; message?: string } } | null)?.error\n return {\n data: null,\n error: new AuthError(\n errorBody?.message ?? `Request failed with status ${response.status}`,\n response.status,\n errorBody?.code,\n ),\n }\n }\n\n return { data: payload as T, error: null }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Network request failed'\n return { data: null, error: new AuthError(message, 0, 'network_error') }\n }\n}\n","// The hosted DeepKey API. Every client talks to this origin; only DeepKey's own\n// console and test suites replace it through the internal override.\nexport const DEEPKEY_API_URL = 'https://deepkey.dev/api'\n\n// Resolves the base URL used for every request. An absent or blank internal\n// override keeps the hosted API; a provided value has any trailing slash removed\n// so path joins stay predictable.\nexport const resolveBaseUrl = (url?: string | null): string => {\n const candidate = typeof url === 'string' ? url.trim() : ''\n return (candidate || DEEPKEY_API_URL).replace(/\\/+$/, '')\n}\n"],"mappings":";AAyCO,IAAM,YAAN,cAAwB,MAAM;AAAA,EAInC,YAAY,SAAiB,QAAiB,MAAe;AAC3D,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AAAA,EACd;AACF;;;ACjCO,IAAM,UAAU,OAAU,YAAuD;AACtF,QAAM,YAAY,QAAQ,aAAa;AACvC,MAAI;AACF,UAAM,UAAkC,EAAE,QAAQ,QAAQ,OAAO;AACjE,QAAI,QAAQ,SAAS,OAAW,SAAQ,cAAc,IAAI;AAC1D,QAAI,QAAQ,YAAa,SAAQ,gBAAgB,UAAU,QAAQ,WAAW;AAE9E,UAAM,WAAW,MAAM,UAAU,GAAG,QAAQ,OAAO,GAAG,QAAQ,IAAI,IAAI;AAAA,MACpE,QAAQ,QAAQ;AAAA,MAChB;AAAA,MACA,MAAM,QAAQ,SAAS,SAAY,KAAK,UAAU,QAAQ,IAAI,IAAI;AAAA,IACpE,CAAC;AAED,QAAI,SAAS,WAAW,IAAK,QAAO,EAAE,MAAM,CAAC,GAAQ,OAAO,KAAK;AAEjE,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,SAAS,KAAK;AAAA,IAChC,QAAQ;AACN,gBAAU;AAAA,IACZ;AAEA,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,YAAa,SAAoE;AACvF,aAAO;AAAA,QACL,MAAM;AAAA,QACN,OAAO,IAAI;AAAA,UACT,WAAW,WAAW,8BAA8B,SAAS,MAAM;AAAA,UACnE,SAAS;AAAA,UACT,WAAW;AAAA,QACb;AAAA,MACF;AAAA,IACF;AAEA,WAAO,EAAE,MAAM,SAAc,OAAO,KAAK;AAAA,EAC3C,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,WAAO,EAAE,MAAM,MAAM,OAAO,IAAI,UAAU,SAAS,GAAG,eAAe,EAAE;AAAA,EACzE;AACF;;;ACvDO,IAAM,kBAAkB;AAKxB,IAAM,iBAAiB,CAAC,QAAgC;AAC7D,QAAM,YAAY,OAAO,QAAQ,WAAW,IAAI,KAAK,IAAI;AACzD,UAAQ,aAAa,iBAAiB,QAAQ,QAAQ,EAAE;AAC1D;","names":[]}
@@ -79,6 +79,30 @@ interface VerifyOtpParams {
79
79
  token: string;
80
80
  type: 'email' | 'magiclink';
81
81
  }
82
+ interface ConnectProviderCredentials {
83
+ provider: string;
84
+ options?: {
85
+ redirectTo?: string;
86
+ skipBrowserRedirect?: boolean;
87
+ };
88
+ }
89
+ interface ProviderConnection {
90
+ id: string;
91
+ user_id: string;
92
+ provider: string;
93
+ provider_user_id: string;
94
+ identity_data: Record<string, unknown>;
95
+ scope: string | null;
96
+ status: 'active' | 'reauthorization_required';
97
+ created_at: string;
98
+ updated_at: string;
99
+ }
100
+ interface ProviderAccessToken {
101
+ access_token: string;
102
+ token_type: 'bearer';
103
+ expires_at: number | null;
104
+ scope: string | null;
105
+ }
82
106
  interface SignInWithOAuthCredentials {
83
107
  provider: string;
84
108
  options?: {
@@ -95,4 +119,4 @@ interface AuthResponse<T> {
95
119
 
96
120
  declare const DEEPKEY_API_URL = "https://deepkey.dev/api";
97
121
 
98
- export { type AuthClientOptions as A, DEEPKEY_API_URL as D, type SignInWithOtpCredentials as S, type User as U, type VerifyOtpParams as V, type AuthResponse as a, type Session as b, type SignInWithOAuthCredentials as c, type AuthChangeEvent as d, type Subscription as e, AuthError as f, type ServerClientOptions as g, type StorageAdapter as h, type UserIdentity as i };
122
+ export { type AuthResponse as A, type ConnectProviderCredentials as C, DEEPKEY_API_URL as D, type ProviderConnection as P, type SignInWithOtpCredentials as S, type User as U, type VerifyOtpParams as V, AuthError as a, type AuthClientOptions as b, type Session as c, type SignInWithOAuthCredentials as d, type AuthChangeEvent as e, type Subscription as f, type ProviderAccessToken as g, type ServerClientOptions as h, type StorageAdapter as i, type UserIdentity as j };
@@ -79,6 +79,30 @@ interface VerifyOtpParams {
79
79
  token: string;
80
80
  type: 'email' | 'magiclink';
81
81
  }
82
+ interface ConnectProviderCredentials {
83
+ provider: string;
84
+ options?: {
85
+ redirectTo?: string;
86
+ skipBrowserRedirect?: boolean;
87
+ };
88
+ }
89
+ interface ProviderConnection {
90
+ id: string;
91
+ user_id: string;
92
+ provider: string;
93
+ provider_user_id: string;
94
+ identity_data: Record<string, unknown>;
95
+ scope: string | null;
96
+ status: 'active' | 'reauthorization_required';
97
+ created_at: string;
98
+ updated_at: string;
99
+ }
100
+ interface ProviderAccessToken {
101
+ access_token: string;
102
+ token_type: 'bearer';
103
+ expires_at: number | null;
104
+ scope: string | null;
105
+ }
82
106
  interface SignInWithOAuthCredentials {
83
107
  provider: string;
84
108
  options?: {
@@ -95,4 +119,4 @@ interface AuthResponse<T> {
95
119
 
96
120
  declare const DEEPKEY_API_URL = "https://deepkey.dev/api";
97
121
 
98
- export { type AuthClientOptions as A, DEEPKEY_API_URL as D, type SignInWithOtpCredentials as S, type User as U, type VerifyOtpParams as V, type AuthResponse as a, type Session as b, type SignInWithOAuthCredentials as c, type AuthChangeEvent as d, type Subscription as e, AuthError as f, type ServerClientOptions as g, type StorageAdapter as h, type UserIdentity as i };
122
+ export { type AuthResponse as A, type ConnectProviderCredentials as C, DEEPKEY_API_URL as D, type ProviderConnection as P, type SignInWithOtpCredentials as S, type User as U, type VerifyOtpParams as V, AuthError as a, type AuthClientOptions as b, type Session as c, type SignInWithOAuthCredentials as d, type AuthChangeEvent as e, type Subscription as f, type ProviderAccessToken as g, type ServerClientOptions as h, type StorageAdapter as i, type UserIdentity as j };
package/dist/index.cjs CHANGED
@@ -22,18 +22,12 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  Auth: () => Auth,
24
24
  AuthError: () => AuthError,
25
+ Connections: () => Connections,
25
26
  DEEPKEY_API_URL: () => DEEPKEY_API_URL,
26
27
  createAuthClient: () => createAuthClient
27
28
  });
28
29
  module.exports = __toCommonJS(index_exports);
29
30
 
30
- // src/constants.ts
31
- var DEEPKEY_API_URL = "https://deepkey.dev/api";
32
- var resolveBaseUrl = (url) => {
33
- const candidate = typeof url === "string" ? url.trim() : "";
34
- return (candidate || DEEPKEY_API_URL).replace(/\/+$/, "");
35
- };
36
-
37
31
  // src/types.ts
38
32
  var AuthError = class extends Error {
39
33
  constructor(message, status, code) {
@@ -81,6 +75,50 @@ var request = async (options) => {
81
75
  }
82
76
  };
83
77
 
78
+ // src/connections.ts
79
+ var Connections = class {
80
+ constructor(auth, options) {
81
+ this.auth = auth;
82
+ this.options = options;
83
+ }
84
+ async connect(credentials) {
85
+ const { data, error } = await this.request(
86
+ "POST",
87
+ "/auth/v1/connections/authorize",
88
+ { provider: credentials.provider, redirect_to: credentials.options?.redirectTo }
89
+ );
90
+ if (error || !data) return { data: { provider: credentials.provider, url: null }, error };
91
+ if (!credentials.options?.skipBrowserRedirect && typeof window !== "undefined") {
92
+ window.location.assign(data.url);
93
+ }
94
+ return { data: { provider: credentials.provider, url: data.url }, error: null };
95
+ }
96
+ async list() {
97
+ const { data, error } = await this.request("GET", "/auth/v1/connections");
98
+ return { data: { connections: data?.connections ?? [] }, error };
99
+ }
100
+ async revoke(connectionId) {
101
+ const { error } = await this.request("DELETE", `/auth/v1/connections/${encodeURIComponent(connectionId)}`);
102
+ return { error };
103
+ }
104
+ async request(method, path, body) {
105
+ const {
106
+ data: { session }
107
+ } = await this.auth.getSession();
108
+ if (!session) {
109
+ return { data: null, error: new AuthError("Auth session missing!", 400, "session_missing") };
110
+ }
111
+ return request({ method, path, body, accessToken: session.access_token, ...this.options });
112
+ }
113
+ };
114
+
115
+ // src/constants.ts
116
+ var DEEPKEY_API_URL = "https://deepkey.dev/api";
117
+ var resolveBaseUrl = (url) => {
118
+ const candidate = typeof url === "string" ? url.trim() : "";
119
+ return (candidate || DEEPKEY_API_URL).replace(/\/+$/, "");
120
+ };
121
+
84
122
  // src/storage.ts
85
123
  var MemoryStorage = class {
86
124
  constructor() {
@@ -425,6 +463,12 @@ var Auth = class {
425
463
  }
426
464
  };
427
465
  var createAuthClient = (publishableKey, options) => {
428
- return { auth: new Auth(publishableKey, options) };
466
+ const auth = new Auth(publishableKey, options);
467
+ const connections = new Connections(auth, {
468
+ apikey: publishableKey ?? "",
469
+ baseUrl: resolveBaseUrl(options?.__internalBaseUrl),
470
+ fetchImpl: options?.fetch
471
+ });
472
+ return { auth, connections };
429
473
  };
430
474
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/types.ts","../src/fetch.ts","../src/storage.ts","../src/url.ts","../src/client.ts"],"sourcesContent":["export { createAuthClient, Auth, type AuthClient } from './client'\nexport { DEEPKEY_API_URL } from './constants'\nexport {\n AuthError,\n type AuthChangeEvent,\n type AuthClientOptions,\n type AuthResponse,\n type ServerClientOptions,\n type Session,\n type SignInWithOAuthCredentials,\n type SignInWithOtpCredentials,\n type StorageAdapter,\n type Subscription,\n type User,\n type UserIdentity,\n type VerifyOtpParams,\n} from './types'\n","// The hosted DeepKey API. Every client talks to this origin; only DeepKey's own\n// console and test suites replace it through the internal override.\nexport const DEEPKEY_API_URL = 'https://deepkey.dev/api'\n\n// Resolves the base URL used for every request. An absent or blank internal\n// override keeps the hosted API; a provided value has any trailing slash removed\n// so path joins stay predictable.\nexport const resolveBaseUrl = (url?: string | null): string => {\n const candidate = typeof url === 'string' ? url.trim() : ''\n return (candidate || DEEPKEY_API_URL).replace(/\\/+$/, '')\n}\n","export interface UserIdentity {\n identity_id: string\n id: string\n user_id: string\n provider: string\n identity_data: Record<string, unknown>\n last_sign_in_at: string | null\n created_at: string\n updated_at: string\n}\n\nexport interface User {\n id: string\n aud: string\n role: string\n email: string | null\n email_confirmed_at: string | null\n app_metadata: { provider?: string | null; providers?: string[]; [key: string]: unknown }\n user_metadata: {\n name?: string\n full_name?: string\n avatar_url?: string\n picture?: string\n email?: string\n [key: string]: unknown\n }\n identities?: UserIdentity[]\n created_at: string\n updated_at?: string\n last_sign_in_at?: string | null\n}\n\nexport interface Session {\n access_token: string\n refresh_token: string\n token_type: 'bearer'\n expires_in: number\n expires_at: number\n user: User\n}\n\nexport class AuthError extends Error {\n status?: number\n code?: string\n\n constructor(message: string, status?: number, code?: string) {\n super(message)\n this.name = 'AuthError'\n this.status = status\n this.code = code\n }\n}\n\nexport type AuthChangeEvent = 'INITIAL_SESSION' | 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED'\n\nexport interface Subscription {\n id: string\n unsubscribe: () => void\n}\n\nexport interface StorageAdapter {\n getItem(key: string): string | null\n setItem(key: string, value: string): void\n removeItem(key: string): void\n}\n\nexport interface AuthClientOptions {\n /**\n * @internal Replaces the hosted DeepKey API origin. Used only by DeepKey's own\n * console and test suites; not supported for consumers and stripped from the\n * published type declarations.\n */\n __internalBaseUrl?: string\n storageKey?: string\n autoRefreshToken?: boolean\n detectSessionInUrl?: boolean\n persistSession?: boolean\n storage?: StorageAdapter\n fetch?: typeof fetch\n}\n\nexport interface ServerClientOptions {\n /**\n * @internal Replaces the hosted DeepKey API origin. Used only by DeepKey's own\n * console and test suites; not supported for consumers and stripped from the\n * published type declarations.\n */\n __internalBaseUrl?: string\n fetch?: typeof fetch\n}\n\nexport interface SignInWithOtpCredentials {\n email: string\n options?: {\n emailRedirectTo?: string\n shouldCreateUser?: boolean\n data?: Record<string, unknown>\n }\n}\n\nexport interface VerifyOtpParams {\n email: string\n token: string\n type: 'email' | 'magiclink'\n}\n\nexport interface SignInWithOAuthCredentials {\n provider: string\n options?: {\n redirectTo?: string\n scopes?: string\n queryParams?: Record<string, string>\n skipBrowserRedirect?: boolean\n }\n}\n\nexport interface AuthResponse<T> {\n data: T\n error: AuthError | null\n}\n","import { AuthError } from './types'\n\nexport interface RequestOptions {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE'\n path: string\n apikey: string\n baseUrl: string\n accessToken?: string\n body?: unknown\n fetchImpl?: typeof fetch\n}\n\nexport interface RequestResult<T> {\n data: T | null\n error: AuthError | null\n}\n\n// All service errors are shaped { error: { code, message } }.\nexport const request = async <T>(options: RequestOptions): Promise<RequestResult<T>> => {\n const fetchImpl = options.fetchImpl ?? fetch\n try {\n const headers: Record<string, string> = { apikey: options.apikey }\n if (options.body !== undefined) headers['Content-Type'] = 'application/json'\n if (options.accessToken) headers.Authorization = `Bearer ${options.accessToken}`\n\n const response = await fetchImpl(`${options.baseUrl}${options.path}`, {\n method: options.method,\n headers,\n body: options.body !== undefined ? JSON.stringify(options.body) : undefined,\n })\n\n if (response.status === 204) return { data: {} as T, error: null }\n\n let payload: unknown\n try {\n payload = await response.json()\n } catch {\n payload = null\n }\n\n if (!response.ok) {\n const errorBody = (payload as { error?: { code?: string; message?: string } } | null)?.error\n return {\n data: null,\n error: new AuthError(\n errorBody?.message ?? `Request failed with status ${response.status}`,\n response.status,\n errorBody?.code,\n ),\n }\n }\n\n return { data: payload as T, error: null }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Network request failed'\n return { data: null, error: new AuthError(message, 0, 'network_error') }\n }\n}\n","import type { StorageAdapter } from './types'\n\nclass MemoryStorage implements StorageAdapter {\n private store = new Map<string, string>()\n getItem(key: string) {\n return this.store.get(key) ?? null\n }\n setItem(key: string, value: string) {\n this.store.set(key, value)\n }\n removeItem(key: string) {\n this.store.delete(key)\n }\n}\n\n// localStorage when available, in-memory fallback (SSR, tests, restricted contexts).\nexport const defaultStorage = (): StorageAdapter => {\n try {\n if (typeof window !== 'undefined' && window.localStorage) {\n const probe = '__bt_auth_probe__'\n window.localStorage.setItem(probe, '1')\n window.localStorage.removeItem(probe)\n return window.localStorage\n }\n } catch {\n // fall through to memory storage\n }\n return new MemoryStorage()\n}\n\n// Publishable keys look like `bt_pub_<project-slug>_<random>`; the slug namespaces the\n// persisted session per project (mirrors supabase's `sb-<ref>-auth-token`).\nexport const deriveStorageKey = (publishableKey: string | undefined): string => {\n const match = publishableKey?.match(/^bt_pub_([a-z0-9-]+)_[A-Za-z0-9_-]+$/)\n return match ? `bt-${match[1]}-auth-token` : 'bt-auth-token'\n}\n","export interface FragmentTokens {\n access_token: string\n refresh_token: string\n expires_in: number\n expires_at: number\n token_type: 'bearer'\n type?: string\n}\n\nexport interface FragmentError {\n error: string\n error_code?: string\n error_description?: string\n}\n\nexport type ParsedFragment = { tokens: FragmentTokens } | { authError: FragmentError } | null\n\n// Parses the implicit-flow return fragment (`#access_token=...` or `#error=...`).\nexport const parseFragment = (hash: string): ParsedFragment => {\n if (!hash || hash.length < 2) return null\n const params = new URLSearchParams(hash.startsWith('#') ? hash.slice(1) : hash)\n\n const error = params.get('error')\n if (error) {\n return {\n authError: {\n error,\n error_code: params.get('error_code') ?? undefined,\n error_description: params.get('error_description') ?? undefined,\n },\n }\n }\n\n const accessToken = params.get('access_token')\n const refreshToken = params.get('refresh_token')\n if (!accessToken || !refreshToken) return null\n\n const expiresIn = Number(params.get('expires_in') ?? 3600)\n const expiresAt = Number(params.get('expires_at') ?? Math.floor(Date.now() / 1000) + expiresIn)\n\n return {\n tokens: {\n access_token: accessToken,\n refresh_token: refreshToken,\n expires_in: expiresIn,\n expires_at: expiresAt,\n token_type: 'bearer',\n type: params.get('type') ?? undefined,\n },\n }\n}\n\n// Removes the auth fragment from the address bar (before any await, so tokens never\n// linger in history).\nexport const cleanFragmentFromUrl = () => {\n if (typeof window === 'undefined' || typeof history === 'undefined') return\n history.replaceState(null, '', window.location.pathname + window.location.search)\n}\n","import { resolveBaseUrl } from './constants'\nimport { request } from './fetch'\nimport { defaultStorage, deriveStorageKey } from './storage'\nimport {\n AuthError,\n type AuthChangeEvent,\n type AuthClientOptions,\n type AuthResponse,\n type Session,\n type SignInWithOAuthCredentials,\n type SignInWithOtpCredentials,\n type StorageAdapter,\n type Subscription,\n type User,\n type VerifyOtpParams,\n} from './types'\nimport { cleanFragmentFromUrl, parseFragment } from './url'\n\nconst REFRESH_TICK_MS = 30_000\n// Refresh when the access token is within this margin of expiry.\nconst EXPIRY_MARGIN_SECONDS = 90\n\ntype Listener = (event: AuthChangeEvent, session: Session | null) => void\n\nexport class Auth {\n private baseUrl: string\n private apikey: string\n private storage: StorageAdapter\n private storageKey: string\n private persistSession: boolean\n private autoRefreshToken: boolean\n private detectSessionInUrl: boolean\n private fetchImpl?: typeof fetch\n\n private session: Session | null = null\n private listeners = new Map<string, Listener>()\n private listenerSeq = 0\n private initializePromise: Promise<void> | null = null\n private refreshPromise: Promise<AuthResponse<{ session: Session | null; user: User | null }>> | null = null\n private refreshTimer: ReturnType<typeof setInterval> | null = null\n\n constructor(publishableKey: string, options: AuthClientOptions = {}) {\n // Lazy by design: an empty key must not throw at construction time (CI builds\n // with empty envs import this module transitively). Failures surface on first call.\n // The hosted DeepKey API is the only supported origin. The internal override\n // exists for DeepKey's console and tests and is not part of the public contract.\n this.baseUrl = resolveBaseUrl(options.__internalBaseUrl)\n this.apikey = publishableKey ?? ''\n this.persistSession = options.persistSession ?? true\n this.autoRefreshToken = options.autoRefreshToken ?? true\n this.detectSessionInUrl = options.detectSessionInUrl ?? true\n this.storage = options.storage ?? defaultStorage()\n this.storageKey = options.storageKey ?? deriveStorageKey(publishableKey)\n this.fetchImpl = options.fetch\n\n this.setupCrossTabSync()\n }\n\n // ---- public API (supabase-js compatible) ----\n\n async signInWithOtp(credentials: SignInWithOtpCredentials): Promise<AuthResponse<{ user: null; session: null }>> {\n const { error } = await this.request<Record<string, never>>('POST', '/auth/v1/otp', {\n email: credentials.email,\n create_user: credentials.options?.shouldCreateUser,\n redirect_to: credentials.options?.emailRedirectTo,\n })\n return { data: { user: null, session: null }, error }\n }\n\n async verifyOtp(params: VerifyOtpParams): Promise<AuthResponse<{ user: User | null; session: Session | null }>> {\n const { data, error } = await this.request<Session>('POST', '/auth/v1/verify', {\n type: 'email',\n email: params.email,\n token: params.token,\n })\n if (error || !data) return { data: { user: null, session: null }, error }\n\n await this.saveSession(data)\n this.emit('SIGNED_IN', data)\n return { data: { user: data.user, session: data }, error: null }\n }\n\n async signInWithOAuth(\n credentials: SignInWithOAuthCredentials,\n ): Promise<AuthResponse<{ provider: string; url: string }>> {\n const url = new URL(`${this.baseUrl}/auth/v1/authorize`)\n url.searchParams.set('provider', credentials.provider)\n url.searchParams.set('apikey', this.apikey)\n if (credentials.options?.redirectTo) url.searchParams.set('redirect_to', credentials.options.redirectTo)\n if (credentials.options?.scopes) url.searchParams.set('scopes', credentials.options.scopes)\n for (const [key, value] of Object.entries(credentials.options?.queryParams ?? {})) {\n url.searchParams.set(key, value)\n }\n\n if (!credentials.options?.skipBrowserRedirect && typeof window !== 'undefined') {\n window.location.assign(url.toString())\n }\n return { data: { provider: credentials.provider, url: url.toString() }, error: null }\n }\n\n onAuthStateChange(callback: Listener): { data: { subscription: Subscription } } {\n const id = `listener-${++this.listenerSeq}`\n this.listeners.set(id, callback)\n\n // Every subscriber receives INITIAL_SESSION asynchronously once initialization\n // settles — the supabase-js contract that AuthProviders rely on to resolve loading.\n this.initialize().then(() => {\n if (this.listeners.has(id)) callback('INITIAL_SESSION', this.session)\n })\n\n return {\n data: {\n subscription: {\n id,\n unsubscribe: () => {\n this.listeners.delete(id)\n },\n },\n },\n }\n }\n\n async signOut(): Promise<{ error: AuthError | null }> {\n await this.initialize()\n const session = this.session\n if (session) {\n // Best-effort server-side revocation; local sign-out always succeeds.\n await this.request('POST', '/auth/v1/logout', {}, session.access_token)\n }\n this.clearSession()\n this.emit('SIGNED_OUT', null)\n return { error: null }\n }\n\n async getSession(): Promise<AuthResponse<{ session: Session | null }>> {\n await this.initialize()\n\n if (this.session && this.isExpired(this.session) && this.autoRefreshToken) {\n const { error } = await this.refreshWithLock()\n if (error && error.code !== 'network_error') {\n return { data: { session: null }, error: null }\n }\n }\n\n return { data: { session: this.session }, error: null }\n }\n\n async getUser(jwt?: string): Promise<AuthResponse<{ user: User | null }>> {\n let token = jwt\n if (!token) {\n const {\n data: { session },\n } = await this.getSession()\n token = session?.access_token\n }\n if (!token) {\n return { data: { user: null }, error: new AuthError('Auth session missing!', 400, 'session_missing') }\n }\n\n const { data, error } = await this.request<User>('GET', '/auth/v1/user', undefined, token)\n return { data: { user: data }, error }\n }\n\n async refreshSession(currentSession?: {\n refresh_token: string\n }): Promise<AuthResponse<{ session: Session | null; user: User | null }>> {\n await this.initialize()\n const refreshToken = currentSession?.refresh_token ?? this.session?.refresh_token\n if (!refreshToken) {\n return {\n data: { session: null, user: null },\n error: new AuthError('Auth session missing!', 400, 'session_missing'),\n }\n }\n return this.refreshWithLock(refreshToken)\n }\n\n // ---- internals ----\n\n private async request<T>(method: 'GET' | 'POST', path: string, body?: unknown, accessToken?: string) {\n return request<T>({\n method,\n path,\n body,\n accessToken,\n apikey: this.apikey,\n baseUrl: this.baseUrl,\n fetchImpl: this.fetchImpl,\n })\n }\n\n private initialize(): Promise<void> {\n this.initializePromise ??= this.doInitialize()\n return this.initializePromise\n }\n\n private async doInitialize(): Promise<void> {\n if (this.detectSessionInUrl && typeof window !== 'undefined') {\n const parsed = parseFragment(window.location.hash)\n if (parsed) {\n // Strip tokens from the address bar synchronously, before any await.\n cleanFragmentFromUrl()\n\n if ('authError' in parsed) {\n console.warn(\n `[deepkey] Auth redirect returned an error: ${parsed.authError.error_code ?? parsed.authError.error}`,\n parsed.authError.error_description ?? '',\n )\n } else {\n const { data: user } = await this.request<User>('GET', '/auth/v1/user', undefined, parsed.tokens.access_token)\n if (user) {\n const session: Session = { ...parsed.tokens, token_type: 'bearer', user }\n await this.saveSession(session)\n this.emit('SIGNED_IN', session)\n return\n }\n }\n }\n }\n\n const stored = this.loadStoredSession()\n if (!stored) return\n\n if (this.isExpired(stored)) {\n if (!this.autoRefreshToken) return\n this.session = stored\n const { error } = await this.refreshWithLock()\n if (error && error.code !== 'network_error') this.clearSession()\n return\n }\n\n this.session = stored\n this.startRefreshTimer()\n }\n\n private isExpired(session: Session): boolean {\n return session.expires_at <= Math.floor(Date.now() / 1000) + EXPIRY_MARGIN_SECONDS\n }\n\n private async refreshWithLock(\n refreshToken?: string,\n ): Promise<AuthResponse<{ session: Session | null; user: User | null }>> {\n this.refreshPromise ??= this.doRefresh(refreshToken).finally(() => {\n this.refreshPromise = null\n })\n return this.refreshPromise\n }\n\n private async doRefresh(\n refreshToken?: string,\n ): Promise<AuthResponse<{ session: Session | null; user: User | null }>> {\n const token = refreshToken ?? this.session?.refresh_token\n if (!token) {\n return {\n data: { session: null, user: null },\n error: new AuthError('Auth session missing!', 400, 'session_missing'),\n }\n }\n\n const { data, error } = await this.request<Session>('POST', '/auth/v1/token?grant_type=refresh_token', {\n refresh_token: token,\n })\n\n if (error) {\n // Network failures keep the session (retry next tick); auth failures clear it.\n if (error.code !== 'network_error') {\n this.clearSession()\n this.emit('SIGNED_OUT', null)\n }\n return { data: { session: null, user: null }, error }\n }\n\n if (data) {\n await this.saveSession(data)\n this.emit('TOKEN_REFRESHED', data)\n return { data: { session: data, user: data.user }, error: null }\n }\n return { data: { session: null, user: null }, error: new AuthError('Empty refresh response') }\n }\n\n private async saveSession(session: Session) {\n this.session = session\n if (this.persistSession) {\n try {\n this.storage.setItem(this.storageKey, JSON.stringify(session))\n } catch {\n // Persistence is best-effort (private mode, quota).\n }\n }\n this.startRefreshTimer()\n }\n\n private clearSession() {\n this.session = null\n try {\n this.storage.removeItem(this.storageKey)\n } catch {\n // ignore\n }\n this.stopRefreshTimer()\n }\n\n private loadStoredSession(): Session | null {\n if (!this.persistSession) return null\n try {\n const raw = this.storage.getItem(this.storageKey)\n if (!raw) return null\n const parsed = JSON.parse(raw) as Session\n if (!parsed.access_token || !parsed.refresh_token) return null\n return parsed\n } catch {\n return null\n }\n }\n\n private startRefreshTimer() {\n if (!this.autoRefreshToken || this.refreshTimer || typeof setInterval === 'undefined') return\n this.refreshTimer = setInterval(() => {\n if (this.session && this.isExpired(this.session)) void this.refreshWithLock()\n }, REFRESH_TICK_MS)\n // Do not keep node processes alive because of the timer (no-op in browsers).\n const timer = this.refreshTimer as unknown as { unref?: () => void }\n if (typeof timer === 'object' && typeof timer.unref === 'function') timer.unref()\n }\n\n private stopRefreshTimer() {\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer)\n this.refreshTimer = null\n }\n }\n\n private setupCrossTabSync() {\n if (typeof window === 'undefined' || !this.persistSession) return\n window.addEventListener('storage', event => {\n if (event.key !== this.storageKey) return\n if (!event.newValue) {\n if (this.session) {\n this.session = null\n this.stopRefreshTimer()\n this.emit('SIGNED_OUT', null)\n }\n return\n }\n try {\n const next = JSON.parse(event.newValue) as Session\n const changed = next.access_token !== this.session?.access_token\n this.session = next\n this.startRefreshTimer()\n if (changed) this.emit('TOKEN_REFRESHED', next)\n } catch {\n // ignore malformed writes\n }\n })\n }\n\n private emit(event: AuthChangeEvent, session: Session | null) {\n for (const listener of this.listeners.values()) {\n try {\n listener(event, session)\n } catch (err) {\n console.error('[deepkey] onAuthStateChange listener threw', err)\n }\n }\n }\n}\n\nexport interface AuthClient {\n auth: Auth\n}\n\nexport const createAuthClient = (publishableKey: string, options?: AuthClientOptions): AuthClient => {\n return { auth: new Auth(publishableKey, options) }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/fetch.ts","../src/connections.ts","../src/constants.ts","../src/storage.ts","../src/url.ts","../src/client.ts"],"sourcesContent":["export { createAuthClient, Auth, type AuthClient } from './client'\nexport { Connections } from './connections'\nexport { DEEPKEY_API_URL } from './constants'\nexport {\n AuthError,\n type AuthChangeEvent,\n type AuthClientOptions,\n type AuthResponse,\n type ConnectProviderCredentials,\n type ServerClientOptions,\n type ProviderAccessToken,\n type ProviderConnection,\n type Session,\n type SignInWithOAuthCredentials,\n type SignInWithOtpCredentials,\n type StorageAdapter,\n type Subscription,\n type User,\n type UserIdentity,\n type VerifyOtpParams,\n} from './types'\n","export interface UserIdentity {\n identity_id: string\n id: string\n user_id: string\n provider: string\n identity_data: Record<string, unknown>\n last_sign_in_at: string | null\n created_at: string\n updated_at: string\n}\n\nexport interface User {\n id: string\n aud: string\n role: string\n email: string | null\n email_confirmed_at: string | null\n app_metadata: { provider?: string | null; providers?: string[]; [key: string]: unknown }\n user_metadata: {\n name?: string\n full_name?: string\n avatar_url?: string\n picture?: string\n email?: string\n [key: string]: unknown\n }\n identities?: UserIdentity[]\n created_at: string\n updated_at?: string\n last_sign_in_at?: string | null\n}\n\nexport interface Session {\n access_token: string\n refresh_token: string\n token_type: 'bearer'\n expires_in: number\n expires_at: number\n user: User\n}\n\nexport class AuthError extends Error {\n status?: number\n code?: string\n\n constructor(message: string, status?: number, code?: string) {\n super(message)\n this.name = 'AuthError'\n this.status = status\n this.code = code\n }\n}\n\nexport type AuthChangeEvent = 'INITIAL_SESSION' | 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED'\n\nexport interface Subscription {\n id: string\n unsubscribe: () => void\n}\n\nexport interface StorageAdapter {\n getItem(key: string): string | null\n setItem(key: string, value: string): void\n removeItem(key: string): void\n}\n\nexport interface AuthClientOptions {\n /**\n * @internal Replaces the hosted DeepKey API origin. Used only by DeepKey's own\n * console and test suites; not supported for consumers and stripped from the\n * published type declarations.\n */\n __internalBaseUrl?: string\n storageKey?: string\n autoRefreshToken?: boolean\n detectSessionInUrl?: boolean\n persistSession?: boolean\n storage?: StorageAdapter\n fetch?: typeof fetch\n}\n\nexport interface ServerClientOptions {\n /**\n * @internal Replaces the hosted DeepKey API origin. Used only by DeepKey's own\n * console and test suites; not supported for consumers and stripped from the\n * published type declarations.\n */\n __internalBaseUrl?: string\n fetch?: typeof fetch\n}\n\nexport interface SignInWithOtpCredentials {\n email: string\n options?: {\n emailRedirectTo?: string\n shouldCreateUser?: boolean\n data?: Record<string, unknown>\n }\n}\n\nexport interface VerifyOtpParams {\n email: string\n token: string\n type: 'email' | 'magiclink'\n}\n\nexport interface ConnectProviderCredentials {\n provider: string\n options?: {\n redirectTo?: string\n skipBrowserRedirect?: boolean\n }\n}\n\n// Metadata only: provider tokens never appear in browser responses.\nexport interface ProviderConnection {\n id: string\n // The DeepKey user that granted the connection: the same `user.id` your server gets from getUser(jwt).\n user_id: string\n provider: string\n provider_user_id: string\n identity_data: Record<string, unknown>\n scope: string | null\n status: 'active' | 'reauthorization_required'\n created_at: string\n updated_at: string\n}\n\n// Issued to consumer servers through the secret key; short-lived and refreshed by DeepKey.\nexport interface ProviderAccessToken {\n access_token: string\n token_type: 'bearer'\n expires_at: number | null\n scope: string | null\n}\n\nexport interface SignInWithOAuthCredentials {\n provider: string\n options?: {\n redirectTo?: string\n scopes?: string\n queryParams?: Record<string, string>\n skipBrowserRedirect?: boolean\n }\n}\n\nexport interface AuthResponse<T> {\n data: T\n error: AuthError | null\n}\n","import { AuthError } from './types'\n\nexport interface RequestOptions {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE'\n path: string\n apikey: string\n baseUrl: string\n accessToken?: string\n body?: unknown\n fetchImpl?: typeof fetch\n}\n\nexport interface RequestResult<T> {\n data: T | null\n error: AuthError | null\n}\n\n// All service errors are shaped { error: { code, message } }.\nexport const request = async <T>(options: RequestOptions): Promise<RequestResult<T>> => {\n const fetchImpl = options.fetchImpl ?? fetch\n try {\n const headers: Record<string, string> = { apikey: options.apikey }\n if (options.body !== undefined) headers['Content-Type'] = 'application/json'\n if (options.accessToken) headers.Authorization = `Bearer ${options.accessToken}`\n\n const response = await fetchImpl(`${options.baseUrl}${options.path}`, {\n method: options.method,\n headers,\n body: options.body !== undefined ? JSON.stringify(options.body) : undefined,\n })\n\n if (response.status === 204) return { data: {} as T, error: null }\n\n let payload: unknown\n try {\n payload = await response.json()\n } catch {\n payload = null\n }\n\n if (!response.ok) {\n const errorBody = (payload as { error?: { code?: string; message?: string } } | null)?.error\n return {\n data: null,\n error: new AuthError(\n errorBody?.message ?? `Request failed with status ${response.status}`,\n response.status,\n errorBody?.code,\n ),\n }\n }\n\n return { data: payload as T, error: null }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Network request failed'\n return { data: null, error: new AuthError(message, 0, 'network_error') }\n }\n}\n","import type { Auth } from './client'\nimport { request } from './fetch'\nimport { AuthError, type AuthResponse, type ConnectProviderCredentials, type ProviderConnection } from './types'\n\nexport interface ConnectionsOptions {\n apikey: string\n baseUrl: string\n fetchImpl?: typeof fetch\n}\n\n// Durable provider access for the signed-in user, kept apart from login identities:\n// a user who signed in with Google can connect several X accounts. Provider refresh\n// tokens stay on DeepKey; browsers only ever see connection metadata.\nexport class Connections {\n constructor(\n private auth: Auth,\n private options: ConnectionsOptions,\n ) {}\n\n async connect(\n credentials: ConnectProviderCredentials,\n ): Promise<AuthResponse<{ provider: string; url: string | null }>> {\n const { data, error } = await this.request<{ provider: string; url: string }>(\n 'POST',\n '/auth/v1/connections/authorize',\n { provider: credentials.provider, redirect_to: credentials.options?.redirectTo },\n )\n if (error || !data) return { data: { provider: credentials.provider, url: null }, error }\n\n if (!credentials.options?.skipBrowserRedirect && typeof window !== 'undefined') {\n window.location.assign(data.url)\n }\n return { data: { provider: credentials.provider, url: data.url }, error: null }\n }\n\n async list(): Promise<AuthResponse<{ connections: ProviderConnection[] }>> {\n const { data, error } = await this.request<{ connections: ProviderConnection[] }>('GET', '/auth/v1/connections')\n return { data: { connections: data?.connections ?? [] }, error }\n }\n\n async revoke(connectionId: string): Promise<{ error: AuthError | null }> {\n const { error } = await this.request('DELETE', `/auth/v1/connections/${encodeURIComponent(connectionId)}`)\n return { error }\n }\n\n private async request<T>(method: 'GET' | 'POST' | 'DELETE', path: string, body?: unknown) {\n const {\n data: { session },\n } = await this.auth.getSession()\n if (!session) {\n return { data: null, error: new AuthError('Auth session missing!', 400, 'session_missing') }\n }\n return request<T>({ method, path, body, accessToken: session.access_token, ...this.options })\n }\n}\n","// The hosted DeepKey API. Every client talks to this origin; only DeepKey's own\n// console and test suites replace it through the internal override.\nexport const DEEPKEY_API_URL = 'https://deepkey.dev/api'\n\n// Resolves the base URL used for every request. An absent or blank internal\n// override keeps the hosted API; a provided value has any trailing slash removed\n// so path joins stay predictable.\nexport const resolveBaseUrl = (url?: string | null): string => {\n const candidate = typeof url === 'string' ? url.trim() : ''\n return (candidate || DEEPKEY_API_URL).replace(/\\/+$/, '')\n}\n","import type { StorageAdapter } from './types'\n\nclass MemoryStorage implements StorageAdapter {\n private store = new Map<string, string>()\n getItem(key: string) {\n return this.store.get(key) ?? null\n }\n setItem(key: string, value: string) {\n this.store.set(key, value)\n }\n removeItem(key: string) {\n this.store.delete(key)\n }\n}\n\n// localStorage when available, in-memory fallback (SSR, tests, restricted contexts).\nexport const defaultStorage = (): StorageAdapter => {\n try {\n if (typeof window !== 'undefined' && window.localStorage) {\n const probe = '__bt_auth_probe__'\n window.localStorage.setItem(probe, '1')\n window.localStorage.removeItem(probe)\n return window.localStorage\n }\n } catch {\n // fall through to memory storage\n }\n return new MemoryStorage()\n}\n\n// Publishable keys look like `bt_pub_<project-slug>_<random>`; the slug namespaces the\n// persisted session per project (mirrors supabase's `sb-<ref>-auth-token`).\nexport const deriveStorageKey = (publishableKey: string | undefined): string => {\n const match = publishableKey?.match(/^bt_pub_([a-z0-9-]+)_[A-Za-z0-9_-]+$/)\n return match ? `bt-${match[1]}-auth-token` : 'bt-auth-token'\n}\n","export interface FragmentTokens {\n access_token: string\n refresh_token: string\n expires_in: number\n expires_at: number\n token_type: 'bearer'\n type?: string\n}\n\nexport interface FragmentError {\n error: string\n error_code?: string\n error_description?: string\n}\n\nexport type ParsedFragment = { tokens: FragmentTokens } | { authError: FragmentError } | null\n\n// Parses the implicit-flow return fragment (`#access_token=...` or `#error=...`).\nexport const parseFragment = (hash: string): ParsedFragment => {\n if (!hash || hash.length < 2) return null\n const params = new URLSearchParams(hash.startsWith('#') ? hash.slice(1) : hash)\n\n const error = params.get('error')\n if (error) {\n return {\n authError: {\n error,\n error_code: params.get('error_code') ?? undefined,\n error_description: params.get('error_description') ?? undefined,\n },\n }\n }\n\n const accessToken = params.get('access_token')\n const refreshToken = params.get('refresh_token')\n if (!accessToken || !refreshToken) return null\n\n const expiresIn = Number(params.get('expires_in') ?? 3600)\n const expiresAt = Number(params.get('expires_at') ?? Math.floor(Date.now() / 1000) + expiresIn)\n\n return {\n tokens: {\n access_token: accessToken,\n refresh_token: refreshToken,\n expires_in: expiresIn,\n expires_at: expiresAt,\n token_type: 'bearer',\n type: params.get('type') ?? undefined,\n },\n }\n}\n\n// Removes the auth fragment from the address bar (before any await, so tokens never\n// linger in history).\nexport const cleanFragmentFromUrl = () => {\n if (typeof window === 'undefined' || typeof history === 'undefined') return\n history.replaceState(null, '', window.location.pathname + window.location.search)\n}\n","import { Connections } from './connections'\nimport { resolveBaseUrl } from './constants'\nimport { request } from './fetch'\nimport { defaultStorage, deriveStorageKey } from './storage'\nimport {\n AuthError,\n type AuthChangeEvent,\n type AuthClientOptions,\n type AuthResponse,\n type Session,\n type SignInWithOAuthCredentials,\n type SignInWithOtpCredentials,\n type StorageAdapter,\n type Subscription,\n type User,\n type VerifyOtpParams,\n} from './types'\nimport { cleanFragmentFromUrl, parseFragment } from './url'\n\nconst REFRESH_TICK_MS = 30_000\n// Refresh when the access token is within this margin of expiry.\nconst EXPIRY_MARGIN_SECONDS = 90\n\ntype Listener = (event: AuthChangeEvent, session: Session | null) => void\n\nexport class Auth {\n private baseUrl: string\n private apikey: string\n private storage: StorageAdapter\n private storageKey: string\n private persistSession: boolean\n private autoRefreshToken: boolean\n private detectSessionInUrl: boolean\n private fetchImpl?: typeof fetch\n\n private session: Session | null = null\n private listeners = new Map<string, Listener>()\n private listenerSeq = 0\n private initializePromise: Promise<void> | null = null\n private refreshPromise: Promise<AuthResponse<{ session: Session | null; user: User | null }>> | null = null\n private refreshTimer: ReturnType<typeof setInterval> | null = null\n\n constructor(publishableKey: string, options: AuthClientOptions = {}) {\n // Lazy by design: an empty key must not throw at construction time (CI builds\n // with empty envs import this module transitively). Failures surface on first call.\n // The hosted DeepKey API is the only supported origin. The internal override\n // exists for DeepKey's console and tests and is not part of the public contract.\n this.baseUrl = resolveBaseUrl(options.__internalBaseUrl)\n this.apikey = publishableKey ?? ''\n this.persistSession = options.persistSession ?? true\n this.autoRefreshToken = options.autoRefreshToken ?? true\n this.detectSessionInUrl = options.detectSessionInUrl ?? true\n this.storage = options.storage ?? defaultStorage()\n this.storageKey = options.storageKey ?? deriveStorageKey(publishableKey)\n this.fetchImpl = options.fetch\n\n this.setupCrossTabSync()\n }\n\n // ---- public API (supabase-js compatible) ----\n\n async signInWithOtp(credentials: SignInWithOtpCredentials): Promise<AuthResponse<{ user: null; session: null }>> {\n const { error } = await this.request<Record<string, never>>('POST', '/auth/v1/otp', {\n email: credentials.email,\n create_user: credentials.options?.shouldCreateUser,\n redirect_to: credentials.options?.emailRedirectTo,\n })\n return { data: { user: null, session: null }, error }\n }\n\n async verifyOtp(params: VerifyOtpParams): Promise<AuthResponse<{ user: User | null; session: Session | null }>> {\n const { data, error } = await this.request<Session>('POST', '/auth/v1/verify', {\n type: 'email',\n email: params.email,\n token: params.token,\n })\n if (error || !data) return { data: { user: null, session: null }, error }\n\n await this.saveSession(data)\n this.emit('SIGNED_IN', data)\n return { data: { user: data.user, session: data }, error: null }\n }\n\n async signInWithOAuth(\n credentials: SignInWithOAuthCredentials,\n ): Promise<AuthResponse<{ provider: string; url: string }>> {\n const url = new URL(`${this.baseUrl}/auth/v1/authorize`)\n url.searchParams.set('provider', credentials.provider)\n url.searchParams.set('apikey', this.apikey)\n if (credentials.options?.redirectTo) url.searchParams.set('redirect_to', credentials.options.redirectTo)\n if (credentials.options?.scopes) url.searchParams.set('scopes', credentials.options.scopes)\n for (const [key, value] of Object.entries(credentials.options?.queryParams ?? {})) {\n url.searchParams.set(key, value)\n }\n\n if (!credentials.options?.skipBrowserRedirect && typeof window !== 'undefined') {\n window.location.assign(url.toString())\n }\n return { data: { provider: credentials.provider, url: url.toString() }, error: null }\n }\n\n onAuthStateChange(callback: Listener): { data: { subscription: Subscription } } {\n const id = `listener-${++this.listenerSeq}`\n this.listeners.set(id, callback)\n\n // Every subscriber receives INITIAL_SESSION asynchronously once initialization\n // settles — the supabase-js contract that AuthProviders rely on to resolve loading.\n this.initialize().then(() => {\n if (this.listeners.has(id)) callback('INITIAL_SESSION', this.session)\n })\n\n return {\n data: {\n subscription: {\n id,\n unsubscribe: () => {\n this.listeners.delete(id)\n },\n },\n },\n }\n }\n\n async signOut(): Promise<{ error: AuthError | null }> {\n await this.initialize()\n const session = this.session\n if (session) {\n // Best-effort server-side revocation; local sign-out always succeeds.\n await this.request('POST', '/auth/v1/logout', {}, session.access_token)\n }\n this.clearSession()\n this.emit('SIGNED_OUT', null)\n return { error: null }\n }\n\n async getSession(): Promise<AuthResponse<{ session: Session | null }>> {\n await this.initialize()\n\n if (this.session && this.isExpired(this.session) && this.autoRefreshToken) {\n const { error } = await this.refreshWithLock()\n if (error && error.code !== 'network_error') {\n return { data: { session: null }, error: null }\n }\n }\n\n return { data: { session: this.session }, error: null }\n }\n\n async getUser(jwt?: string): Promise<AuthResponse<{ user: User | null }>> {\n let token = jwt\n if (!token) {\n const {\n data: { session },\n } = await this.getSession()\n token = session?.access_token\n }\n if (!token) {\n return { data: { user: null }, error: new AuthError('Auth session missing!', 400, 'session_missing') }\n }\n\n const { data, error } = await this.request<User>('GET', '/auth/v1/user', undefined, token)\n return { data: { user: data }, error }\n }\n\n async refreshSession(currentSession?: {\n refresh_token: string\n }): Promise<AuthResponse<{ session: Session | null; user: User | null }>> {\n await this.initialize()\n const refreshToken = currentSession?.refresh_token ?? this.session?.refresh_token\n if (!refreshToken) {\n return {\n data: { session: null, user: null },\n error: new AuthError('Auth session missing!', 400, 'session_missing'),\n }\n }\n return this.refreshWithLock(refreshToken)\n }\n\n // ---- internals ----\n\n private async request<T>(method: 'GET' | 'POST', path: string, body?: unknown, accessToken?: string) {\n return request<T>({\n method,\n path,\n body,\n accessToken,\n apikey: this.apikey,\n baseUrl: this.baseUrl,\n fetchImpl: this.fetchImpl,\n })\n }\n\n private initialize(): Promise<void> {\n this.initializePromise ??= this.doInitialize()\n return this.initializePromise\n }\n\n private async doInitialize(): Promise<void> {\n if (this.detectSessionInUrl && typeof window !== 'undefined') {\n const parsed = parseFragment(window.location.hash)\n if (parsed) {\n // Strip tokens from the address bar synchronously, before any await.\n cleanFragmentFromUrl()\n\n if ('authError' in parsed) {\n console.warn(\n `[deepkey] Auth redirect returned an error: ${parsed.authError.error_code ?? parsed.authError.error}`,\n parsed.authError.error_description ?? '',\n )\n } else {\n const { data: user } = await this.request<User>('GET', '/auth/v1/user', undefined, parsed.tokens.access_token)\n if (user) {\n const session: Session = { ...parsed.tokens, token_type: 'bearer', user }\n await this.saveSession(session)\n this.emit('SIGNED_IN', session)\n return\n }\n }\n }\n }\n\n const stored = this.loadStoredSession()\n if (!stored) return\n\n if (this.isExpired(stored)) {\n if (!this.autoRefreshToken) return\n this.session = stored\n const { error } = await this.refreshWithLock()\n if (error && error.code !== 'network_error') this.clearSession()\n return\n }\n\n this.session = stored\n this.startRefreshTimer()\n }\n\n private isExpired(session: Session): boolean {\n return session.expires_at <= Math.floor(Date.now() / 1000) + EXPIRY_MARGIN_SECONDS\n }\n\n private async refreshWithLock(\n refreshToken?: string,\n ): Promise<AuthResponse<{ session: Session | null; user: User | null }>> {\n this.refreshPromise ??= this.doRefresh(refreshToken).finally(() => {\n this.refreshPromise = null\n })\n return this.refreshPromise\n }\n\n private async doRefresh(\n refreshToken?: string,\n ): Promise<AuthResponse<{ session: Session | null; user: User | null }>> {\n const token = refreshToken ?? this.session?.refresh_token\n if (!token) {\n return {\n data: { session: null, user: null },\n error: new AuthError('Auth session missing!', 400, 'session_missing'),\n }\n }\n\n const { data, error } = await this.request<Session>('POST', '/auth/v1/token?grant_type=refresh_token', {\n refresh_token: token,\n })\n\n if (error) {\n // Network failures keep the session (retry next tick); auth failures clear it.\n if (error.code !== 'network_error') {\n this.clearSession()\n this.emit('SIGNED_OUT', null)\n }\n return { data: { session: null, user: null }, error }\n }\n\n if (data) {\n await this.saveSession(data)\n this.emit('TOKEN_REFRESHED', data)\n return { data: { session: data, user: data.user }, error: null }\n }\n return { data: { session: null, user: null }, error: new AuthError('Empty refresh response') }\n }\n\n private async saveSession(session: Session) {\n this.session = session\n if (this.persistSession) {\n try {\n this.storage.setItem(this.storageKey, JSON.stringify(session))\n } catch {\n // Persistence is best-effort (private mode, quota).\n }\n }\n this.startRefreshTimer()\n }\n\n private clearSession() {\n this.session = null\n try {\n this.storage.removeItem(this.storageKey)\n } catch {\n // ignore\n }\n this.stopRefreshTimer()\n }\n\n private loadStoredSession(): Session | null {\n if (!this.persistSession) return null\n try {\n const raw = this.storage.getItem(this.storageKey)\n if (!raw) return null\n const parsed = JSON.parse(raw) as Session\n if (!parsed.access_token || !parsed.refresh_token) return null\n return parsed\n } catch {\n return null\n }\n }\n\n private startRefreshTimer() {\n if (!this.autoRefreshToken || this.refreshTimer || typeof setInterval === 'undefined') return\n this.refreshTimer = setInterval(() => {\n if (this.session && this.isExpired(this.session)) void this.refreshWithLock()\n }, REFRESH_TICK_MS)\n // Do not keep node processes alive because of the timer (no-op in browsers).\n const timer = this.refreshTimer as unknown as { unref?: () => void }\n if (typeof timer === 'object' && typeof timer.unref === 'function') timer.unref()\n }\n\n private stopRefreshTimer() {\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer)\n this.refreshTimer = null\n }\n }\n\n private setupCrossTabSync() {\n if (typeof window === 'undefined' || !this.persistSession) return\n window.addEventListener('storage', event => {\n if (event.key !== this.storageKey) return\n if (!event.newValue) {\n if (this.session) {\n this.session = null\n this.stopRefreshTimer()\n this.emit('SIGNED_OUT', null)\n }\n return\n }\n try {\n const next = JSON.parse(event.newValue) as Session\n const changed = next.access_token !== this.session?.access_token\n this.session = next\n this.startRefreshTimer()\n if (changed) this.emit('TOKEN_REFRESHED', next)\n } catch {\n // ignore malformed writes\n }\n })\n }\n\n private emit(event: AuthChangeEvent, session: Session | null) {\n for (const listener of this.listeners.values()) {\n try {\n listener(event, session)\n } catch (err) {\n console.error('[deepkey] onAuthStateChange listener threw', err)\n }\n }\n }\n}\n\nexport interface AuthClient {\n auth: Auth\n connections: Connections\n}\n\nexport const createAuthClient = (publishableKey: string, options?: AuthClientOptions): AuthClient => {\n const auth = new Auth(publishableKey, options)\n const connections = new Connections(auth, {\n apikey: publishableKey ?? '',\n baseUrl: resolveBaseUrl(options?.__internalBaseUrl),\n fetchImpl: options?.fetch,\n })\n return { auth, connections }\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,27 @@
1
- import { A as AuthClientOptions, S as SignInWithOtpCredentials, a as AuthResponse, V as VerifyOtpParams, U as User, b as Session, c as SignInWithOAuthCredentials, d as AuthChangeEvent, e as Subscription, f as AuthError } from './constants-BQhswdms.cjs';
2
- export { D as DEEPKEY_API_URL, g as ServerClientOptions, h as StorageAdapter, i as UserIdentity } from './constants-BQhswdms.cjs';
1
+ import { C as ConnectProviderCredentials, A as AuthResponse, P as ProviderConnection, a as AuthError, b as AuthClientOptions, S as SignInWithOtpCredentials, V as VerifyOtpParams, U as User, c as Session, d as SignInWithOAuthCredentials, e as AuthChangeEvent, f as Subscription } from './constants-DgChFH24.cjs';
2
+ export { D as DEEPKEY_API_URL, g as ProviderAccessToken, h as ServerClientOptions, i as StorageAdapter, j as UserIdentity } from './constants-DgChFH24.cjs';
3
+
4
+ interface ConnectionsOptions {
5
+ apikey: string;
6
+ baseUrl: string;
7
+ fetchImpl?: typeof fetch;
8
+ }
9
+ declare class Connections {
10
+ private auth;
11
+ private options;
12
+ constructor(auth: Auth, options: ConnectionsOptions);
13
+ connect(credentials: ConnectProviderCredentials): Promise<AuthResponse<{
14
+ provider: string;
15
+ url: string | null;
16
+ }>>;
17
+ list(): Promise<AuthResponse<{
18
+ connections: ProviderConnection[];
19
+ }>>;
20
+ revoke(connectionId: string): Promise<{
21
+ error: AuthError | null;
22
+ }>;
23
+ private request;
24
+ }
3
25
 
4
26
  type Listener = (event: AuthChangeEvent, session: Session | null) => void;
5
27
  declare class Auth {
@@ -66,7 +88,8 @@ declare class Auth {
66
88
  }
67
89
  interface AuthClient {
68
90
  auth: Auth;
91
+ connections: Connections;
69
92
  }
70
93
  declare const createAuthClient: (publishableKey: string, options?: AuthClientOptions) => AuthClient;
71
94
 
72
- export { Auth, AuthChangeEvent, type AuthClient, AuthClientOptions, AuthError, AuthResponse, Session, SignInWithOAuthCredentials, SignInWithOtpCredentials, Subscription, User, VerifyOtpParams, createAuthClient };
95
+ export { Auth, AuthChangeEvent, type AuthClient, AuthClientOptions, AuthError, AuthResponse, ConnectProviderCredentials, Connections, ProviderConnection, Session, SignInWithOAuthCredentials, SignInWithOtpCredentials, Subscription, User, VerifyOtpParams, createAuthClient };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,27 @@
1
- import { A as AuthClientOptions, S as SignInWithOtpCredentials, a as AuthResponse, V as VerifyOtpParams, U as User, b as Session, c as SignInWithOAuthCredentials, d as AuthChangeEvent, e as Subscription, f as AuthError } from './constants-BQhswdms.js';
2
- export { D as DEEPKEY_API_URL, g as ServerClientOptions, h as StorageAdapter, i as UserIdentity } from './constants-BQhswdms.js';
1
+ import { C as ConnectProviderCredentials, A as AuthResponse, P as ProviderConnection, a as AuthError, b as AuthClientOptions, S as SignInWithOtpCredentials, V as VerifyOtpParams, U as User, c as Session, d as SignInWithOAuthCredentials, e as AuthChangeEvent, f as Subscription } from './constants-DgChFH24.js';
2
+ export { D as DEEPKEY_API_URL, g as ProviderAccessToken, h as ServerClientOptions, i as StorageAdapter, j as UserIdentity } from './constants-DgChFH24.js';
3
+
4
+ interface ConnectionsOptions {
5
+ apikey: string;
6
+ baseUrl: string;
7
+ fetchImpl?: typeof fetch;
8
+ }
9
+ declare class Connections {
10
+ private auth;
11
+ private options;
12
+ constructor(auth: Auth, options: ConnectionsOptions);
13
+ connect(credentials: ConnectProviderCredentials): Promise<AuthResponse<{
14
+ provider: string;
15
+ url: string | null;
16
+ }>>;
17
+ list(): Promise<AuthResponse<{
18
+ connections: ProviderConnection[];
19
+ }>>;
20
+ revoke(connectionId: string): Promise<{
21
+ error: AuthError | null;
22
+ }>;
23
+ private request;
24
+ }
3
25
 
4
26
  type Listener = (event: AuthChangeEvent, session: Session | null) => void;
5
27
  declare class Auth {
@@ -66,7 +88,8 @@ declare class Auth {
66
88
  }
67
89
  interface AuthClient {
68
90
  auth: Auth;
91
+ connections: Connections;
69
92
  }
70
93
  declare const createAuthClient: (publishableKey: string, options?: AuthClientOptions) => AuthClient;
71
94
 
72
- export { Auth, AuthChangeEvent, type AuthClient, AuthClientOptions, AuthError, AuthResponse, Session, SignInWithOAuthCredentials, SignInWithOtpCredentials, Subscription, User, VerifyOtpParams, createAuthClient };
95
+ export { Auth, AuthChangeEvent, type AuthClient, AuthClientOptions, AuthError, AuthResponse, ConnectProviderCredentials, Connections, ProviderConnection, Session, SignInWithOAuthCredentials, SignInWithOtpCredentials, Subscription, User, VerifyOtpParams, createAuthClient };
package/dist/index.js CHANGED
@@ -1,43 +1,44 @@
1
1
  import {
2
2
  AuthError,
3
3
  DEEPKEY_API_URL,
4
+ request,
4
5
  resolveBaseUrl
5
- } from "./chunk-IFNRLMVX.js";
6
+ } from "./chunk-A2CRUXTA.js";
6
7
 
7
- // src/fetch.ts
8
- var request = async (options) => {
9
- const fetchImpl = options.fetchImpl ?? fetch;
10
- try {
11
- const headers = { apikey: options.apikey };
12
- if (options.body !== void 0) headers["Content-Type"] = "application/json";
13
- if (options.accessToken) headers.Authorization = `Bearer ${options.accessToken}`;
14
- const response = await fetchImpl(`${options.baseUrl}${options.path}`, {
15
- method: options.method,
16
- headers,
17
- body: options.body !== void 0 ? JSON.stringify(options.body) : void 0
18
- });
19
- if (response.status === 204) return { data: {}, error: null };
20
- let payload;
21
- try {
22
- payload = await response.json();
23
- } catch {
24
- payload = null;
8
+ // src/connections.ts
9
+ var Connections = class {
10
+ constructor(auth, options) {
11
+ this.auth = auth;
12
+ this.options = options;
13
+ }
14
+ async connect(credentials) {
15
+ const { data, error } = await this.request(
16
+ "POST",
17
+ "/auth/v1/connections/authorize",
18
+ { provider: credentials.provider, redirect_to: credentials.options?.redirectTo }
19
+ );
20
+ if (error || !data) return { data: { provider: credentials.provider, url: null }, error };
21
+ if (!credentials.options?.skipBrowserRedirect && typeof window !== "undefined") {
22
+ window.location.assign(data.url);
25
23
  }
26
- if (!response.ok) {
27
- const errorBody = payload?.error;
28
- return {
29
- data: null,
30
- error: new AuthError(
31
- errorBody?.message ?? `Request failed with status ${response.status}`,
32
- response.status,
33
- errorBody?.code
34
- )
35
- };
24
+ return { data: { provider: credentials.provider, url: data.url }, error: null };
25
+ }
26
+ async list() {
27
+ const { data, error } = await this.request("GET", "/auth/v1/connections");
28
+ return { data: { connections: data?.connections ?? [] }, error };
29
+ }
30
+ async revoke(connectionId) {
31
+ const { error } = await this.request("DELETE", `/auth/v1/connections/${encodeURIComponent(connectionId)}`);
32
+ return { error };
33
+ }
34
+ async request(method, path, body) {
35
+ const {
36
+ data: { session }
37
+ } = await this.auth.getSession();
38
+ if (!session) {
39
+ return { data: null, error: new AuthError("Auth session missing!", 400, "session_missing") };
36
40
  }
37
- return { data: payload, error: null };
38
- } catch (err) {
39
- const message = err instanceof Error ? err.message : "Network request failed";
40
- return { data: null, error: new AuthError(message, 0, "network_error") };
41
+ return request({ method, path, body, accessToken: session.access_token, ...this.options });
41
42
  }
42
43
  };
43
44
 
@@ -385,11 +386,18 @@ var Auth = class {
385
386
  }
386
387
  };
387
388
  var createAuthClient = (publishableKey, options) => {
388
- return { auth: new Auth(publishableKey, options) };
389
+ const auth = new Auth(publishableKey, options);
390
+ const connections = new Connections(auth, {
391
+ apikey: publishableKey ?? "",
392
+ baseUrl: resolveBaseUrl(options?.__internalBaseUrl),
393
+ fetchImpl: options?.fetch
394
+ });
395
+ return { auth, connections };
389
396
  };
390
397
  export {
391
398
  Auth,
392
399
  AuthError,
400
+ Connections,
393
401
  DEEPKEY_API_URL,
394
402
  createAuthClient
395
403
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/fetch.ts","../src/storage.ts","../src/url.ts","../src/client.ts"],"sourcesContent":["import { AuthError } from './types'\n\nexport interface RequestOptions {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE'\n path: string\n apikey: string\n baseUrl: string\n accessToken?: string\n body?: unknown\n fetchImpl?: typeof fetch\n}\n\nexport interface RequestResult<T> {\n data: T | null\n error: AuthError | null\n}\n\n// All service errors are shaped { error: { code, message } }.\nexport const request = async <T>(options: RequestOptions): Promise<RequestResult<T>> => {\n const fetchImpl = options.fetchImpl ?? fetch\n try {\n const headers: Record<string, string> = { apikey: options.apikey }\n if (options.body !== undefined) headers['Content-Type'] = 'application/json'\n if (options.accessToken) headers.Authorization = `Bearer ${options.accessToken}`\n\n const response = await fetchImpl(`${options.baseUrl}${options.path}`, {\n method: options.method,\n headers,\n body: options.body !== undefined ? JSON.stringify(options.body) : undefined,\n })\n\n if (response.status === 204) return { data: {} as T, error: null }\n\n let payload: unknown\n try {\n payload = await response.json()\n } catch {\n payload = null\n }\n\n if (!response.ok) {\n const errorBody = (payload as { error?: { code?: string; message?: string } } | null)?.error\n return {\n data: null,\n error: new AuthError(\n errorBody?.message ?? `Request failed with status ${response.status}`,\n response.status,\n errorBody?.code,\n ),\n }\n }\n\n return { data: payload as T, error: null }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Network request failed'\n return { data: null, error: new AuthError(message, 0, 'network_error') }\n }\n}\n","import type { StorageAdapter } from './types'\n\nclass MemoryStorage implements StorageAdapter {\n private store = new Map<string, string>()\n getItem(key: string) {\n return this.store.get(key) ?? null\n }\n setItem(key: string, value: string) {\n this.store.set(key, value)\n }\n removeItem(key: string) {\n this.store.delete(key)\n }\n}\n\n// localStorage when available, in-memory fallback (SSR, tests, restricted contexts).\nexport const defaultStorage = (): StorageAdapter => {\n try {\n if (typeof window !== 'undefined' && window.localStorage) {\n const probe = '__bt_auth_probe__'\n window.localStorage.setItem(probe, '1')\n window.localStorage.removeItem(probe)\n return window.localStorage\n }\n } catch {\n // fall through to memory storage\n }\n return new MemoryStorage()\n}\n\n// Publishable keys look like `bt_pub_<project-slug>_<random>`; the slug namespaces the\n// persisted session per project (mirrors supabase's `sb-<ref>-auth-token`).\nexport const deriveStorageKey = (publishableKey: string | undefined): string => {\n const match = publishableKey?.match(/^bt_pub_([a-z0-9-]+)_[A-Za-z0-9_-]+$/)\n return match ? `bt-${match[1]}-auth-token` : 'bt-auth-token'\n}\n","export interface FragmentTokens {\n access_token: string\n refresh_token: string\n expires_in: number\n expires_at: number\n token_type: 'bearer'\n type?: string\n}\n\nexport interface FragmentError {\n error: string\n error_code?: string\n error_description?: string\n}\n\nexport type ParsedFragment = { tokens: FragmentTokens } | { authError: FragmentError } | null\n\n// Parses the implicit-flow return fragment (`#access_token=...` or `#error=...`).\nexport const parseFragment = (hash: string): ParsedFragment => {\n if (!hash || hash.length < 2) return null\n const params = new URLSearchParams(hash.startsWith('#') ? hash.slice(1) : hash)\n\n const error = params.get('error')\n if (error) {\n return {\n authError: {\n error,\n error_code: params.get('error_code') ?? undefined,\n error_description: params.get('error_description') ?? undefined,\n },\n }\n }\n\n const accessToken = params.get('access_token')\n const refreshToken = params.get('refresh_token')\n if (!accessToken || !refreshToken) return null\n\n const expiresIn = Number(params.get('expires_in') ?? 3600)\n const expiresAt = Number(params.get('expires_at') ?? Math.floor(Date.now() / 1000) + expiresIn)\n\n return {\n tokens: {\n access_token: accessToken,\n refresh_token: refreshToken,\n expires_in: expiresIn,\n expires_at: expiresAt,\n token_type: 'bearer',\n type: params.get('type') ?? undefined,\n },\n }\n}\n\n// Removes the auth fragment from the address bar (before any await, so tokens never\n// linger in history).\nexport const cleanFragmentFromUrl = () => {\n if (typeof window === 'undefined' || typeof history === 'undefined') return\n history.replaceState(null, '', window.location.pathname + window.location.search)\n}\n","import { resolveBaseUrl } from './constants'\nimport { request } from './fetch'\nimport { defaultStorage, deriveStorageKey } from './storage'\nimport {\n AuthError,\n type AuthChangeEvent,\n type AuthClientOptions,\n type AuthResponse,\n type Session,\n type SignInWithOAuthCredentials,\n type SignInWithOtpCredentials,\n type StorageAdapter,\n type Subscription,\n type User,\n type VerifyOtpParams,\n} from './types'\nimport { cleanFragmentFromUrl, parseFragment } from './url'\n\nconst REFRESH_TICK_MS = 30_000\n// Refresh when the access token is within this margin of expiry.\nconst EXPIRY_MARGIN_SECONDS = 90\n\ntype Listener = (event: AuthChangeEvent, session: Session | null) => void\n\nexport class Auth {\n private baseUrl: string\n private apikey: string\n private storage: StorageAdapter\n private storageKey: string\n private persistSession: boolean\n private autoRefreshToken: boolean\n private detectSessionInUrl: boolean\n private fetchImpl?: typeof fetch\n\n private session: Session | null = null\n private listeners = new Map<string, Listener>()\n private listenerSeq = 0\n private initializePromise: Promise<void> | null = null\n private refreshPromise: Promise<AuthResponse<{ session: Session | null; user: User | null }>> | null = null\n private refreshTimer: ReturnType<typeof setInterval> | null = null\n\n constructor(publishableKey: string, options: AuthClientOptions = {}) {\n // Lazy by design: an empty key must not throw at construction time (CI builds\n // with empty envs import this module transitively). Failures surface on first call.\n // The hosted DeepKey API is the only supported origin. The internal override\n // exists for DeepKey's console and tests and is not part of the public contract.\n this.baseUrl = resolveBaseUrl(options.__internalBaseUrl)\n this.apikey = publishableKey ?? ''\n this.persistSession = options.persistSession ?? true\n this.autoRefreshToken = options.autoRefreshToken ?? true\n this.detectSessionInUrl = options.detectSessionInUrl ?? true\n this.storage = options.storage ?? defaultStorage()\n this.storageKey = options.storageKey ?? deriveStorageKey(publishableKey)\n this.fetchImpl = options.fetch\n\n this.setupCrossTabSync()\n }\n\n // ---- public API (supabase-js compatible) ----\n\n async signInWithOtp(credentials: SignInWithOtpCredentials): Promise<AuthResponse<{ user: null; session: null }>> {\n const { error } = await this.request<Record<string, never>>('POST', '/auth/v1/otp', {\n email: credentials.email,\n create_user: credentials.options?.shouldCreateUser,\n redirect_to: credentials.options?.emailRedirectTo,\n })\n return { data: { user: null, session: null }, error }\n }\n\n async verifyOtp(params: VerifyOtpParams): Promise<AuthResponse<{ user: User | null; session: Session | null }>> {\n const { data, error } = await this.request<Session>('POST', '/auth/v1/verify', {\n type: 'email',\n email: params.email,\n token: params.token,\n })\n if (error || !data) return { data: { user: null, session: null }, error }\n\n await this.saveSession(data)\n this.emit('SIGNED_IN', data)\n return { data: { user: data.user, session: data }, error: null }\n }\n\n async signInWithOAuth(\n credentials: SignInWithOAuthCredentials,\n ): Promise<AuthResponse<{ provider: string; url: string }>> {\n const url = new URL(`${this.baseUrl}/auth/v1/authorize`)\n url.searchParams.set('provider', credentials.provider)\n url.searchParams.set('apikey', this.apikey)\n if (credentials.options?.redirectTo) url.searchParams.set('redirect_to', credentials.options.redirectTo)\n if (credentials.options?.scopes) url.searchParams.set('scopes', credentials.options.scopes)\n for (const [key, value] of Object.entries(credentials.options?.queryParams ?? {})) {\n url.searchParams.set(key, value)\n }\n\n if (!credentials.options?.skipBrowserRedirect && typeof window !== 'undefined') {\n window.location.assign(url.toString())\n }\n return { data: { provider: credentials.provider, url: url.toString() }, error: null }\n }\n\n onAuthStateChange(callback: Listener): { data: { subscription: Subscription } } {\n const id = `listener-${++this.listenerSeq}`\n this.listeners.set(id, callback)\n\n // Every subscriber receives INITIAL_SESSION asynchronously once initialization\n // settles — the supabase-js contract that AuthProviders rely on to resolve loading.\n this.initialize().then(() => {\n if (this.listeners.has(id)) callback('INITIAL_SESSION', this.session)\n })\n\n return {\n data: {\n subscription: {\n id,\n unsubscribe: () => {\n this.listeners.delete(id)\n },\n },\n },\n }\n }\n\n async signOut(): Promise<{ error: AuthError | null }> {\n await this.initialize()\n const session = this.session\n if (session) {\n // Best-effort server-side revocation; local sign-out always succeeds.\n await this.request('POST', '/auth/v1/logout', {}, session.access_token)\n }\n this.clearSession()\n this.emit('SIGNED_OUT', null)\n return { error: null }\n }\n\n async getSession(): Promise<AuthResponse<{ session: Session | null }>> {\n await this.initialize()\n\n if (this.session && this.isExpired(this.session) && this.autoRefreshToken) {\n const { error } = await this.refreshWithLock()\n if (error && error.code !== 'network_error') {\n return { data: { session: null }, error: null }\n }\n }\n\n return { data: { session: this.session }, error: null }\n }\n\n async getUser(jwt?: string): Promise<AuthResponse<{ user: User | null }>> {\n let token = jwt\n if (!token) {\n const {\n data: { session },\n } = await this.getSession()\n token = session?.access_token\n }\n if (!token) {\n return { data: { user: null }, error: new AuthError('Auth session missing!', 400, 'session_missing') }\n }\n\n const { data, error } = await this.request<User>('GET', '/auth/v1/user', undefined, token)\n return { data: { user: data }, error }\n }\n\n async refreshSession(currentSession?: {\n refresh_token: string\n }): Promise<AuthResponse<{ session: Session | null; user: User | null }>> {\n await this.initialize()\n const refreshToken = currentSession?.refresh_token ?? this.session?.refresh_token\n if (!refreshToken) {\n return {\n data: { session: null, user: null },\n error: new AuthError('Auth session missing!', 400, 'session_missing'),\n }\n }\n return this.refreshWithLock(refreshToken)\n }\n\n // ---- internals ----\n\n private async request<T>(method: 'GET' | 'POST', path: string, body?: unknown, accessToken?: string) {\n return request<T>({\n method,\n path,\n body,\n accessToken,\n apikey: this.apikey,\n baseUrl: this.baseUrl,\n fetchImpl: this.fetchImpl,\n })\n }\n\n private initialize(): Promise<void> {\n this.initializePromise ??= this.doInitialize()\n return this.initializePromise\n }\n\n private async doInitialize(): Promise<void> {\n if (this.detectSessionInUrl && typeof window !== 'undefined') {\n const parsed = parseFragment(window.location.hash)\n if (parsed) {\n // Strip tokens from the address bar synchronously, before any await.\n cleanFragmentFromUrl()\n\n if ('authError' in parsed) {\n console.warn(\n `[deepkey] Auth redirect returned an error: ${parsed.authError.error_code ?? parsed.authError.error}`,\n parsed.authError.error_description ?? '',\n )\n } else {\n const { data: user } = await this.request<User>('GET', '/auth/v1/user', undefined, parsed.tokens.access_token)\n if (user) {\n const session: Session = { ...parsed.tokens, token_type: 'bearer', user }\n await this.saveSession(session)\n this.emit('SIGNED_IN', session)\n return\n }\n }\n }\n }\n\n const stored = this.loadStoredSession()\n if (!stored) return\n\n if (this.isExpired(stored)) {\n if (!this.autoRefreshToken) return\n this.session = stored\n const { error } = await this.refreshWithLock()\n if (error && error.code !== 'network_error') this.clearSession()\n return\n }\n\n this.session = stored\n this.startRefreshTimer()\n }\n\n private isExpired(session: Session): boolean {\n return session.expires_at <= Math.floor(Date.now() / 1000) + EXPIRY_MARGIN_SECONDS\n }\n\n private async refreshWithLock(\n refreshToken?: string,\n ): Promise<AuthResponse<{ session: Session | null; user: User | null }>> {\n this.refreshPromise ??= this.doRefresh(refreshToken).finally(() => {\n this.refreshPromise = null\n })\n return this.refreshPromise\n }\n\n private async doRefresh(\n refreshToken?: string,\n ): Promise<AuthResponse<{ session: Session | null; user: User | null }>> {\n const token = refreshToken ?? this.session?.refresh_token\n if (!token) {\n return {\n data: { session: null, user: null },\n error: new AuthError('Auth session missing!', 400, 'session_missing'),\n }\n }\n\n const { data, error } = await this.request<Session>('POST', '/auth/v1/token?grant_type=refresh_token', {\n refresh_token: token,\n })\n\n if (error) {\n // Network failures keep the session (retry next tick); auth failures clear it.\n if (error.code !== 'network_error') {\n this.clearSession()\n this.emit('SIGNED_OUT', null)\n }\n return { data: { session: null, user: null }, error }\n }\n\n if (data) {\n await this.saveSession(data)\n this.emit('TOKEN_REFRESHED', data)\n return { data: { session: data, user: data.user }, error: null }\n }\n return { data: { session: null, user: null }, error: new AuthError('Empty refresh response') }\n }\n\n private async saveSession(session: Session) {\n this.session = session\n if (this.persistSession) {\n try {\n this.storage.setItem(this.storageKey, JSON.stringify(session))\n } catch {\n // Persistence is best-effort (private mode, quota).\n }\n }\n this.startRefreshTimer()\n }\n\n private clearSession() {\n this.session = null\n try {\n this.storage.removeItem(this.storageKey)\n } catch {\n // ignore\n }\n this.stopRefreshTimer()\n }\n\n private loadStoredSession(): Session | null {\n if (!this.persistSession) return null\n try {\n const raw = this.storage.getItem(this.storageKey)\n if (!raw) return null\n const parsed = JSON.parse(raw) as Session\n if (!parsed.access_token || !parsed.refresh_token) return null\n return parsed\n } catch {\n return null\n }\n }\n\n private startRefreshTimer() {\n if (!this.autoRefreshToken || this.refreshTimer || typeof setInterval === 'undefined') return\n this.refreshTimer = setInterval(() => {\n if (this.session && this.isExpired(this.session)) void this.refreshWithLock()\n }, REFRESH_TICK_MS)\n // Do not keep node processes alive because of the timer (no-op in browsers).\n const timer = this.refreshTimer as unknown as { unref?: () => void }\n if (typeof timer === 'object' && typeof timer.unref === 'function') timer.unref()\n }\n\n private stopRefreshTimer() {\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer)\n this.refreshTimer = null\n }\n }\n\n private setupCrossTabSync() {\n if (typeof window === 'undefined' || !this.persistSession) return\n window.addEventListener('storage', event => {\n if (event.key !== this.storageKey) return\n if (!event.newValue) {\n if (this.session) {\n this.session = null\n this.stopRefreshTimer()\n this.emit('SIGNED_OUT', null)\n }\n return\n }\n try {\n const next = JSON.parse(event.newValue) as Session\n const changed = next.access_token !== this.session?.access_token\n this.session = next\n this.startRefreshTimer()\n if (changed) this.emit('TOKEN_REFRESHED', next)\n } catch {\n // ignore malformed writes\n }\n })\n }\n\n private emit(event: AuthChangeEvent, session: Session | null) {\n for (const listener of this.listeners.values()) {\n try {\n listener(event, session)\n } catch (err) {\n console.error('[deepkey] onAuthStateChange listener threw', err)\n }\n }\n }\n}\n\nexport interface AuthClient {\n auth: Auth\n}\n\nexport const createAuthClient = (publishableKey: string, options?: AuthClientOptions): AuthClient => {\n return { auth: new Auth(publishableKey, options) }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/connections.ts","../src/storage.ts","../src/url.ts","../src/client.ts"],"sourcesContent":["import type { Auth } from './client'\nimport { request } from './fetch'\nimport { AuthError, type AuthResponse, type ConnectProviderCredentials, type ProviderConnection } from './types'\n\nexport interface ConnectionsOptions {\n apikey: string\n baseUrl: string\n fetchImpl?: typeof fetch\n}\n\n// Durable provider access for the signed-in user, kept apart from login identities:\n// a user who signed in with Google can connect several X accounts. Provider refresh\n// tokens stay on DeepKey; browsers only ever see connection metadata.\nexport class Connections {\n constructor(\n private auth: Auth,\n private options: ConnectionsOptions,\n ) {}\n\n async connect(\n credentials: ConnectProviderCredentials,\n ): Promise<AuthResponse<{ provider: string; url: string | null }>> {\n const { data, error } = await this.request<{ provider: string; url: string }>(\n 'POST',\n '/auth/v1/connections/authorize',\n { provider: credentials.provider, redirect_to: credentials.options?.redirectTo },\n )\n if (error || !data) return { data: { provider: credentials.provider, url: null }, error }\n\n if (!credentials.options?.skipBrowserRedirect && typeof window !== 'undefined') {\n window.location.assign(data.url)\n }\n return { data: { provider: credentials.provider, url: data.url }, error: null }\n }\n\n async list(): Promise<AuthResponse<{ connections: ProviderConnection[] }>> {\n const { data, error } = await this.request<{ connections: ProviderConnection[] }>('GET', '/auth/v1/connections')\n return { data: { connections: data?.connections ?? [] }, error }\n }\n\n async revoke(connectionId: string): Promise<{ error: AuthError | null }> {\n const { error } = await this.request('DELETE', `/auth/v1/connections/${encodeURIComponent(connectionId)}`)\n return { error }\n }\n\n private async request<T>(method: 'GET' | 'POST' | 'DELETE', path: string, body?: unknown) {\n const {\n data: { session },\n } = await this.auth.getSession()\n if (!session) {\n return { data: null, error: new AuthError('Auth session missing!', 400, 'session_missing') }\n }\n return request<T>({ method, path, body, accessToken: session.access_token, ...this.options })\n }\n}\n","import type { StorageAdapter } from './types'\n\nclass MemoryStorage implements StorageAdapter {\n private store = new Map<string, string>()\n getItem(key: string) {\n return this.store.get(key) ?? null\n }\n setItem(key: string, value: string) {\n this.store.set(key, value)\n }\n removeItem(key: string) {\n this.store.delete(key)\n }\n}\n\n// localStorage when available, in-memory fallback (SSR, tests, restricted contexts).\nexport const defaultStorage = (): StorageAdapter => {\n try {\n if (typeof window !== 'undefined' && window.localStorage) {\n const probe = '__bt_auth_probe__'\n window.localStorage.setItem(probe, '1')\n window.localStorage.removeItem(probe)\n return window.localStorage\n }\n } catch {\n // fall through to memory storage\n }\n return new MemoryStorage()\n}\n\n// Publishable keys look like `bt_pub_<project-slug>_<random>`; the slug namespaces the\n// persisted session per project (mirrors supabase's `sb-<ref>-auth-token`).\nexport const deriveStorageKey = (publishableKey: string | undefined): string => {\n const match = publishableKey?.match(/^bt_pub_([a-z0-9-]+)_[A-Za-z0-9_-]+$/)\n return match ? `bt-${match[1]}-auth-token` : 'bt-auth-token'\n}\n","export interface FragmentTokens {\n access_token: string\n refresh_token: string\n expires_in: number\n expires_at: number\n token_type: 'bearer'\n type?: string\n}\n\nexport interface FragmentError {\n error: string\n error_code?: string\n error_description?: string\n}\n\nexport type ParsedFragment = { tokens: FragmentTokens } | { authError: FragmentError } | null\n\n// Parses the implicit-flow return fragment (`#access_token=...` or `#error=...`).\nexport const parseFragment = (hash: string): ParsedFragment => {\n if (!hash || hash.length < 2) return null\n const params = new URLSearchParams(hash.startsWith('#') ? hash.slice(1) : hash)\n\n const error = params.get('error')\n if (error) {\n return {\n authError: {\n error,\n error_code: params.get('error_code') ?? undefined,\n error_description: params.get('error_description') ?? undefined,\n },\n }\n }\n\n const accessToken = params.get('access_token')\n const refreshToken = params.get('refresh_token')\n if (!accessToken || !refreshToken) return null\n\n const expiresIn = Number(params.get('expires_in') ?? 3600)\n const expiresAt = Number(params.get('expires_at') ?? Math.floor(Date.now() / 1000) + expiresIn)\n\n return {\n tokens: {\n access_token: accessToken,\n refresh_token: refreshToken,\n expires_in: expiresIn,\n expires_at: expiresAt,\n token_type: 'bearer',\n type: params.get('type') ?? undefined,\n },\n }\n}\n\n// Removes the auth fragment from the address bar (before any await, so tokens never\n// linger in history).\nexport const cleanFragmentFromUrl = () => {\n if (typeof window === 'undefined' || typeof history === 'undefined') return\n history.replaceState(null, '', window.location.pathname + window.location.search)\n}\n","import { Connections } from './connections'\nimport { resolveBaseUrl } from './constants'\nimport { request } from './fetch'\nimport { defaultStorage, deriveStorageKey } from './storage'\nimport {\n AuthError,\n type AuthChangeEvent,\n type AuthClientOptions,\n type AuthResponse,\n type Session,\n type SignInWithOAuthCredentials,\n type SignInWithOtpCredentials,\n type StorageAdapter,\n type Subscription,\n type User,\n type VerifyOtpParams,\n} from './types'\nimport { cleanFragmentFromUrl, parseFragment } from './url'\n\nconst REFRESH_TICK_MS = 30_000\n// Refresh when the access token is within this margin of expiry.\nconst EXPIRY_MARGIN_SECONDS = 90\n\ntype Listener = (event: AuthChangeEvent, session: Session | null) => void\n\nexport class Auth {\n private baseUrl: string\n private apikey: string\n private storage: StorageAdapter\n private storageKey: string\n private persistSession: boolean\n private autoRefreshToken: boolean\n private detectSessionInUrl: boolean\n private fetchImpl?: typeof fetch\n\n private session: Session | null = null\n private listeners = new Map<string, Listener>()\n private listenerSeq = 0\n private initializePromise: Promise<void> | null = null\n private refreshPromise: Promise<AuthResponse<{ session: Session | null; user: User | null }>> | null = null\n private refreshTimer: ReturnType<typeof setInterval> | null = null\n\n constructor(publishableKey: string, options: AuthClientOptions = {}) {\n // Lazy by design: an empty key must not throw at construction time (CI builds\n // with empty envs import this module transitively). Failures surface on first call.\n // The hosted DeepKey API is the only supported origin. The internal override\n // exists for DeepKey's console and tests and is not part of the public contract.\n this.baseUrl = resolveBaseUrl(options.__internalBaseUrl)\n this.apikey = publishableKey ?? ''\n this.persistSession = options.persistSession ?? true\n this.autoRefreshToken = options.autoRefreshToken ?? true\n this.detectSessionInUrl = options.detectSessionInUrl ?? true\n this.storage = options.storage ?? defaultStorage()\n this.storageKey = options.storageKey ?? deriveStorageKey(publishableKey)\n this.fetchImpl = options.fetch\n\n this.setupCrossTabSync()\n }\n\n // ---- public API (supabase-js compatible) ----\n\n async signInWithOtp(credentials: SignInWithOtpCredentials): Promise<AuthResponse<{ user: null; session: null }>> {\n const { error } = await this.request<Record<string, never>>('POST', '/auth/v1/otp', {\n email: credentials.email,\n create_user: credentials.options?.shouldCreateUser,\n redirect_to: credentials.options?.emailRedirectTo,\n })\n return { data: { user: null, session: null }, error }\n }\n\n async verifyOtp(params: VerifyOtpParams): Promise<AuthResponse<{ user: User | null; session: Session | null }>> {\n const { data, error } = await this.request<Session>('POST', '/auth/v1/verify', {\n type: 'email',\n email: params.email,\n token: params.token,\n })\n if (error || !data) return { data: { user: null, session: null }, error }\n\n await this.saveSession(data)\n this.emit('SIGNED_IN', data)\n return { data: { user: data.user, session: data }, error: null }\n }\n\n async signInWithOAuth(\n credentials: SignInWithOAuthCredentials,\n ): Promise<AuthResponse<{ provider: string; url: string }>> {\n const url = new URL(`${this.baseUrl}/auth/v1/authorize`)\n url.searchParams.set('provider', credentials.provider)\n url.searchParams.set('apikey', this.apikey)\n if (credentials.options?.redirectTo) url.searchParams.set('redirect_to', credentials.options.redirectTo)\n if (credentials.options?.scopes) url.searchParams.set('scopes', credentials.options.scopes)\n for (const [key, value] of Object.entries(credentials.options?.queryParams ?? {})) {\n url.searchParams.set(key, value)\n }\n\n if (!credentials.options?.skipBrowserRedirect && typeof window !== 'undefined') {\n window.location.assign(url.toString())\n }\n return { data: { provider: credentials.provider, url: url.toString() }, error: null }\n }\n\n onAuthStateChange(callback: Listener): { data: { subscription: Subscription } } {\n const id = `listener-${++this.listenerSeq}`\n this.listeners.set(id, callback)\n\n // Every subscriber receives INITIAL_SESSION asynchronously once initialization\n // settles — the supabase-js contract that AuthProviders rely on to resolve loading.\n this.initialize().then(() => {\n if (this.listeners.has(id)) callback('INITIAL_SESSION', this.session)\n })\n\n return {\n data: {\n subscription: {\n id,\n unsubscribe: () => {\n this.listeners.delete(id)\n },\n },\n },\n }\n }\n\n async signOut(): Promise<{ error: AuthError | null }> {\n await this.initialize()\n const session = this.session\n if (session) {\n // Best-effort server-side revocation; local sign-out always succeeds.\n await this.request('POST', '/auth/v1/logout', {}, session.access_token)\n }\n this.clearSession()\n this.emit('SIGNED_OUT', null)\n return { error: null }\n }\n\n async getSession(): Promise<AuthResponse<{ session: Session | null }>> {\n await this.initialize()\n\n if (this.session && this.isExpired(this.session) && this.autoRefreshToken) {\n const { error } = await this.refreshWithLock()\n if (error && error.code !== 'network_error') {\n return { data: { session: null }, error: null }\n }\n }\n\n return { data: { session: this.session }, error: null }\n }\n\n async getUser(jwt?: string): Promise<AuthResponse<{ user: User | null }>> {\n let token = jwt\n if (!token) {\n const {\n data: { session },\n } = await this.getSession()\n token = session?.access_token\n }\n if (!token) {\n return { data: { user: null }, error: new AuthError('Auth session missing!', 400, 'session_missing') }\n }\n\n const { data, error } = await this.request<User>('GET', '/auth/v1/user', undefined, token)\n return { data: { user: data }, error }\n }\n\n async refreshSession(currentSession?: {\n refresh_token: string\n }): Promise<AuthResponse<{ session: Session | null; user: User | null }>> {\n await this.initialize()\n const refreshToken = currentSession?.refresh_token ?? this.session?.refresh_token\n if (!refreshToken) {\n return {\n data: { session: null, user: null },\n error: new AuthError('Auth session missing!', 400, 'session_missing'),\n }\n }\n return this.refreshWithLock(refreshToken)\n }\n\n // ---- internals ----\n\n private async request<T>(method: 'GET' | 'POST', path: string, body?: unknown, accessToken?: string) {\n return request<T>({\n method,\n path,\n body,\n accessToken,\n apikey: this.apikey,\n baseUrl: this.baseUrl,\n fetchImpl: this.fetchImpl,\n })\n }\n\n private initialize(): Promise<void> {\n this.initializePromise ??= this.doInitialize()\n return this.initializePromise\n }\n\n private async doInitialize(): Promise<void> {\n if (this.detectSessionInUrl && typeof window !== 'undefined') {\n const parsed = parseFragment(window.location.hash)\n if (parsed) {\n // Strip tokens from the address bar synchronously, before any await.\n cleanFragmentFromUrl()\n\n if ('authError' in parsed) {\n console.warn(\n `[deepkey] Auth redirect returned an error: ${parsed.authError.error_code ?? parsed.authError.error}`,\n parsed.authError.error_description ?? '',\n )\n } else {\n const { data: user } = await this.request<User>('GET', '/auth/v1/user', undefined, parsed.tokens.access_token)\n if (user) {\n const session: Session = { ...parsed.tokens, token_type: 'bearer', user }\n await this.saveSession(session)\n this.emit('SIGNED_IN', session)\n return\n }\n }\n }\n }\n\n const stored = this.loadStoredSession()\n if (!stored) return\n\n if (this.isExpired(stored)) {\n if (!this.autoRefreshToken) return\n this.session = stored\n const { error } = await this.refreshWithLock()\n if (error && error.code !== 'network_error') this.clearSession()\n return\n }\n\n this.session = stored\n this.startRefreshTimer()\n }\n\n private isExpired(session: Session): boolean {\n return session.expires_at <= Math.floor(Date.now() / 1000) + EXPIRY_MARGIN_SECONDS\n }\n\n private async refreshWithLock(\n refreshToken?: string,\n ): Promise<AuthResponse<{ session: Session | null; user: User | null }>> {\n this.refreshPromise ??= this.doRefresh(refreshToken).finally(() => {\n this.refreshPromise = null\n })\n return this.refreshPromise\n }\n\n private async doRefresh(\n refreshToken?: string,\n ): Promise<AuthResponse<{ session: Session | null; user: User | null }>> {\n const token = refreshToken ?? this.session?.refresh_token\n if (!token) {\n return {\n data: { session: null, user: null },\n error: new AuthError('Auth session missing!', 400, 'session_missing'),\n }\n }\n\n const { data, error } = await this.request<Session>('POST', '/auth/v1/token?grant_type=refresh_token', {\n refresh_token: token,\n })\n\n if (error) {\n // Network failures keep the session (retry next tick); auth failures clear it.\n if (error.code !== 'network_error') {\n this.clearSession()\n this.emit('SIGNED_OUT', null)\n }\n return { data: { session: null, user: null }, error }\n }\n\n if (data) {\n await this.saveSession(data)\n this.emit('TOKEN_REFRESHED', data)\n return { data: { session: data, user: data.user }, error: null }\n }\n return { data: { session: null, user: null }, error: new AuthError('Empty refresh response') }\n }\n\n private async saveSession(session: Session) {\n this.session = session\n if (this.persistSession) {\n try {\n this.storage.setItem(this.storageKey, JSON.stringify(session))\n } catch {\n // Persistence is best-effort (private mode, quota).\n }\n }\n this.startRefreshTimer()\n }\n\n private clearSession() {\n this.session = null\n try {\n this.storage.removeItem(this.storageKey)\n } catch {\n // ignore\n }\n this.stopRefreshTimer()\n }\n\n private loadStoredSession(): Session | null {\n if (!this.persistSession) return null\n try {\n const raw = this.storage.getItem(this.storageKey)\n if (!raw) return null\n const parsed = JSON.parse(raw) as Session\n if (!parsed.access_token || !parsed.refresh_token) return null\n return parsed\n } catch {\n return null\n }\n }\n\n private startRefreshTimer() {\n if (!this.autoRefreshToken || this.refreshTimer || typeof setInterval === 'undefined') return\n this.refreshTimer = setInterval(() => {\n if (this.session && this.isExpired(this.session)) void this.refreshWithLock()\n }, REFRESH_TICK_MS)\n // Do not keep node processes alive because of the timer (no-op in browsers).\n const timer = this.refreshTimer as unknown as { unref?: () => void }\n if (typeof timer === 'object' && typeof timer.unref === 'function') timer.unref()\n }\n\n private stopRefreshTimer() {\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer)\n this.refreshTimer = null\n }\n }\n\n private setupCrossTabSync() {\n if (typeof window === 'undefined' || !this.persistSession) return\n window.addEventListener('storage', event => {\n if (event.key !== this.storageKey) return\n if (!event.newValue) {\n if (this.session) {\n this.session = null\n this.stopRefreshTimer()\n this.emit('SIGNED_OUT', null)\n }\n return\n }\n try {\n const next = JSON.parse(event.newValue) as Session\n const changed = next.access_token !== this.session?.access_token\n this.session = next\n this.startRefreshTimer()\n if (changed) this.emit('TOKEN_REFRESHED', next)\n } catch {\n // ignore malformed writes\n }\n })\n }\n\n private emit(event: AuthChangeEvent, session: Session | null) {\n for (const listener of this.listeners.values()) {\n try {\n listener(event, session)\n } catch (err) {\n console.error('[deepkey] onAuthStateChange listener threw', err)\n }\n }\n }\n}\n\nexport interface AuthClient {\n auth: Auth\n connections: Connections\n}\n\nexport const createAuthClient = (publishableKey: string, options?: AuthClientOptions): AuthClient => {\n const auth = new Auth(publishableKey, options)\n const connections = new Connections(auth, {\n apikey: publishableKey ?? '',\n baseUrl: resolveBaseUrl(options?.__internalBaseUrl),\n fetchImpl: options?.fetch,\n })\n return { auth, connections }\n}\n"],"mappings":"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","names":[]}
package/dist/server.cjs CHANGED
@@ -43,39 +43,74 @@ var AuthError = class extends Error {
43
43
  }
44
44
  };
45
45
 
46
+ // src/fetch.ts
47
+ var request = async (options) => {
48
+ const fetchImpl = options.fetchImpl ?? fetch;
49
+ try {
50
+ const headers = { apikey: options.apikey };
51
+ if (options.body !== void 0) headers["Content-Type"] = "application/json";
52
+ if (options.accessToken) headers.Authorization = `Bearer ${options.accessToken}`;
53
+ const response = await fetchImpl(`${options.baseUrl}${options.path}`, {
54
+ method: options.method,
55
+ headers,
56
+ body: options.body !== void 0 ? JSON.stringify(options.body) : void 0
57
+ });
58
+ if (response.status === 204) return { data: {}, error: null };
59
+ let payload;
60
+ try {
61
+ payload = await response.json();
62
+ } catch {
63
+ payload = null;
64
+ }
65
+ if (!response.ok) {
66
+ const errorBody = payload?.error;
67
+ return {
68
+ data: null,
69
+ error: new AuthError(
70
+ errorBody?.message ?? `Request failed with status ${response.status}`,
71
+ response.status,
72
+ errorBody?.code
73
+ )
74
+ };
75
+ }
76
+ return { data: payload, error: null };
77
+ } catch (err) {
78
+ const message = err instanceof Error ? err.message : "Network request failed";
79
+ return { data: null, error: new AuthError(message, 0, "network_error") };
80
+ }
81
+ };
82
+
46
83
  // src/server.ts
47
84
  var createServerClient = (secretKey, options = {}) => {
48
- const baseUrl = resolveBaseUrl(options.__internalBaseUrl);
49
- const fetchImpl = options.fetch ?? fetch;
85
+ const base = { apikey: secretKey, baseUrl: resolveBaseUrl(options.__internalBaseUrl), fetchImpl: options.fetch };
86
+ const connection = (id) => `/auth/v1/connections/${encodeURIComponent(id)}`;
50
87
  return {
51
88
  auth: {
52
89
  async getUser(jwt) {
53
- try {
54
- const response = await fetchImpl(`${baseUrl}/auth/v1/user`, {
55
- headers: { Authorization: `Bearer ${jwt}`, apikey: secretKey }
56
- });
57
- let payload = null;
58
- try {
59
- payload = await response.json();
60
- } catch {
61
- payload = null;
62
- }
63
- if (!response.ok) {
64
- const errorBody = payload?.error;
65
- return {
66
- data: { user: null },
67
- error: new AuthError(
68
- errorBody?.message ?? `Request failed with status ${response.status}`,
69
- response.status,
70
- errorBody?.code
71
- )
72
- };
73
- }
74
- return { data: { user: payload }, error: null };
75
- } catch (err) {
76
- const message = err instanceof Error ? err.message : "Network request failed";
77
- return { data: { user: null }, error: new AuthError(message, 0, "network_error") };
78
- }
90
+ const { data, error } = await request({ ...base, method: "GET", path: "/auth/v1/user", accessToken: jwt });
91
+ return { data: { user: data }, error };
92
+ }
93
+ },
94
+ connections: {
95
+ async list({ userId }) {
96
+ const { data, error } = await request({
97
+ ...base,
98
+ method: "GET",
99
+ path: `/auth/v1/connections?user_id=${encodeURIComponent(userId)}`
100
+ });
101
+ return { data: { connections: data?.connections ?? [] }, error };
102
+ },
103
+ async issueAccessToken(connectionId) {
104
+ return request({
105
+ ...base,
106
+ method: "POST",
107
+ path: `${connection(connectionId)}/token`,
108
+ body: {}
109
+ });
110
+ },
111
+ async revoke(connectionId) {
112
+ const { error } = await request({ ...base, method: "DELETE", path: connection(connectionId) });
113
+ return { error };
79
114
  }
80
115
  }
81
116
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts","../src/constants.ts","../src/types.ts"],"sourcesContent":["import { resolveBaseUrl } from './constants'\nimport { AuthError, type ServerClientOptions, type User } from './types'\n\nexport interface ServerAuthClient {\n auth: {\n // Mirrors `supabase.auth.getUser(jwt)` server-side: validates the access token\n // against the auth service and returns the user.\n getUser(jwt: string): Promise<{ data: { user: User | null }; error: AuthError | null }>\n }\n}\n\n// Runs anywhere with global fetch (Bun, Node >= 18). `secretKey` is the project's\n// bt_secret_... key. Requests target the hosted DeepKey API; the internal\n// override is reserved for DeepKey's console and tests.\nexport const createServerClient = (secretKey: string, options: ServerClientOptions = {}): ServerAuthClient => {\n const baseUrl = resolveBaseUrl(options.__internalBaseUrl)\n const fetchImpl = options.fetch ?? fetch\n\n return {\n auth: {\n async getUser(jwt: string) {\n try {\n const response = await fetchImpl(`${baseUrl}/auth/v1/user`, {\n headers: { Authorization: `Bearer ${jwt}`, apikey: secretKey },\n })\n\n let payload: unknown = null\n try {\n payload = await response.json()\n } catch {\n payload = null\n }\n\n if (!response.ok) {\n const errorBody = (payload as { error?: { code?: string; message?: string } } | null)?.error\n return {\n data: { user: null },\n error: new AuthError(\n errorBody?.message ?? `Request failed with status ${response.status}`,\n response.status,\n errorBody?.code,\n ),\n }\n }\n\n return { data: { user: payload as User }, error: null }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Network request failed'\n return { data: { user: null }, error: new AuthError(message, 0, 'network_error') }\n }\n },\n },\n }\n}\n\nexport { DEEPKEY_API_URL } from './constants'\nexport { AuthError, type ServerClientOptions, type User } from './types'\n","// The hosted DeepKey API. Every client talks to this origin; only DeepKey's own\n// console and test suites replace it through the internal override.\nexport const DEEPKEY_API_URL = 'https://deepkey.dev/api'\n\n// Resolves the base URL used for every request. An absent or blank internal\n// override keeps the hosted API; a provided value has any trailing slash removed\n// so path joins stay predictable.\nexport const resolveBaseUrl = (url?: string | null): string => {\n const candidate = typeof url === 'string' ? url.trim() : ''\n return (candidate || DEEPKEY_API_URL).replace(/\\/+$/, '')\n}\n","export interface UserIdentity {\n identity_id: string\n id: string\n user_id: string\n provider: string\n identity_data: Record<string, unknown>\n last_sign_in_at: string | null\n created_at: string\n updated_at: string\n}\n\nexport interface User {\n id: string\n aud: string\n role: string\n email: string | null\n email_confirmed_at: string | null\n app_metadata: { provider?: string | null; providers?: string[]; [key: string]: unknown }\n user_metadata: {\n name?: string\n full_name?: string\n avatar_url?: string\n picture?: string\n email?: string\n [key: string]: unknown\n }\n identities?: UserIdentity[]\n created_at: string\n updated_at?: string\n last_sign_in_at?: string | null\n}\n\nexport interface Session {\n access_token: string\n refresh_token: string\n token_type: 'bearer'\n expires_in: number\n expires_at: number\n user: User\n}\n\nexport class AuthError extends Error {\n status?: number\n code?: string\n\n constructor(message: string, status?: number, code?: string) {\n super(message)\n this.name = 'AuthError'\n this.status = status\n this.code = code\n }\n}\n\nexport type AuthChangeEvent = 'INITIAL_SESSION' | 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED'\n\nexport interface Subscription {\n id: string\n unsubscribe: () => void\n}\n\nexport interface StorageAdapter {\n getItem(key: string): string | null\n setItem(key: string, value: string): void\n removeItem(key: string): void\n}\n\nexport interface AuthClientOptions {\n /**\n * @internal Replaces the hosted DeepKey API origin. Used only by DeepKey's own\n * console and test suites; not supported for consumers and stripped from the\n * published type declarations.\n */\n __internalBaseUrl?: string\n storageKey?: string\n autoRefreshToken?: boolean\n detectSessionInUrl?: boolean\n persistSession?: boolean\n storage?: StorageAdapter\n fetch?: typeof fetch\n}\n\nexport interface ServerClientOptions {\n /**\n * @internal Replaces the hosted DeepKey API origin. Used only by DeepKey's own\n * console and test suites; not supported for consumers and stripped from the\n * published type declarations.\n */\n __internalBaseUrl?: string\n fetch?: typeof fetch\n}\n\nexport interface SignInWithOtpCredentials {\n email: string\n options?: {\n emailRedirectTo?: string\n shouldCreateUser?: boolean\n data?: Record<string, unknown>\n }\n}\n\nexport interface VerifyOtpParams {\n email: string\n token: string\n type: 'email' | 'magiclink'\n}\n\nexport interface SignInWithOAuthCredentials {\n provider: string\n options?: {\n redirectTo?: string\n scopes?: string\n queryParams?: Record<string, string>\n skipBrowserRedirect?: boolean\n }\n}\n\nexport interface AuthResponse<T> {\n data: T\n error: AuthError | null\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEO,IAAM,kBAAkB;AAKxB,IAAM,iBAAiB,CAAC,QAAgC;AAC7D,QAAM,YAAY,OAAO,QAAQ,WAAW,IAAI,KAAK,IAAI;AACzD,UAAQ,aAAa,iBAAiB,QAAQ,QAAQ,EAAE;AAC1D;;;AC+BO,IAAM,YAAN,cAAwB,MAAM;AAAA,EAInC,YAAY,SAAiB,QAAiB,MAAe;AAC3D,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AAAA,EACd;AACF;;;AFrCO,IAAM,qBAAqB,CAAC,WAAmB,UAA+B,CAAC,MAAwB;AAC5G,QAAM,UAAU,eAAe,QAAQ,iBAAiB;AACxD,QAAM,YAAY,QAAQ,SAAS;AAEnC,SAAO;AAAA,IACL,MAAM;AAAA,MACJ,MAAM,QAAQ,KAAa;AACzB,YAAI;AACF,gBAAM,WAAW,MAAM,UAAU,GAAG,OAAO,iBAAiB;AAAA,YAC1D,SAAS,EAAE,eAAe,UAAU,GAAG,IAAI,QAAQ,UAAU;AAAA,UAC/D,CAAC;AAED,cAAI,UAAmB;AACvB,cAAI;AACF,sBAAU,MAAM,SAAS,KAAK;AAAA,UAChC,QAAQ;AACN,sBAAU;AAAA,UACZ;AAEA,cAAI,CAAC,SAAS,IAAI;AAChB,kBAAM,YAAa,SAAoE;AACvF,mBAAO;AAAA,cACL,MAAM,EAAE,MAAM,KAAK;AAAA,cACnB,OAAO,IAAI;AAAA,gBACT,WAAW,WAAW,8BAA8B,SAAS,MAAM;AAAA,gBACnE,SAAS;AAAA,gBACT,WAAW;AAAA,cACb;AAAA,YACF;AAAA,UACF;AAEA,iBAAO,EAAE,MAAM,EAAE,MAAM,QAAgB,GAAG,OAAO,KAAK;AAAA,QACxD,SAAS,KAAK;AACZ,gBAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,iBAAO,EAAE,MAAM,EAAE,MAAM,KAAK,GAAG,OAAO,IAAI,UAAU,SAAS,GAAG,eAAe,EAAE;AAAA,QACnF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/server.ts","../src/constants.ts","../src/types.ts","../src/fetch.ts"],"sourcesContent":["import { resolveBaseUrl } from './constants'\nimport { request } from './fetch'\nimport type {\n AuthError,\n AuthResponse,\n ProviderAccessToken,\n ProviderConnection,\n ServerClientOptions,\n User,\n} from './types'\n\nexport interface ServerAuthClient {\n auth: {\n // Mirrors `supabase.auth.getUser(jwt)` server-side: validates the access token\n // against the auth service and returns the user.\n getUser(jwt: string): Promise<AuthResponse<{ user: User | null }>>\n }\n // Provider connections a user granted through the browser SDK. The secret key acts\n // for the whole project; provider access tokens are issued only here, never to browsers.\n connections: {\n list(params: { userId: string }): Promise<AuthResponse<{ connections: ProviderConnection[] }>>\n issueAccessToken(connectionId: string): Promise<AuthResponse<ProviderAccessToken | null>>\n revoke(connectionId: string): Promise<{ error: AuthError | null }>\n }\n}\n\n// Runs anywhere with global fetch (Bun, Node >= 18). `secretKey` is the project's\n// bt_secret_... key. Requests target the hosted DeepKey API; the internal\n// override is reserved for DeepKey's console and tests.\nexport const createServerClient = (secretKey: string, options: ServerClientOptions = {}): ServerAuthClient => {\n const base = { apikey: secretKey, baseUrl: resolveBaseUrl(options.__internalBaseUrl), fetchImpl: options.fetch }\n const connection = (id: string) => `/auth/v1/connections/${encodeURIComponent(id)}`\n\n return {\n auth: {\n async getUser(jwt: string) {\n const { data, error } = await request<User>({ ...base, method: 'GET', path: '/auth/v1/user', accessToken: jwt })\n return { data: { user: data }, error }\n },\n },\n connections: {\n async list({ userId }) {\n const { data, error } = await request<{ connections: ProviderConnection[] }>({\n ...base,\n method: 'GET',\n path: `/auth/v1/connections?user_id=${encodeURIComponent(userId)}`,\n })\n return { data: { connections: data?.connections ?? [] }, error }\n },\n async issueAccessToken(connectionId) {\n return request<ProviderAccessToken>({\n ...base,\n method: 'POST',\n path: `${connection(connectionId)}/token`,\n body: {},\n })\n },\n async revoke(connectionId) {\n const { error } = await request({ ...base, method: 'DELETE', path: connection(connectionId) })\n return { error }\n },\n },\n }\n}\n\nexport { DEEPKEY_API_URL } from './constants'\nexport {\n AuthError,\n type AuthResponse,\n type ProviderAccessToken,\n type ProviderConnection,\n type ServerClientOptions,\n type User,\n} from './types'\n","// The hosted DeepKey API. Every client talks to this origin; only DeepKey's own\n// console and test suites replace it through the internal override.\nexport const DEEPKEY_API_URL = 'https://deepkey.dev/api'\n\n// Resolves the base URL used for every request. An absent or blank internal\n// override keeps the hosted API; a provided value has any trailing slash removed\n// so path joins stay predictable.\nexport const resolveBaseUrl = (url?: string | null): string => {\n const candidate = typeof url === 'string' ? url.trim() : ''\n return (candidate || DEEPKEY_API_URL).replace(/\\/+$/, '')\n}\n","export interface UserIdentity {\n identity_id: string\n id: string\n user_id: string\n provider: string\n identity_data: Record<string, unknown>\n last_sign_in_at: string | null\n created_at: string\n updated_at: string\n}\n\nexport interface User {\n id: string\n aud: string\n role: string\n email: string | null\n email_confirmed_at: string | null\n app_metadata: { provider?: string | null; providers?: string[]; [key: string]: unknown }\n user_metadata: {\n name?: string\n full_name?: string\n avatar_url?: string\n picture?: string\n email?: string\n [key: string]: unknown\n }\n identities?: UserIdentity[]\n created_at: string\n updated_at?: string\n last_sign_in_at?: string | null\n}\n\nexport interface Session {\n access_token: string\n refresh_token: string\n token_type: 'bearer'\n expires_in: number\n expires_at: number\n user: User\n}\n\nexport class AuthError extends Error {\n status?: number\n code?: string\n\n constructor(message: string, status?: number, code?: string) {\n super(message)\n this.name = 'AuthError'\n this.status = status\n this.code = code\n }\n}\n\nexport type AuthChangeEvent = 'INITIAL_SESSION' | 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED'\n\nexport interface Subscription {\n id: string\n unsubscribe: () => void\n}\n\nexport interface StorageAdapter {\n getItem(key: string): string | null\n setItem(key: string, value: string): void\n removeItem(key: string): void\n}\n\nexport interface AuthClientOptions {\n /**\n * @internal Replaces the hosted DeepKey API origin. Used only by DeepKey's own\n * console and test suites; not supported for consumers and stripped from the\n * published type declarations.\n */\n __internalBaseUrl?: string\n storageKey?: string\n autoRefreshToken?: boolean\n detectSessionInUrl?: boolean\n persistSession?: boolean\n storage?: StorageAdapter\n fetch?: typeof fetch\n}\n\nexport interface ServerClientOptions {\n /**\n * @internal Replaces the hosted DeepKey API origin. Used only by DeepKey's own\n * console and test suites; not supported for consumers and stripped from the\n * published type declarations.\n */\n __internalBaseUrl?: string\n fetch?: typeof fetch\n}\n\nexport interface SignInWithOtpCredentials {\n email: string\n options?: {\n emailRedirectTo?: string\n shouldCreateUser?: boolean\n data?: Record<string, unknown>\n }\n}\n\nexport interface VerifyOtpParams {\n email: string\n token: string\n type: 'email' | 'magiclink'\n}\n\nexport interface ConnectProviderCredentials {\n provider: string\n options?: {\n redirectTo?: string\n skipBrowserRedirect?: boolean\n }\n}\n\n// Metadata only: provider tokens never appear in browser responses.\nexport interface ProviderConnection {\n id: string\n // The DeepKey user that granted the connection: the same `user.id` your server gets from getUser(jwt).\n user_id: string\n provider: string\n provider_user_id: string\n identity_data: Record<string, unknown>\n scope: string | null\n status: 'active' | 'reauthorization_required'\n created_at: string\n updated_at: string\n}\n\n// Issued to consumer servers through the secret key; short-lived and refreshed by DeepKey.\nexport interface ProviderAccessToken {\n access_token: string\n token_type: 'bearer'\n expires_at: number | null\n scope: string | null\n}\n\nexport interface SignInWithOAuthCredentials {\n provider: string\n options?: {\n redirectTo?: string\n scopes?: string\n queryParams?: Record<string, string>\n skipBrowserRedirect?: boolean\n }\n}\n\nexport interface AuthResponse<T> {\n data: T\n error: AuthError | null\n}\n","import { AuthError } from './types'\n\nexport interface RequestOptions {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE'\n path: string\n apikey: string\n baseUrl: string\n accessToken?: string\n body?: unknown\n fetchImpl?: typeof fetch\n}\n\nexport interface RequestResult<T> {\n data: T | null\n error: AuthError | null\n}\n\n// All service errors are shaped { error: { code, message } }.\nexport const request = async <T>(options: RequestOptions): Promise<RequestResult<T>> => {\n const fetchImpl = options.fetchImpl ?? fetch\n try {\n const headers: Record<string, string> = { apikey: options.apikey }\n if (options.body !== undefined) headers['Content-Type'] = 'application/json'\n if (options.accessToken) headers.Authorization = `Bearer ${options.accessToken}`\n\n const response = await fetchImpl(`${options.baseUrl}${options.path}`, {\n method: options.method,\n headers,\n body: options.body !== undefined ? JSON.stringify(options.body) : undefined,\n })\n\n if (response.status === 204) return { data: {} as T, error: null }\n\n let payload: unknown\n try {\n payload = await response.json()\n } catch {\n payload = null\n }\n\n if (!response.ok) {\n const errorBody = (payload as { error?: { code?: string; message?: string } } | null)?.error\n return {\n data: null,\n error: new AuthError(\n errorBody?.message ?? `Request failed with status ${response.status}`,\n response.status,\n errorBody?.code,\n ),\n }\n }\n\n return { data: payload as T, error: null }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Network request failed'\n return { data: null, error: new AuthError(message, 0, 'network_error') }\n }\n}\n"],"mappings":"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","names":[]}
package/dist/server.d.cts CHANGED
@@ -1,16 +1,24 @@
1
- import { U as User, f as AuthError, g as ServerClientOptions } from './constants-BQhswdms.cjs';
2
- export { D as DEEPKEY_API_URL } from './constants-BQhswdms.cjs';
1
+ import { A as AuthResponse, U as User, P as ProviderConnection, g as ProviderAccessToken, a as AuthError, h as ServerClientOptions } from './constants-DgChFH24.cjs';
2
+ export { D as DEEPKEY_API_URL } from './constants-DgChFH24.cjs';
3
3
 
4
4
  interface ServerAuthClient {
5
5
  auth: {
6
- getUser(jwt: string): Promise<{
7
- data: {
8
- user: User | null;
9
- };
6
+ getUser(jwt: string): Promise<AuthResponse<{
7
+ user: User | null;
8
+ }>>;
9
+ };
10
+ connections: {
11
+ list(params: {
12
+ userId: string;
13
+ }): Promise<AuthResponse<{
14
+ connections: ProviderConnection[];
15
+ }>>;
16
+ issueAccessToken(connectionId: string): Promise<AuthResponse<ProviderAccessToken | null>>;
17
+ revoke(connectionId: string): Promise<{
10
18
  error: AuthError | null;
11
19
  }>;
12
20
  };
13
21
  }
14
22
  declare const createServerClient: (secretKey: string, options?: ServerClientOptions) => ServerAuthClient;
15
23
 
16
- export { AuthError, type ServerAuthClient, ServerClientOptions, User, createServerClient };
24
+ export { AuthError, AuthResponse, ProviderAccessToken, ProviderConnection, type ServerAuthClient, ServerClientOptions, User, createServerClient };
package/dist/server.d.ts CHANGED
@@ -1,16 +1,24 @@
1
- import { U as User, f as AuthError, g as ServerClientOptions } from './constants-BQhswdms.js';
2
- export { D as DEEPKEY_API_URL } from './constants-BQhswdms.js';
1
+ import { A as AuthResponse, U as User, P as ProviderConnection, g as ProviderAccessToken, a as AuthError, h as ServerClientOptions } from './constants-DgChFH24.js';
2
+ export { D as DEEPKEY_API_URL } from './constants-DgChFH24.js';
3
3
 
4
4
  interface ServerAuthClient {
5
5
  auth: {
6
- getUser(jwt: string): Promise<{
7
- data: {
8
- user: User | null;
9
- };
6
+ getUser(jwt: string): Promise<AuthResponse<{
7
+ user: User | null;
8
+ }>>;
9
+ };
10
+ connections: {
11
+ list(params: {
12
+ userId: string;
13
+ }): Promise<AuthResponse<{
14
+ connections: ProviderConnection[];
15
+ }>>;
16
+ issueAccessToken(connectionId: string): Promise<AuthResponse<ProviderAccessToken | null>>;
17
+ revoke(connectionId: string): Promise<{
10
18
  error: AuthError | null;
11
19
  }>;
12
20
  };
13
21
  }
14
22
  declare const createServerClient: (secretKey: string, options?: ServerClientOptions) => ServerAuthClient;
15
23
 
16
- export { AuthError, type ServerAuthClient, ServerClientOptions, User, createServerClient };
24
+ export { AuthError, AuthResponse, ProviderAccessToken, ProviderConnection, type ServerAuthClient, ServerClientOptions, User, createServerClient };
package/dist/server.js CHANGED
@@ -1,42 +1,41 @@
1
1
  import {
2
2
  AuthError,
3
3
  DEEPKEY_API_URL,
4
+ request,
4
5
  resolveBaseUrl
5
- } from "./chunk-IFNRLMVX.js";
6
+ } from "./chunk-A2CRUXTA.js";
6
7
 
7
8
  // src/server.ts
8
9
  var createServerClient = (secretKey, options = {}) => {
9
- const baseUrl = resolveBaseUrl(options.__internalBaseUrl);
10
- const fetchImpl = options.fetch ?? fetch;
10
+ const base = { apikey: secretKey, baseUrl: resolveBaseUrl(options.__internalBaseUrl), fetchImpl: options.fetch };
11
+ const connection = (id) => `/auth/v1/connections/${encodeURIComponent(id)}`;
11
12
  return {
12
13
  auth: {
13
14
  async getUser(jwt) {
14
- try {
15
- const response = await fetchImpl(`${baseUrl}/auth/v1/user`, {
16
- headers: { Authorization: `Bearer ${jwt}`, apikey: secretKey }
17
- });
18
- let payload = null;
19
- try {
20
- payload = await response.json();
21
- } catch {
22
- payload = null;
23
- }
24
- if (!response.ok) {
25
- const errorBody = payload?.error;
26
- return {
27
- data: { user: null },
28
- error: new AuthError(
29
- errorBody?.message ?? `Request failed with status ${response.status}`,
30
- response.status,
31
- errorBody?.code
32
- )
33
- };
34
- }
35
- return { data: { user: payload }, error: null };
36
- } catch (err) {
37
- const message = err instanceof Error ? err.message : "Network request failed";
38
- return { data: { user: null }, error: new AuthError(message, 0, "network_error") };
39
- }
15
+ const { data, error } = await request({ ...base, method: "GET", path: "/auth/v1/user", accessToken: jwt });
16
+ return { data: { user: data }, error };
17
+ }
18
+ },
19
+ connections: {
20
+ async list({ userId }) {
21
+ const { data, error } = await request({
22
+ ...base,
23
+ method: "GET",
24
+ path: `/auth/v1/connections?user_id=${encodeURIComponent(userId)}`
25
+ });
26
+ return { data: { connections: data?.connections ?? [] }, error };
27
+ },
28
+ async issueAccessToken(connectionId) {
29
+ return request({
30
+ ...base,
31
+ method: "POST",
32
+ path: `${connection(connectionId)}/token`,
33
+ body: {}
34
+ });
35
+ },
36
+ async revoke(connectionId) {
37
+ const { error } = await request({ ...base, method: "DELETE", path: connection(connectionId) });
38
+ return { error };
40
39
  }
41
40
  }
42
41
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import { resolveBaseUrl } from './constants'\nimport { AuthError, type ServerClientOptions, type User } from './types'\n\nexport interface ServerAuthClient {\n auth: {\n // Mirrors `supabase.auth.getUser(jwt)` server-side: validates the access token\n // against the auth service and returns the user.\n getUser(jwt: string): Promise<{ data: { user: User | null }; error: AuthError | null }>\n }\n}\n\n// Runs anywhere with global fetch (Bun, Node >= 18). `secretKey` is the project's\n// bt_secret_... key. Requests target the hosted DeepKey API; the internal\n// override is reserved for DeepKey's console and tests.\nexport const createServerClient = (secretKey: string, options: ServerClientOptions = {}): ServerAuthClient => {\n const baseUrl = resolveBaseUrl(options.__internalBaseUrl)\n const fetchImpl = options.fetch ?? fetch\n\n return {\n auth: {\n async getUser(jwt: string) {\n try {\n const response = await fetchImpl(`${baseUrl}/auth/v1/user`, {\n headers: { Authorization: `Bearer ${jwt}`, apikey: secretKey },\n })\n\n let payload: unknown = null\n try {\n payload = await response.json()\n } catch {\n payload = null\n }\n\n if (!response.ok) {\n const errorBody = (payload as { error?: { code?: string; message?: string } } | null)?.error\n return {\n data: { user: null },\n error: new AuthError(\n errorBody?.message ?? `Request failed with status ${response.status}`,\n response.status,\n errorBody?.code,\n ),\n }\n }\n\n return { data: { user: payload as User }, error: null }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Network request failed'\n return { data: { user: null }, error: new AuthError(message, 0, 'network_error') }\n }\n },\n },\n }\n}\n\nexport { DEEPKEY_API_URL } from './constants'\nexport { AuthError, type ServerClientOptions, type User } from './types'\n"],"mappings":";;;;;;;AAcO,IAAM,qBAAqB,CAAC,WAAmB,UAA+B,CAAC,MAAwB;AAC5G,QAAM,UAAU,eAAe,QAAQ,iBAAiB;AACxD,QAAM,YAAY,QAAQ,SAAS;AAEnC,SAAO;AAAA,IACL,MAAM;AAAA,MACJ,MAAM,QAAQ,KAAa;AACzB,YAAI;AACF,gBAAM,WAAW,MAAM,UAAU,GAAG,OAAO,iBAAiB;AAAA,YAC1D,SAAS,EAAE,eAAe,UAAU,GAAG,IAAI,QAAQ,UAAU;AAAA,UAC/D,CAAC;AAED,cAAI,UAAmB;AACvB,cAAI;AACF,sBAAU,MAAM,SAAS,KAAK;AAAA,UAChC,QAAQ;AACN,sBAAU;AAAA,UACZ;AAEA,cAAI,CAAC,SAAS,IAAI;AAChB,kBAAM,YAAa,SAAoE;AACvF,mBAAO;AAAA,cACL,MAAM,EAAE,MAAM,KAAK;AAAA,cACnB,OAAO,IAAI;AAAA,gBACT,WAAW,WAAW,8BAA8B,SAAS,MAAM;AAAA,gBACnE,SAAS;AAAA,gBACT,WAAW;AAAA,cACb;AAAA,YACF;AAAA,UACF;AAEA,iBAAO,EAAE,MAAM,EAAE,MAAM,QAAgB,GAAG,OAAO,KAAK;AAAA,QACxD,SAAS,KAAK;AACZ,gBAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,iBAAO,EAAE,MAAM,EAAE,MAAM,KAAK,GAAG,OAAO,IAAI,UAAU,SAAS,GAAG,eAAe,EAAE;AAAA,QACnF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import { resolveBaseUrl } from './constants'\nimport { request } from './fetch'\nimport type {\n AuthError,\n AuthResponse,\n ProviderAccessToken,\n ProviderConnection,\n ServerClientOptions,\n User,\n} from './types'\n\nexport interface ServerAuthClient {\n auth: {\n // Mirrors `supabase.auth.getUser(jwt)` server-side: validates the access token\n // against the auth service and returns the user.\n getUser(jwt: string): Promise<AuthResponse<{ user: User | null }>>\n }\n // Provider connections a user granted through the browser SDK. The secret key acts\n // for the whole project; provider access tokens are issued only here, never to browsers.\n connections: {\n list(params: { userId: string }): Promise<AuthResponse<{ connections: ProviderConnection[] }>>\n issueAccessToken(connectionId: string): Promise<AuthResponse<ProviderAccessToken | null>>\n revoke(connectionId: string): Promise<{ error: AuthError | null }>\n }\n}\n\n// Runs anywhere with global fetch (Bun, Node >= 18). `secretKey` is the project's\n// bt_secret_... key. Requests target the hosted DeepKey API; the internal\n// override is reserved for DeepKey's console and tests.\nexport const createServerClient = (secretKey: string, options: ServerClientOptions = {}): ServerAuthClient => {\n const base = { apikey: secretKey, baseUrl: resolveBaseUrl(options.__internalBaseUrl), fetchImpl: options.fetch }\n const connection = (id: string) => `/auth/v1/connections/${encodeURIComponent(id)}`\n\n return {\n auth: {\n async getUser(jwt: string) {\n const { data, error } = await request<User>({ ...base, method: 'GET', path: '/auth/v1/user', accessToken: jwt })\n return { data: { user: data }, error }\n },\n },\n connections: {\n async list({ userId }) {\n const { data, error } = await request<{ connections: ProviderConnection[] }>({\n ...base,\n method: 'GET',\n path: `/auth/v1/connections?user_id=${encodeURIComponent(userId)}`,\n })\n return { data: { connections: data?.connections ?? [] }, error }\n },\n async issueAccessToken(connectionId) {\n return request<ProviderAccessToken>({\n ...base,\n method: 'POST',\n path: `${connection(connectionId)}/token`,\n body: {},\n })\n },\n async revoke(connectionId) {\n const { error } = await request({ ...base, method: 'DELETE', path: connection(connectionId) })\n return { error }\n },\n },\n }\n}\n\nexport { DEEPKEY_API_URL } from './constants'\nexport {\n AuthError,\n type AuthResponse,\n type ProviderAccessToken,\n type ProviderConnection,\n type ServerClientOptions,\n type User,\n} from './types'\n"],"mappings":";;;;;;;;AA6BO,IAAM,qBAAqB,CAAC,WAAmB,UAA+B,CAAC,MAAwB;AAC5G,QAAM,OAAO,EAAE,QAAQ,WAAW,SAAS,eAAe,QAAQ,iBAAiB,GAAG,WAAW,QAAQ,MAAM;AAC/G,QAAM,aAAa,CAAC,OAAe,wBAAwB,mBAAmB,EAAE,CAAC;AAEjF,SAAO;AAAA,IACL,MAAM;AAAA,MACJ,MAAM,QAAQ,KAAa;AACzB,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,QAAc,EAAE,GAAG,MAAM,QAAQ,OAAO,MAAM,iBAAiB,aAAa,IAAI,CAAC;AAC/G,eAAO,EAAE,MAAM,EAAE,MAAM,KAAK,GAAG,MAAM;AAAA,MACvC;AAAA,IACF;AAAA,IACA,aAAa;AAAA,MACX,MAAM,KAAK,EAAE,OAAO,GAAG;AACrB,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,QAA+C;AAAA,UAC3E,GAAG;AAAA,UACH,QAAQ;AAAA,UACR,MAAM,gCAAgC,mBAAmB,MAAM,CAAC;AAAA,QAClE,CAAC;AACD,eAAO,EAAE,MAAM,EAAE,aAAa,MAAM,eAAe,CAAC,EAAE,GAAG,MAAM;AAAA,MACjE;AAAA,MACA,MAAM,iBAAiB,cAAc;AACnC,eAAO,QAA6B;AAAA,UAClC,GAAG;AAAA,UACH,QAAQ;AAAA,UACR,MAAM,GAAG,WAAW,YAAY,CAAC;AAAA,UACjC,MAAM,CAAC;AAAA,QACT,CAAC;AAAA,MACH;AAAA,MACA,MAAM,OAAO,cAAc;AACzB,cAAM,EAAE,MAAM,IAAI,MAAM,QAAQ,EAAE,GAAG,MAAM,QAAQ,UAAU,MAAM,WAAW,YAAY,EAAE,CAAC;AAC7F,eAAO,EAAE,MAAM;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepkey/sdk",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "DeepKey authentication SDK for the browser and server — a supabase-js compatible auth surface",
5
5
  "homepage": "https://deepkey.dev/sdk",
6
6
  "keywords": [
@@ -1,23 +0,0 @@
1
- // src/constants.ts
2
- var DEEPKEY_API_URL = "https://deepkey.dev/api";
3
- var resolveBaseUrl = (url) => {
4
- const candidate = typeof url === "string" ? url.trim() : "";
5
- return (candidate || DEEPKEY_API_URL).replace(/\/+$/, "");
6
- };
7
-
8
- // src/types.ts
9
- var AuthError = class extends Error {
10
- constructor(message, status, code) {
11
- super(message);
12
- this.name = "AuthError";
13
- this.status = status;
14
- this.code = code;
15
- }
16
- };
17
-
18
- export {
19
- DEEPKEY_API_URL,
20
- resolveBaseUrl,
21
- AuthError
22
- };
23
- //# sourceMappingURL=chunk-IFNRLMVX.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/types.ts"],"sourcesContent":["// The hosted DeepKey API. Every client talks to this origin; only DeepKey's own\n// console and test suites replace it through the internal override.\nexport const DEEPKEY_API_URL = 'https://deepkey.dev/api'\n\n// Resolves the base URL used for every request. An absent or blank internal\n// override keeps the hosted API; a provided value has any trailing slash removed\n// so path joins stay predictable.\nexport const resolveBaseUrl = (url?: string | null): string => {\n const candidate = typeof url === 'string' ? url.trim() : ''\n return (candidate || DEEPKEY_API_URL).replace(/\\/+$/, '')\n}\n","export interface UserIdentity {\n identity_id: string\n id: string\n user_id: string\n provider: string\n identity_data: Record<string, unknown>\n last_sign_in_at: string | null\n created_at: string\n updated_at: string\n}\n\nexport interface User {\n id: string\n aud: string\n role: string\n email: string | null\n email_confirmed_at: string | null\n app_metadata: { provider?: string | null; providers?: string[]; [key: string]: unknown }\n user_metadata: {\n name?: string\n full_name?: string\n avatar_url?: string\n picture?: string\n email?: string\n [key: string]: unknown\n }\n identities?: UserIdentity[]\n created_at: string\n updated_at?: string\n last_sign_in_at?: string | null\n}\n\nexport interface Session {\n access_token: string\n refresh_token: string\n token_type: 'bearer'\n expires_in: number\n expires_at: number\n user: User\n}\n\nexport class AuthError extends Error {\n status?: number\n code?: string\n\n constructor(message: string, status?: number, code?: string) {\n super(message)\n this.name = 'AuthError'\n this.status = status\n this.code = code\n }\n}\n\nexport type AuthChangeEvent = 'INITIAL_SESSION' | 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED'\n\nexport interface Subscription {\n id: string\n unsubscribe: () => void\n}\n\nexport interface StorageAdapter {\n getItem(key: string): string | null\n setItem(key: string, value: string): void\n removeItem(key: string): void\n}\n\nexport interface AuthClientOptions {\n /**\n * @internal Replaces the hosted DeepKey API origin. Used only by DeepKey's own\n * console and test suites; not supported for consumers and stripped from the\n * published type declarations.\n */\n __internalBaseUrl?: string\n storageKey?: string\n autoRefreshToken?: boolean\n detectSessionInUrl?: boolean\n persistSession?: boolean\n storage?: StorageAdapter\n fetch?: typeof fetch\n}\n\nexport interface ServerClientOptions {\n /**\n * @internal Replaces the hosted DeepKey API origin. Used only by DeepKey's own\n * console and test suites; not supported for consumers and stripped from the\n * published type declarations.\n */\n __internalBaseUrl?: string\n fetch?: typeof fetch\n}\n\nexport interface SignInWithOtpCredentials {\n email: string\n options?: {\n emailRedirectTo?: string\n shouldCreateUser?: boolean\n data?: Record<string, unknown>\n }\n}\n\nexport interface VerifyOtpParams {\n email: string\n token: string\n type: 'email' | 'magiclink'\n}\n\nexport interface SignInWithOAuthCredentials {\n provider: string\n options?: {\n redirectTo?: string\n scopes?: string\n queryParams?: Record<string, string>\n skipBrowserRedirect?: boolean\n }\n}\n\nexport interface AuthResponse<T> {\n data: T\n error: AuthError | null\n}\n"],"mappings":";AAEO,IAAM,kBAAkB;AAKxB,IAAM,iBAAiB,CAAC,QAAgC;AAC7D,QAAM,YAAY,OAAO,QAAQ,WAAW,IAAI,KAAK,IAAI;AACzD,UAAQ,aAAa,iBAAiB,QAAQ,QAAQ,EAAE;AAC1D;;;AC+BO,IAAM,YAAN,cAAwB,MAAM;AAAA,EAInC,YAAY,SAAiB,QAAiB,MAAe;AAC3D,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AAAA,EACd;AACF;","names":[]}