@better-auth/expo 1.4.0-beta.11 → 1.4.0-beta.13

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/client.cjs CHANGED
@@ -84,12 +84,88 @@ function getCookie(cookie) {
84
84
  function getOrigin(scheme) {
85
85
  return expo_linking.createURL("", { scheme });
86
86
  }
87
+ /**
88
+ * Compare if session cookies have actually changed by comparing their values.
89
+ * Ignores expiry timestamps that naturally change on each request.
90
+ *
91
+ * @param prevCookie - Previous cookie JSON string
92
+ * @param newCookie - New cookie JSON string
93
+ * @returns true if session cookies have changed, false otherwise
94
+ */
95
+ function hasSessionCookieChanged(prevCookie, newCookie) {
96
+ if (!prevCookie) return true;
97
+ try {
98
+ const prev = JSON.parse(prevCookie);
99
+ const next = JSON.parse(newCookie);
100
+ const sessionKeys = /* @__PURE__ */ new Set();
101
+ Object.keys(prev).forEach((key) => {
102
+ if (key.includes("session_token") || key.includes("session_data")) sessionKeys.add(key);
103
+ });
104
+ Object.keys(next).forEach((key) => {
105
+ if (key.includes("session_token") || key.includes("session_data")) sessionKeys.add(key);
106
+ });
107
+ for (const key of sessionKeys) if (prev[key]?.value !== next[key]?.value) return true;
108
+ return false;
109
+ } catch {
110
+ return true;
111
+ }
112
+ }
113
+ /**
114
+ * Check if the Set-Cookie header contains session-related better-auth cookies.
115
+ * Only triggers session updates when session_token or session_data cookies are present.
116
+ * This prevents infinite refetching when non-session cookies (like third-party cookies) change.
117
+ *
118
+ * Supports multiple cookie naming patterns:
119
+ * - Default: "better-auth.session_token", "__Secure-better-auth.session_token"
120
+ * - Custom prefix: "myapp.session_token", "__Secure-myapp.session_token"
121
+ * - Custom full names: "my_custom_session_token", "custom_session_data"
122
+ * - No prefix (cookiePrefix=""): "session_token", "my_session_token", etc.
123
+ *
124
+ * @param setCookieHeader - The Set-Cookie header value
125
+ * @param cookiePrefix - The cookie prefix to check for. Can be empty string for custom cookie names.
126
+ * @returns true if the header contains session-related cookies, false otherwise
127
+ */
128
+ function hasBetterAuthCookies(setCookieHeader, cookiePrefix) {
129
+ const cookies = parseSetCookieHeader(setCookieHeader);
130
+ const sessionCookieSuffixes = ["session_token", "session_data"];
131
+ for (const name of cookies.keys()) {
132
+ const nameWithoutSecure = name.startsWith("__Secure-") ? name.slice(9) : name;
133
+ for (const suffix of sessionCookieSuffixes) if (cookiePrefix) {
134
+ if (nameWithoutSecure === `${cookiePrefix}.${suffix}`) return true;
135
+ } else if (nameWithoutSecure.endsWith(suffix)) return true;
136
+ }
137
+ return false;
138
+ }
139
+ /**
140
+ * Expo secure store does not support colons in the keys.
141
+ * This function replaces colons with underscores.
142
+ *
143
+ * @see https://github.com/better-auth/better-auth/issues/5426
144
+ *
145
+ * @param name cookie name to be saved in the storage
146
+ * @returns normalized cookie name
147
+ */
148
+ function normalizeCookieName(name) {
149
+ return name.replace(/:/g, "_");
150
+ }
151
+ function storageAdapter(storage) {
152
+ return {
153
+ getItem: (name) => {
154
+ return storage.getItem(normalizeCookieName(name));
155
+ },
156
+ setItem: (name, value) => {
157
+ return storage.setItem(normalizeCookieName(name), value);
158
+ }
159
+ };
160
+ }
87
161
  const expoClient = (opts) => {
88
162
  let store = null;
89
- const cookieName = `${opts?.storagePrefix || "better-auth"}_cookie`;
90
- const localCacheName = `${opts?.storagePrefix || "better-auth"}_session_data`;
91
- const storage = opts?.storage;
163
+ const storagePrefix = opts?.storagePrefix || "better-auth";
164
+ const cookieName = `${storagePrefix}_cookie`;
165
+ const localCacheName = `${storagePrefix}_session_data`;
166
+ const storage = storageAdapter(opts?.storage);
92
167
  const isWeb = react_native.Platform.OS === "web";
168
+ const cookiePrefix = opts?.cookiePrefix || "better-auth";
93
169
  const rawScheme = opts?.scheme || expo_constants.default.expoConfig?.scheme || expo_constants.default.platform?.scheme;
94
170
  const scheme = Array.isArray(rawScheme) ? rawScheme[0] : rawScheme;
95
171
  if (!scheme && !isWeb) throw new Error("Scheme not found in app.json. Please provide a scheme in the options.");
@@ -108,10 +184,14 @@ const expoClient = (opts) => {
108
184
  if (isWeb) return;
109
185
  const setCookie = context.response.headers.get("set-cookie");
110
186
  if (setCookie) {
111
- const prevCookie = await storage.getItem(cookieName);
112
- const toSetCookie = getSetCookie(setCookie || "", prevCookie ?? void 0);
113
- await storage.setItem(cookieName, toSetCookie);
114
- store?.notify("$sessionSignal");
187
+ if (hasBetterAuthCookies(setCookie, cookiePrefix)) {
188
+ const prevCookie = await storage.getItem(cookieName);
189
+ const toSetCookie = getSetCookie(setCookie || "", prevCookie ?? void 0);
190
+ if (hasSessionCookieChanged(prevCookie, toSetCookie)) {
191
+ await storage.setItem(cookieName, toSetCookie);
192
+ store?.notify("$sessionSignal");
193
+ } else await storage.setItem(cookieName, toSetCookie);
194
+ }
115
195
  }
116
196
  if (context.request.url.toString().includes("/get-session") && !opts?.disableCache) {
117
197
  const data = context.data;
@@ -191,4 +271,7 @@ const expoClient = (opts) => {
191
271
  exports.expoClient = expoClient;
192
272
  exports.getCookie = getCookie;
193
273
  exports.getSetCookie = getSetCookie;
194
- exports.parseSetCookieHeader = parseSetCookieHeader;
274
+ exports.hasBetterAuthCookies = hasBetterAuthCookies;
275
+ exports.normalizeCookieName = normalizeCookieName;
276
+ exports.parseSetCookieHeader = parseSetCookieHeader;
277
+ exports.storageAdapter = storageAdapter;
package/dist/client.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _better_fetch_fetch0 from "@better-fetch/fetch";
2
2
  import { BetterFetchOption } from "@better-fetch/fetch";
3
- import * as better_auth_types0 from "better-auth/types";
3
+ import { ClientStore } from "@better-auth/core";
4
4
 
5
5
  //#region src/client.d.ts
6
6
  interface CookieAttributes {
@@ -20,14 +20,58 @@ interface ExpoClientOptions {
20
20
  setItem: (key: string, value: string) => any;
21
21
  getItem: (key: string) => string | null;
22
22
  };
23
+ /**
24
+ * Prefix for local storage keys (e.g., "my-app_cookie", "my-app_session_data")
25
+ * @default "better-auth"
26
+ */
23
27
  storagePrefix?: string;
28
+ /**
29
+ * Prefix for server cookie names to filter (e.g., "better-auth.session_token")
30
+ * This is used to identify which cookies belong to better-auth to prevent
31
+ * infinite refetching when third-party cookies are set.
32
+ * @default "better-auth"
33
+ */
34
+ cookiePrefix?: string;
24
35
  disableCache?: boolean;
25
36
  }
26
37
  declare function getSetCookie(header: string, prevCookie?: string): string;
27
38
  declare function getCookie(cookie: string): string;
39
+ /**
40
+ * Check if the Set-Cookie header contains session-related better-auth cookies.
41
+ * Only triggers session updates when session_token or session_data cookies are present.
42
+ * This prevents infinite refetching when non-session cookies (like third-party cookies) change.
43
+ *
44
+ * Supports multiple cookie naming patterns:
45
+ * - Default: "better-auth.session_token", "__Secure-better-auth.session_token"
46
+ * - Custom prefix: "myapp.session_token", "__Secure-myapp.session_token"
47
+ * - Custom full names: "my_custom_session_token", "custom_session_data"
48
+ * - No prefix (cookiePrefix=""): "session_token", "my_session_token", etc.
49
+ *
50
+ * @param setCookieHeader - The Set-Cookie header value
51
+ * @param cookiePrefix - The cookie prefix to check for. Can be empty string for custom cookie names.
52
+ * @returns true if the header contains session-related cookies, false otherwise
53
+ */
54
+ declare function hasBetterAuthCookies(setCookieHeader: string, cookiePrefix: string): boolean;
55
+ /**
56
+ * Expo secure store does not support colons in the keys.
57
+ * This function replaces colons with underscores.
58
+ *
59
+ * @see https://github.com/better-auth/better-auth/issues/5426
60
+ *
61
+ * @param name cookie name to be saved in the storage
62
+ * @returns normalized cookie name
63
+ */
64
+ declare function normalizeCookieName(name: string): string;
65
+ declare function storageAdapter(storage: {
66
+ getItem: (name: string) => string | null;
67
+ setItem: (name: string, value: string) => void;
68
+ }): {
69
+ getItem: (name: string) => string | null;
70
+ setItem: (name: string, value: string) => void;
71
+ };
28
72
  declare const expoClient: (opts: ExpoClientOptions) => {
29
73
  id: "expo";
30
- getActions(_: _better_fetch_fetch0.BetterFetch, $store: better_auth_types0.ClientStore): {
74
+ getActions(_: _better_fetch_fetch0.BetterFetch, $store: ClientStore): {
31
75
  /**
32
76
  * Get the stored cookie.
33
77
  *
@@ -52,19 +96,19 @@ declare const expoClient: (opts: ExpoClientOptions) => {
52
96
  onSuccess(context: _better_fetch_fetch0.SuccessContext<any>): Promise<void>;
53
97
  };
54
98
  init(url: string, options: {
55
- cache?: RequestCache | undefined;
56
- credentials?: RequestCredentials | undefined;
99
+ method?: string | undefined;
57
100
  headers?: (HeadersInit & (HeadersInit | {
58
101
  accept: "application/json" | "text/plain" | "application/octet-stream";
59
102
  "content-type": "application/json" | "text/plain" | "application/x-www-form-urlencoded" | "multipart/form-data" | "application/octet-stream";
60
103
  authorization: "Bearer" | "Basic";
61
104
  })) | undefined;
105
+ redirect?: RequestRedirect | undefined;
106
+ cache?: RequestCache | undefined;
107
+ credentials?: RequestCredentials | undefined;
62
108
  integrity?: string | undefined;
63
109
  keepalive?: boolean | undefined;
64
- method?: string | undefined;
65
110
  mode?: RequestMode | undefined;
66
111
  priority?: RequestPriority | undefined;
67
- redirect?: RequestRedirect | undefined;
68
112
  referrer?: string | undefined;
69
113
  referrerPolicy?: ReferrerPolicy | undefined;
70
114
  signal?: (AbortSignal | null) | undefined;
@@ -111,4 +155,4 @@ declare const expoClient: (opts: ExpoClientOptions) => {
111
155
  }[];
112
156
  };
113
157
  //#endregion
114
- export { expoClient, getCookie, getSetCookie, parseSetCookieHeader };
158
+ export { expoClient, getCookie, getSetCookie, hasBetterAuthCookies, normalizeCookieName, parseSetCookieHeader, storageAdapter };
package/dist/client.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _better_fetch_fetch0 from "@better-fetch/fetch";
2
2
  import { BetterFetchOption } from "@better-fetch/fetch";
3
- import * as better_auth_types0 from "better-auth/types";
3
+ import { ClientStore } from "@better-auth/core";
4
4
 
5
5
  //#region src/client.d.ts
6
6
  interface CookieAttributes {
@@ -20,14 +20,58 @@ interface ExpoClientOptions {
20
20
  setItem: (key: string, value: string) => any;
21
21
  getItem: (key: string) => string | null;
22
22
  };
23
+ /**
24
+ * Prefix for local storage keys (e.g., "my-app_cookie", "my-app_session_data")
25
+ * @default "better-auth"
26
+ */
23
27
  storagePrefix?: string;
28
+ /**
29
+ * Prefix for server cookie names to filter (e.g., "better-auth.session_token")
30
+ * This is used to identify which cookies belong to better-auth to prevent
31
+ * infinite refetching when third-party cookies are set.
32
+ * @default "better-auth"
33
+ */
34
+ cookiePrefix?: string;
24
35
  disableCache?: boolean;
25
36
  }
26
37
  declare function getSetCookie(header: string, prevCookie?: string): string;
27
38
  declare function getCookie(cookie: string): string;
39
+ /**
40
+ * Check if the Set-Cookie header contains session-related better-auth cookies.
41
+ * Only triggers session updates when session_token or session_data cookies are present.
42
+ * This prevents infinite refetching when non-session cookies (like third-party cookies) change.
43
+ *
44
+ * Supports multiple cookie naming patterns:
45
+ * - Default: "better-auth.session_token", "__Secure-better-auth.session_token"
46
+ * - Custom prefix: "myapp.session_token", "__Secure-myapp.session_token"
47
+ * - Custom full names: "my_custom_session_token", "custom_session_data"
48
+ * - No prefix (cookiePrefix=""): "session_token", "my_session_token", etc.
49
+ *
50
+ * @param setCookieHeader - The Set-Cookie header value
51
+ * @param cookiePrefix - The cookie prefix to check for. Can be empty string for custom cookie names.
52
+ * @returns true if the header contains session-related cookies, false otherwise
53
+ */
54
+ declare function hasBetterAuthCookies(setCookieHeader: string, cookiePrefix: string): boolean;
55
+ /**
56
+ * Expo secure store does not support colons in the keys.
57
+ * This function replaces colons with underscores.
58
+ *
59
+ * @see https://github.com/better-auth/better-auth/issues/5426
60
+ *
61
+ * @param name cookie name to be saved in the storage
62
+ * @returns normalized cookie name
63
+ */
64
+ declare function normalizeCookieName(name: string): string;
65
+ declare function storageAdapter(storage: {
66
+ getItem: (name: string) => string | null;
67
+ setItem: (name: string, value: string) => void;
68
+ }): {
69
+ getItem: (name: string) => string | null;
70
+ setItem: (name: string, value: string) => void;
71
+ };
28
72
  declare const expoClient: (opts: ExpoClientOptions) => {
29
73
  id: "expo";
30
- getActions(_: _better_fetch_fetch0.BetterFetch, $store: better_auth_types0.ClientStore): {
74
+ getActions(_: _better_fetch_fetch0.BetterFetch, $store: ClientStore): {
31
75
  /**
32
76
  * Get the stored cookie.
33
77
  *
@@ -52,19 +96,19 @@ declare const expoClient: (opts: ExpoClientOptions) => {
52
96
  onSuccess(context: _better_fetch_fetch0.SuccessContext<any>): Promise<void>;
53
97
  };
54
98
  init(url: string, options: {
55
- cache?: RequestCache | undefined;
56
- credentials?: RequestCredentials | undefined;
99
+ method?: string | undefined;
57
100
  headers?: (HeadersInit & (HeadersInit | {
58
101
  accept: "application/json" | "text/plain" | "application/octet-stream";
59
102
  "content-type": "application/json" | "text/plain" | "application/x-www-form-urlencoded" | "multipart/form-data" | "application/octet-stream";
60
103
  authorization: "Bearer" | "Basic";
61
104
  })) | undefined;
105
+ redirect?: RequestRedirect | undefined;
106
+ cache?: RequestCache | undefined;
107
+ credentials?: RequestCredentials | undefined;
62
108
  integrity?: string | undefined;
63
109
  keepalive?: boolean | undefined;
64
- method?: string | undefined;
65
110
  mode?: RequestMode | undefined;
66
111
  priority?: RequestPriority | undefined;
67
- redirect?: RequestRedirect | undefined;
68
112
  referrer?: string | undefined;
69
113
  referrerPolicy?: ReferrerPolicy | undefined;
70
114
  signal?: (AbortSignal | null) | undefined;
@@ -111,4 +155,4 @@ declare const expoClient: (opts: ExpoClientOptions) => {
111
155
  }[];
112
156
  };
113
157
  //#endregion
114
- export { expoClient, getCookie, getSetCookie, parseSetCookieHeader };
158
+ export { expoClient, getCookie, getSetCookie, hasBetterAuthCookies, normalizeCookieName, parseSetCookieHeader, storageAdapter };
package/dist/client.js CHANGED
@@ -80,12 +80,88 @@ function getCookie(cookie) {
80
80
  function getOrigin(scheme) {
81
81
  return Linking.createURL("", { scheme });
82
82
  }
83
+ /**
84
+ * Compare if session cookies have actually changed by comparing their values.
85
+ * Ignores expiry timestamps that naturally change on each request.
86
+ *
87
+ * @param prevCookie - Previous cookie JSON string
88
+ * @param newCookie - New cookie JSON string
89
+ * @returns true if session cookies have changed, false otherwise
90
+ */
91
+ function hasSessionCookieChanged(prevCookie, newCookie) {
92
+ if (!prevCookie) return true;
93
+ try {
94
+ const prev = JSON.parse(prevCookie);
95
+ const next = JSON.parse(newCookie);
96
+ const sessionKeys = /* @__PURE__ */ new Set();
97
+ Object.keys(prev).forEach((key) => {
98
+ if (key.includes("session_token") || key.includes("session_data")) sessionKeys.add(key);
99
+ });
100
+ Object.keys(next).forEach((key) => {
101
+ if (key.includes("session_token") || key.includes("session_data")) sessionKeys.add(key);
102
+ });
103
+ for (const key of sessionKeys) if (prev[key]?.value !== next[key]?.value) return true;
104
+ return false;
105
+ } catch {
106
+ return true;
107
+ }
108
+ }
109
+ /**
110
+ * Check if the Set-Cookie header contains session-related better-auth cookies.
111
+ * Only triggers session updates when session_token or session_data cookies are present.
112
+ * This prevents infinite refetching when non-session cookies (like third-party cookies) change.
113
+ *
114
+ * Supports multiple cookie naming patterns:
115
+ * - Default: "better-auth.session_token", "__Secure-better-auth.session_token"
116
+ * - Custom prefix: "myapp.session_token", "__Secure-myapp.session_token"
117
+ * - Custom full names: "my_custom_session_token", "custom_session_data"
118
+ * - No prefix (cookiePrefix=""): "session_token", "my_session_token", etc.
119
+ *
120
+ * @param setCookieHeader - The Set-Cookie header value
121
+ * @param cookiePrefix - The cookie prefix to check for. Can be empty string for custom cookie names.
122
+ * @returns true if the header contains session-related cookies, false otherwise
123
+ */
124
+ function hasBetterAuthCookies(setCookieHeader, cookiePrefix) {
125
+ const cookies = parseSetCookieHeader(setCookieHeader);
126
+ const sessionCookieSuffixes = ["session_token", "session_data"];
127
+ for (const name of cookies.keys()) {
128
+ const nameWithoutSecure = name.startsWith("__Secure-") ? name.slice(9) : name;
129
+ for (const suffix of sessionCookieSuffixes) if (cookiePrefix) {
130
+ if (nameWithoutSecure === `${cookiePrefix}.${suffix}`) return true;
131
+ } else if (nameWithoutSecure.endsWith(suffix)) return true;
132
+ }
133
+ return false;
134
+ }
135
+ /**
136
+ * Expo secure store does not support colons in the keys.
137
+ * This function replaces colons with underscores.
138
+ *
139
+ * @see https://github.com/better-auth/better-auth/issues/5426
140
+ *
141
+ * @param name cookie name to be saved in the storage
142
+ * @returns normalized cookie name
143
+ */
144
+ function normalizeCookieName(name) {
145
+ return name.replace(/:/g, "_");
146
+ }
147
+ function storageAdapter(storage) {
148
+ return {
149
+ getItem: (name) => {
150
+ return storage.getItem(normalizeCookieName(name));
151
+ },
152
+ setItem: (name, value) => {
153
+ return storage.setItem(normalizeCookieName(name), value);
154
+ }
155
+ };
156
+ }
83
157
  const expoClient = (opts) => {
84
158
  let store = null;
85
- const cookieName = `${opts?.storagePrefix || "better-auth"}_cookie`;
86
- const localCacheName = `${opts?.storagePrefix || "better-auth"}_session_data`;
87
- const storage = opts?.storage;
159
+ const storagePrefix = opts?.storagePrefix || "better-auth";
160
+ const cookieName = `${storagePrefix}_cookie`;
161
+ const localCacheName = `${storagePrefix}_session_data`;
162
+ const storage = storageAdapter(opts?.storage);
88
163
  const isWeb = Platform.OS === "web";
164
+ const cookiePrefix = opts?.cookiePrefix || "better-auth";
89
165
  const rawScheme = opts?.scheme || Constants.expoConfig?.scheme || Constants.platform?.scheme;
90
166
  const scheme = Array.isArray(rawScheme) ? rawScheme[0] : rawScheme;
91
167
  if (!scheme && !isWeb) throw new Error("Scheme not found in app.json. Please provide a scheme in the options.");
@@ -104,10 +180,14 @@ const expoClient = (opts) => {
104
180
  if (isWeb) return;
105
181
  const setCookie = context.response.headers.get("set-cookie");
106
182
  if (setCookie) {
107
- const prevCookie = await storage.getItem(cookieName);
108
- const toSetCookie = getSetCookie(setCookie || "", prevCookie ?? void 0);
109
- await storage.setItem(cookieName, toSetCookie);
110
- store?.notify("$sessionSignal");
183
+ if (hasBetterAuthCookies(setCookie, cookiePrefix)) {
184
+ const prevCookie = await storage.getItem(cookieName);
185
+ const toSetCookie = getSetCookie(setCookie || "", prevCookie ?? void 0);
186
+ if (hasSessionCookieChanged(prevCookie, toSetCookie)) {
187
+ await storage.setItem(cookieName, toSetCookie);
188
+ store?.notify("$sessionSignal");
189
+ } else await storage.setItem(cookieName, toSetCookie);
190
+ }
111
191
  }
112
192
  if (context.request.url.toString().includes("/get-session") && !opts?.disableCache) {
113
193
  const data = context.data;
@@ -184,4 +264,4 @@ const expoClient = (opts) => {
184
264
  };
185
265
 
186
266
  //#endregion
187
- export { expoClient, getCookie, getSetCookie, parseSetCookieHeader };
267
+ export { expoClient, getCookie, getSetCookie, hasBetterAuthCookies, normalizeCookieName, parseSetCookieHeader, storageAdapter };
package/dist/index.cjs CHANGED
@@ -1,8 +1,10 @@
1
1
  const require_chunk = require('./chunk-CUT6urMc.cjs');
2
- let better_auth_api = require("better-auth/api");
3
- better_auth_api = require_chunk.__toESM(better_auth_api);
2
+ let __better_auth_core_api = require("@better-auth/core/api");
3
+ __better_auth_core_api = require_chunk.__toESM(__better_auth_core_api);
4
4
  let zod = require("zod");
5
5
  zod = require_chunk.__toESM(zod);
6
+ let better_call = require("better-call");
7
+ better_call = require_chunk.__toESM(better_call);
6
8
 
7
9
  //#region src/index.ts
8
10
  const expo = (options) => {
@@ -24,9 +26,9 @@ const expo = (options) => {
24
26
  },
25
27
  hooks: { after: [{
26
28
  matcher(context) {
27
- return context.path?.startsWith("/callback") || context.path?.startsWith("/oauth2/callback");
29
+ return !!(context.path?.startsWith("/callback") || context.path?.startsWith("/oauth2/callback"));
28
30
  },
29
- handler: (0, better_auth_api.createAuthMiddleware)(async (ctx) => {
31
+ handler: (0, __better_auth_core_api.createAuthMiddleware)(async (ctx) => {
30
32
  const headers = ctx.context.responseHeaders;
31
33
  const location = headers?.get("location");
32
34
  if (!location) return;
@@ -39,14 +41,14 @@ const expo = (options) => {
39
41
  ctx.setHeader("location", url.toString());
40
42
  })
41
43
  }] },
42
- endpoints: { expoAuthorizationProxy: (0, better_auth_api.createAuthEndpoint)("/expo-authorization-proxy", {
44
+ endpoints: { expoAuthorizationProxy: (0, __better_auth_core_api.createAuthEndpoint)("/expo-authorization-proxy", {
43
45
  method: "GET",
44
46
  query: zod.z.object({ authorizationURL: zod.z.string() }),
45
47
  metadata: { isAction: false }
46
48
  }, async (ctx) => {
47
49
  const { authorizationURL } = ctx.query;
48
50
  const state = new URL(authorizationURL).searchParams.get("state");
49
- if (!state) throw new better_auth_api.APIError("BAD_REQUEST", { message: "Unexpected error" });
51
+ if (!state) throw new better_call.APIError("BAD_REQUEST", { message: "Unexpected error" });
50
52
  const stateCookie = ctx.context.createAuthCookie("state", { maxAge: 300 * 1e3 });
51
53
  await ctx.setSignedCookie(stateCookie.name, state, ctx.context.secret, stateCookie.attributes);
52
54
  return ctx.redirect(ctx.query.authorizationURL);
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import * as better_auth0 from "better-auth";
1
+ import * as _better_auth_core0 from "@better-auth/core";
2
2
  import * as better_call0 from "better-call";
3
3
  import { z } from "zod";
4
4
 
@@ -11,87 +11,45 @@ interface ExpoOptions {
11
11
  }
12
12
  declare const expo: (options?: ExpoOptions) => {
13
13
  id: "expo";
14
- init: (ctx: better_auth0.AuthContext<better_auth0.BetterAuthOptions>) => {
14
+ init: (ctx: _better_auth_core0.AuthContext) => {
15
15
  options: {
16
16
  trustedOrigins: string[];
17
17
  };
18
18
  };
19
- onRequest(request: Request, ctx: better_auth0.AuthContext<better_auth0.BetterAuthOptions>): Promise<{
19
+ onRequest(request: Request, ctx: _better_auth_core0.AuthContext): Promise<{
20
20
  request: Request;
21
21
  } | undefined>;
22
22
  hooks: {
23
23
  after: {
24
- matcher(context: better_auth0.HookEndpointContext): boolean;
24
+ matcher(context: _better_auth_core0.HookEndpointContext): boolean;
25
25
  handler: (inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<void>;
26
26
  }[];
27
27
  };
28
28
  endpoints: {
29
- expoAuthorizationProxy: {
30
- <AsResponse extends boolean = false, ReturnHeaders extends boolean = false>(inputCtx_0: {
31
- body?: undefined;
32
- } & {
33
- method?: "GET" | undefined;
34
- } & {
35
- query: {
36
- authorizationURL: string;
37
- };
38
- } & {
39
- params?: Record<string, any>;
40
- } & {
41
- request?: Request;
42
- } & {
43
- headers?: HeadersInit;
44
- } & {
45
- asResponse?: boolean;
46
- returnHeaders?: boolean;
47
- use?: better_call0.Middleware[];
48
- path?: string;
49
- } & {
50
- asResponse?: AsResponse | undefined;
51
- returnHeaders?: ReturnHeaders | undefined;
52
- }): Promise<[AsResponse] extends [true] ? Response : [ReturnHeaders] extends [true] ? {
53
- headers: Headers;
54
- response: {
55
- status: ("OK" | "CREATED" | "ACCEPTED" | "NO_CONTENT" | "MULTIPLE_CHOICES" | "MOVED_PERMANENTLY" | "FOUND" | "SEE_OTHER" | "NOT_MODIFIED" | "TEMPORARY_REDIRECT" | "BAD_REQUEST" | "UNAUTHORIZED" | "PAYMENT_REQUIRED" | "FORBIDDEN" | "NOT_FOUND" | "METHOD_NOT_ALLOWED" | "NOT_ACCEPTABLE" | "PROXY_AUTHENTICATION_REQUIRED" | "REQUEST_TIMEOUT" | "CONFLICT" | "GONE" | "LENGTH_REQUIRED" | "PRECONDITION_FAILED" | "PAYLOAD_TOO_LARGE" | "URI_TOO_LONG" | "UNSUPPORTED_MEDIA_TYPE" | "RANGE_NOT_SATISFIABLE" | "EXPECTATION_FAILED" | "I'M_A_TEAPOT" | "MISDIRECTED_REQUEST" | "UNPROCESSABLE_ENTITY" | "LOCKED" | "FAILED_DEPENDENCY" | "TOO_EARLY" | "UPGRADE_REQUIRED" | "PRECONDITION_REQUIRED" | "TOO_MANY_REQUESTS" | "REQUEST_HEADER_FIELDS_TOO_LARGE" | "UNAVAILABLE_FOR_LEGAL_REASONS" | "INTERNAL_SERVER_ERROR" | "NOT_IMPLEMENTED" | "BAD_GATEWAY" | "SERVICE_UNAVAILABLE" | "GATEWAY_TIMEOUT" | "HTTP_VERSION_NOT_SUPPORTED" | "VARIANT_ALSO_NEGOTIATES" | "INSUFFICIENT_STORAGE" | "LOOP_DETECTED" | "NOT_EXTENDED" | "NETWORK_AUTHENTICATION_REQUIRED") | better_call0.Status;
56
- body: ({
57
- message?: string;
58
- code?: string;
59
- cause?: unknown;
60
- } & Record<string, any>) | undefined;
61
- headers: HeadersInit;
62
- statusCode: number;
63
- name: string;
64
- message: string;
65
- stack?: string;
66
- cause?: unknown;
67
- };
68
- } : {
69
- status: ("OK" | "CREATED" | "ACCEPTED" | "NO_CONTENT" | "MULTIPLE_CHOICES" | "MOVED_PERMANENTLY" | "FOUND" | "SEE_OTHER" | "NOT_MODIFIED" | "TEMPORARY_REDIRECT" | "BAD_REQUEST" | "UNAUTHORIZED" | "PAYMENT_REQUIRED" | "FORBIDDEN" | "NOT_FOUND" | "METHOD_NOT_ALLOWED" | "NOT_ACCEPTABLE" | "PROXY_AUTHENTICATION_REQUIRED" | "REQUEST_TIMEOUT" | "CONFLICT" | "GONE" | "LENGTH_REQUIRED" | "PRECONDITION_FAILED" | "PAYLOAD_TOO_LARGE" | "URI_TOO_LONG" | "UNSUPPORTED_MEDIA_TYPE" | "RANGE_NOT_SATISFIABLE" | "EXPECTATION_FAILED" | "I'M_A_TEAPOT" | "MISDIRECTED_REQUEST" | "UNPROCESSABLE_ENTITY" | "LOCKED" | "FAILED_DEPENDENCY" | "TOO_EARLY" | "UPGRADE_REQUIRED" | "PRECONDITION_REQUIRED" | "TOO_MANY_REQUESTS" | "REQUEST_HEADER_FIELDS_TOO_LARGE" | "UNAVAILABLE_FOR_LEGAL_REASONS" | "INTERNAL_SERVER_ERROR" | "NOT_IMPLEMENTED" | "BAD_GATEWAY" | "SERVICE_UNAVAILABLE" | "GATEWAY_TIMEOUT" | "HTTP_VERSION_NOT_SUPPORTED" | "VARIANT_ALSO_NEGOTIATES" | "INSUFFICIENT_STORAGE" | "LOOP_DETECTED" | "NOT_EXTENDED" | "NETWORK_AUTHENTICATION_REQUIRED") | better_call0.Status;
70
- body: ({
71
- message?: string;
72
- code?: string;
73
- cause?: unknown;
74
- } & Record<string, any>) | undefined;
75
- headers: HeadersInit;
76
- statusCode: number;
77
- name: string;
78
- message: string;
79
- stack?: string;
80
- cause?: unknown;
81
- }>;
82
- options: {
83
- method: "GET";
84
- query: z.ZodObject<{
85
- authorizationURL: z.ZodString;
86
- }, z.core.$strip>;
87
- metadata: {
88
- isAction: boolean;
89
- };
90
- } & {
91
- use: any[];
29
+ expoAuthorizationProxy: better_call0.StrictEndpoint<"/expo-authorization-proxy", {
30
+ method: "GET";
31
+ query: z.ZodObject<{
32
+ authorizationURL: z.ZodString;
33
+ }, z.core.$strip>;
34
+ metadata: {
35
+ isAction: boolean;
92
36
  };
93
- path: "/expo-authorization-proxy";
94
- };
37
+ } & {
38
+ use: any[];
39
+ }, {
40
+ status: ("OK" | "CREATED" | "ACCEPTED" | "NO_CONTENT" | "MULTIPLE_CHOICES" | "MOVED_PERMANENTLY" | "FOUND" | "SEE_OTHER" | "NOT_MODIFIED" | "TEMPORARY_REDIRECT" | "BAD_REQUEST" | "UNAUTHORIZED" | "PAYMENT_REQUIRED" | "FORBIDDEN" | "NOT_FOUND" | "METHOD_NOT_ALLOWED" | "NOT_ACCEPTABLE" | "PROXY_AUTHENTICATION_REQUIRED" | "REQUEST_TIMEOUT" | "CONFLICT" | "GONE" | "LENGTH_REQUIRED" | "PRECONDITION_FAILED" | "PAYLOAD_TOO_LARGE" | "URI_TOO_LONG" | "UNSUPPORTED_MEDIA_TYPE" | "RANGE_NOT_SATISFIABLE" | "EXPECTATION_FAILED" | "I'M_A_TEAPOT" | "MISDIRECTED_REQUEST" | "UNPROCESSABLE_ENTITY" | "LOCKED" | "FAILED_DEPENDENCY" | "TOO_EARLY" | "UPGRADE_REQUIRED" | "PRECONDITION_REQUIRED" | "TOO_MANY_REQUESTS" | "REQUEST_HEADER_FIELDS_TOO_LARGE" | "UNAVAILABLE_FOR_LEGAL_REASONS" | "INTERNAL_SERVER_ERROR" | "NOT_IMPLEMENTED" | "BAD_GATEWAY" | "SERVICE_UNAVAILABLE" | "GATEWAY_TIMEOUT" | "HTTP_VERSION_NOT_SUPPORTED" | "VARIANT_ALSO_NEGOTIATES" | "INSUFFICIENT_STORAGE" | "LOOP_DETECTED" | "NOT_EXTENDED" | "NETWORK_AUTHENTICATION_REQUIRED") | better_call0.Status;
41
+ body: ({
42
+ message?: string;
43
+ code?: string;
44
+ cause?: unknown;
45
+ } & Record<string, any>) | undefined;
46
+ headers: HeadersInit;
47
+ statusCode: number;
48
+ name: string;
49
+ message: string;
50
+ stack?: string;
51
+ cause?: unknown;
52
+ }>;
95
53
  };
96
54
  };
97
55
  //#endregion
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
- import * as better_auth0 from "better-auth";
3
2
  import * as better_call0 from "better-call";
3
+ import * as _better_auth_core0 from "@better-auth/core";
4
4
 
5
5
  //#region src/index.d.ts
6
6
  interface ExpoOptions {
@@ -11,87 +11,45 @@ interface ExpoOptions {
11
11
  }
12
12
  declare const expo: (options?: ExpoOptions) => {
13
13
  id: "expo";
14
- init: (ctx: better_auth0.AuthContext<better_auth0.BetterAuthOptions>) => {
14
+ init: (ctx: _better_auth_core0.AuthContext) => {
15
15
  options: {
16
16
  trustedOrigins: string[];
17
17
  };
18
18
  };
19
- onRequest(request: Request, ctx: better_auth0.AuthContext<better_auth0.BetterAuthOptions>): Promise<{
19
+ onRequest(request: Request, ctx: _better_auth_core0.AuthContext): Promise<{
20
20
  request: Request;
21
21
  } | undefined>;
22
22
  hooks: {
23
23
  after: {
24
- matcher(context: better_auth0.HookEndpointContext): boolean;
24
+ matcher(context: _better_auth_core0.HookEndpointContext): boolean;
25
25
  handler: (inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<void>;
26
26
  }[];
27
27
  };
28
28
  endpoints: {
29
- expoAuthorizationProxy: {
30
- <AsResponse extends boolean = false, ReturnHeaders extends boolean = false>(inputCtx_0: {
31
- body?: undefined;
32
- } & {
33
- method?: "GET" | undefined;
34
- } & {
35
- query: {
36
- authorizationURL: string;
37
- };
38
- } & {
39
- params?: Record<string, any>;
40
- } & {
41
- request?: Request;
42
- } & {
43
- headers?: HeadersInit;
44
- } & {
45
- asResponse?: boolean;
46
- returnHeaders?: boolean;
47
- use?: better_call0.Middleware[];
48
- path?: string;
49
- } & {
50
- asResponse?: AsResponse | undefined;
51
- returnHeaders?: ReturnHeaders | undefined;
52
- }): Promise<[AsResponse] extends [true] ? Response : [ReturnHeaders] extends [true] ? {
53
- headers: Headers;
54
- response: {
55
- status: ("OK" | "CREATED" | "ACCEPTED" | "NO_CONTENT" | "MULTIPLE_CHOICES" | "MOVED_PERMANENTLY" | "FOUND" | "SEE_OTHER" | "NOT_MODIFIED" | "TEMPORARY_REDIRECT" | "BAD_REQUEST" | "UNAUTHORIZED" | "PAYMENT_REQUIRED" | "FORBIDDEN" | "NOT_FOUND" | "METHOD_NOT_ALLOWED" | "NOT_ACCEPTABLE" | "PROXY_AUTHENTICATION_REQUIRED" | "REQUEST_TIMEOUT" | "CONFLICT" | "GONE" | "LENGTH_REQUIRED" | "PRECONDITION_FAILED" | "PAYLOAD_TOO_LARGE" | "URI_TOO_LONG" | "UNSUPPORTED_MEDIA_TYPE" | "RANGE_NOT_SATISFIABLE" | "EXPECTATION_FAILED" | "I'M_A_TEAPOT" | "MISDIRECTED_REQUEST" | "UNPROCESSABLE_ENTITY" | "LOCKED" | "FAILED_DEPENDENCY" | "TOO_EARLY" | "UPGRADE_REQUIRED" | "PRECONDITION_REQUIRED" | "TOO_MANY_REQUESTS" | "REQUEST_HEADER_FIELDS_TOO_LARGE" | "UNAVAILABLE_FOR_LEGAL_REASONS" | "INTERNAL_SERVER_ERROR" | "NOT_IMPLEMENTED" | "BAD_GATEWAY" | "SERVICE_UNAVAILABLE" | "GATEWAY_TIMEOUT" | "HTTP_VERSION_NOT_SUPPORTED" | "VARIANT_ALSO_NEGOTIATES" | "INSUFFICIENT_STORAGE" | "LOOP_DETECTED" | "NOT_EXTENDED" | "NETWORK_AUTHENTICATION_REQUIRED") | better_call0.Status;
56
- body: ({
57
- message?: string;
58
- code?: string;
59
- cause?: unknown;
60
- } & Record<string, any>) | undefined;
61
- headers: HeadersInit;
62
- statusCode: number;
63
- name: string;
64
- message: string;
65
- stack?: string;
66
- cause?: unknown;
67
- };
68
- } : {
69
- status: ("OK" | "CREATED" | "ACCEPTED" | "NO_CONTENT" | "MULTIPLE_CHOICES" | "MOVED_PERMANENTLY" | "FOUND" | "SEE_OTHER" | "NOT_MODIFIED" | "TEMPORARY_REDIRECT" | "BAD_REQUEST" | "UNAUTHORIZED" | "PAYMENT_REQUIRED" | "FORBIDDEN" | "NOT_FOUND" | "METHOD_NOT_ALLOWED" | "NOT_ACCEPTABLE" | "PROXY_AUTHENTICATION_REQUIRED" | "REQUEST_TIMEOUT" | "CONFLICT" | "GONE" | "LENGTH_REQUIRED" | "PRECONDITION_FAILED" | "PAYLOAD_TOO_LARGE" | "URI_TOO_LONG" | "UNSUPPORTED_MEDIA_TYPE" | "RANGE_NOT_SATISFIABLE" | "EXPECTATION_FAILED" | "I'M_A_TEAPOT" | "MISDIRECTED_REQUEST" | "UNPROCESSABLE_ENTITY" | "LOCKED" | "FAILED_DEPENDENCY" | "TOO_EARLY" | "UPGRADE_REQUIRED" | "PRECONDITION_REQUIRED" | "TOO_MANY_REQUESTS" | "REQUEST_HEADER_FIELDS_TOO_LARGE" | "UNAVAILABLE_FOR_LEGAL_REASONS" | "INTERNAL_SERVER_ERROR" | "NOT_IMPLEMENTED" | "BAD_GATEWAY" | "SERVICE_UNAVAILABLE" | "GATEWAY_TIMEOUT" | "HTTP_VERSION_NOT_SUPPORTED" | "VARIANT_ALSO_NEGOTIATES" | "INSUFFICIENT_STORAGE" | "LOOP_DETECTED" | "NOT_EXTENDED" | "NETWORK_AUTHENTICATION_REQUIRED") | better_call0.Status;
70
- body: ({
71
- message?: string;
72
- code?: string;
73
- cause?: unknown;
74
- } & Record<string, any>) | undefined;
75
- headers: HeadersInit;
76
- statusCode: number;
77
- name: string;
78
- message: string;
79
- stack?: string;
80
- cause?: unknown;
81
- }>;
82
- options: {
83
- method: "GET";
84
- query: z.ZodObject<{
85
- authorizationURL: z.ZodString;
86
- }, z.core.$strip>;
87
- metadata: {
88
- isAction: boolean;
89
- };
90
- } & {
91
- use: any[];
29
+ expoAuthorizationProxy: better_call0.StrictEndpoint<"/expo-authorization-proxy", {
30
+ method: "GET";
31
+ query: z.ZodObject<{
32
+ authorizationURL: z.ZodString;
33
+ }, z.core.$strip>;
34
+ metadata: {
35
+ isAction: boolean;
92
36
  };
93
- path: "/expo-authorization-proxy";
94
- };
37
+ } & {
38
+ use: any[];
39
+ }, {
40
+ status: ("OK" | "CREATED" | "ACCEPTED" | "NO_CONTENT" | "MULTIPLE_CHOICES" | "MOVED_PERMANENTLY" | "FOUND" | "SEE_OTHER" | "NOT_MODIFIED" | "TEMPORARY_REDIRECT" | "BAD_REQUEST" | "UNAUTHORIZED" | "PAYMENT_REQUIRED" | "FORBIDDEN" | "NOT_FOUND" | "METHOD_NOT_ALLOWED" | "NOT_ACCEPTABLE" | "PROXY_AUTHENTICATION_REQUIRED" | "REQUEST_TIMEOUT" | "CONFLICT" | "GONE" | "LENGTH_REQUIRED" | "PRECONDITION_FAILED" | "PAYLOAD_TOO_LARGE" | "URI_TOO_LONG" | "UNSUPPORTED_MEDIA_TYPE" | "RANGE_NOT_SATISFIABLE" | "EXPECTATION_FAILED" | "I'M_A_TEAPOT" | "MISDIRECTED_REQUEST" | "UNPROCESSABLE_ENTITY" | "LOCKED" | "FAILED_DEPENDENCY" | "TOO_EARLY" | "UPGRADE_REQUIRED" | "PRECONDITION_REQUIRED" | "TOO_MANY_REQUESTS" | "REQUEST_HEADER_FIELDS_TOO_LARGE" | "UNAVAILABLE_FOR_LEGAL_REASONS" | "INTERNAL_SERVER_ERROR" | "NOT_IMPLEMENTED" | "BAD_GATEWAY" | "SERVICE_UNAVAILABLE" | "GATEWAY_TIMEOUT" | "HTTP_VERSION_NOT_SUPPORTED" | "VARIANT_ALSO_NEGOTIATES" | "INSUFFICIENT_STORAGE" | "LOOP_DETECTED" | "NOT_EXTENDED" | "NETWORK_AUTHENTICATION_REQUIRED") | better_call0.Status;
41
+ body: ({
42
+ message?: string;
43
+ code?: string;
44
+ cause?: unknown;
45
+ } & Record<string, any>) | undefined;
46
+ headers: HeadersInit;
47
+ statusCode: number;
48
+ name: string;
49
+ message: string;
50
+ stack?: string;
51
+ cause?: unknown;
52
+ }>;
95
53
  };
96
54
  };
97
55
  //#endregion
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
- import { APIError, createAuthEndpoint, createAuthMiddleware } from "better-auth/api";
1
+ import { createAuthEndpoint, createAuthMiddleware } from "@better-auth/core/api";
2
2
  import { z } from "zod";
3
+ import { APIError } from "better-call";
3
4
 
4
5
  //#region src/index.ts
5
6
  const expo = (options) => {
@@ -21,7 +22,7 @@ const expo = (options) => {
21
22
  },
22
23
  hooks: { after: [{
23
24
  matcher(context) {
24
- return context.path?.startsWith("/callback") || context.path?.startsWith("/oauth2/callback");
25
+ return !!(context.path?.startsWith("/callback") || context.path?.startsWith("/oauth2/callback"));
25
26
  },
26
27
  handler: createAuthMiddleware(async (ctx) => {
27
28
  const headers = ctx.context.responseHeaders;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-auth/expo",
3
- "version": "1.4.0-beta.11",
3
+ "version": "1.4.0-beta.13",
4
4
  "type": "module",
5
5
  "description": "Better Auth integration for Expo and React Native applications.",
6
6
  "main": "dist/index.js",
@@ -13,11 +13,13 @@
13
13
  "homepage": "https://www.better-auth.com/docs/integrations/expo",
14
14
  "exports": {
15
15
  ".": {
16
+ "better-auth-dev-source": "./src/index.ts",
16
17
  "types": "./dist/index.d.ts",
17
18
  "import": "./dist/index.js",
18
19
  "require": "./dist/index.cjs"
19
20
  },
20
21
  "./client": {
22
+ "better-auth-dev-source": "./src/client.ts",
21
23
  "types": "./dist/client.d.ts",
22
24
  "import": "./dist/client.js",
23
25
  "require": "./dist/client.cjs"
@@ -54,8 +56,9 @@
54
56
  "expo-secure-store": "~14.2.3",
55
57
  "expo-web-browser": "~14.2.0",
56
58
  "react-native": "~0.80.2",
57
- "tsdown": "^0.15.6",
58
- "better-auth": "1.4.0-beta.11"
59
+ "tsdown": "^0.15.9",
60
+ "@better-auth/core": "1.4.0-beta.13",
61
+ "better-auth": "1.4.0-beta.13"
59
62
  },
60
63
  "peerDependencies": {
61
64
  "expo-constants": ">=17.0.0",
@@ -63,10 +66,11 @@
63
66
  "expo-linking": ">=7.0.0",
64
67
  "expo-secure-store": ">=14.0.0",
65
68
  "expo-web-browser": ">=14.0.0",
66
- "better-auth": "1.4.0-beta.11"
69
+ "@better-auth/core": "1.4.0-beta.13"
67
70
  },
68
71
  "dependencies": {
69
72
  "@better-fetch/fetch": "1.1.18",
73
+ "better-call": "1.0.24",
70
74
  "zod": "^4.1.5"
71
75
  },
72
76
  "files": [