abckit 0.0.18 → 0.0.20
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.
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Main authentication composable for Better Auth
|
|
3
|
+
* Supports offline-first authentication for Capacitor apps
|
|
3
4
|
*/
|
|
4
5
|
export declare function useAuth(): {
|
|
5
6
|
session: Readonly<import("vue").Ref<{
|
|
@@ -55,16 +56,10 @@ export declare function useAuth(): {
|
|
|
55
56
|
}>>;
|
|
56
57
|
isLoading: import("vue").ComputedRef<boolean>;
|
|
57
58
|
isAuthenticated: import("vue").ComputedRef<boolean>;
|
|
58
|
-
user: import("vue").ComputedRef<
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
readonly email: string;
|
|
63
|
-
readonly emailVerified: boolean;
|
|
64
|
-
readonly name: string;
|
|
65
|
-
readonly image?: string | null | undefined;
|
|
66
|
-
} | null>;
|
|
67
|
-
logout: () => Promise<void>;
|
|
59
|
+
user: import("vue").ComputedRef<any>;
|
|
60
|
+
logout: (options?: {
|
|
61
|
+
skipNavigation?: boolean;
|
|
62
|
+
}) => Promise<void>;
|
|
68
63
|
refreshSession: () => Promise<{
|
|
69
64
|
data: {
|
|
70
65
|
user: {
|
|
@@ -100,7 +95,7 @@ export declare function useAuth(): {
|
|
|
100
95
|
authClient: {
|
|
101
96
|
signIn: {
|
|
102
97
|
social: <FetchOptions extends import("better-auth").ClientFetchOption<Partial<{
|
|
103
|
-
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";
|
|
104
99
|
callbackURL?: string | undefined;
|
|
105
100
|
newUserCallbackURL?: string | undefined;
|
|
106
101
|
errorCallbackURL?: string | undefined;
|
|
@@ -117,7 +112,7 @@ export declare function useAuth(): {
|
|
|
117
112
|
loginHint?: string | undefined;
|
|
118
113
|
additionalData?: Record<string, any> | undefined;
|
|
119
114
|
}> & Record<string, any>, Partial<Record<string, any>> & Record<string, any>, Record<string, any> | undefined>>(data_0: import("better-auth").Prettify<{
|
|
120
|
-
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";
|
|
121
116
|
callbackURL?: string | undefined;
|
|
122
117
|
newUserCallbackURL?: string | undefined;
|
|
123
118
|
errorCallbackURL?: string | undefined;
|
|
@@ -856,7 +851,7 @@ export declare function useAuth(): {
|
|
|
856
851
|
export declare function getAuthClientExports(): {
|
|
857
852
|
signIn: {
|
|
858
853
|
social: <FetchOptions extends import("better-auth").ClientFetchOption<Partial<{
|
|
859
|
-
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";
|
|
860
855
|
callbackURL?: string | undefined;
|
|
861
856
|
newUserCallbackURL?: string | undefined;
|
|
862
857
|
errorCallbackURL?: string | undefined;
|
|
@@ -873,7 +868,7 @@ export declare function getAuthClientExports(): {
|
|
|
873
868
|
loginHint?: string | undefined;
|
|
874
869
|
additionalData?: Record<string, any> | undefined;
|
|
875
870
|
}> & Record<string, any>, Partial<Record<string, any>> & Record<string, any>, Record<string, any> | undefined>>(data_0: import("better-auth").Prettify<{
|
|
876
|
-
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";
|
|
877
872
|
callbackURL?: string | undefined;
|
|
878
873
|
newUserCallbackURL?: string | undefined;
|
|
879
874
|
errorCallbackURL?: string | undefined;
|
|
@@ -1131,7 +1126,7 @@ export declare function getAuthClientExports(): {
|
|
|
1131
1126
|
authClient: {
|
|
1132
1127
|
signIn: {
|
|
1133
1128
|
social: <FetchOptions extends import("better-auth").ClientFetchOption<Partial<{
|
|
1134
|
-
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";
|
|
1135
1130
|
callbackURL?: string | undefined;
|
|
1136
1131
|
newUserCallbackURL?: string | undefined;
|
|
1137
1132
|
errorCallbackURL?: string | undefined;
|
|
@@ -1148,7 +1143,7 @@ export declare function getAuthClientExports(): {
|
|
|
1148
1143
|
loginHint?: string | undefined;
|
|
1149
1144
|
additionalData?: Record<string, any> | undefined;
|
|
1150
1145
|
}> & Record<string, any>, Partial<Record<string, any>> & Record<string, any>, Record<string, any> | undefined>>(data_0: import("better-auth").Prettify<{
|
|
1151
|
-
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";
|
|
1152
1147
|
callbackURL?: string | undefined;
|
|
1153
1148
|
newUserCallbackURL?: string | undefined;
|
|
1154
1149
|
errorCallbackURL?: string | undefined;
|
|
@@ -1,78 +1,88 @@
|
|
|
1
1
|
import { navigateTo, useRuntimeConfig } from "#app";
|
|
2
|
-
import { Preferences } from "@capacitor/preferences";
|
|
3
2
|
import { adminClient } from "better-auth/client/plugins";
|
|
4
3
|
import { createAuthClient } from "better-auth/vue";
|
|
5
|
-
import { computed, watch } from "vue";
|
|
6
|
-
|
|
4
|
+
import { computed, ref, watch } from "vue";
|
|
5
|
+
import { capacitorClient } from "../plugins/capacitor-client.js";
|
|
7
6
|
let authClient = null;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
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
|
+
}
|
|
17
22
|
}
|
|
18
23
|
function getAuthClient() {
|
|
19
24
|
if (authClient)
|
|
20
25
|
return authClient;
|
|
21
26
|
const config = useRuntimeConfig();
|
|
22
27
|
const authConfig = config.public.abckit?.auth;
|
|
23
|
-
const baseURL = authConfig?.baseURL;
|
|
24
|
-
const basePath = authConfig?.basePath;
|
|
25
28
|
const isCapacitor = authConfig?.capacitor ?? false;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
basePath,
|
|
29
|
-
plugins: [adminClient()]
|
|
30
|
-
};
|
|
29
|
+
initOfflineSession(isCapacitor);
|
|
30
|
+
const plugins = [adminClient()];
|
|
31
31
|
if (isCapacitor) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const authToken = ctx.response.headers.get("set-auth-token");
|
|
36
|
-
if (authToken) {
|
|
37
|
-
await setStoredToken(authToken);
|
|
38
|
-
}
|
|
39
|
-
},
|
|
40
|
-
auth: {
|
|
41
|
-
type: "Bearer",
|
|
42
|
-
token: getStoredToken
|
|
43
|
-
}
|
|
44
|
-
};
|
|
32
|
+
plugins.push(capacitorClient({
|
|
33
|
+
storagePrefix: "better-auth"
|
|
34
|
+
}));
|
|
45
35
|
}
|
|
46
|
-
authClient = createAuthClient(
|
|
36
|
+
authClient = createAuthClient({
|
|
37
|
+
baseURL: authConfig?.baseURL,
|
|
38
|
+
basePath: authConfig?.basePath,
|
|
39
|
+
plugins
|
|
40
|
+
});
|
|
47
41
|
return authClient;
|
|
48
42
|
}
|
|
49
43
|
export function useAuth() {
|
|
50
44
|
const client = getAuthClient();
|
|
51
45
|
const session = client.useSession();
|
|
52
46
|
const config = useRuntimeConfig();
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
|
|
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
|
+
}
|
|
56
71
|
if (config.public.abckit?.sentry) {
|
|
57
72
|
watch(user, async (currentUser) => {
|
|
58
73
|
const Sentry = await import("@sentry/nuxt");
|
|
59
|
-
|
|
60
|
-
Sentry.setUser({ id: currentUser.id });
|
|
61
|
-
} else {
|
|
62
|
-
Sentry.setUser(null);
|
|
63
|
-
}
|
|
74
|
+
Sentry.setUser(currentUser ? { id: currentUser.id } : null);
|
|
64
75
|
}, { immediate: true });
|
|
65
76
|
}
|
|
66
|
-
async function logout() {
|
|
77
|
+
async function logout(options = {}) {
|
|
67
78
|
await client.signOut();
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
79
|
+
offlineSession.value = null;
|
|
80
|
+
if (options.skipNavigation)
|
|
81
|
+
return;
|
|
71
82
|
navigateTo("/");
|
|
72
83
|
}
|
|
73
84
|
async function refreshSession() {
|
|
74
|
-
|
|
75
|
-
return result;
|
|
85
|
+
return await client.getSession({ fetchOptions: { cache: "no-store" } });
|
|
76
86
|
}
|
|
77
87
|
return {
|
|
78
88
|
session,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { BetterAuthClientPlugin } from 'better-auth';
|
|
2
|
+
import type { FocusManager, OnlineManager } from 'better-auth/client';
|
|
3
|
+
interface CapacitorClientOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Prefix for storage keys
|
|
6
|
+
* @default 'better-auth'
|
|
7
|
+
*/
|
|
8
|
+
storagePrefix?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Prefix(es) for server cookie names to filter
|
|
11
|
+
* Prevents infinite refetching when third-party cookies are set
|
|
12
|
+
* @default 'better-auth'
|
|
13
|
+
*/
|
|
14
|
+
cookiePrefix?: string | string[];
|
|
15
|
+
}
|
|
16
|
+
export declare function setupCapacitorFocusManager(): FocusManager;
|
|
17
|
+
export declare function setupCapacitorOnlineManager(): OnlineManager;
|
|
18
|
+
/**
|
|
19
|
+
* Capacitor client plugin for Better Auth
|
|
20
|
+
* Provides offline-first authentication with persistent storage
|
|
21
|
+
*/
|
|
22
|
+
export declare function capacitorClient(opts?: CapacitorClientOptions): BetterAuthClientPlugin;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { Preferences } from "@capacitor/preferences";
|
|
2
|
+
import { kFocusManager, kOnlineManager } from "better-auth/client";
|
|
3
|
+
class CapacitorFocusManager {
|
|
4
|
+
listeners = /* @__PURE__ */ new Set();
|
|
5
|
+
unsubscribe;
|
|
6
|
+
subscribe(listener) {
|
|
7
|
+
this.listeners.add(listener);
|
|
8
|
+
return () => {
|
|
9
|
+
this.listeners.delete(listener);
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
setFocused(focused) {
|
|
13
|
+
this.listeners.forEach((listener) => listener(focused));
|
|
14
|
+
}
|
|
15
|
+
setup() {
|
|
16
|
+
import("@capacitor/app").then(async ({ App }) => {
|
|
17
|
+
const handle = await App.addListener("appStateChange", (state) => {
|
|
18
|
+
this.setFocused(state.isActive);
|
|
19
|
+
});
|
|
20
|
+
this.unsubscribe = () => handle.remove();
|
|
21
|
+
}).catch(() => {
|
|
22
|
+
});
|
|
23
|
+
return () => {
|
|
24
|
+
this.unsubscribe?.();
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function setupCapacitorFocusManager() {
|
|
29
|
+
const global = globalThis;
|
|
30
|
+
if (!global[kFocusManager]) {
|
|
31
|
+
global[kFocusManager] = new CapacitorFocusManager();
|
|
32
|
+
}
|
|
33
|
+
return global[kFocusManager];
|
|
34
|
+
}
|
|
35
|
+
class CapacitorOnlineManager {
|
|
36
|
+
listeners = /* @__PURE__ */ new Set();
|
|
37
|
+
isOnline = true;
|
|
38
|
+
unsubscribe;
|
|
39
|
+
subscribe(listener) {
|
|
40
|
+
this.listeners.add(listener);
|
|
41
|
+
return () => {
|
|
42
|
+
this.listeners.delete(listener);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
setOnline(online) {
|
|
46
|
+
this.isOnline = online;
|
|
47
|
+
this.listeners.forEach((listener) => listener(online));
|
|
48
|
+
}
|
|
49
|
+
setup() {
|
|
50
|
+
import("@capacitor/network").then(async ({ Network }) => {
|
|
51
|
+
const handle = await Network.addListener("networkStatusChange", (status) => {
|
|
52
|
+
this.setOnline(status.connected);
|
|
53
|
+
});
|
|
54
|
+
this.unsubscribe = () => handle.remove();
|
|
55
|
+
}).catch(() => {
|
|
56
|
+
this.setOnline(true);
|
|
57
|
+
});
|
|
58
|
+
return () => {
|
|
59
|
+
this.unsubscribe?.();
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export function setupCapacitorOnlineManager() {
|
|
64
|
+
const global = globalThis;
|
|
65
|
+
if (!global[kOnlineManager]) {
|
|
66
|
+
global[kOnlineManager] = new CapacitorOnlineManager();
|
|
67
|
+
}
|
|
68
|
+
return global[kOnlineManager];
|
|
69
|
+
}
|
|
70
|
+
setupCapacitorFocusManager();
|
|
71
|
+
setupCapacitorOnlineManager();
|
|
72
|
+
function parseSetCookieHeader(header) {
|
|
73
|
+
const cookieMap = /* @__PURE__ */ new Map();
|
|
74
|
+
const cookies = splitSetCookieHeader(header);
|
|
75
|
+
cookies.forEach((cookie) => {
|
|
76
|
+
const parts = cookie.split(";").map((p) => p.trim());
|
|
77
|
+
const [nameValue, ...attributes] = parts;
|
|
78
|
+
if (!nameValue)
|
|
79
|
+
return;
|
|
80
|
+
const [name, ...valueParts] = nameValue.split("=");
|
|
81
|
+
const value = valueParts.join("=");
|
|
82
|
+
const cookieObj = { value };
|
|
83
|
+
attributes.forEach((attr) => {
|
|
84
|
+
const [attrName, ...attrValueParts] = attr.split("=");
|
|
85
|
+
const attrValue = attrValueParts.join("=");
|
|
86
|
+
if (attrName)
|
|
87
|
+
cookieObj[attrName.toLowerCase()] = attrValue;
|
|
88
|
+
});
|
|
89
|
+
if (name)
|
|
90
|
+
cookieMap.set(name, cookieObj);
|
|
91
|
+
});
|
|
92
|
+
return cookieMap;
|
|
93
|
+
}
|
|
94
|
+
function splitSetCookieHeader(setCookie) {
|
|
95
|
+
const parts = [];
|
|
96
|
+
let buffer = "";
|
|
97
|
+
let i = 0;
|
|
98
|
+
while (i < setCookie.length) {
|
|
99
|
+
const char = setCookie[i];
|
|
100
|
+
if (char === ",") {
|
|
101
|
+
const recent = buffer.toLowerCase();
|
|
102
|
+
const hasExpires = recent.includes("expires=");
|
|
103
|
+
const hasGmt = /gmt/i.test(recent);
|
|
104
|
+
if (hasExpires && !hasGmt) {
|
|
105
|
+
buffer += char;
|
|
106
|
+
i += 1;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (buffer.trim().length > 0) {
|
|
110
|
+
parts.push(buffer.trim());
|
|
111
|
+
buffer = "";
|
|
112
|
+
}
|
|
113
|
+
i += 1;
|
|
114
|
+
if (setCookie[i] === " ")
|
|
115
|
+
i += 1;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
buffer += char;
|
|
119
|
+
i += 1;
|
|
120
|
+
}
|
|
121
|
+
if (buffer.trim().length > 0)
|
|
122
|
+
parts.push(buffer.trim());
|
|
123
|
+
return parts;
|
|
124
|
+
}
|
|
125
|
+
function mergeCookies(setCookieHeader, prevCookie) {
|
|
126
|
+
const parsed = parseSetCookieHeader(setCookieHeader);
|
|
127
|
+
let cookies = {};
|
|
128
|
+
if (prevCookie) {
|
|
129
|
+
try {
|
|
130
|
+
cookies = JSON.parse(prevCookie);
|
|
131
|
+
} catch {
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
parsed.forEach((cookie, key) => {
|
|
135
|
+
const maxAge = cookie["max-age"];
|
|
136
|
+
const expiresAt = cookie.expires;
|
|
137
|
+
const expires = maxAge ? new Date(Date.now() + Number(maxAge) * 1e3) : expiresAt ? new Date(String(expiresAt)) : null;
|
|
138
|
+
cookies[key] = {
|
|
139
|
+
value: cookie.value,
|
|
140
|
+
expires: expires ? expires.toISOString() : null
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
return JSON.stringify(cookies);
|
|
144
|
+
}
|
|
145
|
+
function getCookieString(storedCookies) {
|
|
146
|
+
let parsed = {};
|
|
147
|
+
try {
|
|
148
|
+
parsed = JSON.parse(storedCookies);
|
|
149
|
+
} catch {
|
|
150
|
+
return "";
|
|
151
|
+
}
|
|
152
|
+
const parts = [];
|
|
153
|
+
for (const [key, cookie] of Object.entries(parsed)) {
|
|
154
|
+
if (cookie.expires && new Date(cookie.expires) < /* @__PURE__ */ new Date())
|
|
155
|
+
continue;
|
|
156
|
+
parts.push(`${key}=${cookie.value}`);
|
|
157
|
+
}
|
|
158
|
+
return parts.join("; ");
|
|
159
|
+
}
|
|
160
|
+
function hasBetterAuthCookies(setCookieHeader, cookiePrefix) {
|
|
161
|
+
const cookies = parseSetCookieHeader(setCookieHeader);
|
|
162
|
+
const cookieSuffixes = ["session_token", "session_data"];
|
|
163
|
+
const prefixes = Array.isArray(cookiePrefix) ? cookiePrefix : [cookiePrefix];
|
|
164
|
+
for (const name of cookies.keys()) {
|
|
165
|
+
const nameWithoutSecure = name.startsWith("__Secure-") ? name.slice(9) : name;
|
|
166
|
+
for (const prefix of prefixes) {
|
|
167
|
+
if (prefix) {
|
|
168
|
+
if (nameWithoutSecure.startsWith(prefix))
|
|
169
|
+
return true;
|
|
170
|
+
} else {
|
|
171
|
+
for (const suffix of cookieSuffixes) {
|
|
172
|
+
if (nameWithoutSecure.endsWith(suffix))
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
function hasSessionCookieChanged(prevCookie, newCookie) {
|
|
181
|
+
if (!prevCookie)
|
|
182
|
+
return true;
|
|
183
|
+
try {
|
|
184
|
+
const prev = JSON.parse(prevCookie);
|
|
185
|
+
const next = JSON.parse(newCookie);
|
|
186
|
+
const sessionKeys = /* @__PURE__ */ new Set();
|
|
187
|
+
for (const key of Object.keys(prev)) {
|
|
188
|
+
if (key.includes("session_token") || key.includes("session_data"))
|
|
189
|
+
sessionKeys.add(key);
|
|
190
|
+
}
|
|
191
|
+
for (const key of Object.keys(next)) {
|
|
192
|
+
if (key.includes("session_token") || key.includes("session_data"))
|
|
193
|
+
sessionKeys.add(key);
|
|
194
|
+
}
|
|
195
|
+
for (const key of sessionKeys) {
|
|
196
|
+
if (prev[key]?.value !== next[key]?.value)
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
return false;
|
|
200
|
+
} catch {
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
export function capacitorClient(opts) {
|
|
205
|
+
let store = null;
|
|
206
|
+
const storagePrefix = opts?.storagePrefix || "better-auth";
|
|
207
|
+
const cookiePrefix = opts?.cookiePrefix || "better-auth";
|
|
208
|
+
const cookieName = `${storagePrefix}_cookie`;
|
|
209
|
+
const sessionCacheName = `${storagePrefix}_session`;
|
|
210
|
+
return {
|
|
211
|
+
id: "capacitor",
|
|
212
|
+
getActions: (_$fetch, $store) => {
|
|
213
|
+
store = $store;
|
|
214
|
+
return {
|
|
215
|
+
/**
|
|
216
|
+
* Get stored cookie string for manual fetch requests
|
|
217
|
+
*/
|
|
218
|
+
getCookie: async () => {
|
|
219
|
+
const result = await Preferences.get({ key: cookieName });
|
|
220
|
+
return getCookieString(result?.value || "{}");
|
|
221
|
+
},
|
|
222
|
+
/**
|
|
223
|
+
* Get cached session data for offline use
|
|
224
|
+
*/
|
|
225
|
+
getCachedSession: async () => {
|
|
226
|
+
const result = await Preferences.get({ key: sessionCacheName });
|
|
227
|
+
if (!result?.value)
|
|
228
|
+
return null;
|
|
229
|
+
try {
|
|
230
|
+
return JSON.parse(result.value);
|
|
231
|
+
} catch {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
/**
|
|
236
|
+
* Clear all stored auth data
|
|
237
|
+
*/
|
|
238
|
+
clearStorage: async () => {
|
|
239
|
+
await Preferences.remove({ key: cookieName });
|
|
240
|
+
await Preferences.remove({ key: sessionCacheName });
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
},
|
|
244
|
+
fetchPlugins: [
|
|
245
|
+
{
|
|
246
|
+
id: "capacitor",
|
|
247
|
+
name: "Capacitor Auth",
|
|
248
|
+
hooks: {
|
|
249
|
+
async onSuccess(context) {
|
|
250
|
+
const authToken = context.response.headers.get("set-auth-token");
|
|
251
|
+
if (authToken) {
|
|
252
|
+
const prevCookie = (await Preferences.get({ key: cookieName }))?.value;
|
|
253
|
+
const tokenCookie = `session_token=${authToken}`;
|
|
254
|
+
const newCookie = mergeCookies(tokenCookie, prevCookie ?? void 0);
|
|
255
|
+
if (hasSessionCookieChanged(prevCookie ?? null, newCookie)) {
|
|
256
|
+
await Preferences.set({ key: cookieName, value: newCookie });
|
|
257
|
+
store?.notify("$sessionSignal");
|
|
258
|
+
} else {
|
|
259
|
+
await Preferences.set({ key: cookieName, value: newCookie });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
const setCookie = context.response.headers.get("set-cookie");
|
|
263
|
+
if (setCookie) {
|
|
264
|
+
if (hasBetterAuthCookies(setCookie, cookiePrefix)) {
|
|
265
|
+
const prevCookie = (await Preferences.get({ key: cookieName }))?.value;
|
|
266
|
+
const newCookie = mergeCookies(setCookie, prevCookie ?? void 0);
|
|
267
|
+
if (hasSessionCookieChanged(prevCookie ?? null, newCookie)) {
|
|
268
|
+
await Preferences.set({ key: cookieName, value: newCookie });
|
|
269
|
+
store?.notify("$sessionSignal");
|
|
270
|
+
} else {
|
|
271
|
+
await Preferences.set({ key: cookieName, value: newCookie });
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
if (context.request.url.toString().includes("/get-session")) {
|
|
276
|
+
if (context.data?.session || context.data?.user) {
|
|
277
|
+
await Preferences.set({
|
|
278
|
+
key: sessionCacheName,
|
|
279
|
+
value: JSON.stringify(context.data)
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
async init(url, options) {
|
|
286
|
+
const storedCookie = (await Preferences.get({ key: cookieName }))?.value;
|
|
287
|
+
const cookie = getCookieString(storedCookie || "{}");
|
|
288
|
+
if (cookie) {
|
|
289
|
+
options = options || {};
|
|
290
|
+
options.headers = {
|
|
291
|
+
...options.headers,
|
|
292
|
+
cookie
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
if (url.includes("/sign-out")) {
|
|
296
|
+
await Preferences.remove({ key: cookieName });
|
|
297
|
+
await Preferences.remove({ key: sessionCacheName });
|
|
298
|
+
if (store?.atoms?.session) {
|
|
299
|
+
const currentSession = store.atoms.session.get();
|
|
300
|
+
store.atoms.session.set({
|
|
301
|
+
...currentSession,
|
|
302
|
+
data: null,
|
|
303
|
+
error: null,
|
|
304
|
+
isPending: false
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return { url, options };
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
]
|
|
312
|
+
};
|
|
313
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "abckit",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.20",
|
|
5
5
|
"private": false,
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"exports": {
|
|
@@ -56,7 +56,9 @@
|
|
|
56
56
|
"release": "pnpm publish --no-git-checks --access public"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
+
"@capacitor/app": "^7.1.1",
|
|
59
60
|
"@capacitor/core": "^7.0.1",
|
|
61
|
+
"@capacitor/network": "^7.0.3",
|
|
60
62
|
"@capacitor/preferences": "^7.0.1",
|
|
61
63
|
"@graphql-tools/utils": "^10.11.0",
|
|
62
64
|
"@nuxt/icon": "^2.1.0",
|