@deepkey/sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +294 -0
- package/dist/chunk-IFNRLMVX.js +23 -0
- package/dist/chunk-IFNRLMVX.js.map +1 -0
- package/dist/constants-BQhswdms.d.cts +98 -0
- package/dist/constants-BQhswdms.d.ts +98 -0
- package/dist/index.cjs +430 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +72 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.js +396 -0
- package/dist/index.js.map +1 -0
- package/dist/server.cjs +83 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +16 -0
- package/dist/server.d.ts +16 -0
- package/dist/server.js +49 -0
- package/dist/server.js.map +1 -0
- package/package.json +48 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AuthError,
|
|
3
|
+
DEEPKEY_API_URL,
|
|
4
|
+
resolveBaseUrl
|
|
5
|
+
} from "./chunk-IFNRLMVX.js";
|
|
6
|
+
|
|
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;
|
|
25
|
+
}
|
|
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
|
+
};
|
|
36
|
+
}
|
|
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
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// src/storage.ts
|
|
45
|
+
var MemoryStorage = class {
|
|
46
|
+
constructor() {
|
|
47
|
+
this.store = /* @__PURE__ */ new Map();
|
|
48
|
+
}
|
|
49
|
+
getItem(key) {
|
|
50
|
+
return this.store.get(key) ?? null;
|
|
51
|
+
}
|
|
52
|
+
setItem(key, value) {
|
|
53
|
+
this.store.set(key, value);
|
|
54
|
+
}
|
|
55
|
+
removeItem(key) {
|
|
56
|
+
this.store.delete(key);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var defaultStorage = () => {
|
|
60
|
+
try {
|
|
61
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
62
|
+
const probe = "__bt_auth_probe__";
|
|
63
|
+
window.localStorage.setItem(probe, "1");
|
|
64
|
+
window.localStorage.removeItem(probe);
|
|
65
|
+
return window.localStorage;
|
|
66
|
+
}
|
|
67
|
+
} catch {
|
|
68
|
+
}
|
|
69
|
+
return new MemoryStorage();
|
|
70
|
+
};
|
|
71
|
+
var deriveStorageKey = (publishableKey) => {
|
|
72
|
+
const match = publishableKey?.match(/^bt_pub_([a-z0-9-]+)_[A-Za-z0-9_-]+$/);
|
|
73
|
+
return match ? `bt-${match[1]}-auth-token` : "bt-auth-token";
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// src/url.ts
|
|
77
|
+
var parseFragment = (hash) => {
|
|
78
|
+
if (!hash || hash.length < 2) return null;
|
|
79
|
+
const params = new URLSearchParams(hash.startsWith("#") ? hash.slice(1) : hash);
|
|
80
|
+
const error = params.get("error");
|
|
81
|
+
if (error) {
|
|
82
|
+
return {
|
|
83
|
+
authError: {
|
|
84
|
+
error,
|
|
85
|
+
error_code: params.get("error_code") ?? void 0,
|
|
86
|
+
error_description: params.get("error_description") ?? void 0
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const accessToken = params.get("access_token");
|
|
91
|
+
const refreshToken = params.get("refresh_token");
|
|
92
|
+
if (!accessToken || !refreshToken) return null;
|
|
93
|
+
const expiresIn = Number(params.get("expires_in") ?? 3600);
|
|
94
|
+
const expiresAt = Number(params.get("expires_at") ?? Math.floor(Date.now() / 1e3) + expiresIn);
|
|
95
|
+
return {
|
|
96
|
+
tokens: {
|
|
97
|
+
access_token: accessToken,
|
|
98
|
+
refresh_token: refreshToken,
|
|
99
|
+
expires_in: expiresIn,
|
|
100
|
+
expires_at: expiresAt,
|
|
101
|
+
token_type: "bearer",
|
|
102
|
+
type: params.get("type") ?? void 0
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
var cleanFragmentFromUrl = () => {
|
|
107
|
+
if (typeof window === "undefined" || typeof history === "undefined") return;
|
|
108
|
+
history.replaceState(null, "", window.location.pathname + window.location.search);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// src/client.ts
|
|
112
|
+
var REFRESH_TICK_MS = 3e4;
|
|
113
|
+
var EXPIRY_MARGIN_SECONDS = 90;
|
|
114
|
+
var Auth = class {
|
|
115
|
+
constructor(publishableKey, options = {}) {
|
|
116
|
+
this.session = null;
|
|
117
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
118
|
+
this.listenerSeq = 0;
|
|
119
|
+
this.initializePromise = null;
|
|
120
|
+
this.refreshPromise = null;
|
|
121
|
+
this.refreshTimer = null;
|
|
122
|
+
this.baseUrl = resolveBaseUrl(options.__internalBaseUrl);
|
|
123
|
+
this.apikey = publishableKey ?? "";
|
|
124
|
+
this.persistSession = options.persistSession ?? true;
|
|
125
|
+
this.autoRefreshToken = options.autoRefreshToken ?? true;
|
|
126
|
+
this.detectSessionInUrl = options.detectSessionInUrl ?? true;
|
|
127
|
+
this.storage = options.storage ?? defaultStorage();
|
|
128
|
+
this.storageKey = options.storageKey ?? deriveStorageKey(publishableKey);
|
|
129
|
+
this.fetchImpl = options.fetch;
|
|
130
|
+
this.setupCrossTabSync();
|
|
131
|
+
}
|
|
132
|
+
// ---- public API (supabase-js compatible) ----
|
|
133
|
+
async signInWithOtp(credentials) {
|
|
134
|
+
const { error } = await this.request("POST", "/auth/v1/otp", {
|
|
135
|
+
email: credentials.email,
|
|
136
|
+
create_user: credentials.options?.shouldCreateUser,
|
|
137
|
+
redirect_to: credentials.options?.emailRedirectTo
|
|
138
|
+
});
|
|
139
|
+
return { data: { user: null, session: null }, error };
|
|
140
|
+
}
|
|
141
|
+
async verifyOtp(params) {
|
|
142
|
+
const { data, error } = await this.request("POST", "/auth/v1/verify", {
|
|
143
|
+
type: "email",
|
|
144
|
+
email: params.email,
|
|
145
|
+
token: params.token
|
|
146
|
+
});
|
|
147
|
+
if (error || !data) return { data: { user: null, session: null }, error };
|
|
148
|
+
await this.saveSession(data);
|
|
149
|
+
this.emit("SIGNED_IN", data);
|
|
150
|
+
return { data: { user: data.user, session: data }, error: null };
|
|
151
|
+
}
|
|
152
|
+
async signInWithOAuth(credentials) {
|
|
153
|
+
const url = new URL(`${this.baseUrl}/auth/v1/authorize`);
|
|
154
|
+
url.searchParams.set("provider", credentials.provider);
|
|
155
|
+
url.searchParams.set("apikey", this.apikey);
|
|
156
|
+
if (credentials.options?.redirectTo) url.searchParams.set("redirect_to", credentials.options.redirectTo);
|
|
157
|
+
if (credentials.options?.scopes) url.searchParams.set("scopes", credentials.options.scopes);
|
|
158
|
+
for (const [key, value] of Object.entries(credentials.options?.queryParams ?? {})) {
|
|
159
|
+
url.searchParams.set(key, value);
|
|
160
|
+
}
|
|
161
|
+
if (!credentials.options?.skipBrowserRedirect && typeof window !== "undefined") {
|
|
162
|
+
window.location.assign(url.toString());
|
|
163
|
+
}
|
|
164
|
+
return { data: { provider: credentials.provider, url: url.toString() }, error: null };
|
|
165
|
+
}
|
|
166
|
+
onAuthStateChange(callback) {
|
|
167
|
+
const id = `listener-${++this.listenerSeq}`;
|
|
168
|
+
this.listeners.set(id, callback);
|
|
169
|
+
this.initialize().then(() => {
|
|
170
|
+
if (this.listeners.has(id)) callback("INITIAL_SESSION", this.session);
|
|
171
|
+
});
|
|
172
|
+
return {
|
|
173
|
+
data: {
|
|
174
|
+
subscription: {
|
|
175
|
+
id,
|
|
176
|
+
unsubscribe: () => {
|
|
177
|
+
this.listeners.delete(id);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
async signOut() {
|
|
184
|
+
await this.initialize();
|
|
185
|
+
const session = this.session;
|
|
186
|
+
if (session) {
|
|
187
|
+
await this.request("POST", "/auth/v1/logout", {}, session.access_token);
|
|
188
|
+
}
|
|
189
|
+
this.clearSession();
|
|
190
|
+
this.emit("SIGNED_OUT", null);
|
|
191
|
+
return { error: null };
|
|
192
|
+
}
|
|
193
|
+
async getSession() {
|
|
194
|
+
await this.initialize();
|
|
195
|
+
if (this.session && this.isExpired(this.session) && this.autoRefreshToken) {
|
|
196
|
+
const { error } = await this.refreshWithLock();
|
|
197
|
+
if (error && error.code !== "network_error") {
|
|
198
|
+
return { data: { session: null }, error: null };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return { data: { session: this.session }, error: null };
|
|
202
|
+
}
|
|
203
|
+
async getUser(jwt) {
|
|
204
|
+
let token = jwt;
|
|
205
|
+
if (!token) {
|
|
206
|
+
const {
|
|
207
|
+
data: { session }
|
|
208
|
+
} = await this.getSession();
|
|
209
|
+
token = session?.access_token;
|
|
210
|
+
}
|
|
211
|
+
if (!token) {
|
|
212
|
+
return { data: { user: null }, error: new AuthError("Auth session missing!", 400, "session_missing") };
|
|
213
|
+
}
|
|
214
|
+
const { data, error } = await this.request("GET", "/auth/v1/user", void 0, token);
|
|
215
|
+
return { data: { user: data }, error };
|
|
216
|
+
}
|
|
217
|
+
async refreshSession(currentSession) {
|
|
218
|
+
await this.initialize();
|
|
219
|
+
const refreshToken = currentSession?.refresh_token ?? this.session?.refresh_token;
|
|
220
|
+
if (!refreshToken) {
|
|
221
|
+
return {
|
|
222
|
+
data: { session: null, user: null },
|
|
223
|
+
error: new AuthError("Auth session missing!", 400, "session_missing")
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
return this.refreshWithLock(refreshToken);
|
|
227
|
+
}
|
|
228
|
+
// ---- internals ----
|
|
229
|
+
async request(method, path, body, accessToken) {
|
|
230
|
+
return request({
|
|
231
|
+
method,
|
|
232
|
+
path,
|
|
233
|
+
body,
|
|
234
|
+
accessToken,
|
|
235
|
+
apikey: this.apikey,
|
|
236
|
+
baseUrl: this.baseUrl,
|
|
237
|
+
fetchImpl: this.fetchImpl
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
initialize() {
|
|
241
|
+
this.initializePromise ?? (this.initializePromise = this.doInitialize());
|
|
242
|
+
return this.initializePromise;
|
|
243
|
+
}
|
|
244
|
+
async doInitialize() {
|
|
245
|
+
if (this.detectSessionInUrl && typeof window !== "undefined") {
|
|
246
|
+
const parsed = parseFragment(window.location.hash);
|
|
247
|
+
if (parsed) {
|
|
248
|
+
cleanFragmentFromUrl();
|
|
249
|
+
if ("authError" in parsed) {
|
|
250
|
+
console.warn(
|
|
251
|
+
`[deepkey] Auth redirect returned an error: ${parsed.authError.error_code ?? parsed.authError.error}`,
|
|
252
|
+
parsed.authError.error_description ?? ""
|
|
253
|
+
);
|
|
254
|
+
} else {
|
|
255
|
+
const { data: user } = await this.request("GET", "/auth/v1/user", void 0, parsed.tokens.access_token);
|
|
256
|
+
if (user) {
|
|
257
|
+
const session = { ...parsed.tokens, token_type: "bearer", user };
|
|
258
|
+
await this.saveSession(session);
|
|
259
|
+
this.emit("SIGNED_IN", session);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const stored = this.loadStoredSession();
|
|
266
|
+
if (!stored) return;
|
|
267
|
+
if (this.isExpired(stored)) {
|
|
268
|
+
if (!this.autoRefreshToken) return;
|
|
269
|
+
this.session = stored;
|
|
270
|
+
const { error } = await this.refreshWithLock();
|
|
271
|
+
if (error && error.code !== "network_error") this.clearSession();
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
this.session = stored;
|
|
275
|
+
this.startRefreshTimer();
|
|
276
|
+
}
|
|
277
|
+
isExpired(session) {
|
|
278
|
+
return session.expires_at <= Math.floor(Date.now() / 1e3) + EXPIRY_MARGIN_SECONDS;
|
|
279
|
+
}
|
|
280
|
+
async refreshWithLock(refreshToken) {
|
|
281
|
+
this.refreshPromise ?? (this.refreshPromise = this.doRefresh(refreshToken).finally(() => {
|
|
282
|
+
this.refreshPromise = null;
|
|
283
|
+
}));
|
|
284
|
+
return this.refreshPromise;
|
|
285
|
+
}
|
|
286
|
+
async doRefresh(refreshToken) {
|
|
287
|
+
const token = refreshToken ?? this.session?.refresh_token;
|
|
288
|
+
if (!token) {
|
|
289
|
+
return {
|
|
290
|
+
data: { session: null, user: null },
|
|
291
|
+
error: new AuthError("Auth session missing!", 400, "session_missing")
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
const { data, error } = await this.request("POST", "/auth/v1/token?grant_type=refresh_token", {
|
|
295
|
+
refresh_token: token
|
|
296
|
+
});
|
|
297
|
+
if (error) {
|
|
298
|
+
if (error.code !== "network_error") {
|
|
299
|
+
this.clearSession();
|
|
300
|
+
this.emit("SIGNED_OUT", null);
|
|
301
|
+
}
|
|
302
|
+
return { data: { session: null, user: null }, error };
|
|
303
|
+
}
|
|
304
|
+
if (data) {
|
|
305
|
+
await this.saveSession(data);
|
|
306
|
+
this.emit("TOKEN_REFRESHED", data);
|
|
307
|
+
return { data: { session: data, user: data.user }, error: null };
|
|
308
|
+
}
|
|
309
|
+
return { data: { session: null, user: null }, error: new AuthError("Empty refresh response") };
|
|
310
|
+
}
|
|
311
|
+
async saveSession(session) {
|
|
312
|
+
this.session = session;
|
|
313
|
+
if (this.persistSession) {
|
|
314
|
+
try {
|
|
315
|
+
this.storage.setItem(this.storageKey, JSON.stringify(session));
|
|
316
|
+
} catch {
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
this.startRefreshTimer();
|
|
320
|
+
}
|
|
321
|
+
clearSession() {
|
|
322
|
+
this.session = null;
|
|
323
|
+
try {
|
|
324
|
+
this.storage.removeItem(this.storageKey);
|
|
325
|
+
} catch {
|
|
326
|
+
}
|
|
327
|
+
this.stopRefreshTimer();
|
|
328
|
+
}
|
|
329
|
+
loadStoredSession() {
|
|
330
|
+
if (!this.persistSession) return null;
|
|
331
|
+
try {
|
|
332
|
+
const raw = this.storage.getItem(this.storageKey);
|
|
333
|
+
if (!raw) return null;
|
|
334
|
+
const parsed = JSON.parse(raw);
|
|
335
|
+
if (!parsed.access_token || !parsed.refresh_token) return null;
|
|
336
|
+
return parsed;
|
|
337
|
+
} catch {
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
startRefreshTimer() {
|
|
342
|
+
if (!this.autoRefreshToken || this.refreshTimer || typeof setInterval === "undefined") return;
|
|
343
|
+
this.refreshTimer = setInterval(() => {
|
|
344
|
+
if (this.session && this.isExpired(this.session)) void this.refreshWithLock();
|
|
345
|
+
}, REFRESH_TICK_MS);
|
|
346
|
+
const timer = this.refreshTimer;
|
|
347
|
+
if (typeof timer === "object" && typeof timer.unref === "function") timer.unref();
|
|
348
|
+
}
|
|
349
|
+
stopRefreshTimer() {
|
|
350
|
+
if (this.refreshTimer) {
|
|
351
|
+
clearInterval(this.refreshTimer);
|
|
352
|
+
this.refreshTimer = null;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
setupCrossTabSync() {
|
|
356
|
+
if (typeof window === "undefined" || !this.persistSession) return;
|
|
357
|
+
window.addEventListener("storage", (event) => {
|
|
358
|
+
if (event.key !== this.storageKey) return;
|
|
359
|
+
if (!event.newValue) {
|
|
360
|
+
if (this.session) {
|
|
361
|
+
this.session = null;
|
|
362
|
+
this.stopRefreshTimer();
|
|
363
|
+
this.emit("SIGNED_OUT", null);
|
|
364
|
+
}
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
try {
|
|
368
|
+
const next = JSON.parse(event.newValue);
|
|
369
|
+
const changed = next.access_token !== this.session?.access_token;
|
|
370
|
+
this.session = next;
|
|
371
|
+
this.startRefreshTimer();
|
|
372
|
+
if (changed) this.emit("TOKEN_REFRESHED", next);
|
|
373
|
+
} catch {
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
emit(event, session) {
|
|
378
|
+
for (const listener of this.listeners.values()) {
|
|
379
|
+
try {
|
|
380
|
+
listener(event, session);
|
|
381
|
+
} catch (err) {
|
|
382
|
+
console.error("[deepkey] onAuthStateChange listener threw", err);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
var createAuthClient = (publishableKey, options) => {
|
|
388
|
+
return { auth: new Auth(publishableKey, options) };
|
|
389
|
+
};
|
|
390
|
+
export {
|
|
391
|
+
Auth,
|
|
392
|
+
AuthError,
|
|
393
|
+
DEEPKEY_API_URL,
|
|
394
|
+
createAuthClient
|
|
395
|
+
};
|
|
396
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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":[]}
|
package/dist/server.cjs
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/server.ts
|
|
21
|
+
var server_exports = {};
|
|
22
|
+
__export(server_exports, {
|
|
23
|
+
AuthError: () => AuthError,
|
|
24
|
+
DEEPKEY_API_URL: () => DEEPKEY_API_URL,
|
|
25
|
+
createServerClient: () => createServerClient
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(server_exports);
|
|
28
|
+
|
|
29
|
+
// src/constants.ts
|
|
30
|
+
var DEEPKEY_API_URL = "https://deepkey.dev/api";
|
|
31
|
+
var resolveBaseUrl = (url) => {
|
|
32
|
+
const candidate = typeof url === "string" ? url.trim() : "";
|
|
33
|
+
return (candidate || DEEPKEY_API_URL).replace(/\/+$/, "");
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// src/types.ts
|
|
37
|
+
var AuthError = class extends Error {
|
|
38
|
+
constructor(message, status, code) {
|
|
39
|
+
super(message);
|
|
40
|
+
this.name = "AuthError";
|
|
41
|
+
this.status = status;
|
|
42
|
+
this.code = code;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// src/server.ts
|
|
47
|
+
var createServerClient = (secretKey, options = {}) => {
|
|
48
|
+
const baseUrl = resolveBaseUrl(options.__internalBaseUrl);
|
|
49
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
50
|
+
return {
|
|
51
|
+
auth: {
|
|
52
|
+
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
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=server.cjs.map
|
|
@@ -0,0 +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":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
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';
|
|
3
|
+
|
|
4
|
+
interface ServerAuthClient {
|
|
5
|
+
auth: {
|
|
6
|
+
getUser(jwt: string): Promise<{
|
|
7
|
+
data: {
|
|
8
|
+
user: User | null;
|
|
9
|
+
};
|
|
10
|
+
error: AuthError | null;
|
|
11
|
+
}>;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
declare const createServerClient: (secretKey: string, options?: ServerClientOptions) => ServerAuthClient;
|
|
15
|
+
|
|
16
|
+
export { AuthError, type ServerAuthClient, ServerClientOptions, User, createServerClient };
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
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';
|
|
3
|
+
|
|
4
|
+
interface ServerAuthClient {
|
|
5
|
+
auth: {
|
|
6
|
+
getUser(jwt: string): Promise<{
|
|
7
|
+
data: {
|
|
8
|
+
user: User | null;
|
|
9
|
+
};
|
|
10
|
+
error: AuthError | null;
|
|
11
|
+
}>;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
declare const createServerClient: (secretKey: string, options?: ServerClientOptions) => ServerAuthClient;
|
|
15
|
+
|
|
16
|
+
export { AuthError, type ServerAuthClient, ServerClientOptions, User, createServerClient };
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AuthError,
|
|
3
|
+
DEEPKEY_API_URL,
|
|
4
|
+
resolveBaseUrl
|
|
5
|
+
} from "./chunk-IFNRLMVX.js";
|
|
6
|
+
|
|
7
|
+
// src/server.ts
|
|
8
|
+
var createServerClient = (secretKey, options = {}) => {
|
|
9
|
+
const baseUrl = resolveBaseUrl(options.__internalBaseUrl);
|
|
10
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
11
|
+
return {
|
|
12
|
+
auth: {
|
|
13
|
+
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
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export {
|
|
45
|
+
AuthError,
|
|
46
|
+
DEEPKEY_API_URL,
|
|
47
|
+
createServerClient
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +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":[]}
|