@better-auth/electron 1.5.0-beta.12

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.
@@ -0,0 +1,239 @@
1
+ import * as better_auth0 from "better-auth";
2
+ import * as z from "zod";
3
+ import { HookEndpointContext } from "@better-auth/core";
4
+ import * as better_call0 from "better-call";
5
+
6
+ //#region src/types/options.d.ts
7
+ interface ElectronOptions {
8
+ /**
9
+ * The duration (in seconds) for which the authorization code remains valid.
10
+ *
11
+ * @default 300 (5 minutes)
12
+ */
13
+ codeExpiresIn?: number | undefined;
14
+ /**
15
+ * The duration (in seconds) for which the redirect cookie remains valid.
16
+ *
17
+ * @default 120 (2 minutes)
18
+ */
19
+ redirectCookieExpiresIn?: number | undefined;
20
+ /**
21
+ * The prefix to use for cookies set by the plugin.
22
+ *
23
+ * @default "better-auth"
24
+ */
25
+ cookiePrefix?: string | undefined;
26
+ /**
27
+ * Client ID to use for identifying the Electron client during authorization.
28
+ *
29
+ * @default "electron"
30
+ */
31
+ clientID?: string | undefined;
32
+ /**
33
+ * Override the origin for Electron API routes.
34
+ * Enable this if you're facing cors origin issues with Electron API routes.
35
+ *
36
+ * @default false
37
+ */
38
+ disableOriginOverride?: boolean | undefined;
39
+ }
40
+ //#endregion
41
+ //#region src/index.d.ts
42
+ declare module "@better-auth/core" {
43
+ interface BetterAuthPluginRegistry<AuthOptions, Options> {
44
+ electron: {
45
+ creator: typeof electron;
46
+ };
47
+ }
48
+ }
49
+ declare const electron: (options?: ElectronOptions | undefined) => {
50
+ id: "electron";
51
+ onRequest(request: Request, _ctx: better_auth0.AuthContext): Promise<{
52
+ request: Request;
53
+ } | undefined>;
54
+ hooks: {
55
+ after: ({
56
+ matcher: (ctx: HookEndpointContext) => boolean;
57
+ handler: (inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<void>;
58
+ } | {
59
+ matcher: (ctx: HookEndpointContext) => boolean;
60
+ handler: (inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<better_call0.MiddlewareContext<better_call0.MiddlewareOptions, {
61
+ returned?: unknown | undefined;
62
+ responseHeaders?: Headers | undefined;
63
+ } & better_auth0.PluginContext<better_auth0.BetterAuthOptions> & better_auth0.InfoContext & {
64
+ options: better_auth0.BetterAuthOptions;
65
+ trustedOrigins: string[];
66
+ isTrustedOrigin: (url: string, settings?: {
67
+ allowRelativePaths: boolean;
68
+ }) => boolean;
69
+ oauthConfig: {
70
+ skipStateCookieCheck?: boolean | undefined;
71
+ storeStateStrategy: "database" | "cookie";
72
+ };
73
+ newSession: {
74
+ session: {
75
+ id: string;
76
+ createdAt: Date;
77
+ updatedAt: Date;
78
+ userId: string;
79
+ expiresAt: Date;
80
+ token: string;
81
+ ipAddress?: string | null | undefined;
82
+ userAgent?: string | null | undefined;
83
+ } & Record<string, any>;
84
+ user: {
85
+ id: string;
86
+ createdAt: Date;
87
+ updatedAt: Date;
88
+ email: string;
89
+ emailVerified: boolean;
90
+ name: string;
91
+ image?: string | null | undefined;
92
+ } & Record<string, any>;
93
+ } | null;
94
+ session: {
95
+ session: {
96
+ id: string;
97
+ createdAt: Date;
98
+ updatedAt: Date;
99
+ userId: string;
100
+ expiresAt: Date;
101
+ token: string;
102
+ ipAddress?: string | null | undefined;
103
+ userAgent?: string | null | undefined;
104
+ } & Record<string, any>;
105
+ user: {
106
+ id: string;
107
+ createdAt: Date;
108
+ updatedAt: Date;
109
+ email: string;
110
+ emailVerified: boolean;
111
+ name: string;
112
+ image?: string | null | undefined;
113
+ } & Record<string, any>;
114
+ } | null;
115
+ setNewSession: (session: {
116
+ session: {
117
+ id: string;
118
+ createdAt: Date;
119
+ updatedAt: Date;
120
+ userId: string;
121
+ expiresAt: Date;
122
+ token: string;
123
+ ipAddress?: string | null | undefined;
124
+ userAgent?: string | null | undefined;
125
+ } & Record<string, any>;
126
+ user: {
127
+ id: string;
128
+ createdAt: Date;
129
+ updatedAt: Date;
130
+ email: string;
131
+ emailVerified: boolean;
132
+ name: string;
133
+ image?: string | null | undefined;
134
+ } & Record<string, any>;
135
+ } | null) => void;
136
+ socialProviders: better_auth0.OAuthProvider[];
137
+ authCookies: better_auth0.BetterAuthCookies;
138
+ logger: ReturnType<typeof better_auth0.createLogger>;
139
+ rateLimit: {
140
+ enabled: boolean;
141
+ window: number;
142
+ max: number;
143
+ storage: "memory" | "database" | "secondary-storage";
144
+ } & Omit<better_auth0.BetterAuthRateLimitOptions, "enabled" | "window" | "max" | "storage">;
145
+ adapter: better_auth0.DBAdapter<better_auth0.BetterAuthOptions>;
146
+ internalAdapter: better_auth0.InternalAdapter<better_auth0.BetterAuthOptions>;
147
+ createAuthCookie: (cookieName: string, overrideAttributes?: Partial<better_call0.CookieOptions> | undefined) => better_auth0.BetterAuthCookie;
148
+ secret: string;
149
+ sessionConfig: {
150
+ updateAge: number;
151
+ expiresIn: number;
152
+ freshAge: number;
153
+ cookieRefreshCache: false | {
154
+ enabled: true;
155
+ updateAge: number;
156
+ };
157
+ };
158
+ generateId: (options: {
159
+ model: better_auth0.ModelNames;
160
+ size?: number | undefined;
161
+ }) => string | false;
162
+ secondaryStorage: better_auth0.SecondaryStorage | undefined;
163
+ password: {
164
+ hash: (password: string) => Promise<string>;
165
+ verify: (data: {
166
+ password: string;
167
+ hash: string;
168
+ }) => Promise<boolean>;
169
+ config: {
170
+ minPasswordLength: number;
171
+ maxPasswordLength: number;
172
+ };
173
+ checkPassword: (userId: string, ctx: better_auth0.GenericEndpointContext<better_auth0.BetterAuthOptions>) => Promise<boolean>;
174
+ };
175
+ tables: better_auth0.BetterAuthDBSchema;
176
+ runMigrations: () => Promise<void>;
177
+ publishTelemetry: (event: {
178
+ type: string;
179
+ anonymousId?: string | undefined;
180
+ payload: Record<string, any>;
181
+ }) => Promise<void>;
182
+ skipOriginCheck: boolean | string[];
183
+ skipCSRFCheck: boolean;
184
+ runInBackground: (promise: Promise<unknown>) => void;
185
+ runInBackgroundOrAwait: (promise: Promise<unknown> | void) => better_auth0.Awaitable<unknown>;
186
+ }> | undefined>;
187
+ })[];
188
+ };
189
+ endpoints: {
190
+ electronToken: better_call0.StrictEndpoint<"/electron/token", {
191
+ method: "POST";
192
+ body: z.ZodObject<{
193
+ token: z.ZodString;
194
+ state: z.ZodString;
195
+ code_verifier: z.ZodString;
196
+ }, z.core.$strip>;
197
+ metadata: {
198
+ scope: "http";
199
+ };
200
+ }, {
201
+ token: string;
202
+ user: better_auth0.User & Record<string, any>;
203
+ }>;
204
+ electronInitOAuthProxy: better_call0.StrictEndpoint<"/electron/init-oauth-proxy", {
205
+ method: "GET";
206
+ query: z.ZodObject<{
207
+ provider: z.ZodString;
208
+ state: z.ZodString;
209
+ code_challenge: z.ZodString;
210
+ code_challenge_method: z.ZodOptional<z.ZodString>;
211
+ }, z.core.$strip>;
212
+ metadata: {
213
+ scope: "http";
214
+ };
215
+ }, {
216
+ url: string | undefined;
217
+ redirect: boolean;
218
+ user?: better_auth0.User & Record<string, any>;
219
+ token?: string;
220
+ } | undefined>;
221
+ };
222
+ options: {
223
+ codeExpiresIn: number;
224
+ redirectCookieExpiresIn: number;
225
+ cookiePrefix: string;
226
+ clientID: string;
227
+ disableOriginOverride?: boolean | undefined;
228
+ };
229
+ $ERROR_CODES: {
230
+ INVALID_TOKEN: better_auth0.RawError<"INVALID_TOKEN">;
231
+ STATE_MISMATCH: better_auth0.RawError<"STATE_MISMATCH">;
232
+ MISSING_CODE_CHALLENGE: better_auth0.RawError<"MISSING_CODE_CHALLENGE">;
233
+ INVALID_CODE_VERIFIER: better_auth0.RawError<"INVALID_CODE_VERIFIER">;
234
+ MISSING_STATE: better_auth0.RawError<"MISSING_STATE">;
235
+ MISSING_PKCE: better_auth0.RawError<"MISSING_PKCE">;
236
+ };
237
+ };
238
+ //#endregion
239
+ export { ElectronOptions, electron };
package/dist/index.mjs ADDED
@@ -0,0 +1,201 @@
1
+ import { createAuthMiddleware } from "@better-auth/core/api";
2
+ import { APIError, BASE_ERROR_CODES } from "@better-auth/core/error";
3
+ import { defineErrorCodes, safeJSONParse } from "better-auth";
4
+ import { generateRandomString } from "better-auth/crypto";
5
+ import * as z from "zod";
6
+ import { Buffer } from "node:buffer";
7
+ import { timingSafeEqual } from "node:crypto";
8
+ import { SocialProviderListEnum } from "@better-auth/core/social-providers";
9
+ import { safeJSONParse as safeJSONParse$1 } from "@better-auth/core/utils/json";
10
+ import { base64Url } from "@better-auth/utils/base64";
11
+ import { createHash } from "@better-auth/utils/hash";
12
+ import { betterFetch } from "@better-fetch/fetch";
13
+ import { createAuthEndpoint } from "better-auth/api";
14
+ import { setSessionCookie } from "better-auth/cookies";
15
+ import { parseUserOutput } from "better-auth/db";
16
+
17
+ //#region src/error-codes.ts
18
+ const ELECTRON_ERROR_CODES = defineErrorCodes({
19
+ INVALID_TOKEN: "Invalid or expired token.",
20
+ STATE_MISMATCH: "state mismatch",
21
+ MISSING_CODE_CHALLENGE: "missing code challenge",
22
+ INVALID_CODE_VERIFIER: "Invalid code verifier",
23
+ MISSING_STATE: "state is required",
24
+ MISSING_PKCE: "pkce is required"
25
+ });
26
+
27
+ //#endregion
28
+ //#region src/routes.ts
29
+ const electronTokenBodySchema = z.object({
30
+ token: z.string().nonempty(),
31
+ state: z.string().nonempty(),
32
+ code_verifier: z.string().nonempty()
33
+ });
34
+ const electronToken = (opts) => createAuthEndpoint("/electron/token", {
35
+ method: "POST",
36
+ body: electronTokenBodySchema,
37
+ metadata: { scope: "http" }
38
+ }, async (ctx) => {
39
+ const token = await ctx.context.internalAdapter.findVerificationValue(`electron:${ctx.body.token}`);
40
+ if (!token || token.expiresAt < /* @__PURE__ */ new Date()) throw APIError.from("NOT_FOUND", ELECTRON_ERROR_CODES.INVALID_TOKEN);
41
+ const tokenRecord = safeJSONParse$1(token.value);
42
+ if (!tokenRecord) throw APIError.from("INTERNAL_SERVER_ERROR", ELECTRON_ERROR_CODES.INVALID_TOKEN);
43
+ if (tokenRecord.state !== ctx.body.state) throw APIError.from("BAD_REQUEST", ELECTRON_ERROR_CODES.STATE_MISMATCH);
44
+ if (!tokenRecord.codeChallenge) throw APIError.from("BAD_REQUEST", ELECTRON_ERROR_CODES.MISSING_CODE_CHALLENGE);
45
+ if (tokenRecord.codeChallengeMethod === "s256") {
46
+ const codeChallenge = Buffer.from(base64Url.decode(tokenRecord.codeChallenge));
47
+ const codeVerifier = Buffer.from(await createHash("SHA-256").digest(ctx.body.code_verifier));
48
+ if (codeChallenge.length !== codeVerifier.length || !timingSafeEqual(codeChallenge, codeVerifier)) throw APIError.from("BAD_REQUEST", ELECTRON_ERROR_CODES.INVALID_CODE_VERIFIER);
49
+ } else if (tokenRecord.codeChallenge !== ctx.body.code_verifier) throw APIError.from("BAD_REQUEST", ELECTRON_ERROR_CODES.INVALID_CODE_VERIFIER);
50
+ await ctx.context.internalAdapter.deleteVerificationValue(token.id);
51
+ const user = await ctx.context.internalAdapter.findUserById(tokenRecord.userId);
52
+ if (!user) throw APIError.from("INTERNAL_SERVER_ERROR", BASE_ERROR_CODES.USER_NOT_FOUND);
53
+ const session = await ctx.context.internalAdapter.createSession(user.id);
54
+ if (!session) throw APIError.from("INTERNAL_SERVER_ERROR", BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION);
55
+ await setSessionCookie(ctx, {
56
+ session,
57
+ user
58
+ });
59
+ return ctx.json({
60
+ token: session.token,
61
+ user: parseUserOutput(ctx.context.options, user)
62
+ });
63
+ });
64
+ const electronInitOAuthProxyQuerySchema = z.object({
65
+ provider: z.string().nonempty(),
66
+ state: z.string(),
67
+ code_challenge: z.string(),
68
+ code_challenge_method: z.string().optional()
69
+ });
70
+ const electronInitOAuthProxy = (opts) => createAuthEndpoint("/electron/init-oauth-proxy", {
71
+ method: "GET",
72
+ query: electronInitOAuthProxyQuerySchema,
73
+ metadata: { scope: "http" }
74
+ }, async (ctx) => {
75
+ const isSocialProvider = SocialProviderListEnum.safeParse(ctx.query.provider);
76
+ if (!isSocialProvider && !ctx.context.getPlugin("generic-oauth")) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.PROVIDER_NOT_FOUND);
77
+ const headers = new Headers(ctx.request?.headers);
78
+ headers.set("origin", new URL(ctx.context.baseURL).origin);
79
+ let setCookie = null;
80
+ const searchParams = new URLSearchParams();
81
+ searchParams.set("client_id", opts.clientID || "electron");
82
+ searchParams.set("code_challenge", ctx.query.code_challenge);
83
+ searchParams.set("code_challenge_method", ctx.query.code_challenge_method || "plain");
84
+ searchParams.set("state", ctx.query.state);
85
+ const res = await betterFetch(`${isSocialProvider ? "/sign-in/social" : "/sign-in/oauth2"}?${searchParams.toString()}`, {
86
+ baseURL: ctx.context.baseURL,
87
+ method: "POST",
88
+ body: {
89
+ provider: ctx.query.provider,
90
+ disableRedirect: true
91
+ },
92
+ onResponse: (ctx) => {
93
+ setCookie = ctx.response.headers.get("set-cookie") ?? null;
94
+ },
95
+ headers
96
+ });
97
+ if (res.error) throw new APIError("INTERNAL_SERVER_ERROR", { message: res.error.message || "An unknown error occurred." });
98
+ if (setCookie) ctx.setHeader("set-cookie", setCookie);
99
+ if (res.data.url) {
100
+ ctx.setHeader("Location", res.data.url);
101
+ ctx.setStatus(302);
102
+ return;
103
+ }
104
+ return ctx.json(res.data);
105
+ });
106
+
107
+ //#endregion
108
+ //#region src/index.ts
109
+ const electron = (options) => {
110
+ const opts = {
111
+ codeExpiresIn: 300,
112
+ redirectCookieExpiresIn: 120,
113
+ cookiePrefix: "better-auth",
114
+ clientID: "electron",
115
+ ...options || {}
116
+ };
117
+ const hookMatcher = (ctx) => {
118
+ return !!(ctx.path?.startsWith("/sign-in") || ctx.path?.startsWith("/sign-up") || ctx.path?.startsWith("/callback") || ctx.path?.startsWith("/oauth2/callback") || ctx.path?.startsWith("/magic-link/verify") || ctx.path?.startsWith("/email-otp/verify-email") || ctx.path?.startsWith("/verify-email") || ctx.path?.startsWith("/one-tap/callback") || ctx.path?.startsWith("/passkey/verify-authentication") || ctx.path?.startsWith("/phone-number/verify"));
119
+ };
120
+ return {
121
+ id: "electron",
122
+ async onRequest(request, _ctx) {
123
+ if (opts.disableOriginOverride || request.headers.get("origin")) return;
124
+ const electronOrigin = request.headers.get("electron-origin");
125
+ if (!electronOrigin) return;
126
+ const req = request.clone();
127
+ req.headers.set("origin", electronOrigin);
128
+ return { request: req };
129
+ },
130
+ hooks: { after: [{
131
+ matcher: (ctx) => !hookMatcher(ctx),
132
+ handler: createAuthMiddleware(async (ctx) => {
133
+ const transferCookie = await ctx.getSignedCookie(`${opts.cookiePrefix}.transfer_token`, ctx.context.secret);
134
+ if (!ctx.context.newSession?.session || !transferCookie) return;
135
+ const cookie = ctx.context.createAuthCookie("transfer_token", { maxAge: opts.codeExpiresIn });
136
+ await ctx.setSignedCookie(cookie.name, transferCookie, ctx.context.secret, cookie.attributes);
137
+ })
138
+ }, {
139
+ matcher: hookMatcher,
140
+ handler: createAuthMiddleware(async (ctx) => {
141
+ const querySchema = z.object({
142
+ client_id: z.string(),
143
+ code_challenge: z.string().nonempty(),
144
+ code_challenge_method: z.string().optional().default("plain"),
145
+ state: z.string().nonempty()
146
+ });
147
+ const cookie = ctx.context.createAuthCookie("transfer_token", { maxAge: opts.codeExpiresIn });
148
+ if (ctx.query?.client_id === opts.clientID && (ctx.path.startsWith("/sign-in") || ctx.path.startsWith("/sign-up"))) {
149
+ const query = querySchema.safeParse(ctx.query);
150
+ if (query.success) await ctx.setSignedCookie(cookie.name, JSON.stringify(query.data), ctx.context.secret, cookie.attributes);
151
+ }
152
+ if (!ctx.context.newSession?.session) return;
153
+ const transferCookie = await ctx.getSignedCookie(cookie.name, ctx.context.secret);
154
+ ctx.setCookie(cookie.name, "", {
155
+ ...cookie.attributes,
156
+ maxAge: 0
157
+ });
158
+ let transferPayload = null;
159
+ if (!!transferCookie) transferPayload = safeJSONParse(transferCookie);
160
+ else {
161
+ const query = querySchema.safeParse(ctx.query);
162
+ if (query.success) transferPayload = query.data;
163
+ }
164
+ if (!transferPayload) return;
165
+ const { client_id, code_challenge, code_challenge_method, state } = transferPayload;
166
+ if (client_id !== opts.clientID) return;
167
+ if (!state) throw APIError.from("BAD_REQUEST", ELECTRON_ERROR_CODES.MISSING_STATE);
168
+ if (!code_challenge) throw APIError.from("BAD_REQUEST", ELECTRON_ERROR_CODES.MISSING_PKCE);
169
+ const redirectCookieName = `${opts.cookiePrefix}.${opts.clientID}`;
170
+ const identifier = generateRandomString(32, "a-z", "A-Z", "0-9");
171
+ const codeExpiresInMs = opts.codeExpiresIn * 1e3;
172
+ const expiresAt = new Date(Date.now() + codeExpiresInMs);
173
+ await ctx.context.internalAdapter.createVerificationValue({
174
+ identifier: `electron:${identifier}`,
175
+ value: JSON.stringify({
176
+ userId: ctx.context.newSession.user.id,
177
+ codeChallenge: code_challenge,
178
+ codeChallengeMethod: code_challenge_method.toLowerCase(),
179
+ state
180
+ }),
181
+ expiresAt
182
+ });
183
+ ctx.setCookie(redirectCookieName, identifier, {
184
+ ...ctx.context.authCookies.sessionToken.attributes,
185
+ maxAge: opts.redirectCookieExpiresIn,
186
+ httpOnly: false
187
+ });
188
+ return ctx;
189
+ })
190
+ }] },
191
+ endpoints: {
192
+ electronToken: electronToken(opts),
193
+ electronInitOAuthProxy: electronInitOAuthProxy(opts)
194
+ },
195
+ options: opts,
196
+ $ERROR_CODES: ELECTRON_ERROR_CODES
197
+ };
198
+ };
199
+
200
+ //#endregion
201
+ export { electron };
@@ -0,0 +1,27 @@
1
+ import { r as ElectronProxyClientOptions } from "./authenticate-CWAVJ4W8.mjs";
2
+
3
+ //#region src/proxy.d.ts
4
+ declare const electronProxyClient: (options: ElectronProxyClientOptions) => {
5
+ id: "electron-proxy";
6
+ getActions: () => {
7
+ /**
8
+ * Ensures redirecting to the Electron app.
9
+ *
10
+ * Polls for a cookie set by the server to indicate that an authorization code is available.
11
+ *
12
+ * @returns The interval ID which can be used to clear the polling.
13
+ */
14
+ ensureElectronRedirect: (cfg?: {
15
+ /**
16
+ * @default 10_000
17
+ */
18
+ timeout?: number | undefined;
19
+ /**
20
+ * @default 100
21
+ */
22
+ interval?: number | undefined;
23
+ } | undefined) => NodeJS.Timeout;
24
+ };
25
+ };
26
+ //#endregion
27
+ export { electronProxyClient };
package/dist/proxy.mjs ADDED
@@ -0,0 +1,39 @@
1
+ import { n as parseProtocolScheme } from "./utils-C3fLmbAT.mjs";
2
+ import { parseCookies } from "better-auth/cookies";
3
+
4
+ //#region src/proxy.ts
5
+ const electronProxyClient = (options) => {
6
+ const opts = {
7
+ clientID: "electron",
8
+ cookiePrefix: "better-auth",
9
+ callbackPath: "/auth/callback",
10
+ ...options
11
+ };
12
+ const redirectCookieName = `${opts.cookiePrefix}.${opts.clientID}`;
13
+ const { scheme } = parseProtocolScheme(opts.protocol);
14
+ return {
15
+ id: "electron-proxy",
16
+ getActions: () => {
17
+ return { ensureElectronRedirect: (cfg) => {
18
+ const timeout = cfg?.timeout || 1e4;
19
+ const interval = cfg?.interval || 100;
20
+ const handleRedirect = () => {
21
+ if (typeof document === "undefined") return false;
22
+ const authorizationCode = parseCookies(document.cookie).get(redirectCookieName);
23
+ if (!authorizationCode) return false;
24
+ document.cookie = `${redirectCookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;
25
+ window.location.replace(`${scheme}:/${opts.callbackPath}#token=${authorizationCode}`);
26
+ return true;
27
+ };
28
+ const start = Date.now();
29
+ const id = setInterval(() => {
30
+ if (handleRedirect() || Date.now() - start > timeout) clearInterval(id);
31
+ }, interval);
32
+ return id;
33
+ } };
34
+ }
35
+ };
36
+ };
37
+
38
+ //#endregion
39
+ export { electronProxyClient };
@@ -0,0 +1,8 @@
1
+ import { i as Storage } from "./authenticate-CWAVJ4W8.mjs";
2
+ import "./client-BBp9yCmE.mjs";
3
+ import { Options } from "conf";
4
+
5
+ //#region src/storage.d.ts
6
+ declare const storage: (opts?: Options<Record<string, any>> | undefined) => Storage;
7
+ //#endregion
8
+ export { storage };
@@ -0,0 +1,28 @@
1
+ import electron from "electron";
2
+ import Conf from "conf";
3
+
4
+ //#region src/storage.ts
5
+ const { app } = electron;
6
+ const storage = (opts) => {
7
+ if (!app) return {
8
+ getItem: () => null,
9
+ setItem: () => {}
10
+ };
11
+ const config = new Conf({
12
+ cwd: app.getPath("userData"),
13
+ projectName: app.getName(),
14
+ projectVersion: app.getVersion(),
15
+ ...opts
16
+ });
17
+ return {
18
+ getItem: (key) => {
19
+ return config.get(key, null);
20
+ },
21
+ setItem: (key, value) => {
22
+ config.set(key, value);
23
+ }
24
+ };
25
+ };
26
+
27
+ //#endregion
28
+ export { storage };
@@ -0,0 +1,17 @@
1
+ //#region src/utils.ts
2
+ function isProcessType(type) {
3
+ return typeof process !== "undefined" && process.type === type;
4
+ }
5
+ function parseProtocolScheme(protocolOption) {
6
+ if (typeof protocolOption === "string") return {
7
+ scheme: protocolOption,
8
+ privileges: {}
9
+ };
10
+ return {
11
+ scheme: protocolOption.scheme,
12
+ privileges: protocolOption.privileges || {}
13
+ };
14
+ }
15
+
16
+ //#endregion
17
+ export { parseProtocolScheme as n, isProcessType as t };
package/package.json ADDED
@@ -0,0 +1,104 @@
1
+ {
2
+ "name": "@better-auth/electron",
3
+ "version": "1.5.0-beta.12",
4
+ "type": "module",
5
+ "description": "Better Auth integration for Electron applications.",
6
+ "main": "dist/index.mjs",
7
+ "module": "dist/index.mjs",
8
+ "types": "dist/index.d.mts",
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "license": "MIT",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/better-auth/better-auth",
16
+ "directory": "packages/electron"
17
+ },
18
+ "homepage": "https://www.better-auth.com/docs/integrations/electron",
19
+ "keywords": [
20
+ "electron",
21
+ "auth",
22
+ "better-auth",
23
+ "typescript"
24
+ ],
25
+ "exports": {
26
+ ".": {
27
+ "dev-source": "./src/index.ts",
28
+ "types": "./dist/index.d.mts",
29
+ "default": "./dist/index.mjs"
30
+ },
31
+ "./client": {
32
+ "dev-source": "./src/client.ts",
33
+ "types": "./dist/client.d.mts",
34
+ "default": "./dist/client.mjs"
35
+ },
36
+ "./proxy": {
37
+ "dev-source": "./src/proxy.ts",
38
+ "types": "./dist/proxy.d.mts",
39
+ "default": "./dist/proxy.mjs"
40
+ },
41
+ "./storage": {
42
+ "dev-source": "./src/storage.ts",
43
+ "types": "./dist/storage.d.mts",
44
+ "default": "./dist/storage.mjs"
45
+ }
46
+ },
47
+ "typesVersions": {
48
+ "*": {
49
+ "*": [
50
+ "./dist/index.d.mts"
51
+ ],
52
+ "client": [
53
+ "./dist/client.d.mts"
54
+ ],
55
+ "proxy": [
56
+ "./dist/proxy.d.mts"
57
+ ],
58
+ "storage": [
59
+ "./dist/storage.d.mts"
60
+ ]
61
+ }
62
+ },
63
+ "peerDependenciesMeta": {
64
+ "electron": {
65
+ "optional": true
66
+ },
67
+ "conf": {
68
+ "optional": true
69
+ }
70
+ },
71
+ "peerDependencies": {
72
+ "@better-auth/utils": "0.3.1",
73
+ "@better-fetch/fetch": "1.1.21",
74
+ "better-call": "1.2.1",
75
+ "conf": "^15.0.2",
76
+ "@better-auth/core": "1.5.0-beta.12",
77
+ "better-auth": "1.5.0-beta.12"
78
+ },
79
+ "dependencies": {
80
+ "zod": "^4.3.5"
81
+ },
82
+ "devDependencies": {
83
+ "@types/better-sqlite3": "^7.6.13",
84
+ "better-sqlite3": "^12.6.2",
85
+ "tsdown": "^0.20.1",
86
+ "@better-auth/core": "1.5.0-beta.12",
87
+ "better-auth": "1.5.0-beta.12"
88
+ },
89
+ "engines": {
90
+ "node": ">=22.0.0"
91
+ },
92
+ "files": [
93
+ "dist"
94
+ ],
95
+ "scripts": {
96
+ "test": "vitest",
97
+ "coverage": "vitest run --coverage --coverage.provider=istanbul",
98
+ "lint:package": "publint run --strict",
99
+ "lint:types": "attw --profile esm-only --pack .",
100
+ "build": "tsdown",
101
+ "dev": "tsdown --watch",
102
+ "typecheck": "tsc --project tsconfig.json"
103
+ }
104
+ }