abckit 0.0.17 → 0.0.19
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/runtime/composables/useAuth.d.ts +11 -29
- package/dist/runtime/composables/useAuth.js +59 -54
- package/dist/runtime/middleware/auth.global.js +1 -1
- package/dist/runtime/plugins/capacitor-client.d.ts +14 -0
- package/dist/runtime/plugins/capacitor-client.js +220 -0
- package/package.json +1 -1
- package/dist/runtime/composables/useAuthMobile.d.ts +0 -871
- package/dist/runtime/composables/useAuthMobile.js +0 -23
|
@@ -1,15 +1,6 @@
|
|
|
1
|
-
declare let capacitorTokenHandlers: {
|
|
2
|
-
onSuccess: (authToken: string) => Promise<void>;
|
|
3
|
-
getToken: () => Promise<string>;
|
|
4
|
-
clearToken: () => Promise<void>;
|
|
5
|
-
} | null;
|
|
6
|
-
/**
|
|
7
|
-
* Register Capacitor token handlers for mobile apps
|
|
8
|
-
* Call this from useAuthMobile before using useAuth
|
|
9
|
-
*/
|
|
10
|
-
export declare function registerCapacitorHandlers(handlers: typeof capacitorTokenHandlers): void;
|
|
11
1
|
/**
|
|
12
2
|
* Main authentication composable for Better Auth
|
|
3
|
+
* Supports offline-first authentication for Capacitor apps
|
|
13
4
|
*/
|
|
14
5
|
export declare function useAuth(): {
|
|
15
6
|
session: Readonly<import("vue").Ref<{
|
|
@@ -65,18 +56,10 @@ export declare function useAuth(): {
|
|
|
65
56
|
}>>;
|
|
66
57
|
isLoading: import("vue").ComputedRef<boolean>;
|
|
67
58
|
isAuthenticated: import("vue").ComputedRef<boolean>;
|
|
68
|
-
user: import("vue").ComputedRef<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
readonly email: string;
|
|
73
|
-
readonly emailVerified: boolean;
|
|
74
|
-
readonly name: string;
|
|
75
|
-
readonly image?: string | null | undefined;
|
|
76
|
-
} | null>;
|
|
77
|
-
login: (returnTo?: string) => void;
|
|
78
|
-
register: (returnTo?: string) => void;
|
|
79
|
-
logout: () => Promise<void>;
|
|
59
|
+
user: import("vue").ComputedRef<any>;
|
|
60
|
+
logout: (options?: {
|
|
61
|
+
skipNavigation?: boolean;
|
|
62
|
+
}) => Promise<void>;
|
|
80
63
|
refreshSession: () => Promise<{
|
|
81
64
|
data: {
|
|
82
65
|
user: {
|
|
@@ -112,7 +95,7 @@ export declare function useAuth(): {
|
|
|
112
95
|
authClient: {
|
|
113
96
|
signIn: {
|
|
114
97
|
social: <FetchOptions extends import("better-auth").ClientFetchOption<Partial<{
|
|
115
|
-
provider: "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel"
|
|
98
|
+
provider: (string & {}) | "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel";
|
|
116
99
|
callbackURL?: string | undefined;
|
|
117
100
|
newUserCallbackURL?: string | undefined;
|
|
118
101
|
errorCallbackURL?: string | undefined;
|
|
@@ -129,7 +112,7 @@ export declare function useAuth(): {
|
|
|
129
112
|
loginHint?: string | undefined;
|
|
130
113
|
additionalData?: Record<string, any> | undefined;
|
|
131
114
|
}> & Record<string, any>, Partial<Record<string, any>> & Record<string, any>, Record<string, any> | undefined>>(data_0: import("better-auth").Prettify<{
|
|
132
|
-
provider: "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel"
|
|
115
|
+
provider: (string & {}) | "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel";
|
|
133
116
|
callbackURL?: string | undefined;
|
|
134
117
|
newUserCallbackURL?: string | undefined;
|
|
135
118
|
errorCallbackURL?: string | undefined;
|
|
@@ -868,7 +851,7 @@ export declare function useAuth(): {
|
|
|
868
851
|
export declare function getAuthClientExports(): {
|
|
869
852
|
signIn: {
|
|
870
853
|
social: <FetchOptions extends import("better-auth").ClientFetchOption<Partial<{
|
|
871
|
-
provider: "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel"
|
|
854
|
+
provider: (string & {}) | "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel";
|
|
872
855
|
callbackURL?: string | undefined;
|
|
873
856
|
newUserCallbackURL?: string | undefined;
|
|
874
857
|
errorCallbackURL?: string | undefined;
|
|
@@ -885,7 +868,7 @@ export declare function getAuthClientExports(): {
|
|
|
885
868
|
loginHint?: string | undefined;
|
|
886
869
|
additionalData?: Record<string, any> | undefined;
|
|
887
870
|
}> & Record<string, any>, Partial<Record<string, any>> & Record<string, any>, Record<string, any> | undefined>>(data_0: import("better-auth").Prettify<{
|
|
888
|
-
provider: "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel"
|
|
871
|
+
provider: (string & {}) | "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel";
|
|
889
872
|
callbackURL?: string | undefined;
|
|
890
873
|
newUserCallbackURL?: string | undefined;
|
|
891
874
|
errorCallbackURL?: string | undefined;
|
|
@@ -1143,7 +1126,7 @@ export declare function getAuthClientExports(): {
|
|
|
1143
1126
|
authClient: {
|
|
1144
1127
|
signIn: {
|
|
1145
1128
|
social: <FetchOptions extends import("better-auth").ClientFetchOption<Partial<{
|
|
1146
|
-
provider: "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel"
|
|
1129
|
+
provider: (string & {}) | "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel";
|
|
1147
1130
|
callbackURL?: string | undefined;
|
|
1148
1131
|
newUserCallbackURL?: string | undefined;
|
|
1149
1132
|
errorCallbackURL?: string | undefined;
|
|
@@ -1160,7 +1143,7 @@ export declare function getAuthClientExports(): {
|
|
|
1160
1143
|
loginHint?: string | undefined;
|
|
1161
1144
|
additionalData?: Record<string, any> | undefined;
|
|
1162
1145
|
}> & Record<string, any>, Partial<Record<string, any>> & Record<string, any>, Record<string, any> | undefined>>(data_0: import("better-auth").Prettify<{
|
|
1163
|
-
provider: "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel"
|
|
1146
|
+
provider: (string & {}) | "github" | "apple" | "atlassian" | "cognito" | "discord" | "facebook" | "figma" | "microsoft" | "google" | "huggingface" | "slack" | "spotify" | "twitch" | "twitter" | "dropbox" | "kick" | "linear" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "salesforce" | "vk" | "zoom" | "notion" | "kakao" | "naver" | "line" | "paybin" | "paypal" | "polar" | "vercel";
|
|
1164
1147
|
callbackURL?: string | undefined;
|
|
1165
1148
|
newUserCallbackURL?: string | undefined;
|
|
1166
1149
|
errorCallbackURL?: string | undefined;
|
|
@@ -1896,4 +1879,3 @@ export declare function getAuthClientExports(): {
|
|
|
1896
1879
|
};
|
|
1897
1880
|
};
|
|
1898
1881
|
};
|
|
1899
|
-
export {};
|
|
@@ -1,89 +1,94 @@
|
|
|
1
1
|
import { navigateTo, useRuntimeConfig } from "#app";
|
|
2
2
|
import { adminClient } from "better-auth/client/plugins";
|
|
3
3
|
import { createAuthClient } from "better-auth/vue";
|
|
4
|
-
import { computed, watch } from "vue";
|
|
4
|
+
import { computed, ref, watch } from "vue";
|
|
5
|
+
import { capacitorClient } from "../plugins/capacitor-client.js";
|
|
5
6
|
let authClient = null;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const offlineSession = ref(null);
|
|
8
|
+
const offlineChecked = ref(false);
|
|
9
|
+
async function initOfflineSession(isCapacitor) {
|
|
10
|
+
if (!isCapacitor || offlineChecked.value)
|
|
11
|
+
return;
|
|
12
|
+
try {
|
|
13
|
+
const { Preferences } = await import("@capacitor/preferences");
|
|
14
|
+
const result = await Preferences.get({ key: "better-auth_session" });
|
|
15
|
+
if (result?.value) {
|
|
16
|
+
offlineSession.value = JSON.parse(result.value);
|
|
17
|
+
}
|
|
18
|
+
} catch {
|
|
19
|
+
} finally {
|
|
20
|
+
offlineChecked.value = true;
|
|
21
|
+
}
|
|
9
22
|
}
|
|
10
23
|
function getAuthClient() {
|
|
11
24
|
if (authClient)
|
|
12
25
|
return authClient;
|
|
13
26
|
const config = useRuntimeConfig();
|
|
14
27
|
const authConfig = config.public.abckit?.auth;
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (capacitorTokenHandlers) {
|
|
23
|
-
clientOptions.fetchOptions = {
|
|
24
|
-
credentials: "include",
|
|
25
|
-
onSuccess: async (ctx) => {
|
|
26
|
-
const authToken = ctx.response.headers.get("set-auth-token");
|
|
27
|
-
if (authToken && capacitorTokenHandlers) {
|
|
28
|
-
await capacitorTokenHandlers.onSuccess(authToken);
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
auth: {
|
|
32
|
-
type: "Bearer",
|
|
33
|
-
token: async () => {
|
|
34
|
-
if (!capacitorTokenHandlers)
|
|
35
|
-
return "";
|
|
36
|
-
return capacitorTokenHandlers.getToken();
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
};
|
|
28
|
+
const isCapacitor = authConfig?.capacitor ?? false;
|
|
29
|
+
initOfflineSession(isCapacitor);
|
|
30
|
+
const plugins = [adminClient()];
|
|
31
|
+
if (isCapacitor) {
|
|
32
|
+
plugins.push(capacitorClient({
|
|
33
|
+
storagePrefix: "better-auth"
|
|
34
|
+
}));
|
|
40
35
|
}
|
|
41
|
-
authClient = createAuthClient(
|
|
36
|
+
authClient = createAuthClient({
|
|
37
|
+
baseURL: authConfig?.baseURL,
|
|
38
|
+
basePath: authConfig?.basePath,
|
|
39
|
+
plugins
|
|
40
|
+
});
|
|
42
41
|
return authClient;
|
|
43
42
|
}
|
|
44
43
|
export function useAuth() {
|
|
45
44
|
const client = getAuthClient();
|
|
46
45
|
const session = client.useSession();
|
|
47
46
|
const config = useRuntimeConfig();
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
|
|
47
|
+
const isCapacitor = config.public.abckit?.auth?.capacitor ?? false;
|
|
48
|
+
const isLoading = computed(() => {
|
|
49
|
+
if (session.value.isPending)
|
|
50
|
+
return true;
|
|
51
|
+
if (isCapacitor && !offlineChecked.value)
|
|
52
|
+
return true;
|
|
53
|
+
return false;
|
|
54
|
+
});
|
|
55
|
+
const effectiveSession = computed(() => {
|
|
56
|
+
if (session.value.data?.user)
|
|
57
|
+
return session.value.data;
|
|
58
|
+
if (isCapacitor && offlineSession.value?.user)
|
|
59
|
+
return offlineSession.value;
|
|
60
|
+
return null;
|
|
61
|
+
});
|
|
62
|
+
const isAuthenticated = computed(() => !!effectiveSession.value?.user);
|
|
63
|
+
const user = computed(() => effectiveSession.value?.user || null);
|
|
64
|
+
if (isCapacitor) {
|
|
65
|
+
watch(() => session.value.data, (data) => {
|
|
66
|
+
if (data?.user) {
|
|
67
|
+
offlineSession.value = data;
|
|
68
|
+
}
|
|
69
|
+
}, { immediate: true });
|
|
70
|
+
}
|
|
51
71
|
if (config.public.abckit?.sentry) {
|
|
52
72
|
watch(user, async (currentUser) => {
|
|
53
73
|
const Sentry = await import("@sentry/nuxt");
|
|
54
|
-
|
|
55
|
-
Sentry.setUser({ id: currentUser.id });
|
|
56
|
-
} else {
|
|
57
|
-
Sentry.setUser(null);
|
|
58
|
-
}
|
|
74
|
+
Sentry.setUser(currentUser ? { id: currentUser.id } : null);
|
|
59
75
|
}, { immediate: true });
|
|
60
76
|
}
|
|
61
|
-
function
|
|
62
|
-
const query = returnTo ? `?return_to=${encodeURIComponent(returnTo)}` : "";
|
|
63
|
-
navigateTo(`/auth/login${query}`);
|
|
64
|
-
}
|
|
65
|
-
function register(returnTo) {
|
|
66
|
-
const query = returnTo ? `?return_to=${encodeURIComponent(returnTo)}` : "";
|
|
67
|
-
navigateTo(`/auth/register${query}`);
|
|
68
|
-
}
|
|
69
|
-
async function logout() {
|
|
77
|
+
async function logout(options = {}) {
|
|
70
78
|
await client.signOut();
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
offlineSession.value = null;
|
|
80
|
+
if (options.skipNavigation)
|
|
81
|
+
return;
|
|
74
82
|
navigateTo("/");
|
|
75
83
|
}
|
|
76
84
|
async function refreshSession() {
|
|
77
|
-
|
|
78
|
-
return result;
|
|
85
|
+
return await client.getSession({ fetchOptions: { cache: "no-store" } });
|
|
79
86
|
}
|
|
80
87
|
return {
|
|
81
88
|
session,
|
|
82
89
|
isLoading,
|
|
83
90
|
isAuthenticated,
|
|
84
91
|
user,
|
|
85
|
-
login,
|
|
86
|
-
register,
|
|
87
92
|
logout,
|
|
88
93
|
refreshSession,
|
|
89
94
|
authClient: client
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { BetterAuthClientPlugin } from 'better-auth';
|
|
2
|
+
interface CapacitorClientOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Prefix for storage keys
|
|
5
|
+
* @default 'better-auth'
|
|
6
|
+
*/
|
|
7
|
+
storagePrefix?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Capacitor client plugin for Better Auth
|
|
11
|
+
* Provides offline-first authentication with persistent storage
|
|
12
|
+
*/
|
|
13
|
+
export declare function capacitorClient(opts?: CapacitorClientOptions): BetterAuthClientPlugin;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { Preferences } from "@capacitor/preferences";
|
|
2
|
+
function parseSetCookieHeader(header) {
|
|
3
|
+
const cookieMap = /* @__PURE__ */ new Map();
|
|
4
|
+
const cookies = splitSetCookieHeader(header);
|
|
5
|
+
cookies.forEach((cookie) => {
|
|
6
|
+
const parts = cookie.split(";").map((p) => p.trim());
|
|
7
|
+
const [nameValue, ...attributes] = parts;
|
|
8
|
+
if (!nameValue)
|
|
9
|
+
return;
|
|
10
|
+
const [name, ...valueParts] = nameValue.split("=");
|
|
11
|
+
const value = valueParts.join("=");
|
|
12
|
+
const cookieObj = { value };
|
|
13
|
+
attributes.forEach((attr) => {
|
|
14
|
+
const [attrName, ...attrValueParts] = attr.split("=");
|
|
15
|
+
const attrValue = attrValueParts.join("=");
|
|
16
|
+
if (attrName)
|
|
17
|
+
cookieObj[attrName.toLowerCase()] = attrValue;
|
|
18
|
+
});
|
|
19
|
+
if (name)
|
|
20
|
+
cookieMap.set(name, cookieObj);
|
|
21
|
+
});
|
|
22
|
+
return cookieMap;
|
|
23
|
+
}
|
|
24
|
+
function splitSetCookieHeader(setCookie) {
|
|
25
|
+
const parts = [];
|
|
26
|
+
let buffer = "";
|
|
27
|
+
let i = 0;
|
|
28
|
+
while (i < setCookie.length) {
|
|
29
|
+
const char = setCookie[i];
|
|
30
|
+
if (char === ",") {
|
|
31
|
+
const recent = buffer.toLowerCase();
|
|
32
|
+
const hasExpires = recent.includes("expires=");
|
|
33
|
+
const hasGmt = /gmt/i.test(recent);
|
|
34
|
+
if (hasExpires && !hasGmt) {
|
|
35
|
+
buffer += char;
|
|
36
|
+
i += 1;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (buffer.trim().length > 0) {
|
|
40
|
+
parts.push(buffer.trim());
|
|
41
|
+
buffer = "";
|
|
42
|
+
}
|
|
43
|
+
i += 1;
|
|
44
|
+
if (setCookie[i] === " ")
|
|
45
|
+
i += 1;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
buffer += char;
|
|
49
|
+
i += 1;
|
|
50
|
+
}
|
|
51
|
+
if (buffer.trim().length > 0)
|
|
52
|
+
parts.push(buffer.trim());
|
|
53
|
+
return parts;
|
|
54
|
+
}
|
|
55
|
+
function mergeCookies(setCookieHeader, prevCookie) {
|
|
56
|
+
const parsed = parseSetCookieHeader(setCookieHeader);
|
|
57
|
+
let cookies = {};
|
|
58
|
+
if (prevCookie) {
|
|
59
|
+
try {
|
|
60
|
+
cookies = JSON.parse(prevCookie);
|
|
61
|
+
} catch {
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
parsed.forEach((cookie, key) => {
|
|
65
|
+
const maxAge = cookie["max-age"];
|
|
66
|
+
const expiresAt = cookie.expires;
|
|
67
|
+
const expires = maxAge ? new Date(Date.now() + Number(maxAge) * 1e3) : expiresAt ? new Date(String(expiresAt)) : null;
|
|
68
|
+
cookies[key] = {
|
|
69
|
+
value: cookie.value,
|
|
70
|
+
expires: expires ? expires.toISOString() : null
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
return JSON.stringify(cookies);
|
|
74
|
+
}
|
|
75
|
+
function getCookieString(storedCookies) {
|
|
76
|
+
let parsed = {};
|
|
77
|
+
try {
|
|
78
|
+
parsed = JSON.parse(storedCookies);
|
|
79
|
+
} catch {
|
|
80
|
+
return "";
|
|
81
|
+
}
|
|
82
|
+
const parts = [];
|
|
83
|
+
for (const [key, cookie] of Object.entries(parsed)) {
|
|
84
|
+
if (cookie.expires && new Date(cookie.expires) < /* @__PURE__ */ new Date())
|
|
85
|
+
continue;
|
|
86
|
+
parts.push(`${key}=${cookie.value}`);
|
|
87
|
+
}
|
|
88
|
+
return parts.join("; ");
|
|
89
|
+
}
|
|
90
|
+
function hasSessionCookieChanged(prevCookie, newCookie) {
|
|
91
|
+
if (!prevCookie)
|
|
92
|
+
return true;
|
|
93
|
+
try {
|
|
94
|
+
const prev = JSON.parse(prevCookie);
|
|
95
|
+
const next = JSON.parse(newCookie);
|
|
96
|
+
const sessionKeys = /* @__PURE__ */ new Set();
|
|
97
|
+
for (const key of Object.keys(prev)) {
|
|
98
|
+
if (key.includes("session_token") || key.includes("session_data"))
|
|
99
|
+
sessionKeys.add(key);
|
|
100
|
+
}
|
|
101
|
+
for (const key of Object.keys(next)) {
|
|
102
|
+
if (key.includes("session_token") || key.includes("session_data"))
|
|
103
|
+
sessionKeys.add(key);
|
|
104
|
+
}
|
|
105
|
+
for (const key of sessionKeys) {
|
|
106
|
+
if (prev[key]?.value !== next[key]?.value)
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
} catch {
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
export function capacitorClient(opts) {
|
|
115
|
+
let store = null;
|
|
116
|
+
const storagePrefix = opts?.storagePrefix || "better-auth";
|
|
117
|
+
const cookieName = `${storagePrefix}_cookie`;
|
|
118
|
+
const sessionCacheName = `${storagePrefix}_session`;
|
|
119
|
+
return {
|
|
120
|
+
id: "capacitor",
|
|
121
|
+
getActions: (_$fetch, $store) => {
|
|
122
|
+
store = $store;
|
|
123
|
+
return {
|
|
124
|
+
/**
|
|
125
|
+
* Get stored cookie string for manual fetch requests
|
|
126
|
+
*/
|
|
127
|
+
getCookie: async () => {
|
|
128
|
+
const result = await Preferences.get({ key: cookieName });
|
|
129
|
+
return getCookieString(result?.value || "{}");
|
|
130
|
+
},
|
|
131
|
+
/**
|
|
132
|
+
* Get cached session data for offline use
|
|
133
|
+
*/
|
|
134
|
+
getCachedSession: async () => {
|
|
135
|
+
const result = await Preferences.get({ key: sessionCacheName });
|
|
136
|
+
if (!result?.value)
|
|
137
|
+
return null;
|
|
138
|
+
try {
|
|
139
|
+
return JSON.parse(result.value);
|
|
140
|
+
} catch {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
/**
|
|
145
|
+
* Clear all stored auth data
|
|
146
|
+
*/
|
|
147
|
+
clearStorage: async () => {
|
|
148
|
+
await Preferences.remove({ key: cookieName });
|
|
149
|
+
await Preferences.remove({ key: sessionCacheName });
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
},
|
|
153
|
+
fetchPlugins: [
|
|
154
|
+
{
|
|
155
|
+
id: "capacitor",
|
|
156
|
+
name: "Capacitor Auth",
|
|
157
|
+
hooks: {
|
|
158
|
+
async onSuccess(context) {
|
|
159
|
+
const authToken = context.response.headers.get("set-auth-token");
|
|
160
|
+
if (authToken) {
|
|
161
|
+
const prevCookie = (await Preferences.get({ key: cookieName }))?.value;
|
|
162
|
+
const tokenCookie = `session_token=${authToken}`;
|
|
163
|
+
const newCookie = mergeCookies(tokenCookie, prevCookie ?? void 0);
|
|
164
|
+
if (hasSessionCookieChanged(prevCookie ?? null, newCookie)) {
|
|
165
|
+
await Preferences.set({ key: cookieName, value: newCookie });
|
|
166
|
+
store?.notify("$sessionSignal");
|
|
167
|
+
} else {
|
|
168
|
+
await Preferences.set({ key: cookieName, value: newCookie });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const setCookie = context.response.headers.get("set-cookie");
|
|
172
|
+
if (setCookie) {
|
|
173
|
+
const prevCookie = (await Preferences.get({ key: cookieName }))?.value;
|
|
174
|
+
const newCookie = mergeCookies(setCookie, prevCookie ?? void 0);
|
|
175
|
+
if (hasSessionCookieChanged(prevCookie ?? null, newCookie)) {
|
|
176
|
+
await Preferences.set({ key: cookieName, value: newCookie });
|
|
177
|
+
store?.notify("$sessionSignal");
|
|
178
|
+
} else {
|
|
179
|
+
await Preferences.set({ key: cookieName, value: newCookie });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (context.request.url.toString().includes("/get-session")) {
|
|
183
|
+
if (context.data?.session || context.data?.user) {
|
|
184
|
+
await Preferences.set({
|
|
185
|
+
key: sessionCacheName,
|
|
186
|
+
value: JSON.stringify(context.data)
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
async init(url, options) {
|
|
193
|
+
const storedCookie = (await Preferences.get({ key: cookieName }))?.value;
|
|
194
|
+
const cookie = getCookieString(storedCookie || "{}");
|
|
195
|
+
if (cookie) {
|
|
196
|
+
options = options || {};
|
|
197
|
+
options.headers = {
|
|
198
|
+
...options.headers,
|
|
199
|
+
cookie
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
if (url.includes("/sign-out")) {
|
|
203
|
+
await Preferences.remove({ key: cookieName });
|
|
204
|
+
await Preferences.remove({ key: sessionCacheName });
|
|
205
|
+
if (store?.atoms?.session) {
|
|
206
|
+
const currentSession = store.atoms.session.get();
|
|
207
|
+
store.atoms.session.set({
|
|
208
|
+
...currentSession,
|
|
209
|
+
data: null,
|
|
210
|
+
error: null,
|
|
211
|
+
isPending: false
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return { url, options };
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
]
|
|
219
|
+
};
|
|
220
|
+
}
|