@ubean/auth 0.1.2 → 0.1.3

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/dist/core.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import { a as AuthState, c as ResolvedAuthOptions, d as UbeanAuthOptions, i as AuthSession, n as AuthClient, o as AuthUser, r as AuthError } from "./types-DlL9lr7A.js";
2
+ import { Context, MiddlewareHandler } from "hono";
3
+ import { BetterAuthOptions } from "better-auth";
4
+ //#region src/core.d.ts
5
+ declare function resolveAuthOptions(options?: UbeanAuthOptions): ResolvedAuthOptions;
6
+ declare function defineAuth(config: UbeanAuthOptions | ((ctx: {
7
+ defaults: BetterAuthOptions;
8
+ }) => UbeanAuthOptions)): UbeanAuthOptions;
9
+ declare function createAuthHandler(options?: UbeanAuthOptions): {
10
+ handler: (request: Request) => Promise<Response>;
11
+ resolveAuth: () => Promise<unknown>;
12
+ getOptions: () => ResolvedAuthOptions;
13
+ };
14
+ declare function authMiddleware(): MiddlewareHandler;
15
+ declare function getUser(): AuthUser | null;
16
+ declare function getSession(): AuthState | null;
17
+ declare function requireAuth(c?: Context): AuthUser;
18
+ declare function createAuthClient(basePath?: string): AuthClient;
19
+ declare function getServerSession(req?: Request): Promise<AuthSession | null>;
20
+ //#endregion
21
+ export { type AuthClient, type AuthError, type AuthSession, type AuthState, type AuthUser, authMiddleware, createAuthClient, createAuthHandler, defineAuth, getServerSession, getSession, getUser, requireAuth, resolveAuthOptions };
package/dist/core.js ADDED
@@ -0,0 +1,520 @@
1
+ import { consola } from "consola";
2
+ import { AsyncLocalStorage } from "node:async_hooks";
3
+ import { defu } from "defu";
4
+ //#region src/core.ts
5
+ const AUTH_CONTEXT_SYMBOL = Symbol.for("ubean.authContext.v1");
6
+ function getAuthAsyncLocalStorage() {
7
+ const g = globalThis;
8
+ if (!g[AUTH_CONTEXT_SYMBOL]) g[AUTH_CONTEXT_SYMBOL] = new AsyncLocalStorage();
9
+ return g[AUTH_CONTEXT_SYMBOL];
10
+ }
11
+ const authContext = getAuthAsyncLocalStorage();
12
+ const authInstance = {
13
+ handler: null,
14
+ api: null,
15
+ options: null
16
+ };
17
+ function resetAuthInstance() {
18
+ authInstance.handler = null;
19
+ authInstance.api = null;
20
+ authInstance.options = null;
21
+ }
22
+ function resolveAuthOptions(options = {}) {
23
+ return defu(options, {
24
+ enabled: true,
25
+ basePath: "/api/auth",
26
+ baseURL: "",
27
+ secret: process.env.BETTER_AUTH_SECRET || process.env.AUTH_SECRET || "ubean-dev-secret-change-me",
28
+ clientOptions: {
29
+ fetchOptions: {},
30
+ plugins: []
31
+ },
32
+ redirectTo: {
33
+ login: "/login",
34
+ signup: "/signup",
35
+ callback: "/"
36
+ },
37
+ session: {
38
+ cookieName: "ubean_session",
39
+ expiresIn: 3600 * 24 * 7,
40
+ updateAge: 3600 * 24
41
+ }
42
+ });
43
+ }
44
+ function defineAuth(config) {
45
+ if (typeof config === "function") return config({ defaults: {
46
+ basePath: "/api/auth",
47
+ emailAndPassword: { enabled: true }
48
+ } });
49
+ return config;
50
+ }
51
+ function createFallbackAuth(resolved) {
52
+ consola.warn("[auth] better-auth not installed, using minimal fallback auth implementation");
53
+ consola.warn("[auth] Install better-auth with: pnpm add better-auth");
54
+ const users = /* @__PURE__ */ new Map();
55
+ const sessions = /* @__PURE__ */ new Map();
56
+ function generateId() {
57
+ return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
58
+ }
59
+ function hashPassword(password) {
60
+ return Buffer.from(password).toString("base64");
61
+ }
62
+ function createSession(userId) {
63
+ const token = generateId();
64
+ const expiresAt = new Date(Date.now() + resolved.session.expiresIn * 1e3);
65
+ sessions.set(token, {
66
+ userId,
67
+ token,
68
+ expiresAt
69
+ });
70
+ return {
71
+ token,
72
+ expiresAt
73
+ };
74
+ }
75
+ function findSessionByToken(token) {
76
+ if (!token) return null;
77
+ const session = sessions.get(token);
78
+ if (!session) return null;
79
+ if (session.expiresAt < /* @__PURE__ */ new Date()) {
80
+ sessions.delete(token);
81
+ return null;
82
+ }
83
+ return session;
84
+ }
85
+ const fallbackHandler = async (request) => {
86
+ const path = new URL(request.url).pathname.replace(resolved.basePath, "");
87
+ const method = request.method;
88
+ const setSessionCookie = (token, expiresAt) => {
89
+ const headers = new Headers({ "content-type": "application/json" });
90
+ if (token) headers.append("set-cookie", `${resolved.session.cookieName}=${token}; Path=/; HttpOnly; SameSite=Lax; Expires=${expiresAt?.toUTCString()}`);
91
+ else headers.append("set-cookie", `${resolved.session.cookieName}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`);
92
+ return headers;
93
+ };
94
+ const getTokenFromCookie = (req) => {
95
+ return (req.headers.get("cookie") || "").match(new RegExp(`${resolved.session.cookieName}=([^;]+)`))?.[1];
96
+ };
97
+ try {
98
+ if (path === "/sign-up/email" && method === "POST") {
99
+ const { email, password, name } = await request.json().catch(() => ({}));
100
+ if (!email || !password) return new Response(JSON.stringify({ error: "Email and password required" }), {
101
+ status: 400,
102
+ headers: { "content-type": "application/json" }
103
+ });
104
+ for (const [, u] of users) if (u.email === email) return new Response(JSON.stringify({ error: "User already exists" }), {
105
+ status: 400,
106
+ headers: { "content-type": "application/json" }
107
+ });
108
+ const id = generateId();
109
+ users.set(id, {
110
+ id,
111
+ email,
112
+ password: hashPassword(password),
113
+ name: name || email.split("@")[0],
114
+ createdAt: /* @__PURE__ */ new Date()
115
+ });
116
+ const { token, expiresAt } = createSession(id);
117
+ const user = users.get(id);
118
+ return new Response(JSON.stringify({
119
+ token,
120
+ user: {
121
+ id: user.id,
122
+ email: user.email,
123
+ name: user.name,
124
+ emailVerified: false,
125
+ createdAt: user.createdAt,
126
+ updatedAt: user.createdAt
127
+ }
128
+ }), {
129
+ status: 200,
130
+ headers: setSessionCookie(token, expiresAt)
131
+ });
132
+ }
133
+ if (path === "/sign-in/email" && method === "POST") {
134
+ const { email, password } = await request.json().catch(() => ({}));
135
+ let foundUser = null;
136
+ for (const [, u] of users) if (u.email === email && u.password === hashPassword(password)) {
137
+ foundUser = u;
138
+ break;
139
+ }
140
+ if (!foundUser) return new Response(JSON.stringify({ error: "Invalid credentials" }), {
141
+ status: 401,
142
+ headers: { "content-type": "application/json" }
143
+ });
144
+ const { token, expiresAt } = createSession(foundUser.id);
145
+ return new Response(JSON.stringify({
146
+ token,
147
+ user: {
148
+ id: foundUser.id,
149
+ email: foundUser.email,
150
+ name: foundUser.name,
151
+ emailVerified: false,
152
+ createdAt: foundUser.createdAt,
153
+ updatedAt: foundUser.createdAt
154
+ }
155
+ }), {
156
+ status: 200,
157
+ headers: setSessionCookie(token, expiresAt)
158
+ });
159
+ }
160
+ if (path === "/sign-out" && method === "POST") {
161
+ const token = getTokenFromCookie(request);
162
+ if (token) sessions.delete(token);
163
+ return new Response(JSON.stringify({ success: true }), {
164
+ status: 200,
165
+ headers: setSessionCookie(null)
166
+ });
167
+ }
168
+ if (path === "/get-session" && method === "GET") {
169
+ const session = findSessionByToken(getTokenFromCookie(request));
170
+ if (!session) return new Response(JSON.stringify(null), {
171
+ status: 200,
172
+ headers: { "content-type": "application/json" }
173
+ });
174
+ const u = users.get(session.userId);
175
+ return new Response(JSON.stringify({
176
+ session: {
177
+ id: session.token,
178
+ userId: u.id,
179
+ token: session.token,
180
+ expiresAt: session.expiresAt,
181
+ createdAt: /* @__PURE__ */ new Date(),
182
+ updatedAt: /* @__PURE__ */ new Date()
183
+ },
184
+ user: {
185
+ id: u.id,
186
+ email: u.email,
187
+ name: u.name,
188
+ emailVerified: false,
189
+ createdAt: u.createdAt,
190
+ updatedAt: u.createdAt
191
+ }
192
+ }), {
193
+ status: 200,
194
+ headers: { "content-type": "application/json" }
195
+ });
196
+ }
197
+ return new Response(JSON.stringify({ error: "Not found" }), {
198
+ status: 404,
199
+ headers: { "content-type": "application/json" }
200
+ });
201
+ } catch {
202
+ return new Response(JSON.stringify({ error: "Internal error" }), {
203
+ status: 500,
204
+ headers: { "content-type": "application/json" }
205
+ });
206
+ }
207
+ };
208
+ authInstance.handler = fallbackHandler;
209
+ authInstance.api = { getSession: (async (headersInput) => {
210
+ const session = findSessionByToken(((headersInput instanceof Headers ? headersInput : new Headers(headersInput)).get("cookie") || "").match(new RegExp(`${resolved.session.cookieName}=([^;]+)`))?.[1]);
211
+ if (!session) return null;
212
+ const u = users.get(session.userId);
213
+ if (!u) return null;
214
+ return {
215
+ session: {
216
+ id: session.token,
217
+ userId: u.id,
218
+ token: session.token,
219
+ expiresAt: session.expiresAt,
220
+ createdAt: /* @__PURE__ */ new Date(),
221
+ updatedAt: /* @__PURE__ */ new Date()
222
+ },
223
+ user: {
224
+ id: u.id,
225
+ email: u.email,
226
+ name: u.name,
227
+ emailVerified: false,
228
+ createdAt: u.createdAt,
229
+ updatedAt: u.createdAt
230
+ }
231
+ };
232
+ }) };
233
+ return {
234
+ handler: fallbackHandler,
235
+ api: authInstance.api
236
+ };
237
+ }
238
+ function createAuthHandler(options = {}) {
239
+ const resolved = resolveAuthOptions(options);
240
+ resetAuthInstance();
241
+ authInstance.options = resolved;
242
+ const hasBetterAuthConfig = !!(resolved.betterAuth && Object.keys(resolved.betterAuth).length > 0) || !!resolved.database;
243
+ async function initBetterAuth() {
244
+ if (!hasBetterAuthConfig) return createFallbackAuth(resolved);
245
+ try {
246
+ const { betterAuth } = await import("better-auth");
247
+ const defaults = {
248
+ baseURL: resolved.baseURL || void 0,
249
+ basePath: resolved.basePath,
250
+ secret: resolved.secret,
251
+ trustedOrigins: resolved.baseURL ? [resolved.baseURL] : [],
252
+ database: resolved.database,
253
+ session: {
254
+ expiresIn: resolved.session.expiresIn,
255
+ updateAge: resolved.session.updateAge
256
+ },
257
+ emailAndPassword: { enabled: true }
258
+ };
259
+ let betterAuthOpts;
260
+ if (typeof options.betterAuth === "function") betterAuthOpts = options.betterAuth({ defaults });
261
+ else betterAuthOpts = defu(options.betterAuth, defaults);
262
+ const auth = betterAuth(betterAuthOpts);
263
+ authInstance.handler = auth.handler;
264
+ authInstance.api = auth.api;
265
+ return auth;
266
+ } catch {
267
+ return createFallbackAuth(resolved);
268
+ }
269
+ }
270
+ let initPromise = null;
271
+ async function resolveAuth() {
272
+ if (!initPromise) initPromise = initBetterAuth();
273
+ return initPromise;
274
+ }
275
+ async function handler(request) {
276
+ await resolveAuth();
277
+ if (authInstance.handler) return authInstance.handler(request);
278
+ return new Response(JSON.stringify({ error: "Auth handler not initialized" }), {
279
+ status: 500,
280
+ headers: { "content-type": "application/json" }
281
+ });
282
+ }
283
+ return {
284
+ handler,
285
+ resolveAuth,
286
+ getOptions: () => resolved
287
+ };
288
+ }
289
+ function authMiddleware() {
290
+ return async (c, next) => {
291
+ const opts = authInstance.options || resolveAuthOptions();
292
+ try {
293
+ const request = c.req.raw;
294
+ const sessionCookieMatch = (request.headers.get("cookie") || "").match(new RegExp(`${opts.session.cookieName}=([^;]+)`));
295
+ const bearerMatch = (request.headers.get("authorization") || "").match(/^Bearer\s+(.+)$/i);
296
+ const token = sessionCookieMatch?.[1] || bearerMatch?.[1];
297
+ let user = null;
298
+ let session = null;
299
+ await (authInstance.handler ? Promise.resolve() : Promise.resolve(createAuthHandler(opts)).then(({ resolveAuth }) => resolveAuth()));
300
+ if (authInstance.api?.getSession && token) try {
301
+ const headers = new Headers({ cookie: `${opts.session.cookieName}=${token}` });
302
+ const result = await authInstance.api.getSession(headers);
303
+ if (result) {
304
+ session = result.session;
305
+ user = result.user;
306
+ }
307
+ } catch {}
308
+ if (user) c.set("user", user);
309
+ if (session) c.set("session", session);
310
+ await authContext.run({
311
+ user,
312
+ session
313
+ }, next);
314
+ } catch {
315
+ await next();
316
+ }
317
+ };
318
+ }
319
+ function getUser() {
320
+ return authContext.getStore()?.user ?? null;
321
+ }
322
+ function getSession() {
323
+ const store = authContext.getStore();
324
+ if (!store?.user || !store?.session) return null;
325
+ return {
326
+ user: store.user,
327
+ session: store.session
328
+ };
329
+ }
330
+ function requireAuth(c) {
331
+ if (c) {
332
+ const user = c.get("user");
333
+ if (!user) {
334
+ const err = /* @__PURE__ */ new Error("Unauthorized");
335
+ err.status = 401;
336
+ throw err;
337
+ }
338
+ return user;
339
+ }
340
+ const user = getUser();
341
+ if (!user) {
342
+ const err = /* @__PURE__ */ new Error("Unauthorized");
343
+ err.status = 401;
344
+ throw err;
345
+ }
346
+ return user;
347
+ }
348
+ function createAuthClient(basePath = "/api/auth") {
349
+ async function authFetch(path, init) {
350
+ const res = await fetch(`${basePath}${path}`, {
351
+ credentials: "include",
352
+ headers: {
353
+ "content-type": "application/json",
354
+ ...init?.headers
355
+ },
356
+ ...init
357
+ });
358
+ if (!res.ok) throw await res.json().catch(() => ({ message: res.statusText }));
359
+ return await res.json().catch(() => null);
360
+ }
361
+ function buildFetchOptions(body) {
362
+ return {
363
+ method: "POST",
364
+ body: body ? JSON.stringify(body) : void 0
365
+ };
366
+ }
367
+ return {
368
+ signIn: {
369
+ email: async ({ email, password, callbackURL, rememberMe }) => {
370
+ try {
371
+ const data = await authFetch("/sign-in/email", buildFetchOptions({
372
+ email,
373
+ password,
374
+ rememberMe
375
+ }));
376
+ if (callbackURL && typeof window !== "undefined") window.location.href = callbackURL;
377
+ return { data };
378
+ } catch (error) {
379
+ return { error };
380
+ }
381
+ },
382
+ social: (provider, opts) => {
383
+ if (typeof window === "undefined") return Promise.resolve();
384
+ const redirect = opts?.callbackURL || window.location.href;
385
+ window.location.href = `${basePath}/sign-in/social/${provider}?callbackURL=${encodeURIComponent(redirect)}`;
386
+ return Promise.resolve();
387
+ }
388
+ },
389
+ signUp: { email: async ({ email, password, name, callbackURL }) => {
390
+ try {
391
+ const data = await authFetch("/sign-up/email", buildFetchOptions({
392
+ email,
393
+ password,
394
+ name
395
+ }));
396
+ if (callbackURL && typeof window !== "undefined") window.location.href = callbackURL;
397
+ return { data };
398
+ } catch (error) {
399
+ return { error };
400
+ }
401
+ } },
402
+ signOut: async () => {
403
+ try {
404
+ return { data: await authFetch("/sign-out", buildFetchOptions()) };
405
+ } catch (error) {
406
+ return { error };
407
+ }
408
+ },
409
+ getSession: async () => {
410
+ try {
411
+ return await authFetch("/get-session");
412
+ } catch {
413
+ return null;
414
+ }
415
+ },
416
+ sendVerificationEmail: async (email, opts) => {
417
+ try {
418
+ return { data: await authFetch("/send-verification-email", buildFetchOptions({
419
+ email,
420
+ ...opts
421
+ })) };
422
+ } catch (error) {
423
+ return { error };
424
+ }
425
+ },
426
+ resetPassword: async (newPassword, token) => {
427
+ try {
428
+ return { data: await authFetch("/reset-password", buildFetchOptions({
429
+ newPassword,
430
+ token
431
+ })) };
432
+ } catch (error) {
433
+ return { error };
434
+ }
435
+ },
436
+ forgetPassword: async (email, opts) => {
437
+ try {
438
+ return { data: await authFetch("/forget-password", buildFetchOptions({
439
+ email,
440
+ ...opts
441
+ })) };
442
+ } catch (error) {
443
+ return { error };
444
+ }
445
+ },
446
+ updateUser: async (data) => {
447
+ try {
448
+ return { data: (await authFetch("/update-user", buildFetchOptions(data))).user };
449
+ } catch (error) {
450
+ return { error };
451
+ }
452
+ },
453
+ changeEmail: async (newEmail, callbackURL) => {
454
+ try {
455
+ return { data: await authFetch("/change-email", buildFetchOptions({
456
+ newEmail,
457
+ callbackURL
458
+ })) };
459
+ } catch (error) {
460
+ return { error };
461
+ }
462
+ },
463
+ changePassword: async (currentPassword, newPassword, revokeOtherSessions) => {
464
+ try {
465
+ return { data: await authFetch("/change-password", buildFetchOptions({
466
+ currentPassword,
467
+ newPassword,
468
+ revokeOtherSessions
469
+ })) };
470
+ } catch (error) {
471
+ return { error };
472
+ }
473
+ },
474
+ listSessions: async () => {
475
+ try {
476
+ return { data: (await authFetch("/list-sessions")).sessions };
477
+ } catch (error) {
478
+ return { error };
479
+ }
480
+ },
481
+ revokeSession: async (sessionId) => {
482
+ try {
483
+ return { data: await authFetch("/revoke-session", buildFetchOptions({ sessionId })) };
484
+ } catch (error) {
485
+ return { error };
486
+ }
487
+ },
488
+ revokeSessions: async () => {
489
+ try {
490
+ return { data: await authFetch("/revoke-sessions", buildFetchOptions()) };
491
+ } catch (error) {
492
+ return { error };
493
+ }
494
+ },
495
+ $fetch: (input, init) => fetch(input, {
496
+ credentials: "include",
497
+ ...init
498
+ })
499
+ };
500
+ }
501
+ async function getServerSession(req) {
502
+ if (!authInstance.handler) createAuthHandler();
503
+ await new Promise((resolve) => {
504
+ if (authInstance.handler) resolve();
505
+ else setTimeout(() => resolve(), 100);
506
+ });
507
+ const current = authContext.getStore();
508
+ if (current?.user && current?.session) return {
509
+ session: current.session,
510
+ user: current.user
511
+ };
512
+ if (req && authInstance.api?.getSession) try {
513
+ return await authInstance.api.getSession(req.headers);
514
+ } catch {
515
+ return null;
516
+ }
517
+ return null;
518
+ }
519
+ //#endregion
520
+ export { authMiddleware, createAuthClient, createAuthHandler, defineAuth, getServerSession, getSession, getUser, requireAuth, resolveAuthOptions };
@@ -0,0 +1,5 @@
1
+ import { a as AuthState, c as ResolvedAuthOptions, d as UbeanAuthOptions, f as UseAuthReturn, i as AuthSession, l as Session, m as Verification, n as AuthClient, o as AuthUser, p as User, r as AuthError, s as BetterAuthOptions, t as Account, u as SocialProviderConfig } from "./types-DlL9lr7A.js";
2
+ import { authMiddleware, createAuthClient, createAuthHandler, defineAuth, getServerSession, getSession, getUser, requireAuth, resolveAuthOptions } from "./core.js";
3
+ import ubeanAuthPlugin, { defineAuthConfig } from "./vite.js";
4
+ import { getSessionFromHeaders, protectRoute, useAuth, useSession } from "./runtime.js";
5
+ export { type Account, type AuthClient, type AuthError, type AuthSession, type AuthState, type AuthUser, type BetterAuthOptions as BetterAuthConfig, type BetterAuthOptions, type ResolvedAuthOptions, type Session, type SocialProviderConfig, type UbeanAuthOptions, type UseAuthReturn, type User, type Verification, authMiddleware, createAuthClient, createAuthHandler, defineAuth, defineAuthConfig, getSession as getAuthSession, getServerSession, getSessionFromHeaders, getUser, protectRoute, requireAuth, resolveAuthOptions, ubeanAuthPlugin, useAuth, useSession };
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import { authMiddleware, createAuthClient, createAuthHandler, defineAuth, getServerSession, getSession, getUser, requireAuth, resolveAuthOptions } from "./core.js";
2
+ import ubeanAuthPlugin, { defineAuthConfig } from "./vite.js";
3
+ import { getSessionFromHeaders, protectRoute, useAuth, useSession } from "./runtime.js";
4
+ export { authMiddleware, createAuthClient, createAuthHandler, defineAuth, defineAuthConfig, getSession as getAuthSession, getServerSession, getSessionFromHeaders, getUser, protectRoute, requireAuth, resolveAuthOptions, ubeanAuthPlugin, useAuth, useSession };
@@ -0,0 +1,62 @@
1
+ import { f as UseAuthReturn, i as AuthSession, n as AuthClient, p as User, r as AuthError } from "./types-DlL9lr7A.js";
2
+ import { createAuthClient } from "./core.js";
3
+ //#region src/runtime.d.ts
4
+ declare function useAuth(basePath?: string): UseAuthReturn;
5
+ declare function useSession(basePath?: string): {
6
+ data: import("vue").Ref<{
7
+ session: {
8
+ id: string;
9
+ createdAt: Date;
10
+ updatedAt: Date;
11
+ userId: string;
12
+ expiresAt: Date;
13
+ token: string;
14
+ ipAddress?: string | null | undefined;
15
+ userAgent?: string | null | undefined;
16
+ };
17
+ user: {
18
+ id: string;
19
+ createdAt: Date;
20
+ updatedAt: Date;
21
+ email: string;
22
+ emailVerified: boolean;
23
+ name: string;
24
+ image?: string | null | undefined;
25
+ };
26
+ } | null, AuthSession | {
27
+ session: {
28
+ id: string;
29
+ createdAt: Date;
30
+ updatedAt: Date;
31
+ userId: string;
32
+ expiresAt: Date;
33
+ token: string;
34
+ ipAddress?: string | null | undefined;
35
+ userAgent?: string | null | undefined;
36
+ };
37
+ user: {
38
+ id: string;
39
+ createdAt: Date;
40
+ updatedAt: Date;
41
+ email: string;
42
+ emailVerified: boolean;
43
+ name: string;
44
+ image?: string | null | undefined;
45
+ };
46
+ } | null>;
47
+ isPending: import("vue").Ref<boolean, boolean>;
48
+ error: import("vue").Ref<{
49
+ message: string;
50
+ code?: string | undefined;
51
+ statusCode?: number | undefined;
52
+ } | null, AuthError | {
53
+ message: string;
54
+ code?: string | undefined;
55
+ statusCode?: number | undefined;
56
+ } | null>;
57
+ refetch: () => Promise<void>;
58
+ };
59
+ declare function getSessionFromHeaders(headers: Headers, basePath?: string): Promise<AuthSession | null>;
60
+ declare function protectRoute(redirectTo?: string): void;
61
+ //#endregion
62
+ export { type AuthClient, type AuthError, type AuthSession, type UseAuthReturn, type User, createAuthClient, getSessionFromHeaders, protectRoute, useAuth, useSession };
@@ -0,0 +1,155 @@
1
+ import { createAuthClient } from "./core.js";
2
+ import { computed, onMounted, ref } from "vue";
3
+ //#region src/runtime.ts
4
+ function useAuth(basePath = "/api/auth") {
5
+ const client = createAuthClient(basePath);
6
+ const session = ref(null);
7
+ const isLoading = ref(false);
8
+ const isPending = ref(true);
9
+ const error = ref(null);
10
+ const user = computed(() => session.value?.user || null);
11
+ const isAuthenticated = computed(() => !!session.value?.user);
12
+ async function fetchSession() {
13
+ if (typeof window === "undefined") return;
14
+ isLoading.value = true;
15
+ isPending.value = true;
16
+ error.value = null;
17
+ try {
18
+ const result = await client.getSession();
19
+ session.value = result;
20
+ } catch (err) {
21
+ session.value = null;
22
+ error.value = err;
23
+ } finally {
24
+ isLoading.value = false;
25
+ isPending.value = false;
26
+ }
27
+ }
28
+ const signIn = {
29
+ email: async ({ email, password, callbackURL }) => {
30
+ isLoading.value = true;
31
+ try {
32
+ const result = await client.signIn.email({
33
+ email,
34
+ password,
35
+ callbackURL
36
+ });
37
+ if (result.data) {
38
+ session.value = result.data;
39
+ if (callbackURL && typeof window !== "undefined") window.location.href = callbackURL;
40
+ }
41
+ if (result.error) error.value = result.error;
42
+ return result;
43
+ } finally {
44
+ isLoading.value = false;
45
+ }
46
+ },
47
+ social: (provider, opts) => {
48
+ return client.signIn.social(provider, opts);
49
+ }
50
+ };
51
+ const signUp = { email: async ({ email, password, name, callbackURL }) => {
52
+ isLoading.value = true;
53
+ try {
54
+ const result = await client.signUp.email({
55
+ email,
56
+ password,
57
+ name,
58
+ callbackURL
59
+ });
60
+ if (result.data) {
61
+ session.value = result.data;
62
+ if (callbackURL && typeof window !== "undefined") window.location.href = callbackURL;
63
+ }
64
+ if (result.error) error.value = result.error;
65
+ return result;
66
+ } finally {
67
+ isLoading.value = false;
68
+ }
69
+ } };
70
+ async function signOut() {
71
+ isLoading.value = true;
72
+ try {
73
+ const result = await client.signOut();
74
+ session.value = null;
75
+ return result;
76
+ } finally {
77
+ isLoading.value = false;
78
+ }
79
+ }
80
+ async function refreshSession() {
81
+ await fetchSession();
82
+ }
83
+ onMounted(() => {
84
+ fetchSession();
85
+ if (typeof window !== "undefined") {
86
+ window.addEventListener("focus", fetchSession);
87
+ document.addEventListener("visibilitychange", () => {
88
+ if (document.visibilityState === "visible") fetchSession();
89
+ });
90
+ }
91
+ });
92
+ return {
93
+ session,
94
+ user,
95
+ isLoading,
96
+ isPending,
97
+ isAuthenticated,
98
+ error,
99
+ signIn,
100
+ signUp,
101
+ signOut,
102
+ getSession: client.getSession,
103
+ updateUser: client.updateUser,
104
+ refreshSession
105
+ };
106
+ }
107
+ function useSession(basePath = "/api/auth") {
108
+ const data = ref(null);
109
+ const isPending = ref(true);
110
+ const error = ref(null);
111
+ const client = createAuthClient(basePath);
112
+ const refetch = async () => {
113
+ isPending.value = true;
114
+ error.value = null;
115
+ try {
116
+ data.value = await client.getSession();
117
+ } catch (err) {
118
+ data.value = null;
119
+ error.value = err;
120
+ } finally {
121
+ isPending.value = false;
122
+ }
123
+ };
124
+ onMounted(refetch);
125
+ if (typeof window !== "undefined") {
126
+ window.addEventListener("focus", refetch);
127
+ document.addEventListener("visibilitychange", () => {
128
+ if (document.visibilityState === "visible") refetch();
129
+ });
130
+ }
131
+ return {
132
+ data,
133
+ isPending,
134
+ error,
135
+ refetch
136
+ };
137
+ }
138
+ function getSessionFromHeaders(headers, basePath = "/api/auth") {
139
+ return fetch(`${basePath}/get-session`, {
140
+ headers: { cookie: headers.get("cookie") || "" },
141
+ credentials: "include"
142
+ }).then((r) => r.json()).then((data) => {
143
+ if (data?.session && data?.user) return data;
144
+ return null;
145
+ }).catch(() => null);
146
+ }
147
+ function protectRoute(redirectTo = "/login") {
148
+ const auth = useAuth();
149
+ if (typeof window !== "undefined" && !auth.isPending.value && !auth.isAuthenticated.value) {
150
+ const redirectUrl = `${redirectTo}?redirect=${encodeURIComponent(window.location.pathname)}`;
151
+ window.location.href = redirectUrl;
152
+ }
153
+ }
154
+ //#endregion
155
+ export { createAuthClient, getSessionFromHeaders, protectRoute, useAuth, useSession };
@@ -0,0 +1,220 @@
1
+ import { Account, BetterAuthOptions as BetterAuthOptions$1, Session, User, Verification } from "better-auth";
2
+ //#region src/types.d.ts
3
+ interface AuthUser {
4
+ id: string;
5
+ email: string;
6
+ emailVerified: boolean;
7
+ name: string;
8
+ image?: string | null;
9
+ createdAt: string | Date;
10
+ updatedAt: string | Date;
11
+ [key: string]: unknown;
12
+ }
13
+ interface AuthState {
14
+ session: Session;
15
+ user: AuthUser;
16
+ }
17
+ interface UbeanAuthOptions {
18
+ enabled?: boolean;
19
+ basePath?: string;
20
+ baseURL?: string;
21
+ secret?: string;
22
+ betterAuth?: Omit<BetterAuthOptions$1, 'baseURL' | 'basePath' | 'trustedOrigins'> | ((ctx: {
23
+ defaults: BetterAuthOptions$1;
24
+ }) => BetterAuthOptions$1);
25
+ clientOptions?: {
26
+ fetchOptions?: Record<string, unknown>;
27
+ plugins?: Array<{
28
+ id: string;
29
+ [key: string]: unknown;
30
+ }>;
31
+ };
32
+ redirectTo?: {
33
+ login?: string;
34
+ signup?: string;
35
+ callback?: string;
36
+ };
37
+ session?: {
38
+ cookieName?: string;
39
+ expiresIn?: number;
40
+ updateAge?: number;
41
+ };
42
+ socialProviders?: Record<string, SocialProviderConfig>;
43
+ database?: BetterAuthOptions$1['database'];
44
+ }
45
+ interface SocialProviderConfig {
46
+ clientId: string;
47
+ clientSecret: string;
48
+ redirectURI?: string;
49
+ [key: string]: unknown;
50
+ }
51
+ interface ResolvedAuthOptions extends Required<Omit<UbeanAuthOptions, 'betterAuth' | 'socialProviders' | 'database'>> {
52
+ enabled: boolean;
53
+ basePath: string;
54
+ baseURL: string;
55
+ secret: string;
56
+ clientOptions: {
57
+ fetchOptions: Record<string, unknown>;
58
+ plugins: Array<{
59
+ id: string;
60
+ [key: string]: unknown;
61
+ }>;
62
+ };
63
+ redirectTo: {
64
+ login: string;
65
+ signup: string;
66
+ callback: string;
67
+ };
68
+ session: {
69
+ cookieName: string;
70
+ expiresIn: number;
71
+ updateAge: number;
72
+ };
73
+ betterAuth?: BetterAuthOptions$1;
74
+ database?: BetterAuthOptions$1['database'];
75
+ socialProviders?: Record<string, SocialProviderConfig>;
76
+ }
77
+ interface AuthSession {
78
+ session: Session;
79
+ user: User;
80
+ }
81
+ interface AuthClient {
82
+ signIn: {
83
+ email: (credentials: {
84
+ email: string;
85
+ password: string;
86
+ callbackURL?: string;
87
+ rememberMe?: boolean;
88
+ }) => Promise<{
89
+ data?: AuthSession;
90
+ error?: AuthError;
91
+ }>;
92
+ social: (provider: string, opts?: {
93
+ callbackURL?: string;
94
+ }) => Promise<void>;
95
+ };
96
+ signUp: {
97
+ email: (credentials: {
98
+ email: string;
99
+ password: string;
100
+ name: string;
101
+ callbackURL?: string;
102
+ }) => Promise<{
103
+ data?: AuthSession;
104
+ error?: AuthError;
105
+ }>;
106
+ };
107
+ signOut: () => Promise<{
108
+ data?: {
109
+ success: boolean;
110
+ };
111
+ error?: AuthError;
112
+ }>;
113
+ getSession: () => Promise<AuthSession | null>;
114
+ sendVerificationEmail: (email: string, opts?: {
115
+ callbackURL?: string;
116
+ }) => Promise<{
117
+ data?: {
118
+ status: boolean;
119
+ };
120
+ error?: AuthError;
121
+ }>;
122
+ resetPassword: (newPassword: string, token: string) => Promise<{
123
+ data?: {
124
+ status: boolean;
125
+ };
126
+ error?: AuthError;
127
+ }>;
128
+ forgetPassword: (email: string, opts?: {
129
+ redirectTo?: string;
130
+ }) => Promise<{
131
+ data?: {
132
+ status: boolean;
133
+ };
134
+ error?: AuthError;
135
+ }>;
136
+ updateUser: (data: Partial<User> & {
137
+ currentPassword?: string;
138
+ newPassword?: string;
139
+ }) => Promise<{
140
+ data?: User;
141
+ error?: AuthError;
142
+ }>;
143
+ changeEmail: (newEmail: string, callbackURL?: string) => Promise<{
144
+ data?: {
145
+ status: boolean;
146
+ };
147
+ error?: AuthError;
148
+ }>;
149
+ changePassword: (currentPassword: string, newPassword: string, revokeOtherSessions?: boolean) => Promise<{
150
+ data?: {
151
+ status: boolean;
152
+ };
153
+ error?: AuthError;
154
+ }>;
155
+ listSessions: () => Promise<{
156
+ data?: Session[];
157
+ error?: AuthError;
158
+ }>;
159
+ revokeSession: (sessionId: string) => Promise<{
160
+ data?: {
161
+ status: boolean;
162
+ };
163
+ error?: AuthError;
164
+ }>;
165
+ revokeSessions: () => Promise<{
166
+ data?: {
167
+ status: boolean;
168
+ };
169
+ error?: AuthError;
170
+ }>;
171
+ $fetch: typeof fetch;
172
+ }
173
+ interface AuthError {
174
+ message: string;
175
+ code?: string;
176
+ statusCode?: number;
177
+ }
178
+ interface UseAuthReturn {
179
+ session: import('vue').Ref<AuthSession | null>;
180
+ user: import('vue').ComputedRef<User | null>;
181
+ isLoading: import('vue').Ref<boolean>;
182
+ isPending: import('vue').Ref<boolean>;
183
+ isAuthenticated: import('vue').ComputedRef<boolean>;
184
+ error: import('vue').Ref<AuthError | null>;
185
+ signIn: {
186
+ email: (credentials: {
187
+ email: string;
188
+ password: string;
189
+ callbackURL?: string;
190
+ }) => Promise<{
191
+ data?: AuthSession;
192
+ error?: AuthError;
193
+ }>;
194
+ social: (provider: string, opts?: {
195
+ callbackURL?: string;
196
+ }) => Promise<void>;
197
+ };
198
+ signUp: {
199
+ email: (credentials: {
200
+ email: string;
201
+ password: string;
202
+ name: string;
203
+ callbackURL?: string;
204
+ }) => Promise<{
205
+ data?: AuthSession;
206
+ error?: AuthError;
207
+ }>;
208
+ };
209
+ signOut: () => Promise<{
210
+ data?: {
211
+ success: boolean;
212
+ };
213
+ error?: AuthError;
214
+ }>;
215
+ getSession: () => Promise<AuthSession | null>;
216
+ updateUser: AuthClient['updateUser'];
217
+ refreshSession: () => Promise<void>;
218
+ }
219
+ //#endregion
220
+ export { AuthState as a, ResolvedAuthOptions as c, UbeanAuthOptions as d, UseAuthReturn as f, AuthSession as i, Session as l, Verification as m, AuthClient as n, AuthUser as o, User as p, AuthError as r, BetterAuthOptions$1 as s, Account as t, SocialProviderConfig as u };
package/dist/vite.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { d as UbeanAuthOptions } from "./types-DlL9lr7A.js";
2
+ import { Plugin } from "vite";
3
+ //#region src/vite.d.ts
4
+ declare function ubeanAuthPlugin(userOptions?: UbeanAuthOptions): Plugin;
5
+ declare function defineAuthConfig(options: UbeanAuthOptions): UbeanAuthOptions;
6
+ //#endregion
7
+ export { ubeanAuthPlugin as default, ubeanAuthPlugin, defineAuthConfig };
package/dist/vite.js ADDED
@@ -0,0 +1,155 @@
1
+ import { resolveAuthOptions } from "./core.js";
2
+ import { consola } from "consola";
3
+ //#region src/vite.ts
4
+ const VIRTUAL_AUTH_CLIENT_ID = "virtual:ubean-auth/client";
5
+ const RESOLVED_VIRTUAL_AUTH_CLIENT_ID = `\0${VIRTUAL_AUTH_CLIENT_ID}`;
6
+ const VIRTUAL_AUTH_SERVER_ID = "virtual:ubean-auth/server";
7
+ const RESOLVED_VIRTUAL_AUTH_SERVER_ID = `\0${VIRTUAL_AUTH_SERVER_ID}`;
8
+ function ubeanAuthPlugin(userOptions = {}) {
9
+ const options = resolveAuthOptions(userOptions);
10
+ let authHandlerInstance = null;
11
+ return {
12
+ name: "ubean:auth",
13
+ enforce: "pre",
14
+ resolveId(id) {
15
+ if (id === VIRTUAL_AUTH_CLIENT_ID) return RESOLVED_VIRTUAL_AUTH_CLIENT_ID;
16
+ if (id === VIRTUAL_AUTH_SERVER_ID) return RESOLVED_VIRTUAL_AUTH_SERVER_ID;
17
+ return null;
18
+ },
19
+ load(id) {
20
+ if (id === RESOLVED_VIRTUAL_AUTH_CLIENT_ID) return generateClientCode(options);
21
+ if (id === RESOLVED_VIRTUAL_AUTH_SERVER_ID) return generateServerCode(options);
22
+ return null;
23
+ },
24
+ configureServer(server) {
25
+ if (!options.enabled) return;
26
+ server.middlewares.use((req, res, next) => {
27
+ const url = req.url || "";
28
+ if (!url.startsWith(options.basePath)) return next();
29
+ Promise.resolve().then(async () => {
30
+ if (!authHandlerInstance) {
31
+ const { createAuthHandler } = await import("./core.js");
32
+ authHandlerInstance = createAuthHandler(userOptions);
33
+ await authHandlerInstance.resolveAuth();
34
+ }
35
+ const fullUrl = `${server.config.server.https ? "https" : "http"}://${req.headers.host || "localhost"}${url}`;
36
+ const request = new Request(fullUrl, {
37
+ method: req.method,
38
+ headers: new Headers(req.headers),
39
+ body: req.method !== "GET" && req.method !== "HEAD" ? req : void 0,
40
+ duplex: "half"
41
+ });
42
+ const response = await authHandlerInstance.handler(request);
43
+ res.statusCode = response.status;
44
+ response.headers.forEach((value, key) => {
45
+ res.setHeader(key, value);
46
+ });
47
+ const text = await response.text();
48
+ res.end(text);
49
+ }).catch((error) => {
50
+ consola.error("[auth] Error handling auth request:", error);
51
+ res.statusCode = 500;
52
+ res.end(JSON.stringify({ error: "Internal auth error" }));
53
+ });
54
+ });
55
+ consola.success(`[auth] Better Auth routes mounted at ${options.basePath}/*`);
56
+ }
57
+ };
58
+ }
59
+ function generateClientCode(options) {
60
+ return `
61
+ const BASE_URL = ${JSON.stringify(options.basePath)};
62
+
63
+ async function authFetch(path, init = {}) {
64
+ const res = await fetch(BASE_URL + path, {
65
+ credentials: 'include',
66
+ headers: { 'content-type': 'application/json', ...(init.headers || {}) },
67
+ ...init
68
+ });
69
+ if (!res.ok) {
70
+ let err = { message: res.statusText };
71
+ try { err = await res.json(); } catch (_) {}
72
+ throw err;
73
+ }
74
+ return res.json().catch(() => null);
75
+ }
76
+
77
+ function buildBody(body) {
78
+ return { method: 'POST', body: body ? JSON.stringify(body) : undefined };
79
+ }
80
+
81
+ export const authClient = {
82
+ signIn: {
83
+ email: async ({ email, password, callbackURL, rememberMe }) => {
84
+ try {
85
+ const data = await authFetch('/sign-in/email', buildBody({ email, password, rememberMe }));
86
+ if (callbackURL && typeof window !== 'undefined') window.location.href = callbackURL;
87
+ return { data };
88
+ } catch (error) { return { error }; }
89
+ },
90
+ social: (provider, opts) => {
91
+ if (typeof window === 'undefined') return Promise.resolve();
92
+ const redirect = opts?.callbackURL || window.location.href;
93
+ window.location.href = BASE_URL + '/sign-in/social/' + provider + '?callbackURL=' + encodeURIComponent(redirect);
94
+ return Promise.resolve();
95
+ }
96
+ },
97
+ signUp: {
98
+ email: async ({ email, password, name, callbackURL }) => {
99
+ try {
100
+ const data = await authFetch('/sign-up/email', buildBody({ email, password, name }));
101
+ if (callbackURL && typeof window !== 'undefined') window.location.href = callbackURL;
102
+ return { data };
103
+ } catch (error) { return { error }; }
104
+ }
105
+ },
106
+ signOut: async () => {
107
+ try { const data = await authFetch('/sign-out', buildBody()); return { data }; }
108
+ catch (error) { return { error }; }
109
+ },
110
+ getSession: async () => {
111
+ try { return await authFetch('/get-session'); } catch (_) { return null; }
112
+ },
113
+ forgetPassword: async (email, opts) => {
114
+ try { const data = await authFetch('/forget-password', buildBody({ email, ...opts })); return { data }; }
115
+ catch (error) { return { error }; }
116
+ },
117
+ resetPassword: async (newPassword, token) => {
118
+ try { const data = await authFetch('/reset-password', buildBody({ newPassword, token })); return { data }; }
119
+ catch (error) { return { error }; }
120
+ },
121
+ updateUser: async (data) => {
122
+ try { const r = await authFetch('/update-user', buildBody(data)); return { data: r.user }; }
123
+ catch (error) { return { error }; }
124
+ },
125
+ changePassword: async (currentPassword, newPassword, revokeOtherSessions) => {
126
+ try { const data = await authFetch('/change-password', buildBody({ currentPassword, newPassword, revokeOtherSessions })); return { data }; }
127
+ catch (error) { return { error }; }
128
+ },
129
+ listSessions: async () => {
130
+ try { const d = await authFetch('/list-sessions'); return { data: d.sessions }; }
131
+ catch (error) { return { error }; }
132
+ },
133
+ revokeSession: async (sessionId) => {
134
+ try { const data = await authFetch('/revoke-session', buildBody({ sessionId })); return { data }; }
135
+ catch (error) { return { error }; }
136
+ },
137
+ revokeSessions: async () => {
138
+ try { const data = await authFetch('/revoke-sessions', buildBody()); return { data }; }
139
+ catch (error) { return { error }; }
140
+ },
141
+ $fetch: (input, init) => fetch(input, { credentials: 'include', ...init })
142
+ };
143
+ export default authClient;
144
+ `;
145
+ }
146
+ function generateServerCode(_options) {
147
+ return `
148
+ export { createAuthHandler, authMiddleware, getUser, getSession, requireAuth, getServerSession, defineAuth } from '@ubean/auth/core';
149
+ `;
150
+ }
151
+ function defineAuthConfig(options) {
152
+ return options;
153
+ }
154
+ //#endregion
155
+ export { ubeanAuthPlugin as default, ubeanAuthPlugin, defineAuthConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ubean/auth",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Better Auth integration for ubean framework",
5
5
  "files": [
6
6
  "dist"