@clerk/electron 0.0.1

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.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/dist/cjs/index.js +172 -0
  4. package/dist/cjs/index.js.map +1 -0
  5. package/dist/cjs/preload/index.js +39 -0
  6. package/dist/cjs/preload/index.js.map +1 -0
  7. package/dist/cjs/react/index.js +76 -0
  8. package/dist/cjs/react/index.js.map +1 -0
  9. package/dist/cjs/storage/index.js +133 -0
  10. package/dist/cjs/storage/index.js.map +1 -0
  11. package/dist/esm/chunk-WJNPPS7B.js +14 -0
  12. package/dist/esm/chunk-WJNPPS7B.js.map +1 -0
  13. package/dist/esm/index.js +157 -0
  14. package/dist/esm/index.js.map +1 -0
  15. package/dist/esm/preload/index.js +24 -0
  16. package/dist/esm/preload/index.js.map +1 -0
  17. package/dist/esm/react/index.js +68 -0
  18. package/dist/esm/react/index.js.map +1 -0
  19. package/dist/esm/storage/index.js +127 -0
  20. package/dist/esm/storage/index.js.map +1 -0
  21. package/dist/types/index.d.ts +3 -0
  22. package/dist/types/index.d.ts.map +1 -0
  23. package/dist/types/main/create-clerk-bridge.d.ts +10 -0
  24. package/dist/types/main/create-clerk-bridge.d.ts.map +1 -0
  25. package/dist/types/main/ipc-handlers.d.ts +3 -0
  26. package/dist/types/main/ipc-handlers.d.ts.map +1 -0
  27. package/dist/types/main/oauth-transport.d.ts +7 -0
  28. package/dist/types/main/oauth-transport.d.ts.map +1 -0
  29. package/dist/types/preload/index.d.ts +8 -0
  30. package/dist/types/preload/index.d.ts.map +1 -0
  31. package/dist/types/react/create-clerk-instance.d.ts +5 -0
  32. package/dist/types/react/create-clerk-instance.d.ts.map +1 -0
  33. package/dist/types/react/index.d.ts +12 -0
  34. package/dist/types/react/index.d.ts.map +1 -0
  35. package/dist/types/shared/ipc.d.ts +10 -0
  36. package/dist/types/shared/ipc.d.ts.map +1 -0
  37. package/dist/types/shared/types.d.ts +45 -0
  38. package/dist/types/shared/types.d.ts.map +1 -0
  39. package/dist/types/storage/index.d.ts +47 -0
  40. package/dist/types/storage/index.d.ts.map +1 -0
  41. package/package.json +121 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Clerk, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ <p align="center">
2
+ <a href="https://clerk.com?utm_source=github&utm_medium=clerk_electron" target="_blank" rel="noopener noreferrer">
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://images.clerk.com/static/logo-dark-mode-400x400.png">
5
+ <img src="https://images.clerk.com/static/logo-light-mode-400x400.png" height="64">
6
+ </picture>
7
+ </a>
8
+ <br />
9
+ <h1 align="center">@clerk/electron</h1>
10
+ </p>
11
+
12
+ <div align="center">
13
+
14
+ [![Clerk documentation](https://img.shields.io/badge/documentation-clerk-green.svg)](https://clerk.com/docs?utm_source=github&utm_medium=clerk_electron)
15
+ [![Follow on X](https://img.shields.io/twitter/follow/clerk?style=social)](https://x.com/intent/follow?screen_name=clerk)
16
+
17
+ [Changelog](https://github.com/clerk/javascript/blob/main/packages/electron/CHANGELOG.md)
18
+ ·
19
+ [Report a Bug](https://github.com/clerk/javascript/issues/new?assignees=&labels=needs-triage&projects=&template=BUG_REPORT.yml)
20
+ ·
21
+ [Request a Feature](https://feedback.clerk.com/roadmap)
22
+ ·
23
+ [Get help](https://clerk.com/contact/support?utm_source=github&utm_medium=clerk_electron)
24
+
25
+ </div>
26
+
27
+ ## Getting Started
28
+
29
+ [Clerk](https://clerk.com/?utm_source=github&utm_medium=clerk_electron) is the easiest way to add authentication and user management to your Electron application.
30
+
31
+ > [!WARNING]
32
+ > `@clerk/electron` is under active development and is not yet ready for production use. The API is incomplete and subject to change.
33
+
34
+ This package exposes entrypoints for Electron's distinct runtime contexts:
35
+
36
+ - `@clerk/electron` — for use in the Electron **main** process.
37
+ - `@clerk/electron/preload` — for use in Electron **preload** scripts.
38
+ - `@clerk/electron/react` — for use in the Electron **renderer** process.
39
+ - `@clerk/electron/storage` — default token storage backed by `electron-store`.
40
+
41
+ ```ts
42
+ // main.ts
43
+ import { app, BrowserWindow, net, protocol } from 'electron';
44
+ import { createClerkBridge } from '@clerk/electron';
45
+ import { storage } from '@clerk/electron/storage';
46
+ import { join } from 'node:path';
47
+ import { pathToFileURL } from 'node:url';
48
+
49
+ createClerkBridge({
50
+ storage: storage(),
51
+ renderer: {
52
+ scheme: 'my-app',
53
+ host: 'renderer',
54
+ },
55
+ });
56
+
57
+ app.whenReady().then(() => {
58
+ protocol.handle('my-app', request => {
59
+ const url = new URL(request.url);
60
+ const file = url.pathname === '/' ? 'index.html' : url.pathname;
61
+
62
+ return net.fetch(pathToFileURL(join(__dirname, '../renderer', file)).toString());
63
+ });
64
+
65
+ const win = new BrowserWindow({
66
+ webPreferences: {
67
+ preload: join(__dirname, '../preload/index.js'),
68
+ },
69
+ });
70
+
71
+ win.loadURL('my-app://renderer/');
72
+ });
73
+ ```
74
+
75
+ In `my-app://renderer/sign-in`, `my-app` is the scheme, `renderer` is the host, `my-app://renderer` is the origin, and `/sign-in` is the path. If your renderer uses path-based routing, serve every route from the same origin and fall back to your renderer entrypoint as needed.
76
+
77
+ ```ts
78
+ // preload.ts
79
+ import { exposeClerkBridge } from '@clerk/electron/preload';
80
+
81
+ exposeClerkBridge();
82
+ ```
83
+
84
+ ```tsx
85
+ // renderer.tsx
86
+ import { ClerkProvider } from '@clerk/electron/react';
87
+
88
+ <ClerkProvider publishableKey={import.meta.env.VITE_CLERK_PUBLISHABLE_KEY}>{/* ... */}</ClerkProvider>;
89
+ ```
90
+
91
+ ## Support
92
+
93
+ For help, visit our [support page](https://clerk.com/contact/support?utm_source=github&utm_medium=clerk_electron).
94
+
95
+ ## Contributing
96
+
97
+ We're open to all community contributions! If you'd like to contribute in any way, please read [our contribution guidelines](https://github.com/clerk/javascript/blob/main/docs/CONTRIBUTING.md) and [code of conduct](https://github.com/clerk/javascript/blob/main/docs/CODE_OF_CONDUCT.md).
98
+
99
+ ## Security
100
+
101
+ `@clerk/electron` follows good practices of security, but 100% security cannot be assured.
102
+
103
+ `@clerk/electron` is provided **"as is"** without any **warranty**. Use at your own risk.
104
+
105
+ _For more information and to report security issues, please refer to our [security documentation](https://github.com/clerk/javascript/blob/main/docs/SECURITY.md)._
106
+
107
+ ## License
108
+
109
+ This project is licensed under the **MIT license**.
110
+
111
+ See [LICENSE](https://github.com/clerk/javascript/blob/main/packages/electron/LICENSE) for more information.
@@ -0,0 +1,172 @@
1
+ 'use strict';
2
+
3
+ var electron = require('electron');
4
+
5
+ // src/main/create-clerk-bridge.ts
6
+
7
+ // src/shared/ipc.ts
8
+ var TOKEN_CACHE_CHANNELS = {
9
+ getToken: "clerk:token-cache:get",
10
+ saveToken: "clerk:token-cache:save",
11
+ clearToken: "clerk:token-cache:clear"
12
+ };
13
+ var OAUTH_TRANSPORT_CHANNELS = {
14
+ getRedirectUrl: "clerk:oauth-transport:get-redirect-url",
15
+ open: "clerk:oauth-transport:open"
16
+ };
17
+
18
+ // src/main/ipc-handlers.ts
19
+ function setupTokenCacheIpcHandlers(storage) {
20
+ electron.ipcMain.handle(TOKEN_CACHE_CHANNELS.getToken, (_event, key) => {
21
+ return storage.getItem(key);
22
+ });
23
+ electron.ipcMain.handle(TOKEN_CACHE_CHANNELS.saveToken, (_event, key, value) => {
24
+ return storage.setItem(key, value);
25
+ });
26
+ electron.ipcMain.handle(TOKEN_CACHE_CHANNELS.clearToken, (_event, key) => {
27
+ return storage.removeItem(key);
28
+ });
29
+ return () => {
30
+ electron.ipcMain.removeHandler(TOKEN_CACHE_CHANNELS.getToken);
31
+ electron.ipcMain.removeHandler(TOKEN_CACHE_CHANNELS.saveToken);
32
+ electron.ipcMain.removeHandler(TOKEN_CACHE_CHANNELS.clearToken);
33
+ };
34
+ }
35
+ var CALLBACK_TIMEOUT_MS = 3 * 60 * 1e3;
36
+ function buildRedirectUrl(options) {
37
+ return `${options.renderer.scheme}://${options.renderer.host}/`;
38
+ }
39
+ function isMatchingCallbackUrl(url, redirectUrl) {
40
+ try {
41
+ const callback = new URL(url);
42
+ const expected = new URL(redirectUrl);
43
+ return callback.protocol === expected.protocol && callback.host === expected.host && callback.pathname === expected.pathname;
44
+ } catch {
45
+ return false;
46
+ }
47
+ }
48
+ function assertExternalOAuthUrl(url) {
49
+ const parsedUrl = new URL(url);
50
+ if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
51
+ throw new TypeError(`Clerk: refusing to open unsupported OAuth URL protocol: ${parsedUrl.protocol}`);
52
+ }
53
+ }
54
+ function setupOAuthTransportIpcHandlers(options) {
55
+ const redirectUrl = buildRedirectUrl(options);
56
+ let pendingOAuthFlow = null;
57
+ const disposePendingOAuthFlow = (reason) => {
58
+ if (!pendingOAuthFlow) {
59
+ return;
60
+ }
61
+ const pending = pendingOAuthFlow;
62
+ clearTimeout(pendingOAuthFlow.timeout);
63
+ pendingOAuthFlow = null;
64
+ if (reason) {
65
+ pending.reject(reason);
66
+ }
67
+ };
68
+ const handleCallbackUrl = (url) => {
69
+ if (!pendingOAuthFlow || !isMatchingCallbackUrl(url, redirectUrl)) {
70
+ return;
71
+ }
72
+ const pending = pendingOAuthFlow;
73
+ disposePendingOAuthFlow();
74
+ pending.resolve({ callbackUrl: url });
75
+ };
76
+ const openUrlListener = (event, url) => {
77
+ if (!isMatchingCallbackUrl(url, redirectUrl)) {
78
+ return;
79
+ }
80
+ event.preventDefault();
81
+ handleCallbackUrl(url);
82
+ };
83
+ const secondInstanceListener = (_event, argv) => {
84
+ const callbackUrl = argv.find((url) => isMatchingCallbackUrl(url, redirectUrl));
85
+ if (callbackUrl) {
86
+ handleCallbackUrl(callbackUrl);
87
+ }
88
+ };
89
+ electron.app.setAsDefaultProtocolClient(options.renderer.scheme);
90
+ electron.app.on("open-url", openUrlListener);
91
+ electron.app.on("second-instance", secondInstanceListener);
92
+ electron.ipcMain.handle(OAUTH_TRANSPORT_CHANNELS.getRedirectUrl, () => {
93
+ return redirectUrl;
94
+ });
95
+ electron.ipcMain.handle(OAUTH_TRANSPORT_CHANNELS.open, async (_event, url) => {
96
+ if (pendingOAuthFlow) {
97
+ throw new Error("Clerk: an OAuth flow is already pending.");
98
+ }
99
+ assertExternalOAuthUrl(url);
100
+ const callbackPromise = new Promise((resolve, reject) => {
101
+ const timeout = setTimeout(() => {
102
+ disposePendingOAuthFlow();
103
+ reject(new Error("Clerk: OAuth callback timed out."));
104
+ }, CALLBACK_TIMEOUT_MS);
105
+ pendingOAuthFlow = { resolve, reject, timeout };
106
+ });
107
+ try {
108
+ await electron.shell.openExternal(url);
109
+ } catch (err) {
110
+ disposePendingOAuthFlow(err instanceof Error ? err : new Error(String(err)));
111
+ }
112
+ return callbackPromise;
113
+ });
114
+ return () => {
115
+ disposePendingOAuthFlow(new Error("Clerk: OAuth flow was cancelled."));
116
+ electron.app.removeListener("open-url", openUrlListener);
117
+ electron.app.removeListener("second-instance", secondInstanceListener);
118
+ electron.ipcMain.removeHandler(OAUTH_TRANSPORT_CHANNELS.getRedirectUrl);
119
+ electron.ipcMain.removeHandler(OAUTH_TRANSPORT_CHANNELS.open);
120
+ };
121
+ }
122
+
123
+ // src/main/create-clerk-bridge.ts
124
+ function assertValidRendererOriginConfig(renderer) {
125
+ if (renderer.scheme.includes(":") || renderer.scheme.includes("/")) {
126
+ throw new Error(
127
+ 'Clerk: renderer.scheme must be a scheme name like "my-app", not a URL or protocol like "my-app://".'
128
+ );
129
+ }
130
+ if (renderer.host.includes(":") || renderer.host.includes("/")) {
131
+ throw new Error(
132
+ 'Clerk: renderer.host must be a host name like "renderer", not a URL or origin like "my-app://renderer".'
133
+ );
134
+ }
135
+ }
136
+ function createClerkBridge(options) {
137
+ if (!options.storage) {
138
+ throw new Error(
139
+ "Clerk: createClerkBridge requires a storage adapter. Pass createClerkBridge({ storage: storage() }) from @clerk/electron/storage, or provide a custom storage adapter."
140
+ );
141
+ }
142
+ const cleanupTokenPersistence = setupTokenCacheIpcHandlers(options.storage);
143
+ let cleanupOAuthTransport;
144
+ if (options.renderer) {
145
+ assertValidRendererOriginConfig(options.renderer);
146
+ electron.protocol.registerSchemesAsPrivileged([
147
+ {
148
+ scheme: options.renderer.scheme,
149
+ privileges: {
150
+ standard: true,
151
+ secure: true,
152
+ supportFetchAPI: true,
153
+ corsEnabled: true,
154
+ stream: true
155
+ }
156
+ }
157
+ ]);
158
+ cleanupOAuthTransport = setupOAuthTransportIpcHandlers({
159
+ renderer: options.renderer
160
+ });
161
+ }
162
+ return {
163
+ cleanup() {
164
+ cleanupTokenPersistence();
165
+ cleanupOAuthTransport == null ? void 0 : cleanupOAuthTransport();
166
+ }
167
+ };
168
+ }
169
+
170
+ exports.createClerkBridge = createClerkBridge;
171
+ //# sourceMappingURL=index.js.map
172
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/shared/ipc.ts","../../src/main/ipc-handlers.ts","../../src/main/oauth-transport.ts","../../src/main/create-clerk-bridge.ts"],"names":["ipcMain","app","shell","protocol"],"mappings":"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","file":"index.js","sourcesContent":["export const TOKEN_CACHE_CHANNELS = {\n getToken: 'clerk:token-cache:get',\n saveToken: 'clerk:token-cache:save',\n clearToken: 'clerk:token-cache:clear',\n} as const;\n\nexport const OAUTH_TRANSPORT_CHANNELS = {\n getRedirectUrl: 'clerk:oauth-transport:get-redirect-url',\n open: 'clerk:oauth-transport:open',\n} as const;\n","import { ipcMain } from 'electron';\n\nimport { TOKEN_CACHE_CHANNELS } from '../shared/ipc';\nimport type { TokenStorage } from '../shared/types';\n\nexport function setupTokenCacheIpcHandlers(storage: TokenStorage): () => void {\n ipcMain.handle(TOKEN_CACHE_CHANNELS.getToken, (_event, key: string) => {\n return storage.getItem(key);\n });\n\n ipcMain.handle(TOKEN_CACHE_CHANNELS.saveToken, (_event, key: string, value: string) => {\n return storage.setItem(key, value);\n });\n\n ipcMain.handle(TOKEN_CACHE_CHANNELS.clearToken, (_event, key: string) => {\n return storage.removeItem(key);\n });\n\n return () => {\n ipcMain.removeHandler(TOKEN_CACHE_CHANNELS.getToken);\n ipcMain.removeHandler(TOKEN_CACHE_CHANNELS.saveToken);\n ipcMain.removeHandler(TOKEN_CACHE_CHANNELS.clearToken);\n };\n}\n","import { app, ipcMain, shell } from 'electron';\n\nimport { OAUTH_TRANSPORT_CHANNELS } from '../shared/ipc';\nimport type { RendererSchemeOptions } from '../shared/types';\n\nconst CALLBACK_TIMEOUT_MS = 3 * 60 * 1000;\n\ntype PendingOAuthFlow = {\n resolve: (value: { callbackUrl: string }) => void;\n reject: (reason: Error) => void;\n timeout: NodeJS.Timeout;\n};\n\ntype OAuthTransportOptions = {\n renderer: RendererSchemeOptions;\n};\n\nfunction buildRedirectUrl(options: OAuthTransportOptions): string {\n return `${options.renderer.scheme}://${options.renderer.host}/`;\n}\n\nfunction isMatchingCallbackUrl(url: string, redirectUrl: string): boolean {\n try {\n const callback = new URL(url);\n const expected = new URL(redirectUrl);\n\n return (\n callback.protocol === expected.protocol &&\n callback.host === expected.host &&\n callback.pathname === expected.pathname\n );\n } catch {\n return false;\n }\n}\n\nfunction assertExternalOAuthUrl(url: string): void {\n const parsedUrl = new URL(url);\n\n if (parsedUrl.protocol !== 'http:' && parsedUrl.protocol !== 'https:') {\n throw new TypeError(`Clerk: refusing to open unsupported OAuth URL protocol: ${parsedUrl.protocol}`);\n }\n}\n\nexport function setupOAuthTransportIpcHandlers(options: OAuthTransportOptions): () => void {\n const redirectUrl = buildRedirectUrl(options);\n let pendingOAuthFlow: PendingOAuthFlow | null = null;\n\n const disposePendingOAuthFlow = (reason?: Error): void => {\n if (!pendingOAuthFlow) {\n return;\n }\n\n const pending = pendingOAuthFlow;\n clearTimeout(pendingOAuthFlow.timeout);\n pendingOAuthFlow = null;\n\n if (reason) {\n pending.reject(reason);\n }\n };\n\n const handleCallbackUrl = (url: string): void => {\n if (!pendingOAuthFlow || !isMatchingCallbackUrl(url, redirectUrl)) {\n return;\n }\n\n const pending = pendingOAuthFlow;\n disposePendingOAuthFlow();\n pending.resolve({ callbackUrl: url });\n };\n\n const openUrlListener = (event: Electron.Event, url: string): void => {\n if (!isMatchingCallbackUrl(url, redirectUrl)) {\n return;\n }\n\n event.preventDefault();\n handleCallbackUrl(url);\n };\n\n const secondInstanceListener = (_event: Electron.Event, argv: string[]): void => {\n const callbackUrl = argv.find(url => isMatchingCallbackUrl(url, redirectUrl));\n\n if (callbackUrl) {\n handleCallbackUrl(callbackUrl);\n }\n };\n\n app.setAsDefaultProtocolClient(options.renderer.scheme);\n app.on('open-url', openUrlListener);\n app.on('second-instance', secondInstanceListener);\n\n ipcMain.handle(OAUTH_TRANSPORT_CHANNELS.getRedirectUrl, () => {\n return redirectUrl;\n });\n\n ipcMain.handle(OAUTH_TRANSPORT_CHANNELS.open, async (_event, url: string) => {\n if (pendingOAuthFlow) {\n throw new Error('Clerk: an OAuth flow is already pending.');\n }\n\n assertExternalOAuthUrl(url);\n\n const callbackPromise = new Promise<{ callbackUrl: string }>((resolve, reject) => {\n const timeout = setTimeout(() => {\n disposePendingOAuthFlow();\n reject(new Error('Clerk: OAuth callback timed out.'));\n }, CALLBACK_TIMEOUT_MS);\n\n pendingOAuthFlow = { resolve, reject, timeout };\n });\n\n try {\n await shell.openExternal(url);\n } catch (err) {\n disposePendingOAuthFlow(err instanceof Error ? err : new Error(String(err)));\n }\n\n return callbackPromise;\n });\n\n return () => {\n disposePendingOAuthFlow(new Error('Clerk: OAuth flow was cancelled.'));\n app.removeListener('open-url', openUrlListener);\n app.removeListener('second-instance', secondInstanceListener);\n ipcMain.removeHandler(OAUTH_TRANSPORT_CHANNELS.getRedirectUrl);\n ipcMain.removeHandler(OAUTH_TRANSPORT_CHANNELS.open);\n };\n}\n","import { protocol } from 'electron';\n\nimport type { ClerkBridge, CreateClerkBridgeOptions } from '../shared/types';\nimport { setupTokenCacheIpcHandlers } from './ipc-handlers';\nimport { setupOAuthTransportIpcHandlers } from './oauth-transport';\n\nfunction assertValidRendererOriginConfig(renderer: NonNullable<CreateClerkBridgeOptions['renderer']>): void {\n if (renderer.scheme.includes(':') || renderer.scheme.includes('/')) {\n throw new Error(\n 'Clerk: renderer.scheme must be a scheme name like \"my-app\", not a URL or protocol like \"my-app://\".',\n );\n }\n\n if (renderer.host.includes(':') || renderer.host.includes('/')) {\n throw new Error(\n 'Clerk: renderer.host must be a host name like \"renderer\", not a URL or origin like \"my-app://renderer\".',\n );\n }\n}\n\n/**\n * Creates the Clerk bridge for Electron's main process.\n *\n * The bridge owns Clerk's main-process IPC handlers, token persistence, and OAuth deep-link\n * transport. Call this before creating renderer windows, and call the returned `cleanup` method\n * when tearing down the app or test environment.\n */\nexport function createClerkBridge(options: CreateClerkBridgeOptions): ClerkBridge {\n if (!options.storage) {\n throw new Error(\n 'Clerk: createClerkBridge requires a storage adapter. Pass createClerkBridge({ storage: storage() }) from @clerk/electron/storage, or provide a custom storage adapter.',\n );\n }\n\n const cleanupTokenPersistence = setupTokenCacheIpcHandlers(options.storage);\n let cleanupOAuthTransport: (() => void) | undefined;\n\n if (options.renderer) {\n assertValidRendererOriginConfig(options.renderer);\n\n protocol.registerSchemesAsPrivileged([\n {\n scheme: options.renderer.scheme,\n privileges: {\n standard: true,\n secure: true,\n supportFetchAPI: true,\n corsEnabled: true,\n stream: true,\n },\n },\n ]);\n\n cleanupOAuthTransport = setupOAuthTransportIpcHandlers({\n renderer: options.renderer,\n });\n }\n\n return {\n cleanup() {\n cleanupTokenPersistence();\n cleanupOAuthTransport?.();\n },\n };\n}\n"]}
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ var electron = require('electron');
4
+
5
+ // src/preload/index.ts
6
+
7
+ // src/shared/ipc.ts
8
+ var TOKEN_CACHE_CHANNELS = {
9
+ getToken: "clerk:token-cache:get",
10
+ saveToken: "clerk:token-cache:save",
11
+ clearToken: "clerk:token-cache:clear"
12
+ };
13
+ var OAUTH_TRANSPORT_CHANNELS = {
14
+ getRedirectUrl: "clerk:oauth-transport:get-redirect-url",
15
+ open: "clerk:oauth-transport:open"
16
+ };
17
+
18
+ // src/preload/index.ts
19
+ function exposeClerkBridge() {
20
+ const tokenCache = {
21
+ getToken: (key) => electron.ipcRenderer.invoke(TOKEN_CACHE_CHANNELS.getToken, key),
22
+ saveToken: (key, value) => electron.ipcRenderer.invoke(TOKEN_CACHE_CHANNELS.saveToken, key, value),
23
+ clearToken: (key) => electron.ipcRenderer.invoke(TOKEN_CACHE_CHANNELS.clearToken, key)
24
+ };
25
+ const oauthTransport = {
26
+ getRedirectUrl: () => electron.ipcRenderer.invoke(OAUTH_TRANSPORT_CHANNELS.getRedirectUrl),
27
+ open: (url) => electron.ipcRenderer.invoke(OAUTH_TRANSPORT_CHANNELS.open, url)
28
+ };
29
+ const bridge = { tokenCache, oauthTransport };
30
+ if (process.contextIsolated) {
31
+ electron.contextBridge.exposeInMainWorld("__clerk_internal_electron", bridge);
32
+ } else {
33
+ window.__clerk_internal_electron = bridge;
34
+ }
35
+ }
36
+
37
+ exports.exposeClerkBridge = exposeClerkBridge;
38
+ //# sourceMappingURL=index.js.map
39
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/shared/ipc.ts","../../../src/preload/index.ts"],"names":["ipcRenderer","contextBridge"],"mappings":";;;;;;;AAAO,IAAM,oBAAA,GAAuB;AAAA,EAClC,QAAA,EAAU,uBAAA;AAAA,EACV,SAAA,EAAW,wBAAA;AAAA,EACX,UAAA,EAAY;AACd,CAAA;AAEO,IAAM,wBAAA,GAA2B;AAAA,EACtC,cAAA,EAAgB,wCAAA;AAAA,EAChB,IAAA,EAAM;AACR,CAAA;;;ACEO,SAAS,iBAAA,GAA0B;AACxC,EAAA,MAAM,UAAA,GAAyB;AAAA,IAC7B,UAAU,CAAA,GAAA,KAAOA,oBAAA,CAAY,MAAA,CAAO,oBAAA,CAAqB,UAAU,GAAG,CAAA;AAAA,IACtE,SAAA,EAAW,CAAC,GAAA,EAAK,KAAA,KAAUA,qBAAY,MAAA,CAAO,oBAAA,CAAqB,SAAA,EAAW,GAAA,EAAK,KAAK,CAAA;AAAA,IACxF,YAAY,CAAA,GAAA,KAAOA,oBAAA,CAAY,MAAA,CAAO,oBAAA,CAAqB,YAAY,GAAG;AAAA,GAC5E;AACA,EAAA,MAAM,cAAA,GAAiC;AAAA,IACrC,cAAA,EAAgB,MAAMA,oBAAA,CAAY,MAAA,CAAO,yBAAyB,cAAc,CAAA;AAAA,IAChF,MAAM,CAAA,GAAA,KAAOA,oBAAA,CAAY,MAAA,CAAO,wBAAA,CAAyB,MAAM,GAAG;AAAA,GACpE;AACA,EAAA,MAAM,MAAA,GAAS,EAAE,UAAA,EAAY,cAAA,EAAe;AAE5C,EAAA,IAAI,QAAQ,eAAA,EAAiB;AAC3B,IAAAC,sBAAA,CAAc,iBAAA,CAAkB,6BAA6B,MAAM,CAAA;AAAA,EACrE,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,yBAAA,GAA4B,MAAA;AAAA,EACrC;AACF","file":"index.js","sourcesContent":["export const TOKEN_CACHE_CHANNELS = {\n getToken: 'clerk:token-cache:get',\n saveToken: 'clerk:token-cache:save',\n clearToken: 'clerk:token-cache:clear',\n} as const;\n\nexport const OAUTH_TRANSPORT_CHANNELS = {\n getRedirectUrl: 'clerk:oauth-transport:get-redirect-url',\n open: 'clerk:oauth-transport:open',\n} as const;\n","import { contextBridge, ipcRenderer } from 'electron';\n\nimport { OAUTH_TRANSPORT_CHANNELS, TOKEN_CACHE_CHANNELS } from '../shared/ipc';\nimport type { OAuthTransport, TokenCache } from '../shared/types';\n\n/**\n * Exposes Clerk's Electron bridge from the preload script to the renderer.\n *\n * Call this from an Electron preload script. It publishes a narrow internal bridge used by\n * `@clerk/electron/react` for token storage and OAuth transport.\n */\nexport function exposeClerkBridge(): void {\n const tokenCache: TokenCache = {\n getToken: key => ipcRenderer.invoke(TOKEN_CACHE_CHANNELS.getToken, key),\n saveToken: (key, value) => ipcRenderer.invoke(TOKEN_CACHE_CHANNELS.saveToken, key, value),\n clearToken: key => ipcRenderer.invoke(TOKEN_CACHE_CHANNELS.clearToken, key),\n };\n const oauthTransport: OAuthTransport = {\n getRedirectUrl: () => ipcRenderer.invoke(OAUTH_TRANSPORT_CHANNELS.getRedirectUrl),\n open: url => ipcRenderer.invoke(OAUTH_TRANSPORT_CHANNELS.open, url),\n };\n const bridge = { tokenCache, oauthTransport };\n\n if (process.contextIsolated) {\n contextBridge.exposeInMainWorld('__clerk_internal_electron', bridge);\n } else {\n window.__clerk_internal_electron = bridge;\n }\n}\n"]}
@@ -0,0 +1,76 @@
1
+ 'use strict';
2
+
3
+ var internal = require('@clerk/react/internal');
4
+ var ui = require('@clerk/ui');
5
+ var clerkJs = require('@clerk/clerk-js');
6
+ var react = require('@clerk/react');
7
+ var jsxRuntime = require('react/jsx-runtime');
8
+
9
+ // src/react/index.tsx
10
+ var CLERK_CLIENT_JWT_KEY = "__clerk_client_jwt";
11
+ var cached = null;
12
+ function createClerkInstance(publishableKey) {
13
+ if ((cached == null ? void 0 : cached.publishableKey) === publishableKey) {
14
+ return cached.instance;
15
+ }
16
+ const clerk = new clerkJs.Clerk(publishableKey);
17
+ clerk.__internal_onBeforeRequest(async (request) => {
18
+ var _a, _b;
19
+ request.credentials = "omit";
20
+ (_a = request.url) == null ? void 0 : _a.searchParams.append("_is_native", "1");
21
+ const token = await ((_b = window.__clerk_internal_electron) == null ? void 0 : _b.tokenCache.getToken(CLERK_CLIENT_JWT_KEY));
22
+ if (token) {
23
+ const headers = new Headers(request.headers);
24
+ headers.set("Authorization", `Bearer ${token}`);
25
+ request.headers = headers;
26
+ }
27
+ });
28
+ clerk.__internal_onAfterResponse(async (_request, response) => {
29
+ var _a;
30
+ const authorization = response.headers.get("Authorization");
31
+ if (!authorization) {
32
+ return;
33
+ }
34
+ const token = authorization.startsWith("Bearer ") ? authorization.slice("Bearer ".length) : authorization;
35
+ await ((_a = window.__clerk_internal_electron) == null ? void 0 : _a.tokenCache.saveToken(CLERK_CLIENT_JWT_KEY, token));
36
+ });
37
+ cached = { instance: clerk, publishableKey };
38
+ return clerk;
39
+ }
40
+ function createOAuthTransport() {
41
+ var _a;
42
+ const bridge = (_a = window.__clerk_internal_electron) == null ? void 0 : _a.oauthTransport;
43
+ if (!bridge) {
44
+ return void 0;
45
+ }
46
+ return {
47
+ getRedirectUrl: () => bridge.getRedirectUrl(),
48
+ open: (url) => bridge.open(url.href)
49
+ };
50
+ }
51
+ function ClerkProvider({ children, publishableKey, ...props }) {
52
+ const clerk = createClerkInstance(publishableKey);
53
+ const oauthTransport = createOAuthTransport();
54
+ return /* @__PURE__ */ jsxRuntime.jsx(
55
+ internal.InternalClerkProvider,
56
+ {
57
+ ...props,
58
+ Clerk: clerk,
59
+ __internal_oauthTransport: oauthTransport,
60
+ publishableKey,
61
+ standardBrowser: false,
62
+ ui: ui.ui,
63
+ children
64
+ }
65
+ );
66
+ }
67
+
68
+ exports.ClerkProvider = ClerkProvider;
69
+ Object.keys(react).forEach(function (k) {
70
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
71
+ enumerable: true,
72
+ get: function () { return react[k]; }
73
+ });
74
+ });
75
+ //# sourceMappingURL=index.js.map
76
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/react/create-clerk-instance.ts","../../../src/react/index.tsx"],"names":["Clerk","jsx","ReactClerkProvider","ui"],"mappings":"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","file":"index.js","sourcesContent":["import { Clerk } from '@clerk/clerk-js';\n\nconst CLERK_CLIENT_JWT_KEY = '__clerk_client_jwt';\n\ntype ClerkInstance = InstanceType<typeof Clerk>;\n\nlet cached: { instance: ClerkInstance; publishableKey: string } | null = null;\n\nexport function createClerkInstance(publishableKey: string): ClerkInstance {\n if (cached?.publishableKey === publishableKey) {\n return cached.instance;\n }\n\n const clerk = new Clerk(publishableKey);\n\n clerk.__internal_onBeforeRequest(async request => {\n request.credentials = 'omit';\n request.url?.searchParams.append('_is_native', '1');\n\n const token = await window.__clerk_internal_electron?.tokenCache.getToken(CLERK_CLIENT_JWT_KEY);\n if (token) {\n const headers = new Headers(request.headers);\n headers.set('Authorization', `Bearer ${token}`);\n request.headers = headers;\n }\n });\n\n clerk.__internal_onAfterResponse(async (_request, response) => {\n const authorization = (response as Response).headers.get('Authorization');\n if (!authorization) {\n return;\n }\n\n const token = authorization.startsWith('Bearer ') ? authorization.slice('Bearer '.length) : authorization;\n await window.__clerk_internal_electron?.tokenCache.saveToken(CLERK_CLIENT_JWT_KEY, token);\n });\n\n cached = { instance: clerk, publishableKey };\n return clerk;\n}\n","import type { ClerkProviderProps as ReactClerkProviderProps } from '@clerk/react';\nimport { InternalClerkProvider as ReactClerkProvider } from '@clerk/react/internal';\nimport { ui } from '@clerk/ui';\nimport type { ReactNode } from 'react';\n\nimport { createClerkInstance } from './create-clerk-instance';\n\ntype ClerkOAuthTransport = NonNullable<ReactClerkProviderProps['__internal_oauthTransport']>;\n\nexport type ClerkProviderProps = Omit<\n ReactClerkProviderProps,\n 'Clerk' | 'children' | 'publishableKey' | 'standardBrowser' | 'ui' | '__internal_oauthTransport'\n> & {\n children: ReactNode;\n /**\n * Your Clerk publishable key, available in the Clerk Dashboard.\n */\n publishableKey: string;\n};\n\nfunction createOAuthTransport(): ClerkOAuthTransport | undefined {\n const bridge = window.__clerk_internal_electron?.oauthTransport;\n\n if (!bridge) {\n return undefined;\n }\n\n return {\n getRedirectUrl: () => bridge.getRedirectUrl(),\n open: url => bridge.open(url.href),\n };\n}\n\nexport function ClerkProvider({ children, publishableKey, ...props }: ClerkProviderProps): JSX.Element {\n const clerk = createClerkInstance(publishableKey);\n const oauthTransport = createOAuthTransport();\n\n return (\n <ReactClerkProvider\n {...props}\n Clerk={clerk}\n __internal_oauthTransport={oauthTransport}\n publishableKey={publishableKey}\n standardBrowser={false}\n ui={ui}\n >\n {children}\n </ReactClerkProvider>\n );\n}\n\nexport * from '@clerk/react';\n"]}
@@ -0,0 +1,133 @@
1
+ 'use strict';
2
+
3
+ var electron = require('electron');
4
+ var Store = require('electron-store');
5
+
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var Store__default = /*#__PURE__*/_interopDefault(Store);
9
+
10
+ // src/storage/index.ts
11
+ var ENCRYPTED_PREFIX = "enc:";
12
+ var RAW_PREFIX = "raw:";
13
+ var syncCipher = {
14
+ encrypt: (value) => Promise.resolve(electron.safeStorage.encryptString(value).toString("base64")),
15
+ decrypt: (payload) => Promise.resolve({ value: electron.safeStorage.decryptString(Buffer.from(payload, "base64")), shouldReEncrypt: false })
16
+ };
17
+ function hasAsyncSafeStorage(storage2) {
18
+ const candidate = storage2;
19
+ return typeof candidate.encryptStringAsync === "function" && typeof candidate.decryptStringAsync === "function" && typeof candidate.isAsyncEncryptionAvailable === "function";
20
+ }
21
+ function createAsyncCipher(storage2) {
22
+ return {
23
+ encrypt: async (value) => (await storage2.encryptStringAsync(value)).toString("base64"),
24
+ decrypt: async (payload) => {
25
+ const { result, shouldReEncrypt } = await storage2.decryptStringAsync(Buffer.from(payload, "base64"));
26
+ return { value: result, shouldReEncrypt };
27
+ }
28
+ };
29
+ }
30
+ async function resolveCipher() {
31
+ if (hasAsyncSafeStorage(electron.safeStorage)) {
32
+ try {
33
+ if (await electron.safeStorage.isAsyncEncryptionAvailable()) {
34
+ return createAsyncCipher(electron.safeStorage);
35
+ }
36
+ } catch {
37
+ }
38
+ }
39
+ if (typeof electron.safeStorage.isEncryptionAvailable === "function" && electron.safeStorage.isEncryptionAvailable()) {
40
+ return syncCipher;
41
+ }
42
+ return null;
43
+ }
44
+ function storage(options = {}) {
45
+ var _a;
46
+ const store = new Store__default.default({
47
+ name: (_a = options.name) != null ? _a : "clerk-tokens",
48
+ ...options.path ? { cwd: options.path } : {}
49
+ });
50
+ let cachedCipher = null;
51
+ let resolving = null;
52
+ const getCipher = () => {
53
+ if (cachedCipher) {
54
+ return Promise.resolve(cachedCipher);
55
+ }
56
+ resolving != null ? resolving : resolving = resolveCipher().then((resolved) => {
57
+ resolving = null;
58
+ if (resolved) {
59
+ cachedCipher = resolved;
60
+ }
61
+ return resolved;
62
+ });
63
+ return resolving;
64
+ };
65
+ let warned = false;
66
+ const warnOnce = (message) => {
67
+ if (warned) {
68
+ return;
69
+ }
70
+ warned = true;
71
+ console.warn(message);
72
+ };
73
+ return {
74
+ async getItem(key) {
75
+ const stored = store.get(key);
76
+ if (!stored) {
77
+ return null;
78
+ }
79
+ if (stored.startsWith(RAW_PREFIX)) {
80
+ return stored.slice(RAW_PREFIX.length);
81
+ }
82
+ if (stored.startsWith(ENCRYPTED_PREFIX)) {
83
+ const cipher = await getCipher();
84
+ if (!cipher) {
85
+ return null;
86
+ }
87
+ const payload = stored.slice(ENCRYPTED_PREFIX.length);
88
+ try {
89
+ const { value, shouldReEncrypt } = await cipher.decrypt(payload);
90
+ if (shouldReEncrypt) {
91
+ try {
92
+ store.set(key, ENCRYPTED_PREFIX + await cipher.encrypt(value));
93
+ } catch {
94
+ }
95
+ }
96
+ return value;
97
+ } catch {
98
+ return null;
99
+ }
100
+ }
101
+ store.delete(key);
102
+ return null;
103
+ },
104
+ async setItem(key, value) {
105
+ const cipher = await getCipher();
106
+ if (!cipher) {
107
+ if (options.unencryptedFallback) {
108
+ warnOnce(
109
+ "Clerk: OS encryption is unavailable; falling back to unencrypted storage. Session tokens are being stored unencrypted on local disk."
110
+ );
111
+ store.set(key, RAW_PREFIX + value);
112
+ } else {
113
+ warnOnce(
114
+ "Clerk: OS encryption is unavailable and unencryptedFallback is not enabled, so tokens are not being persisted. The user will be signed out on the next launch. Pass `storage({ unencryptedFallback: true })` to persist unencrypted (less secure)."
115
+ );
116
+ }
117
+ return;
118
+ }
119
+ try {
120
+ store.set(key, ENCRYPTED_PREFIX + await cipher.encrypt(value));
121
+ } catch {
122
+ warnOnce("Clerk: failed to encrypt the session token; it was not persisted.");
123
+ }
124
+ },
125
+ removeItem(key) {
126
+ store.delete(key);
127
+ }
128
+ };
129
+ }
130
+
131
+ exports.storage = storage;
132
+ //# sourceMappingURL=index.js.map
133
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/storage/index.ts"],"names":["safeStorage","storage","Store"],"mappings":"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","file":"index.js","sourcesContent":["import { safeStorage } from 'electron';\nimport Store from 'electron-store';\n\nimport type { TokenStorage } from '../shared/types';\n\ntype StorageOptions = {\n /**\n * The name of the file (without extension) used to persist tokens.\n *\n * @default 'clerk-tokens'\n */\n name?: string;\n /**\n * The directory in which the token file is stored. Maps to `electron-store`'s `cwd` option.\n * When omitted, the OS default user config directory is used.\n */\n path?: string;\n /**\n * When OS-level encryption is unavailable (e.g. a Linux machine without a keyring), tokens are\n * not persisted by default, which signs the user out on the next app launch. Set this to `true`\n * to instead persist tokens **unencrypted** in that scenario, keeping the user signed in across\n * restarts at the cost of storing tokens in plaintext on disk.\n *\n * @default false\n */\n unencryptedFallback?: boolean;\n};\n\n/**\n * Marks a value that was encrypted via {@link safeStorage}; the remainder is base64 ciphertext.\n * values will be stored as: `enc:<encrypted value>`\n */\nconst ENCRYPTED_PREFIX = 'enc:';\n/**\n * Marks a value persisted unencrypted via the `unencryptedFallback` option.\n * values will be stored as: `raw:<value>`\n */\nconst RAW_PREFIX = 'raw:';\n\ntype Cipher = {\n encrypt: (value: string) => Promise<string>;\n /**\n * Decrypts a base64 payload. `shouldReEncrypt` is `true` (async backend only) when the OS key\n * has rotated and the payload should be re-encrypted with the new key.\n */\n decrypt: (payload: string) => Promise<{ value: string; shouldReEncrypt: boolean }>;\n};\n\ntype AsyncSafeStorage = {\n encryptStringAsync: (plainText: string) => Promise<Buffer>;\n decryptStringAsync: (encrypted: Buffer) => Promise<{ result: string; shouldReEncrypt: boolean }>;\n isAsyncEncryptionAvailable: () => Promise<boolean>;\n};\n\nconst syncCipher: Cipher = {\n encrypt: value => Promise.resolve(safeStorage.encryptString(value).toString('base64')),\n decrypt: payload =>\n Promise.resolve({ value: safeStorage.decryptString(Buffer.from(payload, 'base64')), shouldReEncrypt: false }),\n};\n\nfunction hasAsyncSafeStorage(storage: typeof safeStorage): storage is typeof safeStorage & AsyncSafeStorage {\n const candidate = storage as Partial<AsyncSafeStorage>;\n\n return (\n typeof candidate.encryptStringAsync === 'function' &&\n typeof candidate.decryptStringAsync === 'function' &&\n typeof candidate.isAsyncEncryptionAvailable === 'function'\n );\n}\n\nfunction createAsyncCipher(storage: AsyncSafeStorage): Cipher {\n return {\n encrypt: async value => (await storage.encryptStringAsync(value)).toString('base64'),\n decrypt: async payload => {\n const { result, shouldReEncrypt } = await storage.decryptStringAsync(Buffer.from(payload, 'base64'));\n return { value: result, shouldReEncrypt };\n },\n };\n}\n\n/**\n * Resolves the crypto backend to use, or `null` when no OS encryption is currently available.\n */\nasync function resolveCipher(): Promise<Cipher | null> {\n // Prefer the async API, but only when the full optional function surface exists.\n if (hasAsyncSafeStorage(safeStorage)) {\n try {\n if (await safeStorage.isAsyncEncryptionAvailable()) {\n return createAsyncCipher(safeStorage);\n }\n } catch {\n /* fall through to the synchronous API */\n }\n }\n\n // The synchronous API blocks the calling thread on the OS prompt during the first encrypt/decrypt,\n if (typeof safeStorage.isEncryptionAvailable === 'function' && safeStorage.isEncryptionAvailable()) {\n return syncCipher;\n }\n\n return null;\n}\n\n/**\n * Creates a secure {@link TokenStorage} adapter for the Electron main process.\n *\n * Tokens are persisted with `electron-store` and encrypted at rest using Electron's\n * {@link safeStorage} API, which is backed by the OS keystore (Keychain on macOS, DPAPI on\n * Windows, libsecret/kwallet on Linux). It uses Electron 42's async `safeStorage` API only when it\n * reports itself available (which generally requires a code-signed app) and otherwise falls back to\n * the synchronous API. Pass the result to `createClerkBridge({ storage: storage() })`.\n *\n * Behavior is secure by default: when OS encryption is unavailable the adapter does not persist\n * tokens (the user will be signed out on restart) unless {@link StorageOptions.unencryptedFallback}\n * is enabled. Undecryptable entries return `null`.\n *\n * @example\n * ```ts\n * import { createClerkBridge } from '@clerk/electron';\n * import { storage } from '@clerk/electron/storage';\n *\n * createClerkBridge({ storage: storage({ name: 'my-app-tokens' }) });\n * ```\n */\nexport function storage(options: StorageOptions = {}): TokenStorage {\n const store = new Store<Record<string, string>>({\n name: options.name ?? 'clerk-tokens',\n ...(options.path ? { cwd: options.path } : {}),\n });\n\n let cachedCipher: Cipher | null = null;\n let resolving: Promise<Cipher | null> | null = null;\n const getCipher = (): Promise<Cipher | null> => {\n if (cachedCipher) {\n return Promise.resolve(cachedCipher);\n }\n resolving ??= resolveCipher().then(resolved => {\n resolving = null;\n if (resolved) {\n cachedCipher = resolved;\n }\n return resolved;\n });\n return resolving;\n };\n\n let warned = false;\n const warnOnce = (message: string) => {\n if (warned) {\n return;\n }\n warned = true;\n console.warn(message);\n };\n\n return {\n async getItem(key) {\n const stored = store.get(key);\n\n if (!stored) {\n return null;\n }\n\n if (stored.startsWith(RAW_PREFIX)) {\n return stored.slice(RAW_PREFIX.length);\n }\n\n if (stored.startsWith(ENCRYPTED_PREFIX)) {\n const cipher = await getCipher();\n\n // No usable OS encryption, preserve entry.\n if (!cipher) {\n return null;\n }\n\n const payload = stored.slice(ENCRYPTED_PREFIX.length);\n\n try {\n const { value, shouldReEncrypt } = await cipher.decrypt(payload);\n\n if (shouldReEncrypt) {\n // OS key has rotated, persist with new value\n try {\n store.set(key, ENCRYPTED_PREFIX + (await cipher.encrypt(value)));\n } catch {\n // keep the existing payload; it still decrypts for now\n }\n }\n\n return value;\n } catch {\n // Decryption failed, preserve the entry, new write on next sign-in.\n return null;\n }\n }\n\n // Unknown or unrecognized format, drop the entry so we don't repeatedly fail on it.\n store.delete(key);\n return null;\n },\n async setItem(key, value) {\n const cipher = await getCipher();\n\n if (!cipher) {\n if (options.unencryptedFallback) {\n warnOnce(\n 'Clerk: OS encryption is unavailable; falling back to unencrypted storage. Session tokens are being stored unencrypted on local disk.',\n );\n store.set(key, RAW_PREFIX + value);\n } else {\n warnOnce(\n 'Clerk: OS encryption is unavailable and unencryptedFallback is not enabled, so tokens are not being persisted. The user will be signed out on the next launch. Pass `storage({ unencryptedFallback: true })` to persist unencrypted (less secure).',\n );\n }\n return;\n }\n\n try {\n store.set(key, ENCRYPTED_PREFIX + (await cipher.encrypt(value)));\n } catch {\n // Encryption is available but encryption failed\n warnOnce('Clerk: failed to encrypt the session token; it was not persisted.');\n }\n },\n removeItem(key) {\n store.delete(key);\n },\n };\n}\n"]}
@@ -0,0 +1,14 @@
1
+ // src/shared/ipc.ts
2
+ var TOKEN_CACHE_CHANNELS = {
3
+ getToken: "clerk:token-cache:get",
4
+ saveToken: "clerk:token-cache:save",
5
+ clearToken: "clerk:token-cache:clear"
6
+ };
7
+ var OAUTH_TRANSPORT_CHANNELS = {
8
+ getRedirectUrl: "clerk:oauth-transport:get-redirect-url",
9
+ open: "clerk:oauth-transport:open"
10
+ };
11
+
12
+ export { OAUTH_TRANSPORT_CHANNELS, TOKEN_CACHE_CHANNELS };
13
+ //# sourceMappingURL=chunk-WJNPPS7B.js.map
14
+ //# sourceMappingURL=chunk-WJNPPS7B.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/shared/ipc.ts"],"names":[],"mappings":";AAAO,IAAM,oBAAA,GAAuB;AAAA,EAClC,QAAA,EAAU,uBAAA;AAAA,EACV,SAAA,EAAW,wBAAA;AAAA,EACX,UAAA,EAAY;AACd;AAEO,IAAM,wBAAA,GAA2B;AAAA,EACtC,cAAA,EAAgB,wCAAA;AAAA,EAChB,IAAA,EAAM;AACR","file":"chunk-WJNPPS7B.js","sourcesContent":["export const TOKEN_CACHE_CHANNELS = {\n getToken: 'clerk:token-cache:get',\n saveToken: 'clerk:token-cache:save',\n clearToken: 'clerk:token-cache:clear',\n} as const;\n\nexport const OAUTH_TRANSPORT_CHANNELS = {\n getRedirectUrl: 'clerk:oauth-transport:get-redirect-url',\n open: 'clerk:oauth-transport:open',\n} as const;\n"]}