@glinr/theauth-electron 0.1.0 → 0.3.0
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/README.md +21 -11
- package/dist/index.d.ts +24 -24
- package/dist/index.js +22 -22
- package/dist/index.js.map +1 -1
- package/package.json +17 -3
package/README.md
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
# @glinr/theauth-electron
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[npm](https://www.npmjs.com/package/@glinr/theauth-electron) · [Source](https://github.com/glincker/theauth/tree/main/packages/electron) · [Docs](https://docs.theauth.dev/electron) · [All packages](https://github.com/glincker/theauth#packages)
|
|
4
|
+
|
|
5
|
+
Electron integration for theAuth: secure storage, OAuth windows, and IPC bridge.
|
|
4
6
|
|
|
5
7
|
[](https://www.npmjs.com/package/@glinr/theauth-electron)
|
|
6
8
|
|
|
9
|
+
Part of [theAuth](https://theauth.dev), open-source auth for AI agents and humans. Docs: [docs.theauth.dev](https://docs.theauth.dev).
|
|
10
|
+
|
|
7
11
|
## Install
|
|
8
12
|
|
|
9
13
|
```bash
|
|
10
|
-
npm install @glinr
|
|
14
|
+
npm install @glinr/theauth-electron
|
|
11
15
|
```
|
|
12
16
|
|
|
13
17
|
## Usage
|
|
@@ -16,21 +20,21 @@ Set up the IPC bridge in the main process, then use the provider in the renderer
|
|
|
16
20
|
|
|
17
21
|
```ts
|
|
18
22
|
// main.ts (main process)
|
|
19
|
-
import {
|
|
23
|
+
import { setupTheAuthIpc, createElectronStorage } from '@glinr/theauth-electron';
|
|
20
24
|
|
|
21
25
|
const storage = createElectronStorage({ encryptionKey: process.env.STORAGE_KEY });
|
|
22
|
-
|
|
26
|
+
setupTheAuthIpc({ storage });
|
|
23
27
|
```
|
|
24
28
|
|
|
25
29
|
```tsx
|
|
26
30
|
// renderer.tsx
|
|
27
|
-
import {
|
|
31
|
+
import { ElectronTheAuthProvider, useElectronTheAuthContext } from '@glinr/theauth-electron';
|
|
28
32
|
|
|
29
33
|
function App() {
|
|
30
34
|
return (
|
|
31
|
-
<
|
|
35
|
+
<ElectronTheAuthProvider apiUrl="https://auth.yourapp.com" tenantId="your-tenant-id">
|
|
32
36
|
<MainWindow />
|
|
33
|
-
</
|
|
37
|
+
</ElectronTheAuthProvider>
|
|
34
38
|
);
|
|
35
39
|
}
|
|
36
40
|
```
|
|
@@ -39,20 +43,26 @@ function App() {
|
|
|
39
43
|
// OAuth login from renderer
|
|
40
44
|
import { openOAuthWindow } from '@glinr/theauth-electron';
|
|
41
45
|
|
|
42
|
-
const result = await openOAuthWindow({ provider: 'google', redirectUri: '
|
|
46
|
+
const result = await openOAuthWindow({ provider: 'google', redirectUri: 'theauth://oauth' });
|
|
43
47
|
```
|
|
44
48
|
|
|
45
49
|
## Exports
|
|
46
50
|
|
|
47
|
-
- `
|
|
51
|
+
- `ElectronTheAuthProvider` / `ElectronTheAuthContext` / `useElectronTheAuthContext`: renderer-side provider
|
|
48
52
|
- `createElectronStorage`: encrypted keychain-backed storage
|
|
49
53
|
- `createMemoryStorage`: in-memory storage for testing
|
|
50
|
-
- `
|
|
54
|
+
- `setupTheAuthIpc` / `createIpcStorage` / `THEAUTH_IPC_CHANNELS`: main-process IPC setup
|
|
51
55
|
- `openOAuthWindow`: opens a managed OAuth popup window
|
|
52
56
|
|
|
53
57
|
## Docs
|
|
54
58
|
|
|
55
|
-
[https://docs.theauth.
|
|
59
|
+
[https://docs.theauth.dev](https://docs.theauth.dev)
|
|
60
|
+
|
|
61
|
+
## Community
|
|
62
|
+
|
|
63
|
+
[](https://discord.gg/Ar5pcaZB99)
|
|
64
|
+
|
|
65
|
+
Questions and help in the `#theauth` forum on the [GLINR Discord](https://discord.gg/Ar5pcaZB99).
|
|
56
66
|
|
|
57
67
|
## License
|
|
58
68
|
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as react from 'react';
|
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
|
|
4
4
|
interface ElectronStorageConfig {
|
|
5
|
-
/** File name for the session data. Defaults to "
|
|
5
|
+
/** File name for the session data. Defaults to "theauth-session.json". */
|
|
6
6
|
fileName?: string;
|
|
7
7
|
/** Optional additional encryption key applied on top of safeStorage. */
|
|
8
8
|
encryptionKey?: string;
|
|
@@ -100,7 +100,7 @@ interface OAuthWindowConfig {
|
|
|
100
100
|
width?: number;
|
|
101
101
|
/** Window height in pixels. Defaults to 700. */
|
|
102
102
|
height?: number;
|
|
103
|
-
/** Base path where TheAuth is mounted. Defaults to "/api/
|
|
103
|
+
/** Base path where TheAuth is mounted. Defaults to "/api/theauth". */
|
|
104
104
|
basePath?: string;
|
|
105
105
|
}
|
|
106
106
|
interface OAuthWindowResult {
|
|
@@ -123,7 +123,7 @@ declare function openOAuthWindow(providerId: string, config?: OAuthWindowConfig)
|
|
|
123
123
|
* Call this once from your main process entry point after creating your
|
|
124
124
|
* SecureStorage instance via createElectronStorage().
|
|
125
125
|
*/
|
|
126
|
-
declare function
|
|
126
|
+
declare function setupTheAuthIpc(storage: SecureStorage): void;
|
|
127
127
|
/**
|
|
128
128
|
* Creates a SecureStorage implementation that delegates all operations to the
|
|
129
129
|
* main process via IPC. Use this in the renderer process in place of a direct
|
|
@@ -139,11 +139,11 @@ declare function createIpcStorage(): SecureStorage;
|
|
|
139
139
|
*
|
|
140
140
|
* ```ts
|
|
141
141
|
* import { contextBridge, ipcRenderer } from "electron";
|
|
142
|
-
* import {
|
|
142
|
+
* import { THEAUTH_IPC_CHANNELS } from "@glinr/theauth-electron";
|
|
143
143
|
*
|
|
144
|
-
* contextBridge.exposeInMainWorld("
|
|
144
|
+
* contextBridge.exposeInMainWorld("theauthStorage", {
|
|
145
145
|
* invoke: (channel: string, ...args: unknown[]) => {
|
|
146
|
-
* if (!Object.values(
|
|
146
|
+
* if (!Object.values(THEAUTH_IPC_CHANNELS).includes(channel)) {
|
|
147
147
|
* throw new Error(`Blocked IPC channel: ${channel}`);
|
|
148
148
|
* }
|
|
149
149
|
* return ipcRenderer.invoke(channel, ...args);
|
|
@@ -151,22 +151,22 @@ declare function createIpcStorage(): SecureStorage;
|
|
|
151
151
|
* });
|
|
152
152
|
* ```
|
|
153
153
|
*/
|
|
154
|
-
declare const
|
|
155
|
-
readonly GET: "
|
|
156
|
-
readonly SET: "
|
|
157
|
-
readonly REMOVE: "
|
|
158
|
-
readonly CLEAR: "
|
|
154
|
+
declare const THEAUTH_IPC_CHANNELS: {
|
|
155
|
+
readonly GET: "theauth:storage:get";
|
|
156
|
+
readonly SET: "theauth:storage:set";
|
|
157
|
+
readonly REMOVE: "theauth:storage:remove";
|
|
158
|
+
readonly CLEAR: "theauth:storage:clear";
|
|
159
159
|
};
|
|
160
160
|
|
|
161
|
-
interface
|
|
161
|
+
interface TheAuthUser {
|
|
162
162
|
id: string;
|
|
163
163
|
email?: string;
|
|
164
164
|
name?: string;
|
|
165
165
|
image?: string;
|
|
166
166
|
}
|
|
167
|
-
interface
|
|
167
|
+
interface TheAuthSession {
|
|
168
168
|
token: string;
|
|
169
|
-
user:
|
|
169
|
+
user: TheAuthUser;
|
|
170
170
|
expiresAt?: string;
|
|
171
171
|
}
|
|
172
172
|
type ActionResult<T = void> = {
|
|
@@ -176,9 +176,9 @@ type ActionResult<T = void> = {
|
|
|
176
176
|
success: false;
|
|
177
177
|
error: string;
|
|
178
178
|
};
|
|
179
|
-
interface
|
|
180
|
-
session:
|
|
181
|
-
user:
|
|
179
|
+
interface TheAuthContextValue {
|
|
180
|
+
session: TheAuthSession | null;
|
|
181
|
+
user: TheAuthUser | null;
|
|
182
182
|
isLoading: boolean;
|
|
183
183
|
isAuthenticated: boolean;
|
|
184
184
|
signIn: (email: string, password: string) => Promise<ActionResult>;
|
|
@@ -186,21 +186,21 @@ interface KavachContextValue {
|
|
|
186
186
|
signOut: () => Promise<void>;
|
|
187
187
|
refresh: () => Promise<void>;
|
|
188
188
|
}
|
|
189
|
-
interface
|
|
189
|
+
interface ElectronTheAuthProviderProps {
|
|
190
190
|
children: ReactNode;
|
|
191
|
-
/** Base path where TheAuth is mounted. Defaults to "/api/
|
|
191
|
+
/** Base path where TheAuth is mounted. Defaults to "/api/theauth". */
|
|
192
192
|
basePath?: string;
|
|
193
193
|
/** Custom storage adapter. Defaults to in-memory if not provided. */
|
|
194
194
|
storage?: SecureStorage;
|
|
195
195
|
/** Persist session to secure storage across restarts. Defaults to true. */
|
|
196
196
|
persistSession?: boolean;
|
|
197
197
|
}
|
|
198
|
-
declare const
|
|
199
|
-
declare function
|
|
198
|
+
declare const ElectronTheAuthContext: react.Context<TheAuthContextValue | null>;
|
|
199
|
+
declare function useElectronTheAuthContext(): TheAuthContextValue;
|
|
200
200
|
/**
|
|
201
201
|
* Wraps your Electron renderer with TheAuth auth state.
|
|
202
202
|
*
|
|
203
|
-
* Extends the base
|
|
203
|
+
* Extends the base TheAuthProvider behaviour with:
|
|
204
204
|
* - Session persistence to Electron's safeStorage on sign-in
|
|
205
205
|
* - Session restoration from storage on app launch
|
|
206
206
|
* - Storage cleared on sign-out
|
|
@@ -208,6 +208,6 @@ declare function useElectronKavachContext(): KavachContextValue;
|
|
|
208
208
|
* Pass a SecureStorage created by createElectronStorage() or createIpcStorage()
|
|
209
209
|
* depending on whether your renderer runs with Node integration or via IPC.
|
|
210
210
|
*/
|
|
211
|
-
declare function
|
|
211
|
+
declare function ElectronTheAuthProvider({ children, basePath, storage, persistSession, }: ElectronTheAuthProviderProps): ReactNode;
|
|
212
212
|
|
|
213
|
-
export { type ElectronApi,
|
|
213
|
+
export { type ElectronApi, type ElectronStorageConfig, ElectronTheAuthContext, ElectronTheAuthProvider, type ElectronTheAuthProviderProps, type OAuthWindowConfig, type OAuthWindowResult, type SecureStorage, THEAUTH_IPC_CHANNELS, createElectronStorage, createIpcStorage, createMemoryStorage, openOAuthWindow, setElectronApiForTesting, setupTheAuthIpc, useElectronTheAuthContext };
|
package/dist/index.js
CHANGED
|
@@ -74,7 +74,7 @@ function writeStorageFile(filePath, data) {
|
|
|
74
74
|
fs.writeFileSync(filePath, JSON.stringify(data), "utf8");
|
|
75
75
|
}
|
|
76
76
|
function createElectronStorage(config) {
|
|
77
|
-
const fileName = config?.fileName ?? "
|
|
77
|
+
const fileName = config?.fileName ?? "theauth-session.json";
|
|
78
78
|
const encryptionKey = config?.encryptionKey ?? "";
|
|
79
79
|
let warned = false;
|
|
80
80
|
let filePath = null;
|
|
@@ -165,7 +165,7 @@ function createMemoryStorage() {
|
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
// src/oauth-window.ts
|
|
168
|
-
var SESSION_COOKIE_NAMES = ["
|
|
168
|
+
var SESSION_COOKIE_NAMES = ["theauth-session", "better-auth.session_token", "__session"];
|
|
169
169
|
async function extractSessionCookie(win, baseUrl) {
|
|
170
170
|
const cookies = await win.webContents.session.cookies.get({ url: baseUrl });
|
|
171
171
|
for (const name of SESSION_COOKIE_NAMES) {
|
|
@@ -187,7 +187,7 @@ function extractOAuthError(url) {
|
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
189
|
async function openOAuthWindow(providerId, config = {}) {
|
|
190
|
-
const { width = 500, height = 700, basePath = "/api/
|
|
190
|
+
const { width = 500, height = 700, basePath = "/api/theauth" } = config;
|
|
191
191
|
const base = basePath.replace(/\/$/, "");
|
|
192
192
|
const { BrowserWindow } = getElectronApi();
|
|
193
193
|
const win = new BrowserWindow({
|
|
@@ -248,11 +248,11 @@ async function openOAuthWindow(providerId, config = {}) {
|
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
// src/ipc.ts
|
|
251
|
-
var CHANNEL_GET = "
|
|
252
|
-
var CHANNEL_SET = "
|
|
253
|
-
var CHANNEL_REMOVE = "
|
|
254
|
-
var CHANNEL_CLEAR = "
|
|
255
|
-
function
|
|
251
|
+
var CHANNEL_GET = "theauth:storage:get";
|
|
252
|
+
var CHANNEL_SET = "theauth:storage:set";
|
|
253
|
+
var CHANNEL_REMOVE = "theauth:storage:remove";
|
|
254
|
+
var CHANNEL_CLEAR = "theauth:storage:clear";
|
|
255
|
+
function setupTheAuthIpc(storage) {
|
|
256
256
|
const { ipcMain } = getElectronApi();
|
|
257
257
|
ipcMain.removeHandler(CHANNEL_GET);
|
|
258
258
|
ipcMain.removeHandler(CHANNEL_SET);
|
|
@@ -296,7 +296,7 @@ function createIpcStorage() {
|
|
|
296
296
|
}
|
|
297
297
|
};
|
|
298
298
|
}
|
|
299
|
-
var
|
|
299
|
+
var THEAUTH_IPC_CHANNELS = {
|
|
300
300
|
GET: CHANNEL_GET,
|
|
301
301
|
SET: CHANNEL_SET,
|
|
302
302
|
REMOVE: CHANNEL_REMOVE,
|
|
@@ -306,12 +306,12 @@ var KAVACH_IPC_CHANNELS = {
|
|
|
306
306
|
// src/provider.tsx
|
|
307
307
|
import { createContext, useCallback, useContext, useEffect, useState } from "react";
|
|
308
308
|
import { jsx } from "react/jsx-runtime";
|
|
309
|
-
var SESSION_STORAGE_KEY = "
|
|
310
|
-
var
|
|
311
|
-
function
|
|
312
|
-
const ctx = useContext(
|
|
309
|
+
var SESSION_STORAGE_KEY = "theauth:session";
|
|
310
|
+
var ElectronTheAuthContext = createContext(null);
|
|
311
|
+
function useElectronTheAuthContext() {
|
|
312
|
+
const ctx = useContext(ElectronTheAuthContext);
|
|
313
313
|
if (!ctx) {
|
|
314
|
-
throw new Error("
|
|
314
|
+
throw new Error("useElectronTheAuthContext must be used inside <ElectronTheAuthProvider>");
|
|
315
315
|
}
|
|
316
316
|
return ctx;
|
|
317
317
|
}
|
|
@@ -321,9 +321,9 @@ function extractErrorMessage(body, fallback) {
|
|
|
321
321
|
}
|
|
322
322
|
return fallback;
|
|
323
323
|
}
|
|
324
|
-
function
|
|
324
|
+
function ElectronTheAuthProvider({
|
|
325
325
|
children,
|
|
326
|
-
basePath = "/api/
|
|
326
|
+
basePath = "/api/theauth",
|
|
327
327
|
storage,
|
|
328
328
|
persistSession = true
|
|
329
329
|
}) {
|
|
@@ -463,18 +463,18 @@ function ElectronKavachProvider({
|
|
|
463
463
|
signOut,
|
|
464
464
|
refresh
|
|
465
465
|
};
|
|
466
|
-
return /* @__PURE__ */ jsx(
|
|
466
|
+
return /* @__PURE__ */ jsx(ElectronTheAuthContext.Provider, { value, children });
|
|
467
467
|
}
|
|
468
468
|
export {
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
469
|
+
ElectronTheAuthContext,
|
|
470
|
+
ElectronTheAuthProvider,
|
|
471
|
+
THEAUTH_IPC_CHANNELS,
|
|
472
472
|
createElectronStorage,
|
|
473
473
|
createIpcStorage,
|
|
474
474
|
createMemoryStorage,
|
|
475
475
|
openOAuthWindow,
|
|
476
476
|
setElectronApiForTesting,
|
|
477
|
-
|
|
478
|
-
|
|
477
|
+
setupTheAuthIpc,
|
|
478
|
+
useElectronTheAuthContext
|
|
479
479
|
};
|
|
480
480
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/electron-api.ts","../src/storage.ts","../src/oauth-window.ts","../src/ipc.ts","../src/provider.tsx"],"sourcesContent":["// ─── Electron API injection ───────────────────────────────────────────────────\n//\n// Modules that need Electron APIs call getElectronApi() to retrieve the live\n// bindings. In a real Electron process this resolves to the real electron\n// module; in tests it resolves to the mock set via setElectronApiForTesting().\n\nimport type { SecureStorage } from \"./storage.js\";\n\n// ─── Surface interfaces ───────────────────────────────────────────────────────\n\nexport interface ElectronSafeStorage {\n\tisEncryptionAvailable(): boolean;\n\tencryptString(value: string): Uint8Array;\n\tdecryptString(encrypted: Uint8Array): string;\n}\n\nexport interface ElectronApp {\n\tgetPath(name: \"userData\"): string;\n}\n\nexport interface BrowserWindowOptions {\n\twidth: number;\n\theight: number;\n\twebPreferences: {\n\t\tnodeIntegration: boolean;\n\t\tcontextIsolation: boolean;\n\t\tsandbox: boolean;\n\t};\n\ttitle: string;\n\tresizable: boolean;\n\tminimizable: boolean;\n\tmaximizable: boolean;\n\tshow: boolean;\n}\n\nexport interface BrowserWindowInstance {\n\tloadURL(url: string): Promise<void>;\n\ton(event: \"closed\", listener: () => void): void;\n\twebContents: {\n\t\ton(\n\t\t\tevent: \"will-redirect\" | \"will-navigate\",\n\t\t\tlistener: (event: unknown, url: string) => void,\n\t\t): void;\n\t\tsession: {\n\t\t\tcookies: {\n\t\t\t\tget(filter: { url: string }): Promise<Array<{ name: string; value: string }>>;\n\t\t\t};\n\t\t};\n\t};\n\tdestroy(): void;\n\tshow(): void;\n}\n\nexport interface BrowserWindowConstructor {\n\tnew (options: BrowserWindowOptions): BrowserWindowInstance;\n}\n\nexport type IpcMainListener = (\n\tevent: { reply(channel: string, ...args: unknown[]): void },\n\t...args: unknown[]\n) => Promise<unknown>;\n\nexport interface ElectronIpcMain {\n\thandle(channel: string, listener: IpcMainListener): void;\n\tremoveHandler(channel: string): void;\n}\n\nexport interface ElectronIpcRenderer {\n\tinvoke(channel: string, ...args: unknown[]): Promise<unknown>;\n}\n\nexport interface ElectronApi {\n\tsafeStorage: ElectronSafeStorage;\n\tapp: ElectronApp;\n\tBrowserWindow: BrowserWindowConstructor;\n\tipcMain: ElectronIpcMain;\n\tipcRenderer: ElectronIpcRenderer;\n}\n\n// ─── Singleton ────────────────────────────────────────────────────────────────\n\nlet _override: ElectronApi | null = null;\n\nfunction loadElectron(): ElectronApi | null {\n\tif (_override) return _override;\n\ttry {\n\t\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\t\treturn require(\"electron\") as ElectronApi;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport function getElectronApi(): ElectronApi {\n\tconst api = loadElectron();\n\tif (!api) {\n\t\tthrow new Error(\n\t\t\t\"[TheAuth] Electron API not available. Ensure this code runs in an Electron process.\",\n\t\t);\n\t}\n\treturn api;\n}\n\n/**\n * For testing only — injects a mock Electron API so modules don't need a real\n * Electron runtime. Call setElectronApiForTesting(null) to reset.\n */\nexport function setElectronApiForTesting(mock: ElectronApi | null): void {\n\t_override = mock;\n}\n\n// Re-export SecureStorage so ipc.ts can reference it without a circular dep\nexport type { SecureStorage };\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { ElectronSafeStorage } from \"./electron-api.js\";\nimport { getElectronApi } from \"./electron-api.js\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface ElectronStorageConfig {\n\t/** File name for the session data. Defaults to \"kavach-session.json\". */\n\tfileName?: string;\n\t/** Optional additional encryption key applied on top of safeStorage. */\n\tencryptionKey?: string;\n}\n\nexport interface SecureStorage {\n\tget(key: string): Promise<string | null>;\n\tset(key: string, value: string): Promise<void>;\n\tremove(key: string): Promise<void>;\n\tclear(): Promise<void>;\n}\n\n// ─── XOR cipher for optional encryptionKey ────────────────────────────────────\n\nfunction xorWithKey(data: Uint8Array, key: string): Uint8Array {\n\tif (key.length === 0) return data;\n\tconst encoder = new TextEncoder();\n\tconst keyBytes = encoder.encode(key);\n\tconst result = new Uint8Array(data.length);\n\tfor (let i = 0; i < data.length; i++) {\n\t\tresult[i] = (data[i] ?? 0) ^ (keyBytes[i % keyBytes.length] ?? 0);\n\t}\n\treturn result;\n}\n\n// ─── Base64 helpers (no Buffer) ───────────────────────────────────────────────\n\nfunction uint8ArrayToBase64(bytes: Uint8Array): string {\n\tlet binary = \"\";\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tbinary += String.fromCharCode(bytes[i] ?? 0);\n\t}\n\treturn btoa(binary);\n}\n\nfunction base64ToUint8Array(base64: string): Uint8Array {\n\tconst binary = atob(base64);\n\tconst bytes = new Uint8Array(binary.length);\n\tfor (let i = 0; i < binary.length; i++) {\n\t\tbytes[i] = binary.charCodeAt(i);\n\t}\n\treturn bytes;\n}\n\n// ─── Storage file helpers ─────────────────────────────────────────────────────\n\ntype StorageMap = Record<string, string>;\n\nfunction readStorageFile(filePath: string): StorageMap {\n\ttry {\n\t\tconst raw = fs.readFileSync(filePath, \"utf8\");\n\t\tconst parsed: unknown = JSON.parse(raw);\n\t\tif (parsed !== null && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n\t\t\treturn parsed as StorageMap;\n\t\t}\n\t\treturn {};\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nfunction writeStorageFile(filePath: string, data: StorageMap): void {\n\tconst dir = path.dirname(filePath);\n\tfs.mkdirSync(dir, { recursive: true });\n\tfs.writeFileSync(filePath, JSON.stringify(data), \"utf8\");\n}\n\n// ─── Factory ──────────────────────────────────────────────────────────────────\n\n/**\n * Creates a SecureStorage adapter backed by Electron's safeStorage API.\n *\n * Values are encrypted with safeStorage before being written to a JSON file\n * in the app's userData directory. If safeStorage is unavailable (e.g. during\n * testing or on headless Linux without a keychain), values are stored as\n * plaintext and a warning is emitted once.\n */\nexport function createElectronStorage(config?: ElectronStorageConfig): SecureStorage {\n\tconst fileName = config?.fileName ?? \"kavach-session.json\";\n\tconst encryptionKey = config?.encryptionKey ?? \"\";\n\n\tlet warned = false;\n\tlet filePath: string | null = null;\n\n\tfunction getFilePath(): string {\n\t\tif (filePath) return filePath;\n\t\tconst electron = getElectronApi();\n\t\tconst resolved = path.join(electron.app.getPath(\"userData\"), fileName);\n\t\tfilePath = resolved;\n\t\treturn resolved;\n\t}\n\n\tfunction getSafeStorage(): ElectronSafeStorage | null {\n\t\tconst electron = getElectronApi();\n\t\tif (!electron.safeStorage.isEncryptionAvailable()) {\n\t\t\tif (!warned) {\n\t\t\t\twarned = true;\n\t\t\t\t// biome-ignore lint/suspicious/noConsole: intentional user-facing warning\n\t\t\t\tconsole.warn(\n\t\t\t\t\t\"TheAuth: safeStorage encryption unavailable — storing session data in plaintext\",\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t\treturn electron.safeStorage;\n\t}\n\n\tfunction encryptValue(value: string): string {\n\t\tconst safeStorage = getSafeStorage();\n\t\tif (!safeStorage) return value;\n\t\tconst encrypted = safeStorage.encryptString(value);\n\t\tconst keyed = encryptionKey ? xorWithKey(encrypted, encryptionKey) : encrypted;\n\t\treturn uint8ArrayToBase64(keyed);\n\t}\n\n\tfunction decryptValue(stored: string): string {\n\t\tconst safeStorage = getSafeStorage();\n\t\tif (!safeStorage) return stored;\n\t\ttry {\n\t\t\tlet bytes = base64ToUint8Array(stored);\n\t\t\tif (encryptionKey) {\n\t\t\t\tbytes = xorWithKey(bytes, encryptionKey);\n\t\t\t}\n\t\t\treturn safeStorage.decryptString(bytes);\n\t\t} catch {\n\t\t\treturn stored;\n\t\t}\n\t}\n\n\treturn {\n\t\tasync get(key: string): Promise<string | null> {\n\t\t\tconst map = readStorageFile(getFilePath());\n\t\t\tconst stored = map[key];\n\t\t\tif (stored === undefined) return null;\n\t\t\treturn decryptValue(stored);\n\t\t},\n\n\t\tasync set(key: string, value: string): Promise<void> {\n\t\t\tconst fp = getFilePath();\n\t\t\tconst map = readStorageFile(fp);\n\t\t\tmap[key] = encryptValue(value);\n\t\t\twriteStorageFile(fp, map);\n\t\t},\n\n\t\tasync remove(key: string): Promise<void> {\n\t\t\tconst fp = getFilePath();\n\t\t\tconst map = readStorageFile(fp);\n\t\t\t// Functional deletion without `delete` operator\n\t\t\tconst next: StorageMap = {};\n\t\t\tfor (const [k, v] of Object.entries(map)) {\n\t\t\t\tif (k !== key) next[k] = v;\n\t\t\t}\n\t\t\twriteStorageFile(fp, next);\n\t\t},\n\n\t\tasync clear(): Promise<void> {\n\t\t\tconst fp = getFilePath();\n\t\t\twriteStorageFile(fp, {});\n\t\t},\n\t};\n}\n\n/**\n * Creates a SecureStorage adapter that operates entirely in memory.\n * Useful for testing or when you explicitly do not want disk persistence.\n */\nexport function createMemoryStorage(): SecureStorage {\n\tconst store = new Map<string, string>();\n\treturn {\n\t\tasync get(key: string): Promise<string | null> {\n\t\t\treturn store.get(key) ?? null;\n\t\t},\n\t\tasync set(key: string, value: string): Promise<void> {\n\t\t\tstore.set(key, value);\n\t\t},\n\t\tasync remove(key: string): Promise<void> {\n\t\t\tstore.delete(key);\n\t\t},\n\t\tasync clear(): Promise<void> {\n\t\t\tstore.clear();\n\t\t},\n\t};\n}\n","import type { BrowserWindowInstance } from \"./electron-api.js\";\nimport { getElectronApi } from \"./electron-api.js\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface OAuthWindowConfig {\n\t/** Window width in pixels. Defaults to 500. */\n\twidth?: number;\n\t/** Window height in pixels. Defaults to 700. */\n\theight?: number;\n\t/** Base path where TheAuth is mounted. Defaults to \"/api/kavach\". */\n\tbasePath?: string;\n}\n\nexport interface OAuthWindowResult {\n\tsuccess: boolean;\n\terror?: string;\n}\n\n// ─── Session cookie extraction ────────────────────────────────────────────────\n\nconst SESSION_COOKIE_NAMES = [\"kavach-session\", \"better-auth.session_token\", \"__session\"];\n\nasync function extractSessionCookie(\n\twin: BrowserWindowInstance,\n\tbaseUrl: string,\n): Promise<string | null> {\n\tconst cookies = await win.webContents.session.cookies.get({ url: baseUrl });\n\tfor (const name of SESSION_COOKIE_NAMES) {\n\t\tconst cookie = cookies.find((c) => c.name === name);\n\t\tif (cookie) return cookie.value;\n\t}\n\treturn null;\n}\n\n// ─── URL parsing helpers ──────────────────────────────────────────────────────\n\nfunction isCallbackUrl(url: string, base: string): boolean {\n\tconst normalised = base.replace(/\\/$/, \"\");\n\treturn (\n\t\turl.includes(`${normalised}/callback`) ||\n\t\turl.includes(`${normalised}/oauth/callback`) ||\n\t\turl.includes(\"code=\") ||\n\t\turl.includes(\"error=\")\n\t);\n}\n\nfunction extractOAuthError(url: string): string | null {\n\ttry {\n\t\t// Use a dummy base so relative paths are accepted\n\t\tconst parsed = new URL(url, \"http://localhost\");\n\t\treturn parsed.searchParams.get(\"error_description\") ?? parsed.searchParams.get(\"error\");\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n// ─── Main export ──────────────────────────────────────────────────────────────\n\n/**\n * Opens a BrowserWindow to the OAuth authorization URL for a given provider,\n * waits for the callback redirect, extracts the session cookie, then closes\n * the window.\n *\n * Must be called from the Electron main process.\n */\nexport async function openOAuthWindow(\n\tproviderId: string,\n\tconfig: OAuthWindowConfig = {},\n): Promise<OAuthWindowResult> {\n\tconst { width = 500, height = 700, basePath = \"/api/kavach\" } = config;\n\tconst base = basePath.replace(/\\/$/, \"\");\n\n\tconst { BrowserWindow } = getElectronApi();\n\n\tconst win = new BrowserWindow({\n\t\twidth,\n\t\theight,\n\t\twebPreferences: {\n\t\t\tnodeIntegration: false,\n\t\t\tcontextIsolation: true,\n\t\t\tsandbox: true,\n\t\t},\n\t\ttitle: \"Sign in\",\n\t\tresizable: false,\n\t\tminimizable: false,\n\t\tmaximizable: false,\n\t\tshow: false,\n\t});\n\n\tconst authUrl = `${base}/sign-in/${encodeURIComponent(providerId)}?redirect=electron`;\n\n\treturn new Promise<OAuthWindowResult>((resolve) => {\n\t\tlet settled = false;\n\n\t\tfunction settle(result: OAuthWindowResult): void {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\twin.destroy();\n\t\t\tresolve(result);\n\t\t}\n\n\t\twin.on(\"closed\", () => {\n\t\t\tsettle({ success: false, error: \"Window closed by user\" });\n\t\t});\n\n\t\tasync function handleNavigate(_event: unknown, url: string): Promise<void> {\n\t\t\tif (!isCallbackUrl(url, base)) return;\n\n\t\t\tconst oauthError = extractOAuthError(url);\n\t\t\tif (oauthError) {\n\t\t\t\tsettle({ success: false, error: oauthError });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst origin = new URL(url).origin;\n\t\t\t\tconst cookie = await extractSessionCookie(win, origin);\n\t\t\t\t// Treat as success whether or not we captured the cookie — the\n\t\t\t\t// session will be verified on the next server round-trip.\n\t\t\t\tvoid cookie;\n\t\t\t\tsettle({ success: true });\n\t\t\t} catch (err) {\n\t\t\t\tsettle({\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: err instanceof Error ? err.message : \"Failed to extract session\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\twin.webContents.on(\"will-redirect\", (ev, url) => {\n\t\t\tvoid handleNavigate(ev, url);\n\t\t});\n\t\twin.webContents.on(\"will-navigate\", (ev, url) => {\n\t\t\tvoid handleNavigate(ev, url);\n\t\t});\n\n\t\tvoid win.loadURL(authUrl).then(() => {\n\t\t\twin.show();\n\t\t});\n\t});\n}\n","import { getElectronApi } from \"./electron-api.js\";\nimport type { SecureStorage } from \"./storage.js\";\n\n// ─── IPC channel names ────────────────────────────────────────────────────────\n\nconst CHANNEL_GET = \"kavach:storage:get\";\nconst CHANNEL_SET = \"kavach:storage:set\";\nconst CHANNEL_REMOVE = \"kavach:storage:remove\";\nconst CHANNEL_CLEAR = \"kavach:storage:clear\";\n\n// ─── Request/response types ───────────────────────────────────────────────────\n\ninterface StorageGetRequest {\n\tkey: string;\n}\n\ninterface StorageSetRequest {\n\tkey: string;\n\tvalue: string;\n}\n\ninterface StorageRemoveRequest {\n\tkey: string;\n}\n\ninterface StorageGetResponse {\n\tvalue: string | null;\n}\n\n// ─── Main process side ────────────────────────────────────────────────────────\n\n/**\n * Registers IPC handlers in the main process so the renderer can securely\n * access storage without needing direct Node.js access.\n *\n * Call this once from your main process entry point after creating your\n * SecureStorage instance via createElectronStorage().\n */\nexport function setupKavachIpc(storage: SecureStorage): void {\n\tconst { ipcMain } = getElectronApi();\n\n\t// Remove any previously registered handlers to allow re-initialization.\n\tipcMain.removeHandler(CHANNEL_GET);\n\tipcMain.removeHandler(CHANNEL_SET);\n\tipcMain.removeHandler(CHANNEL_REMOVE);\n\tipcMain.removeHandler(CHANNEL_CLEAR);\n\n\tipcMain.handle(CHANNEL_GET, async (_event, req: unknown): Promise<StorageGetResponse> => {\n\t\tconst { key } = req as StorageGetRequest;\n\t\tconst value = await storage.get(key);\n\t\treturn { value };\n\t});\n\n\tipcMain.handle(CHANNEL_SET, async (_event, req: unknown): Promise<void> => {\n\t\tconst { key, value } = req as StorageSetRequest;\n\t\tawait storage.set(key, value);\n\t});\n\n\tipcMain.handle(CHANNEL_REMOVE, async (_event, req: unknown): Promise<void> => {\n\t\tconst { key } = req as StorageRemoveRequest;\n\t\tawait storage.remove(key);\n\t});\n\n\tipcMain.handle(CHANNEL_CLEAR, async (): Promise<void> => {\n\t\tawait storage.clear();\n\t});\n}\n\n// ─── Renderer process side ────────────────────────────────────────────────────\n\n/**\n * Creates a SecureStorage implementation that delegates all operations to the\n * main process via IPC. Use this in the renderer process in place of a direct\n * storage adapter so that Node.js APIs and encryption stay in the main process.\n *\n * Requires contextIsolation to be enabled and the IPC channels to be exposed\n * via a preload script, or for contextIsolation to be disabled (not recommended).\n */\nexport function createIpcStorage(): SecureStorage {\n\tconst { ipcRenderer } = getElectronApi();\n\n\treturn {\n\t\tasync get(key: string): Promise<string | null> {\n\t\t\tconst req: StorageGetRequest = { key };\n\t\t\tconst res = (await ipcRenderer.invoke(CHANNEL_GET, req)) as StorageGetResponse;\n\t\t\treturn res.value;\n\t\t},\n\n\t\tasync set(key: string, value: string): Promise<void> {\n\t\t\tconst req: StorageSetRequest = { key, value };\n\t\t\tawait ipcRenderer.invoke(CHANNEL_SET, req);\n\t\t},\n\n\t\tasync remove(key: string): Promise<void> {\n\t\t\tconst req: StorageRemoveRequest = { key };\n\t\t\tawait ipcRenderer.invoke(CHANNEL_REMOVE, req);\n\t\t},\n\n\t\tasync clear(): Promise<void> {\n\t\t\tawait ipcRenderer.invoke(CHANNEL_CLEAR);\n\t\t},\n\t};\n}\n\n// ─── Preload bridge helper ────────────────────────────────────────────────────\n\n/**\n * The IPC channel names exposed for use in a preload script with contextBridge.\n * If you use contextIsolation (recommended), expose these channels explicitly:\n *\n * ```ts\n * import { contextBridge, ipcRenderer } from \"electron\";\n * import { KAVACH_IPC_CHANNELS } from \"@glinr/theauth-electron\";\n *\n * contextBridge.exposeInMainWorld(\"kavachStorage\", {\n * invoke: (channel: string, ...args: unknown[]) => {\n * if (!Object.values(KAVACH_IPC_CHANNELS).includes(channel)) {\n * throw new Error(`Blocked IPC channel: ${channel}`);\n * }\n * return ipcRenderer.invoke(channel, ...args);\n * },\n * });\n * ```\n */\nexport const KAVACH_IPC_CHANNELS = {\n\tGET: CHANNEL_GET,\n\tSET: CHANNEL_SET,\n\tREMOVE: CHANNEL_REMOVE,\n\tCLEAR: CHANNEL_CLEAR,\n} as const;\n","import type { ReactNode } from \"react\";\nimport { createContext, useCallback, useContext, useEffect, useState } from \"react\";\nimport type { SecureStorage } from \"./storage.js\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\ninterface KavachUser {\n\tid: string;\n\temail?: string;\n\tname?: string;\n\timage?: string;\n}\n\ninterface KavachSession {\n\ttoken: string;\n\tuser: KavachUser;\n\texpiresAt?: string;\n}\n\ntype ActionResult<T = void> = { success: true; data: T } | { success: false; error: string };\n\ninterface KavachContextValue {\n\tsession: KavachSession | null;\n\tuser: KavachUser | null;\n\tisLoading: boolean;\n\tisAuthenticated: boolean;\n\tsignIn: (email: string, password: string) => Promise<ActionResult>;\n\tsignUp: (email: string, password: string, name?: string) => Promise<ActionResult>;\n\tsignOut: () => Promise<void>;\n\trefresh: () => Promise<void>;\n}\n\nexport interface ElectronKavachProviderProps {\n\tchildren: ReactNode;\n\t/** Base path where TheAuth is mounted. Defaults to \"/api/kavach\". */\n\tbasePath?: string;\n\t/** Custom storage adapter. Defaults to in-memory if not provided. */\n\tstorage?: SecureStorage;\n\t/** Persist session to secure storage across restarts. Defaults to true. */\n\tpersistSession?: boolean;\n}\n\n// ─── Storage key ──────────────────────────────────────────────────────────────\n\nconst SESSION_STORAGE_KEY = \"kavach:session\";\n\n// ─── Context ──────────────────────────────────────────────────────────────────\n\nexport const ElectronKavachContext = createContext<KavachContextValue | null>(null);\n\nexport function useElectronKavachContext(): KavachContextValue {\n\tconst ctx = useContext(ElectronKavachContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useElectronKavachContext must be used inside <ElectronKavachProvider>\");\n\t}\n\treturn ctx;\n}\n\n// ─── JSON fetch helpers ───────────────────────────────────────────────────────\n\ntype JsonErrorBody = { error?: { code?: string; message?: string } };\n\nfunction extractErrorMessage(body: unknown, fallback: string): string {\n\tif (\n\t\tbody !== null &&\n\t\ttypeof body === \"object\" &&\n\t\t\"error\" in body &&\n\t\ttypeof (body as JsonErrorBody).error === \"object\" &&\n\t\ttypeof (body as JsonErrorBody).error?.message === \"string\"\n\t) {\n\t\treturn (body as JsonErrorBody).error?.message ?? fallback;\n\t}\n\treturn fallback;\n}\n\n// ─── Provider ─────────────────────────────────────────────────────────────────\n\n/**\n * Wraps your Electron renderer with TheAuth auth state.\n *\n * Extends the base KavachProvider behaviour with:\n * - Session persistence to Electron's safeStorage on sign-in\n * - Session restoration from storage on app launch\n * - Storage cleared on sign-out\n *\n * Pass a SecureStorage created by createElectronStorage() or createIpcStorage()\n * depending on whether your renderer runs with Node integration or via IPC.\n */\nexport function ElectronKavachProvider({\n\tchildren,\n\tbasePath = \"/api/kavach\",\n\tstorage,\n\tpersistSession = true,\n}: ElectronKavachProviderProps): ReactNode {\n\tconst [session, setSession] = useState<KavachSession | null>(null);\n\tconst [isLoading, setIsLoading] = useState(true);\n\n\tconst base = basePath.replace(/\\/$/, \"\");\n\n\t// ── Persist / restore helpers ───────────────────────────────────────────\n\n\tconst persistToStorage = useCallback(\n\t\tasync (s: KavachSession | null): Promise<void> => {\n\t\t\tif (!storage || !persistSession) return;\n\t\t\tif (s === null) {\n\t\t\t\tawait storage.remove(SESSION_STORAGE_KEY);\n\t\t\t} else {\n\t\t\t\tawait storage.set(SESSION_STORAGE_KEY, JSON.stringify(s));\n\t\t\t}\n\t\t},\n\t\t[storage, persistSession],\n\t);\n\n\tconst restoreFromStorage = useCallback(async (): Promise<KavachSession | null> => {\n\t\tif (!storage || !persistSession) return null;\n\t\ttry {\n\t\t\tconst raw = await storage.get(SESSION_STORAGE_KEY);\n\t\t\tif (!raw) return null;\n\t\t\tconst parsed: unknown = JSON.parse(raw);\n\t\t\tif (\n\t\t\t\tparsed !== null &&\n\t\t\t\ttypeof parsed === \"object\" &&\n\t\t\t\t\"token\" in parsed &&\n\t\t\t\ttypeof (parsed as KavachSession).token === \"string\" &&\n\t\t\t\t\"user\" in parsed &&\n\t\t\t\ttypeof (parsed as KavachSession).user === \"object\"\n\t\t\t) {\n\t\t\t\treturn parsed as KavachSession;\n\t\t\t}\n\t\t\treturn null;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}, [storage, persistSession]);\n\n\t// ── Session fetch ───────────────────────────────────────────────────────\n\n\tconst fetchSession = useCallback(async (): Promise<void> => {\n\t\ttry {\n\t\t\tconst res = await fetch(`${base}/session`, { credentials: \"include\" });\n\t\t\tif (res.ok) {\n\t\t\t\tconst json = (await res.json()) as { data?: KavachSession };\n\t\t\t\tconst s = json.data ?? null;\n\t\t\t\tsetSession(s);\n\t\t\t\tawait persistToStorage(s);\n\t\t\t} else {\n\t\t\t\tsetSession(null);\n\t\t\t}\n\t\t} catch {\n\t\t\tsetSession(null);\n\t\t}\n\t}, [base, persistToStorage]);\n\n\t// ── Mount: restore from storage, then verify with server ───────────────\n\n\tuseEffect(() => {\n\t\tsetIsLoading(true);\n\n\t\tvoid (async () => {\n\t\t\tconst stored = await restoreFromStorage();\n\t\t\tif (stored) {\n\t\t\t\tsetSession(stored);\n\t\t\t}\n\t\t\t// Always verify the session with the server regardless of storage.\n\t\t\tawait fetchSession();\n\t\t\tsetIsLoading(false);\n\t\t})();\n\t}, [restoreFromStorage, fetchSession]);\n\n\t// ── Auth actions ────────────────────────────────────────────────────────\n\n\tconst refresh = useCallback(async (): Promise<void> => {\n\t\tawait fetchSession();\n\t}, [fetchSession]);\n\n\tconst signIn = useCallback(\n\t\tasync (email: string, password: string): Promise<ActionResult> => {\n\t\t\ttry {\n\t\t\t\tconst res = await fetch(`${base}/sign-in/email`, {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tcredentials: \"include\",\n\t\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\t\tbody: JSON.stringify({ email, password }),\n\t\t\t\t});\n\t\t\t\tconst json = (await res.json()) as\n\t\t\t\t\t| { data: KavachSession }\n\t\t\t\t\t| { error: { code: string; message: string } };\n\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\terror: extractErrorMessage(json, `Sign-in failed (${res.status})`),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst s = (json as { data: KavachSession }).data;\n\t\t\t\tsetSession(s);\n\t\t\t\tawait persistToStorage(s);\n\t\t\t\treturn { success: true, data: undefined };\n\t\t\t} catch (err) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: err instanceof Error ? err.message : \"Network error\",\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t\t[base, persistToStorage],\n\t);\n\n\tconst signUp = useCallback(\n\t\tasync (email: string, password: string, name?: string): Promise<ActionResult> => {\n\t\t\ttry {\n\t\t\t\tconst res = await fetch(`${base}/sign-up/email`, {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tcredentials: \"include\",\n\t\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\t\tbody: JSON.stringify({ email, password, name }),\n\t\t\t\t});\n\t\t\t\tconst json = (await res.json()) as\n\t\t\t\t\t| { data: KavachSession }\n\t\t\t\t\t| { error: { code: string; message: string } };\n\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\terror: extractErrorMessage(json, `Sign-up failed (${res.status})`),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst s = (json as { data: KavachSession }).data;\n\t\t\t\tsetSession(s);\n\t\t\t\tawait persistToStorage(s);\n\t\t\t\treturn { success: true, data: undefined };\n\t\t\t} catch (err) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: err instanceof Error ? err.message : \"Network error\",\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t\t[base, persistToStorage],\n\t);\n\n\tconst signOut = useCallback(async (): Promise<void> => {\n\t\ttry {\n\t\t\tawait fetch(`${base}/sign-out`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\tcredentials: \"include\",\n\t\t\t});\n\t\t} finally {\n\t\t\tsetSession(null);\n\t\t\tawait persistToStorage(null);\n\t\t}\n\t}, [base, persistToStorage]);\n\n\t// ── Context value ───────────────────────────────────────────────────────\n\n\tconst value: KavachContextValue = {\n\t\tsession,\n\t\tuser: session?.user ?? null,\n\t\tisLoading,\n\t\tisAuthenticated: session !== null,\n\t\tsignIn,\n\t\tsignUp,\n\t\tsignOut,\n\t\trefresh,\n\t};\n\n\treturn <ElectronKavachContext.Provider value={value}>{children}</ElectronKavachContext.Provider>;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/electron-api.ts","../src/storage.ts","../src/oauth-window.ts","../src/ipc.ts","../src/provider.tsx"],"sourcesContent":["// ─── Electron API injection ───────────────────────────────────────────────────\n//\n// Modules that need Electron APIs call getElectronApi() to retrieve the live\n// bindings. In a real Electron process this resolves to the real electron\n// module; in tests it resolves to the mock set via setElectronApiForTesting().\n\nimport type { SecureStorage } from \"./storage.js\";\n\n// ─── Surface interfaces ───────────────────────────────────────────────────────\n\nexport interface ElectronSafeStorage {\n\tisEncryptionAvailable(): boolean;\n\tencryptString(value: string): Uint8Array;\n\tdecryptString(encrypted: Uint8Array): string;\n}\n\nexport interface ElectronApp {\n\tgetPath(name: \"userData\"): string;\n}\n\nexport interface BrowserWindowOptions {\n\twidth: number;\n\theight: number;\n\twebPreferences: {\n\t\tnodeIntegration: boolean;\n\t\tcontextIsolation: boolean;\n\t\tsandbox: boolean;\n\t};\n\ttitle: string;\n\tresizable: boolean;\n\tminimizable: boolean;\n\tmaximizable: boolean;\n\tshow: boolean;\n}\n\nexport interface BrowserWindowInstance {\n\tloadURL(url: string): Promise<void>;\n\ton(event: \"closed\", listener: () => void): void;\n\twebContents: {\n\t\ton(\n\t\t\tevent: \"will-redirect\" | \"will-navigate\",\n\t\t\tlistener: (event: unknown, url: string) => void,\n\t\t): void;\n\t\tsession: {\n\t\t\tcookies: {\n\t\t\t\tget(filter: { url: string }): Promise<Array<{ name: string; value: string }>>;\n\t\t\t};\n\t\t};\n\t};\n\tdestroy(): void;\n\tshow(): void;\n}\n\nexport interface BrowserWindowConstructor {\n\tnew (options: BrowserWindowOptions): BrowserWindowInstance;\n}\n\nexport type IpcMainListener = (\n\tevent: { reply(channel: string, ...args: unknown[]): void },\n\t...args: unknown[]\n) => Promise<unknown>;\n\nexport interface ElectronIpcMain {\n\thandle(channel: string, listener: IpcMainListener): void;\n\tremoveHandler(channel: string): void;\n}\n\nexport interface ElectronIpcRenderer {\n\tinvoke(channel: string, ...args: unknown[]): Promise<unknown>;\n}\n\nexport interface ElectronApi {\n\tsafeStorage: ElectronSafeStorage;\n\tapp: ElectronApp;\n\tBrowserWindow: BrowserWindowConstructor;\n\tipcMain: ElectronIpcMain;\n\tipcRenderer: ElectronIpcRenderer;\n}\n\n// ─── Singleton ────────────────────────────────────────────────────────────────\n\nlet _override: ElectronApi | null = null;\n\nfunction loadElectron(): ElectronApi | null {\n\tif (_override) return _override;\n\ttry {\n\t\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\t\treturn require(\"electron\") as ElectronApi;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport function getElectronApi(): ElectronApi {\n\tconst api = loadElectron();\n\tif (!api) {\n\t\tthrow new Error(\n\t\t\t\"[TheAuth] Electron API not available. Ensure this code runs in an Electron process.\",\n\t\t);\n\t}\n\treturn api;\n}\n\n/**\n * For testing only — injects a mock Electron API so modules don't need a real\n * Electron runtime. Call setElectronApiForTesting(null) to reset.\n */\nexport function setElectronApiForTesting(mock: ElectronApi | null): void {\n\t_override = mock;\n}\n\n// Re-export SecureStorage so ipc.ts can reference it without a circular dep\nexport type { SecureStorage };\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { ElectronSafeStorage } from \"./electron-api.js\";\nimport { getElectronApi } from \"./electron-api.js\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface ElectronStorageConfig {\n\t/** File name for the session data. Defaults to \"theauth-session.json\". */\n\tfileName?: string;\n\t/** Optional additional encryption key applied on top of safeStorage. */\n\tencryptionKey?: string;\n}\n\nexport interface SecureStorage {\n\tget(key: string): Promise<string | null>;\n\tset(key: string, value: string): Promise<void>;\n\tremove(key: string): Promise<void>;\n\tclear(): Promise<void>;\n}\n\n// ─── XOR cipher for optional encryptionKey ────────────────────────────────────\n\nfunction xorWithKey(data: Uint8Array, key: string): Uint8Array {\n\tif (key.length === 0) return data;\n\tconst encoder = new TextEncoder();\n\tconst keyBytes = encoder.encode(key);\n\tconst result = new Uint8Array(data.length);\n\tfor (let i = 0; i < data.length; i++) {\n\t\tresult[i] = (data[i] ?? 0) ^ (keyBytes[i % keyBytes.length] ?? 0);\n\t}\n\treturn result;\n}\n\n// ─── Base64 helpers (no Buffer) ───────────────────────────────────────────────\n\nfunction uint8ArrayToBase64(bytes: Uint8Array): string {\n\tlet binary = \"\";\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tbinary += String.fromCharCode(bytes[i] ?? 0);\n\t}\n\treturn btoa(binary);\n}\n\nfunction base64ToUint8Array(base64: string): Uint8Array {\n\tconst binary = atob(base64);\n\tconst bytes = new Uint8Array(binary.length);\n\tfor (let i = 0; i < binary.length; i++) {\n\t\tbytes[i] = binary.charCodeAt(i);\n\t}\n\treturn bytes;\n}\n\n// ─── Storage file helpers ─────────────────────────────────────────────────────\n\ntype StorageMap = Record<string, string>;\n\nfunction readStorageFile(filePath: string): StorageMap {\n\ttry {\n\t\tconst raw = fs.readFileSync(filePath, \"utf8\");\n\t\tconst parsed: unknown = JSON.parse(raw);\n\t\tif (parsed !== null && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n\t\t\treturn parsed as StorageMap;\n\t\t}\n\t\treturn {};\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nfunction writeStorageFile(filePath: string, data: StorageMap): void {\n\tconst dir = path.dirname(filePath);\n\tfs.mkdirSync(dir, { recursive: true });\n\tfs.writeFileSync(filePath, JSON.stringify(data), \"utf8\");\n}\n\n// ─── Factory ──────────────────────────────────────────────────────────────────\n\n/**\n * Creates a SecureStorage adapter backed by Electron's safeStorage API.\n *\n * Values are encrypted with safeStorage before being written to a JSON file\n * in the app's userData directory. If safeStorage is unavailable (e.g. during\n * testing or on headless Linux without a keychain), values are stored as\n * plaintext and a warning is emitted once.\n */\nexport function createElectronStorage(config?: ElectronStorageConfig): SecureStorage {\n\tconst fileName = config?.fileName ?? \"theauth-session.json\";\n\tconst encryptionKey = config?.encryptionKey ?? \"\";\n\n\tlet warned = false;\n\tlet filePath: string | null = null;\n\n\tfunction getFilePath(): string {\n\t\tif (filePath) return filePath;\n\t\tconst electron = getElectronApi();\n\t\tconst resolved = path.join(electron.app.getPath(\"userData\"), fileName);\n\t\tfilePath = resolved;\n\t\treturn resolved;\n\t}\n\n\tfunction getSafeStorage(): ElectronSafeStorage | null {\n\t\tconst electron = getElectronApi();\n\t\tif (!electron.safeStorage.isEncryptionAvailable()) {\n\t\t\tif (!warned) {\n\t\t\t\twarned = true;\n\t\t\t\t// biome-ignore lint/suspicious/noConsole: intentional user-facing warning\n\t\t\t\tconsole.warn(\n\t\t\t\t\t\"TheAuth: safeStorage encryption unavailable — storing session data in plaintext\",\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t\treturn electron.safeStorage;\n\t}\n\n\tfunction encryptValue(value: string): string {\n\t\tconst safeStorage = getSafeStorage();\n\t\tif (!safeStorage) return value;\n\t\tconst encrypted = safeStorage.encryptString(value);\n\t\tconst keyed = encryptionKey ? xorWithKey(encrypted, encryptionKey) : encrypted;\n\t\treturn uint8ArrayToBase64(keyed);\n\t}\n\n\tfunction decryptValue(stored: string): string {\n\t\tconst safeStorage = getSafeStorage();\n\t\tif (!safeStorage) return stored;\n\t\ttry {\n\t\t\tlet bytes = base64ToUint8Array(stored);\n\t\t\tif (encryptionKey) {\n\t\t\t\tbytes = xorWithKey(bytes, encryptionKey);\n\t\t\t}\n\t\t\treturn safeStorage.decryptString(bytes);\n\t\t} catch {\n\t\t\treturn stored;\n\t\t}\n\t}\n\n\treturn {\n\t\tasync get(key: string): Promise<string | null> {\n\t\t\tconst map = readStorageFile(getFilePath());\n\t\t\tconst stored = map[key];\n\t\t\tif (stored === undefined) return null;\n\t\t\treturn decryptValue(stored);\n\t\t},\n\n\t\tasync set(key: string, value: string): Promise<void> {\n\t\t\tconst fp = getFilePath();\n\t\t\tconst map = readStorageFile(fp);\n\t\t\tmap[key] = encryptValue(value);\n\t\t\twriteStorageFile(fp, map);\n\t\t},\n\n\t\tasync remove(key: string): Promise<void> {\n\t\t\tconst fp = getFilePath();\n\t\t\tconst map = readStorageFile(fp);\n\t\t\t// Functional deletion without `delete` operator\n\t\t\tconst next: StorageMap = {};\n\t\t\tfor (const [k, v] of Object.entries(map)) {\n\t\t\t\tif (k !== key) next[k] = v;\n\t\t\t}\n\t\t\twriteStorageFile(fp, next);\n\t\t},\n\n\t\tasync clear(): Promise<void> {\n\t\t\tconst fp = getFilePath();\n\t\t\twriteStorageFile(fp, {});\n\t\t},\n\t};\n}\n\n/**\n * Creates a SecureStorage adapter that operates entirely in memory.\n * Useful for testing or when you explicitly do not want disk persistence.\n */\nexport function createMemoryStorage(): SecureStorage {\n\tconst store = new Map<string, string>();\n\treturn {\n\t\tasync get(key: string): Promise<string | null> {\n\t\t\treturn store.get(key) ?? null;\n\t\t},\n\t\tasync set(key: string, value: string): Promise<void> {\n\t\t\tstore.set(key, value);\n\t\t},\n\t\tasync remove(key: string): Promise<void> {\n\t\t\tstore.delete(key);\n\t\t},\n\t\tasync clear(): Promise<void> {\n\t\t\tstore.clear();\n\t\t},\n\t};\n}\n","import type { BrowserWindowInstance } from \"./electron-api.js\";\nimport { getElectronApi } from \"./electron-api.js\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface OAuthWindowConfig {\n\t/** Window width in pixels. Defaults to 500. */\n\twidth?: number;\n\t/** Window height in pixels. Defaults to 700. */\n\theight?: number;\n\t/** Base path where TheAuth is mounted. Defaults to \"/api/theauth\". */\n\tbasePath?: string;\n}\n\nexport interface OAuthWindowResult {\n\tsuccess: boolean;\n\terror?: string;\n}\n\n// ─── Session cookie extraction ────────────────────────────────────────────────\n\nconst SESSION_COOKIE_NAMES = [\"theauth-session\", \"better-auth.session_token\", \"__session\"];\n\nasync function extractSessionCookie(\n\twin: BrowserWindowInstance,\n\tbaseUrl: string,\n): Promise<string | null> {\n\tconst cookies = await win.webContents.session.cookies.get({ url: baseUrl });\n\tfor (const name of SESSION_COOKIE_NAMES) {\n\t\tconst cookie = cookies.find((c) => c.name === name);\n\t\tif (cookie) return cookie.value;\n\t}\n\treturn null;\n}\n\n// ─── URL parsing helpers ──────────────────────────────────────────────────────\n\nfunction isCallbackUrl(url: string, base: string): boolean {\n\tconst normalised = base.replace(/\\/$/, \"\");\n\treturn (\n\t\turl.includes(`${normalised}/callback`) ||\n\t\turl.includes(`${normalised}/oauth/callback`) ||\n\t\turl.includes(\"code=\") ||\n\t\turl.includes(\"error=\")\n\t);\n}\n\nfunction extractOAuthError(url: string): string | null {\n\ttry {\n\t\t// Use a dummy base so relative paths are accepted\n\t\tconst parsed = new URL(url, \"http://localhost\");\n\t\treturn parsed.searchParams.get(\"error_description\") ?? parsed.searchParams.get(\"error\");\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n// ─── Main export ──────────────────────────────────────────────────────────────\n\n/**\n * Opens a BrowserWindow to the OAuth authorization URL for a given provider,\n * waits for the callback redirect, extracts the session cookie, then closes\n * the window.\n *\n * Must be called from the Electron main process.\n */\nexport async function openOAuthWindow(\n\tproviderId: string,\n\tconfig: OAuthWindowConfig = {},\n): Promise<OAuthWindowResult> {\n\tconst { width = 500, height = 700, basePath = \"/api/theauth\" } = config;\n\tconst base = basePath.replace(/\\/$/, \"\");\n\n\tconst { BrowserWindow } = getElectronApi();\n\n\tconst win = new BrowserWindow({\n\t\twidth,\n\t\theight,\n\t\twebPreferences: {\n\t\t\tnodeIntegration: false,\n\t\t\tcontextIsolation: true,\n\t\t\tsandbox: true,\n\t\t},\n\t\ttitle: \"Sign in\",\n\t\tresizable: false,\n\t\tminimizable: false,\n\t\tmaximizable: false,\n\t\tshow: false,\n\t});\n\n\tconst authUrl = `${base}/sign-in/${encodeURIComponent(providerId)}?redirect=electron`;\n\n\treturn new Promise<OAuthWindowResult>((resolve) => {\n\t\tlet settled = false;\n\n\t\tfunction settle(result: OAuthWindowResult): void {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\twin.destroy();\n\t\t\tresolve(result);\n\t\t}\n\n\t\twin.on(\"closed\", () => {\n\t\t\tsettle({ success: false, error: \"Window closed by user\" });\n\t\t});\n\n\t\tasync function handleNavigate(_event: unknown, url: string): Promise<void> {\n\t\t\tif (!isCallbackUrl(url, base)) return;\n\n\t\t\tconst oauthError = extractOAuthError(url);\n\t\t\tif (oauthError) {\n\t\t\t\tsettle({ success: false, error: oauthError });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst origin = new URL(url).origin;\n\t\t\t\tconst cookie = await extractSessionCookie(win, origin);\n\t\t\t\t// Treat as success whether or not we captured the cookie — the\n\t\t\t\t// session will be verified on the next server round-trip.\n\t\t\t\tvoid cookie;\n\t\t\t\tsettle({ success: true });\n\t\t\t} catch (err) {\n\t\t\t\tsettle({\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: err instanceof Error ? err.message : \"Failed to extract session\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\twin.webContents.on(\"will-redirect\", (ev, url) => {\n\t\t\tvoid handleNavigate(ev, url);\n\t\t});\n\t\twin.webContents.on(\"will-navigate\", (ev, url) => {\n\t\t\tvoid handleNavigate(ev, url);\n\t\t});\n\n\t\tvoid win.loadURL(authUrl).then(() => {\n\t\t\twin.show();\n\t\t});\n\t});\n}\n","import { getElectronApi } from \"./electron-api.js\";\nimport type { SecureStorage } from \"./storage.js\";\n\n// ─── IPC channel names ────────────────────────────────────────────────────────\n\nconst CHANNEL_GET = \"theauth:storage:get\";\nconst CHANNEL_SET = \"theauth:storage:set\";\nconst CHANNEL_REMOVE = \"theauth:storage:remove\";\nconst CHANNEL_CLEAR = \"theauth:storage:clear\";\n\n// ─── Request/response types ───────────────────────────────────────────────────\n\ninterface StorageGetRequest {\n\tkey: string;\n}\n\ninterface StorageSetRequest {\n\tkey: string;\n\tvalue: string;\n}\n\ninterface StorageRemoveRequest {\n\tkey: string;\n}\n\ninterface StorageGetResponse {\n\tvalue: string | null;\n}\n\n// ─── Main process side ────────────────────────────────────────────────────────\n\n/**\n * Registers IPC handlers in the main process so the renderer can securely\n * access storage without needing direct Node.js access.\n *\n * Call this once from your main process entry point after creating your\n * SecureStorage instance via createElectronStorage().\n */\nexport function setupTheAuthIpc(storage: SecureStorage): void {\n\tconst { ipcMain } = getElectronApi();\n\n\t// Remove any previously registered handlers to allow re-initialization.\n\tipcMain.removeHandler(CHANNEL_GET);\n\tipcMain.removeHandler(CHANNEL_SET);\n\tipcMain.removeHandler(CHANNEL_REMOVE);\n\tipcMain.removeHandler(CHANNEL_CLEAR);\n\n\tipcMain.handle(CHANNEL_GET, async (_event, req: unknown): Promise<StorageGetResponse> => {\n\t\tconst { key } = req as StorageGetRequest;\n\t\tconst value = await storage.get(key);\n\t\treturn { value };\n\t});\n\n\tipcMain.handle(CHANNEL_SET, async (_event, req: unknown): Promise<void> => {\n\t\tconst { key, value } = req as StorageSetRequest;\n\t\tawait storage.set(key, value);\n\t});\n\n\tipcMain.handle(CHANNEL_REMOVE, async (_event, req: unknown): Promise<void> => {\n\t\tconst { key } = req as StorageRemoveRequest;\n\t\tawait storage.remove(key);\n\t});\n\n\tipcMain.handle(CHANNEL_CLEAR, async (): Promise<void> => {\n\t\tawait storage.clear();\n\t});\n}\n\n// ─── Renderer process side ────────────────────────────────────────────────────\n\n/**\n * Creates a SecureStorage implementation that delegates all operations to the\n * main process via IPC. Use this in the renderer process in place of a direct\n * storage adapter so that Node.js APIs and encryption stay in the main process.\n *\n * Requires contextIsolation to be enabled and the IPC channels to be exposed\n * via a preload script, or for contextIsolation to be disabled (not recommended).\n */\nexport function createIpcStorage(): SecureStorage {\n\tconst { ipcRenderer } = getElectronApi();\n\n\treturn {\n\t\tasync get(key: string): Promise<string | null> {\n\t\t\tconst req: StorageGetRequest = { key };\n\t\t\tconst res = (await ipcRenderer.invoke(CHANNEL_GET, req)) as StorageGetResponse;\n\t\t\treturn res.value;\n\t\t},\n\n\t\tasync set(key: string, value: string): Promise<void> {\n\t\t\tconst req: StorageSetRequest = { key, value };\n\t\t\tawait ipcRenderer.invoke(CHANNEL_SET, req);\n\t\t},\n\n\t\tasync remove(key: string): Promise<void> {\n\t\t\tconst req: StorageRemoveRequest = { key };\n\t\t\tawait ipcRenderer.invoke(CHANNEL_REMOVE, req);\n\t\t},\n\n\t\tasync clear(): Promise<void> {\n\t\t\tawait ipcRenderer.invoke(CHANNEL_CLEAR);\n\t\t},\n\t};\n}\n\n// ─── Preload bridge helper ────────────────────────────────────────────────────\n\n/**\n * The IPC channel names exposed for use in a preload script with contextBridge.\n * If you use contextIsolation (recommended), expose these channels explicitly:\n *\n * ```ts\n * import { contextBridge, ipcRenderer } from \"electron\";\n * import { THEAUTH_IPC_CHANNELS } from \"@glinr/theauth-electron\";\n *\n * contextBridge.exposeInMainWorld(\"theauthStorage\", {\n * invoke: (channel: string, ...args: unknown[]) => {\n * if (!Object.values(THEAUTH_IPC_CHANNELS).includes(channel)) {\n * throw new Error(`Blocked IPC channel: ${channel}`);\n * }\n * return ipcRenderer.invoke(channel, ...args);\n * },\n * });\n * ```\n */\nexport const THEAUTH_IPC_CHANNELS = {\n\tGET: CHANNEL_GET,\n\tSET: CHANNEL_SET,\n\tREMOVE: CHANNEL_REMOVE,\n\tCLEAR: CHANNEL_CLEAR,\n} as const;\n\n// Kept for backward compatibility with the pre-rebrand \"TheAuth\" API. Will be\n// removed in a future major version.\n","import type { ReactNode } from \"react\";\nimport { createContext, useCallback, useContext, useEffect, useState } from \"react\";\nimport type { SecureStorage } from \"./storage.js\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\ninterface TheAuthUser {\n\tid: string;\n\temail?: string;\n\tname?: string;\n\timage?: string;\n}\n\ninterface TheAuthSession {\n\ttoken: string;\n\tuser: TheAuthUser;\n\texpiresAt?: string;\n}\n\ntype ActionResult<T = void> = { success: true; data: T } | { success: false; error: string };\n\ninterface TheAuthContextValue {\n\tsession: TheAuthSession | null;\n\tuser: TheAuthUser | null;\n\tisLoading: boolean;\n\tisAuthenticated: boolean;\n\tsignIn: (email: string, password: string) => Promise<ActionResult>;\n\tsignUp: (email: string, password: string, name?: string) => Promise<ActionResult>;\n\tsignOut: () => Promise<void>;\n\trefresh: () => Promise<void>;\n}\n\nexport interface ElectronTheAuthProviderProps {\n\tchildren: ReactNode;\n\t/** Base path where TheAuth is mounted. Defaults to \"/api/theauth\". */\n\tbasePath?: string;\n\t/** Custom storage adapter. Defaults to in-memory if not provided. */\n\tstorage?: SecureStorage;\n\t/** Persist session to secure storage across restarts. Defaults to true. */\n\tpersistSession?: boolean;\n}\n\n// ─── Storage key ──────────────────────────────────────────────────────────────\n\nconst SESSION_STORAGE_KEY = \"theauth:session\";\n\n// ─── Context ──────────────────────────────────────────────────────────────────\n\nexport const ElectronTheAuthContext = createContext<TheAuthContextValue | null>(null);\n\nexport function useElectronTheAuthContext(): TheAuthContextValue {\n\tconst ctx = useContext(ElectronTheAuthContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useElectronTheAuthContext must be used inside <ElectronTheAuthProvider>\");\n\t}\n\treturn ctx;\n}\n\n// ─── JSON fetch helpers ───────────────────────────────────────────────────────\n\ntype JsonErrorBody = { error?: { code?: string; message?: string } };\n\nfunction extractErrorMessage(body: unknown, fallback: string): string {\n\tif (\n\t\tbody !== null &&\n\t\ttypeof body === \"object\" &&\n\t\t\"error\" in body &&\n\t\ttypeof (body as JsonErrorBody).error === \"object\" &&\n\t\ttypeof (body as JsonErrorBody).error?.message === \"string\"\n\t) {\n\t\treturn (body as JsonErrorBody).error?.message ?? fallback;\n\t}\n\treturn fallback;\n}\n\n// ─── Provider ─────────────────────────────────────────────────────────────────\n\n/**\n * Wraps your Electron renderer with TheAuth auth state.\n *\n * Extends the base TheAuthProvider behaviour with:\n * - Session persistence to Electron's safeStorage on sign-in\n * - Session restoration from storage on app launch\n * - Storage cleared on sign-out\n *\n * Pass a SecureStorage created by createElectronStorage() or createIpcStorage()\n * depending on whether your renderer runs with Node integration or via IPC.\n */\nexport function ElectronTheAuthProvider({\n\tchildren,\n\tbasePath = \"/api/theauth\",\n\tstorage,\n\tpersistSession = true,\n}: ElectronTheAuthProviderProps): ReactNode {\n\tconst [session, setSession] = useState<TheAuthSession | null>(null);\n\tconst [isLoading, setIsLoading] = useState(true);\n\n\tconst base = basePath.replace(/\\/$/, \"\");\n\n\t// ── Persist / restore helpers ───────────────────────────────────────────\n\n\tconst persistToStorage = useCallback(\n\t\tasync (s: TheAuthSession | null): Promise<void> => {\n\t\t\tif (!storage || !persistSession) return;\n\t\t\tif (s === null) {\n\t\t\t\tawait storage.remove(SESSION_STORAGE_KEY);\n\t\t\t} else {\n\t\t\t\tawait storage.set(SESSION_STORAGE_KEY, JSON.stringify(s));\n\t\t\t}\n\t\t},\n\t\t[storage, persistSession],\n\t);\n\n\tconst restoreFromStorage = useCallback(async (): Promise<TheAuthSession | null> => {\n\t\tif (!storage || !persistSession) return null;\n\t\ttry {\n\t\t\tconst raw = await storage.get(SESSION_STORAGE_KEY);\n\t\t\tif (!raw) return null;\n\t\t\tconst parsed: unknown = JSON.parse(raw);\n\t\t\tif (\n\t\t\t\tparsed !== null &&\n\t\t\t\ttypeof parsed === \"object\" &&\n\t\t\t\t\"token\" in parsed &&\n\t\t\t\ttypeof (parsed as TheAuthSession).token === \"string\" &&\n\t\t\t\t\"user\" in parsed &&\n\t\t\t\ttypeof (parsed as TheAuthSession).user === \"object\"\n\t\t\t) {\n\t\t\t\treturn parsed as TheAuthSession;\n\t\t\t}\n\t\t\treturn null;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}, [storage, persistSession]);\n\n\t// ── Session fetch ───────────────────────────────────────────────────────\n\n\tconst fetchSession = useCallback(async (): Promise<void> => {\n\t\ttry {\n\t\t\tconst res = await fetch(`${base}/session`, { credentials: \"include\" });\n\t\t\tif (res.ok) {\n\t\t\t\tconst json = (await res.json()) as { data?: TheAuthSession };\n\t\t\t\tconst s = json.data ?? null;\n\t\t\t\tsetSession(s);\n\t\t\t\tawait persistToStorage(s);\n\t\t\t} else {\n\t\t\t\tsetSession(null);\n\t\t\t}\n\t\t} catch {\n\t\t\tsetSession(null);\n\t\t}\n\t}, [base, persistToStorage]);\n\n\t// ── Mount: restore from storage, then verify with server ───────────────\n\n\tuseEffect(() => {\n\t\tsetIsLoading(true);\n\n\t\tvoid (async () => {\n\t\t\tconst stored = await restoreFromStorage();\n\t\t\tif (stored) {\n\t\t\t\tsetSession(stored);\n\t\t\t}\n\t\t\t// Always verify the session with the server regardless of storage.\n\t\t\tawait fetchSession();\n\t\t\tsetIsLoading(false);\n\t\t})();\n\t}, [restoreFromStorage, fetchSession]);\n\n\t// ── Auth actions ────────────────────────────────────────────────────────\n\n\tconst refresh = useCallback(async (): Promise<void> => {\n\t\tawait fetchSession();\n\t}, [fetchSession]);\n\n\tconst signIn = useCallback(\n\t\tasync (email: string, password: string): Promise<ActionResult> => {\n\t\t\ttry {\n\t\t\t\tconst res = await fetch(`${base}/sign-in/email`, {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tcredentials: \"include\",\n\t\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\t\tbody: JSON.stringify({ email, password }),\n\t\t\t\t});\n\t\t\t\tconst json = (await res.json()) as\n\t\t\t\t\t| { data: TheAuthSession }\n\t\t\t\t\t| { error: { code: string; message: string } };\n\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\terror: extractErrorMessage(json, `Sign-in failed (${res.status})`),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst s = (json as { data: TheAuthSession }).data;\n\t\t\t\tsetSession(s);\n\t\t\t\tawait persistToStorage(s);\n\t\t\t\treturn { success: true, data: undefined };\n\t\t\t} catch (err) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: err instanceof Error ? err.message : \"Network error\",\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t\t[base, persistToStorage],\n\t);\n\n\tconst signUp = useCallback(\n\t\tasync (email: string, password: string, name?: string): Promise<ActionResult> => {\n\t\t\ttry {\n\t\t\t\tconst res = await fetch(`${base}/sign-up/email`, {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tcredentials: \"include\",\n\t\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\t\tbody: JSON.stringify({ email, password, name }),\n\t\t\t\t});\n\t\t\t\tconst json = (await res.json()) as\n\t\t\t\t\t| { data: TheAuthSession }\n\t\t\t\t\t| { error: { code: string; message: string } };\n\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\terror: extractErrorMessage(json, `Sign-up failed (${res.status})`),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst s = (json as { data: TheAuthSession }).data;\n\t\t\t\tsetSession(s);\n\t\t\t\tawait persistToStorage(s);\n\t\t\t\treturn { success: true, data: undefined };\n\t\t\t} catch (err) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: err instanceof Error ? err.message : \"Network error\",\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t\t[base, persistToStorage],\n\t);\n\n\tconst signOut = useCallback(async (): Promise<void> => {\n\t\ttry {\n\t\t\tawait fetch(`${base}/sign-out`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\tcredentials: \"include\",\n\t\t\t});\n\t\t} finally {\n\t\t\tsetSession(null);\n\t\t\tawait persistToStorage(null);\n\t\t}\n\t}, [base, persistToStorage]);\n\n\t// ── Context value ───────────────────────────────────────────────────────\n\n\tconst value: TheAuthContextValue = {\n\t\tsession,\n\t\tuser: session?.user ?? null,\n\t\tisLoading,\n\t\tisAuthenticated: session !== null,\n\t\tsignIn,\n\t\tsignUp,\n\t\tsignOut,\n\t\trefresh,\n\t};\n\n\treturn (\n\t\t<ElectronTheAuthContext.Provider value={value}>{children}</ElectronTheAuthContext.Provider>\n\t);\n}\n\n// Kept for backward compatibility with the pre-rebrand \"TheAuth\" API. Will be\n// removed in a future major version.\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glinr/theauth-electron",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "TheAuth auth client for Electron desktop apps",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
"dist"
|
|
16
16
|
],
|
|
17
17
|
"license": "MIT",
|
|
18
|
-
"author": "TheAuth <support@
|
|
18
|
+
"author": "TheAuth <support@glinr.com>",
|
|
19
19
|
"repository": {
|
|
20
20
|
"type": "git",
|
|
21
|
-
"url": "https://github.com/glincker/theauth.git",
|
|
21
|
+
"url": "git+https://github.com/glincker/theauth.git",
|
|
22
22
|
"directory": "packages/electron"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
@@ -34,6 +34,20 @@
|
|
|
34
34
|
"typescript": "^6.0.3",
|
|
35
35
|
"vitest": "^2.0.0"
|
|
36
36
|
},
|
|
37
|
+
"homepage": "https://docs.theauth.dev/electron",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/glincker/theauth/issues"
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"keywords": [
|
|
45
|
+
"theauth",
|
|
46
|
+
"auth",
|
|
47
|
+
"electron",
|
|
48
|
+
"desktop",
|
|
49
|
+
"typescript"
|
|
50
|
+
],
|
|
37
51
|
"scripts": {
|
|
38
52
|
"build": "tsup",
|
|
39
53
|
"typecheck": "tsc --noEmit",
|