@rttnd/gau 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-LEYZAXTW.js +1 -0
- package/dist/chunk-LEYZAXTW.js.map +1 -0
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/client/solid/index.d.ts.map +1 -1
- package/dist/src/client/solid/index.jsx +234 -0
- package/dist/src/client/svelte/index.svelte.d.ts.map +1 -1
- package/dist/src/client/svelte/index.svelte.js +1 -1
- package/dist/src/client/svelte/index.svelte.js.map +1 -1
- package/dist/src/runtimes/index.js +1 -1
- package/dist/src/runtimes/tauri/index.d.ts +1 -1
- package/dist/src/runtimes/tauri/index.d.ts.map +1 -1
- package/dist/src/runtimes/tauri/index.js +1 -1
- package/dist/src/solidstart/index.d.ts +15 -1
- package/dist/src/solidstart/index.d.ts.map +1 -1
- package/dist/src/solidstart/index.js +1 -1
- package/dist/src/solidstart/index.js.map +1 -1
- package/package.json +10 -10
- package/dist/chunk-7WBYR3Q6.js +0 -1
- package/dist/chunk-7WBYR3Q6.js.map +0 -1
- package/dist/src/client/solid/index.js +0 -1
- package/dist/src/client/solid/index.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{BROWSER as n}from"esm-env";import{BROWSER as o}from"esm-env";var t=n&&"__TAURI_INTERNALS__"in window;async function a(n,o,a="gau",i){if(!t)return;const{platform:e}=await import("@tauri-apps/plugin-os"),{open:r}=await import("@tauri-apps/plugin-shell"),s=e();let c;c=i||("android"===s||"ios"===s?new URL(o).origin:`${a}://oauth/callback`);const p=`${o}/${n}?redirectTo=${encodeURIComponent(c)}`;await r(p)}async function i(n){if(!t)return;const{listen:o}=await import("@tauri-apps/api/event");try{return await o("deep-link",async o=>{await n(o.payload)})}catch(n){console.error(n)}}function e(n,o,t,a){const i=new URL(n);if(i.protocol!==`${t}:`&&i.origin!==new URL(o).origin)return;const e=new URLSearchParams(i.hash.substring(1)).get("token");e&&a(e)}async function r(n,a,i="gau",e){if(!t)return;const{platform:r}=await import("@tauri-apps/plugin-os"),{open:s}=await import("@tauri-apps/plugin-shell"),c=r();let p;p=e||("android"===c||"ios"===c?new URL(a).origin:`${i}://oauth/callback`);const l=o?localStorage.getItem("gau-token"):null;if(!l)return void console.error("No session token found, cannot link account.");const u=`${a}/link/${n}${`?redirectTo=${encodeURIComponent(p)}&token=${encodeURIComponent(l)}`}`;await s(u)}export{t as isTauri,a as signInWithTauri,i as setupTauriListener,e as handleTauriDeepLink,r as linkAccountWithTauri};//# sourceMappingURL=chunk-LEYZAXTW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtimes/tauri/index.ts","../src/client/token.ts"],"sourcesContent":["import { BROWSER } from 'esm-env'\nimport { getSessionToken } from '../../client/token'\n\nexport const isTauri = BROWSER && '__TAURI_INTERNALS__' in window\n\nexport async function signInWithTauri(\n provider: string,\n baseUrl: string,\n scheme: string = 'gau',\n redirectOverride?: string,\n) {\n if (!isTauri)\n return\n\n const { platform } = await import('@tauri-apps/plugin-os')\n const { open } = await import('@tauri-apps/plugin-shell')\n\n const currentPlatform = platform() // platform is NO LONGER an async function\n let redirectTo: string\n\n if (redirectOverride)\n redirectTo = redirectOverride\n else if (currentPlatform === 'android' || currentPlatform === 'ios')\n redirectTo = new URL(baseUrl).origin\n else\n redirectTo = `${scheme}://oauth/callback`\n\n const authUrl = `${baseUrl}/${provider}?redirectTo=${encodeURIComponent(redirectTo)}`\n await open(authUrl)\n}\n\nexport async function setupTauriListener(\n handler: (url: string) => Promise<void>,\n): Promise<(() => void) | void> {\n if (!isTauri)\n return\n\n const { listen } = await import('@tauri-apps/api/event')\n try {\n const unlisten = await listen<string>('deep-link', async (event) => {\n await handler(event.payload)\n })\n return unlisten\n }\n catch (err) {\n console.error(err)\n }\n}\n\nexport function handleTauriDeepLink(url: string, baseUrl: string, scheme: string, onToken: (token: string) => void) {\n const parsed = new URL(url)\n if (parsed.protocol !== `${scheme}:` && parsed.origin !== new URL(baseUrl).origin)\n return\n\n const params = new URLSearchParams(parsed.hash.substring(1))\n const token = params.get('token')\n if (token)\n onToken(token)\n}\n\nexport async function linkAccountWithTauri(\n provider: string,\n baseUrl: string,\n scheme: string = 'gau',\n redirectOverride?: string,\n) {\n if (!isTauri)\n return\n\n const { platform } = await import('@tauri-apps/plugin-os')\n const { open } = await import('@tauri-apps/plugin-shell')\n\n const currentPlatform = platform()\n let redirectTo: string\n\n if (redirectOverride)\n redirectTo = redirectOverride\n else if (currentPlatform === 'android' || currentPlatform === 'ios')\n redirectTo = new URL(baseUrl).origin\n else\n redirectTo = `${scheme}://oauth/callback`\n\n const token = getSessionToken()\n if (!token) {\n console.error('No session token found, cannot link account.')\n return\n }\n\n const query = `?redirectTo=${encodeURIComponent(redirectTo)}&token=${encodeURIComponent(token)}`\n const linkUrl = `${baseUrl}/link/${provider}${query}`\n await open(linkUrl)\n}\n","import { BROWSER } from 'esm-env'\n\nexport function storeSessionToken(token: string) {\n if (!BROWSER)\n return\n try {\n localStorage.setItem('gau-token', token)\n document.cookie = `__gau-session-token=${token}; path=/; max-age=31536000; samesite=lax; secure`\n }\n catch {}\n}\n\nexport function getSessionToken(): string | null {\n if (!BROWSER)\n return null\n return localStorage.getItem('gau-token')\n}\n\nexport function clearSessionToken() {\n if (!BROWSER)\n return\n try {\n localStorage.removeItem('gau-token')\n document.cookie = `__gau-session-token=; path=/; max-age=0`\n }\n catch {}\n}\n"],"mappings":";AAAA,SAAS,WAAAA,gBAAe;;;ACAxB,SAAS,eAAe;AAYjB,SAAS,kBAAiC;AAC/C,MAAI,CAAC;AACH,WAAO;AACT,SAAO,aAAa,QAAQ,WAAW;AACzC;;;ADbO,IAAM,UAAUC,YAAW,yBAAyB;AAE3D,eAAsB,gBACpB,UACA,SACA,SAAiB,OACjB,kBACA;AACA,MAAI,CAAC;AACH;AAEF,QAAM,EAAE,SAAS,IAAI,MAAM,OAAO,uBAAuB;AACzD,QAAM,EAAE,KAAK,IAAI,MAAM,OAAO,0BAA0B;AAExD,QAAM,kBAAkB,SAAS;AACjC,MAAI;AAEJ,MAAI;AACF,iBAAa;AAAA,WACN,oBAAoB,aAAa,oBAAoB;AAC5D,iBAAa,IAAI,IAAI,OAAO,EAAE;AAAA;AAE9B,iBAAa,GAAG,MAAM;AAExB,QAAM,UAAU,GAAG,OAAO,IAAI,QAAQ,eAAe,mBAAmB,UAAU,CAAC;AACnF,QAAM,KAAK,OAAO;AACpB;AAEA,eAAsB,mBACpB,SAC8B;AAC9B,MAAI,CAAC;AACH;AAEF,QAAM,EAAE,OAAO,IAAI,MAAM,OAAO,uBAAuB;AACvD,MAAI;AACF,UAAM,WAAW,MAAM,OAAe,aAAa,OAAO,UAAU;AAClE,YAAM,QAAQ,MAAM,OAAO;AAAA,IAC7B,CAAC;AACD,WAAO;AAAA,EACT,SACO,KAAK;AACV,YAAQ,MAAM,GAAG;AAAA,EACnB;AACF;AAEO,SAAS,oBAAoB,KAAa,SAAiB,QAAgB,SAAkC;AAClH,QAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,MAAI,OAAO,aAAa,GAAG,MAAM,OAAO,OAAO,WAAW,IAAI,IAAI,OAAO,EAAE;AACzE;AAEF,QAAM,SAAS,IAAI,gBAAgB,OAAO,KAAK,UAAU,CAAC,CAAC;AAC3D,QAAM,QAAQ,OAAO,IAAI,OAAO;AAChC,MAAI;AACF,YAAQ,KAAK;AACjB;AAEA,eAAsB,qBACpB,UACA,SACA,SAAiB,OACjB,kBACA;AACA,MAAI,CAAC;AACH;AAEF,QAAM,EAAE,SAAS,IAAI,MAAM,OAAO,uBAAuB;AACzD,QAAM,EAAE,KAAK,IAAI,MAAM,OAAO,0BAA0B;AAExD,QAAM,kBAAkB,SAAS;AACjC,MAAI;AAEJ,MAAI;AACF,iBAAa;AAAA,WACN,oBAAoB,aAAa,oBAAoB;AAC5D,iBAAa,IAAI,IAAI,OAAO,EAAE;AAAA;AAE9B,iBAAa,GAAG,MAAM;AAExB,QAAM,QAAQ,gBAAgB;AAC9B,MAAI,CAAC,OAAO;AACV,YAAQ,MAAM,8CAA8C;AAC5D;AAAA,EACF;AAEA,QAAM,QAAQ,eAAe,mBAAmB,UAAU,CAAC,UAAU,mBAAmB,KAAK,CAAC;AAC9F,QAAM,UAAU,GAAG,OAAO,SAAS,QAAQ,GAAG,KAAK;AACnD,QAAM,KAAK,OAAO;AACpB;","names":["BROWSER","BROWSER"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/cli/index.ts"],"sourcesContent":["import { Buffer } from 'node:buffer'\nimport process from 'node:process'\n\nasync function generateAuthSecret(): Promise<string> {\n const keyPair = await crypto.subtle.generateKey(\n { name: 'ECDSA', namedCurve: 'P-256' },\n true,\n ['sign', 'verify'],\n )\n\n const exported = await crypto.subtle.exportKey('pkcs8', keyPair.privateKey)\n const base64 = Buffer.from(exported).toString('base64')\n const base64url = base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n return base64url\n}\n\nasync function main() {\n const args = process.argv.slice(2)\n if (args[0] === 'secret') {\n const secret = await generateAuthSecret()\n console.log(`Add this to your .env file:\\n\\nAUTH_SECRET=${secret}`)\n }\n else {\n console.log('Usage: bunx gau secret')\n }\n}\n\nmain().catch(console.error)\n"],"mappings":";AAAA,SAAS,cAAc;AACvB,OAAO,aAAa;AAEpB,eAAe,qBAAsC;AACnD,QAAM,UAAU,MAAM,OAAO,OAAO;AAAA,IAClC,EAAE,MAAM,SAAS,YAAY,QAAQ;AAAA,IACrC;AAAA,IACA,CAAC,QAAQ,QAAQ;AAAA,EACnB;AAEA,QAAM,WAAW,MAAM,OAAO,OAAO,UAAU,SAAS,QAAQ,UAAU;AAC1E,QAAM,SAAS,OAAO,KAAK,QAAQ,EAAE,SAAS,QAAQ;AACtD,QAAM,YAAY,OAAO,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,MAAM,EAAE;AACjF,SAAO;AACT;AAEA,eAAe,OAAO;AACpB,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,MAAI,KAAK,CAAC,MAAM,UAAU;AACxB,UAAM,SAAS,MAAM,mBAAmB;
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/index.ts"],"sourcesContent":["import { Buffer } from 'node:buffer'\nimport process from 'node:process'\n\nasync function generateAuthSecret(): Promise<string> {\n const keyPair = await crypto.subtle.generateKey(\n { name: 'ECDSA', namedCurve: 'P-256' },\n true,\n ['sign', 'verify'],\n )\n\n const exported = await crypto.subtle.exportKey('pkcs8', keyPair.privateKey)\n const base64 = Buffer.from(exported).toString('base64')\n const base64url = base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n return base64url\n}\n\nasync function main() {\n const args = process.argv.slice(2)\n if (args[0] === 'secret') {\n const secret = await generateAuthSecret()\n // eslint-disable-next-line no-console\n console.log(`Add this to your .env file:\\n\\nAUTH_SECRET=${secret}`)\n }\n else {\n // eslint-disable-next-line no-console\n console.log('Usage: bunx gau secret')\n }\n}\n\nmain().catch(console.error)\n"],"mappings":";AAAA,SAAS,cAAc;AACvB,OAAO,aAAa;AAEpB,eAAe,qBAAsC;AACnD,QAAM,UAAU,MAAM,OAAO,OAAO;AAAA,IAClC,EAAE,MAAM,SAAS,YAAY,QAAQ;AAAA,IACrC;AAAA,IACA,CAAC,QAAQ,QAAQ;AAAA,EACnB;AAEA,QAAM,WAAW,MAAM,OAAO,OAAO,UAAU,SAAS,QAAQ,UAAU;AAC1E,QAAM,SAAS,OAAO,KAAK,QAAQ,EAAE,SAAS,QAAQ;AACtD,QAAM,YAAY,OAAO,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,MAAM,EAAE;AACjF,SAAO;AACT;AAEA,eAAe,OAAO;AACpB,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,MAAI,KAAK,CAAC,MAAM,UAAU;AACxB,UAAM,SAAS,MAAM,mBAAmB;AAExC,YAAQ,IAAI;AAAA;AAAA,cAA8C,MAAM,EAAE;AAAA,EACpE,OACK;AAEH,YAAQ,IAAI,wBAAwB;AAAA,EACtC;AACF;AAEA,KAAK,EAAE,MAAM,QAAQ,KAAK;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/client/solid/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAOzD,UAAU,gBAAgB,CAAC,KAAK,GAAG,OAAO;IACxC,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACjD,MAAM,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1F,WAAW,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/F,aAAa,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9D,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAID,wBAAgB,YAAY,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,EAAE,WAAW,GAAG;IAAE,IAAI,CAAC,EAAE,KAAK,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/client/solid/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAOzD,UAAU,gBAAgB,CAAC,KAAK,GAAG,OAAO;IACxC,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACjD,MAAM,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1F,WAAW,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/F,aAAa,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9D,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAID,wBAAgB,YAAY,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,EAAE,WAAW,GAAG;IAAE,IAAI,CAAC,EAAE,KAAK,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,kCAmIhJ;AAED,wBAAgB,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,KAAK,gBAAgB,CAAC,KAAK,CAAC,CAKxE"}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
// src/client/solid/index.tsx
|
|
2
|
+
import { createContext, createResource, onCleanup, onMount, untrack, useContext } from "solid-js";
|
|
3
|
+
import { isServer } from "solid-js/web";
|
|
4
|
+
|
|
5
|
+
// src/core/cookies.ts
|
|
6
|
+
import { parse, serialize } from "cookie";
|
|
7
|
+
var CSRF_MAX_AGE = 60 * 10;
|
|
8
|
+
|
|
9
|
+
// src/jwt/jwt.ts
|
|
10
|
+
import {
|
|
11
|
+
createJWTSignatureMessage,
|
|
12
|
+
encodeJWT,
|
|
13
|
+
JWSRegisteredHeaders,
|
|
14
|
+
JWTRegisteredClaims,
|
|
15
|
+
parseJWT
|
|
16
|
+
} from "@oslojs/jwt";
|
|
17
|
+
|
|
18
|
+
// src/oauth/utils.ts
|
|
19
|
+
import { generateCodeVerifier, generateState } from "arctic";
|
|
20
|
+
|
|
21
|
+
// src/core/index.ts
|
|
22
|
+
var NULL_SESSION = {
|
|
23
|
+
user: null,
|
|
24
|
+
session: null,
|
|
25
|
+
accounts: null
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// src/runtimes/tauri/index.ts
|
|
29
|
+
import { BROWSER as BROWSER2 } from "esm-env";
|
|
30
|
+
|
|
31
|
+
// src/client/token.ts
|
|
32
|
+
import { BROWSER } from "esm-env";
|
|
33
|
+
function storeSessionToken(token) {
|
|
34
|
+
if (!BROWSER)
|
|
35
|
+
return;
|
|
36
|
+
try {
|
|
37
|
+
localStorage.setItem("gau-token", token);
|
|
38
|
+
document.cookie = `__gau-session-token=${token}; path=/; max-age=31536000; samesite=lax; secure`;
|
|
39
|
+
} catch {
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function getSessionToken() {
|
|
43
|
+
if (!BROWSER)
|
|
44
|
+
return null;
|
|
45
|
+
return localStorage.getItem("gau-token");
|
|
46
|
+
}
|
|
47
|
+
function clearSessionToken() {
|
|
48
|
+
if (!BROWSER)
|
|
49
|
+
return;
|
|
50
|
+
try {
|
|
51
|
+
localStorage.removeItem("gau-token");
|
|
52
|
+
document.cookie = `__gau-session-token=; path=/; max-age=0`;
|
|
53
|
+
} catch {
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/runtimes/tauri/index.ts
|
|
58
|
+
var isTauri = BROWSER2 && "__TAURI_INTERNALS__" in window;
|
|
59
|
+
async function signInWithTauri(provider, baseUrl, scheme = "gau", redirectOverride) {
|
|
60
|
+
if (!isTauri)
|
|
61
|
+
return;
|
|
62
|
+
const { platform } = await import("@tauri-apps/plugin-os");
|
|
63
|
+
const { open } = await import("@tauri-apps/plugin-shell");
|
|
64
|
+
const currentPlatform = platform();
|
|
65
|
+
let redirectTo;
|
|
66
|
+
if (redirectOverride)
|
|
67
|
+
redirectTo = redirectOverride;
|
|
68
|
+
else if (currentPlatform === "android" || currentPlatform === "ios")
|
|
69
|
+
redirectTo = new URL(baseUrl).origin;
|
|
70
|
+
else
|
|
71
|
+
redirectTo = `${scheme}://oauth/callback`;
|
|
72
|
+
const authUrl = `${baseUrl}/${provider}?redirectTo=${encodeURIComponent(redirectTo)}`;
|
|
73
|
+
await open(authUrl);
|
|
74
|
+
}
|
|
75
|
+
async function setupTauriListener(handler) {
|
|
76
|
+
if (!isTauri)
|
|
77
|
+
return;
|
|
78
|
+
const { listen } = await import("@tauri-apps/api/event");
|
|
79
|
+
try {
|
|
80
|
+
const unlisten = await listen("deep-link", async (event) => {
|
|
81
|
+
await handler(event.payload);
|
|
82
|
+
});
|
|
83
|
+
return unlisten;
|
|
84
|
+
} catch (err) {
|
|
85
|
+
console.error(err);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function handleTauriDeepLink(url, baseUrl, scheme, onToken) {
|
|
89
|
+
const parsed = new URL(url);
|
|
90
|
+
if (parsed.protocol !== `${scheme}:` && parsed.origin !== new URL(baseUrl).origin)
|
|
91
|
+
return;
|
|
92
|
+
const params = new URLSearchParams(parsed.hash.substring(1));
|
|
93
|
+
const token = params.get("token");
|
|
94
|
+
if (token)
|
|
95
|
+
onToken(token);
|
|
96
|
+
}
|
|
97
|
+
async function linkAccountWithTauri(provider, baseUrl, scheme = "gau", redirectOverride) {
|
|
98
|
+
if (!isTauri)
|
|
99
|
+
return;
|
|
100
|
+
const { platform } = await import("@tauri-apps/plugin-os");
|
|
101
|
+
const { open } = await import("@tauri-apps/plugin-shell");
|
|
102
|
+
const currentPlatform = platform();
|
|
103
|
+
let redirectTo;
|
|
104
|
+
if (redirectOverride)
|
|
105
|
+
redirectTo = redirectOverride;
|
|
106
|
+
else if (currentPlatform === "android" || currentPlatform === "ios")
|
|
107
|
+
redirectTo = new URL(baseUrl).origin;
|
|
108
|
+
else
|
|
109
|
+
redirectTo = `${scheme}://oauth/callback`;
|
|
110
|
+
const token = getSessionToken();
|
|
111
|
+
if (!token) {
|
|
112
|
+
console.error("No session token found, cannot link account.");
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const query = `?redirectTo=${encodeURIComponent(redirectTo)}&token=${encodeURIComponent(token)}`;
|
|
116
|
+
const linkUrl = `${baseUrl}/link/${provider}${query}`;
|
|
117
|
+
await open(linkUrl);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// src/client/solid/index.tsx
|
|
121
|
+
var AuthContext = createContext();
|
|
122
|
+
function AuthProvider(props) {
|
|
123
|
+
const scheme = untrack(() => props.scheme ?? "gau");
|
|
124
|
+
const baseUrl = untrack(() => props.baseUrl ?? "/api/auth");
|
|
125
|
+
const fetchSession = async () => {
|
|
126
|
+
if (isServer)
|
|
127
|
+
return { ...NULL_SESSION, providers: [] };
|
|
128
|
+
const token = getSessionToken();
|
|
129
|
+
const headers = token ? { Authorization: `Bearer ${token}` } : void 0;
|
|
130
|
+
const res = await fetch(`${baseUrl}/session`, token ? { headers } : { credentials: "include" });
|
|
131
|
+
const contentType = res.headers.get("content-type");
|
|
132
|
+
if (contentType?.includes("application/json"))
|
|
133
|
+
return res.json();
|
|
134
|
+
return { ...NULL_SESSION, providers: [] };
|
|
135
|
+
};
|
|
136
|
+
const [session, { refetch }] = createResource(
|
|
137
|
+
fetchSession,
|
|
138
|
+
{ initialValue: { ...NULL_SESSION, providers: [] } }
|
|
139
|
+
);
|
|
140
|
+
async function signIn(provider, { redirectTo } = {}) {
|
|
141
|
+
let finalRedirectTo = redirectTo ?? props.redirectTo;
|
|
142
|
+
if (isTauri) {
|
|
143
|
+
await signInWithTauri(provider, baseUrl, scheme, finalRedirectTo);
|
|
144
|
+
} else {
|
|
145
|
+
if (!finalRedirectTo && !isServer)
|
|
146
|
+
finalRedirectTo = window.location.origin;
|
|
147
|
+
const query = finalRedirectTo ? `?redirectTo=${encodeURIComponent(finalRedirectTo)}` : "";
|
|
148
|
+
const authUrl = `${baseUrl}/${provider}${query}`;
|
|
149
|
+
window.location.href = authUrl;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async function linkAccount(provider, { redirectTo } = {}) {
|
|
153
|
+
if (isTauri) {
|
|
154
|
+
await linkAccountWithTauri(provider, baseUrl, scheme, redirectTo);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
let finalRedirectTo = redirectTo ?? props.redirectTo;
|
|
158
|
+
if (!finalRedirectTo && !isServer)
|
|
159
|
+
finalRedirectTo = window.location.href;
|
|
160
|
+
const query = finalRedirectTo ? `?redirectTo=${encodeURIComponent(finalRedirectTo)}` : "";
|
|
161
|
+
const linkUrl = `${baseUrl}/link/${provider}${query}${query ? "&" : "?"}redirect=false`;
|
|
162
|
+
const token = getSessionToken();
|
|
163
|
+
const fetchOptions = token ? { headers: { Authorization: `Bearer ${token}` } } : { credentials: "include" };
|
|
164
|
+
const res = await fetch(linkUrl, fetchOptions);
|
|
165
|
+
if (res.redirected) {
|
|
166
|
+
window.location.href = res.url;
|
|
167
|
+
} else {
|
|
168
|
+
const data = await res.json();
|
|
169
|
+
if (data.url)
|
|
170
|
+
window.location.href = data.url;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async function unlinkAccount(provider) {
|
|
174
|
+
const token = getSessionToken();
|
|
175
|
+
const fetchOptions = token ? { headers: { Authorization: `Bearer ${token}` } } : { credentials: "include" };
|
|
176
|
+
const res = await fetch(`${baseUrl}/unlink/${provider}`, {
|
|
177
|
+
method: "POST",
|
|
178
|
+
...fetchOptions
|
|
179
|
+
});
|
|
180
|
+
if (res.ok)
|
|
181
|
+
refetch();
|
|
182
|
+
else
|
|
183
|
+
console.error("Failed to unlink account", await res.json());
|
|
184
|
+
}
|
|
185
|
+
const signOut = async () => {
|
|
186
|
+
clearSessionToken();
|
|
187
|
+
const token = getSessionToken();
|
|
188
|
+
const headers = token ? { Authorization: `Bearer ${token}` } : void 0;
|
|
189
|
+
await fetch(`${baseUrl}/signout`, token ? { method: "POST", headers } : { method: "POST", credentials: "include" });
|
|
190
|
+
refetch();
|
|
191
|
+
};
|
|
192
|
+
onMount(() => {
|
|
193
|
+
if (!isTauri) {
|
|
194
|
+
const hash = new URL(window.location.href).hash.substring(1);
|
|
195
|
+
const params = new URLSearchParams(hash);
|
|
196
|
+
const tokenParam = params.get("token");
|
|
197
|
+
if (tokenParam) {
|
|
198
|
+
storeSessionToken(tokenParam);
|
|
199
|
+
refetch();
|
|
200
|
+
window.history.replaceState(null, "", window.location.pathname + window.location.search);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (!isTauri)
|
|
204
|
+
return;
|
|
205
|
+
let disposed = false;
|
|
206
|
+
setupTauriListener(async (url) => {
|
|
207
|
+
handleTauriDeepLink(url, baseUrl, scheme, (token) => {
|
|
208
|
+
storeSessionToken(token);
|
|
209
|
+
refetch();
|
|
210
|
+
});
|
|
211
|
+
}).then((unlisten) => {
|
|
212
|
+
if (disposed)
|
|
213
|
+
unlisten?.();
|
|
214
|
+
else if (unlisten)
|
|
215
|
+
onCleanup(() => unlisten());
|
|
216
|
+
});
|
|
217
|
+
onCleanup(() => {
|
|
218
|
+
disposed = true;
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
return <AuthContext.Provider value={{ session, signIn, linkAccount, unlinkAccount, signOut }}>
|
|
222
|
+
{props.children}
|
|
223
|
+
</AuthContext.Provider>;
|
|
224
|
+
}
|
|
225
|
+
function useAuth() {
|
|
226
|
+
const context = useContext(AuthContext);
|
|
227
|
+
if (!context)
|
|
228
|
+
throw new Error("useAuth must be used within an AuthProvider");
|
|
229
|
+
return context;
|
|
230
|
+
}
|
|
231
|
+
export {
|
|
232
|
+
AuthProvider,
|
|
233
|
+
useAuth
|
|
234
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.svelte.d.ts","sourceRoot":"","sources":["../../../../src/client/svelte/index.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAOzD,UAAU,gBAAgB,CAAC,KAAK,GAAG,OAAO;IACxC,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAA;IACvC,MAAM,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1F,WAAW,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/F,aAAa,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9D,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAID,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,EAAE,EACtD,OAAqB,EACrB,MAAc,EACd,UAAU,EAAE,iBAAiB,EAC9B,GAAE;IACD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;CACf,
|
|
1
|
+
{"version":3,"file":"index.svelte.d.ts","sourceRoot":"","sources":["../../../../src/client/svelte/index.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAOzD,UAAU,gBAAgB,CAAC,KAAK,GAAG,OAAO;IACxC,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAA;IACvC,MAAM,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1F,WAAW,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/F,aAAa,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9D,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAID,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,EAAE,EACtD,OAAqB,EACrB,MAAc,EACd,UAAU,EAAE,iBAAiB,EAC9B,GAAE;IACD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;CACf,QAgKL;AAED,wBAAgB,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,KAAK,gBAAgB,CAAC,KAAK,CAAC,CAMxE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BROWSER as
|
|
1
|
+
import{BROWSER as t}from"esm-env";import{getContext as o,setContext as n}from"svelte";import{parse as e,serialize as i}from"cookie";import{createJWTSignatureMessage as a,encodeJWT as r,JWSRegisteredHeaders as c,JWTRegisteredClaims as s,parseJWT as u}from"@oslojs/jwt";import{generateCodeVerifier as l,generateState as d}from"arctic";var p={user:null,session:null,accounts:null};import{BROWSER as w}from"esm-env";import{BROWSER as f}from"esm-env";function h(t){if(f)try{localStorage.setItem("gau-token",t),document.cookie=`__gau-session-token=${t}; path=/; max-age=31536000; samesite=lax; secure`}catch{}}function m(){return f?localStorage.getItem("gau-token"):null}var g=w&&"__TAURI_INTERNALS__"in window;var k=Symbol("gau-auth");function y({baseUrl:o="/api/auth",scheme:e="gau",redirectTo:i}={}){let a=$state({...p,providers:[]});async function r(){if(!t)return void(a={...p,providers:[]});const n=m(),e=n?{Authorization:`Bearer ${n}`}:void 0,i=await fetch(`${o}/session`,n?{headers:e}:{credentials:"include"}),r=i.headers.get("content-type");a=r?.includes("application/json")?await i.json():{...p,providers:[]}}if(t){const t=new URL(window.location.href).hash.substring(1),o=new URLSearchParams(t).get("token");o?(h(o),(async()=>{try{const{replaceState:t}=await import("$app/navigation");await t(window.location.pathname+window.location.search,{})}catch{window.history.replaceState(null,"",window.location.pathname+window.location.search)}await r()})()):r()}$effect(()=>{if(!t||!g)return;let n,i=!1;return async function(t){if(!g)return;const{listen:o}=await import("@tauri-apps/api/event");try{return await o("deep-link",async o=>{await t(o.payload)})}catch(t){console.error(t)}}(async t=>{!function(t,o,n,e){const i=new URL(t);if(i.protocol!==`${n}:`&&i.origin!==new URL(o).origin)return;const a=new URLSearchParams(i.hash.substring(1)).get("token");a&&e(a)}(t,o,e,async t=>{h(t),await r()})}).then(t=>{i?t?.():n=t}),()=>{i=!0,n?.()}});const c={get session(){return a},signIn:async function(n,{redirectTo:a}={}){let r=a??i;if(g)await async function(t,o,n="gau",e){if(!g)return;const{platform:i}=await import("@tauri-apps/plugin-os"),{open:a}=await import("@tauri-apps/plugin-shell"),r=i();let c;c=e||("android"===r||"ios"===r?new URL(o).origin:`${n}://oauth/callback`);const s=`${o}/${t}?redirectTo=${encodeURIComponent(c)}`;await a(s)}(n,o,e,r);else{!r&&t&&(r=window.location.origin);const e=r?`?redirectTo=${encodeURIComponent(r)}`:"";window.location.href=`${o}/${n}${e}`}},linkAccount:async function(n,{redirectTo:a}={}){if(g)return void await async function(t,o,n="gau",e){if(!g)return;const{platform:i}=await import("@tauri-apps/plugin-os"),{open:a}=await import("@tauri-apps/plugin-shell"),r=i();let c;c=e||("android"===r||"ios"===r?new URL(o).origin:`${n}://oauth/callback`);const s=m();if(!s)return void console.error("No session token found, cannot link account.");const u=`${o}/link/${t}?redirectTo=${encodeURIComponent(c)}&token=${encodeURIComponent(s)}`;await a(u)}(n,o,e,a);let r=a??i;!r&&t&&(r=window.location.href);const c=r?`?redirectTo=${encodeURIComponent(r)}`:"",s=`${o}/link/${n}${c}${c?"&":"?"}redirect=false`,u=m(),l=u?{headers:{Authorization:`Bearer ${u}`}}:{credentials:"include"},d=await fetch(s,l);if(d.redirected)window.location.href=d.url;else try{const t=await d.json();t.url&&(window.location.href=t.url)}catch(t){console.error("Failed to parse response from link endpoint",t)}},unlinkAccount:async function(t){const n=m(),e=n?{headers:{Authorization:`Bearer ${n}`}}:{credentials:"include"},i=await fetch(`${o}/unlink/${t}`,{method:"POST",...e});i.ok?await r():console.error("Failed to unlink account",await i.json())},signOut:async function(){!function(){if(f)try{localStorage.removeItem("gau-token"),document.cookie="__gau-session-token=; path=/; max-age=0"}catch{}}();const t=m(),n=t?{Authorization:`Bearer ${t}`}:void 0;await fetch(`${o}/signout`,t?{method:"POST",headers:n}:{method:"POST",credentials:"include"}),await r()}};n(k,c)}function v(){const t=o(k);if(!t)throw new Error("useAuth must be used within an AuthProvider");return t}export{y as createSvelteAuth,v as useAuth};//# sourceMappingURL=index.svelte.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/client/svelte/index.svelte.ts","../../../../src/core/cookies.ts","../../../../src/jwt/jwt.ts","../../../../src/oauth/utils.ts","../../../../src/core/index.ts","../../../../src/runtimes/tauri/index.ts","../../../../src/client/token.ts"],"sourcesContent":["import type { GauSession, ProviderIds } from '../../core'\nimport { BROWSER } from 'esm-env'\nimport { getContext, setContext } from 'svelte'\nimport { NULL_SESSION } from '../../core'\nimport { handleTauriDeepLink, isTauri, linkAccountWithTauri, setupTauriListener, signInWithTauri } from '../../runtimes/tauri'\nimport { clearSessionToken, getSessionToken, storeSessionToken } from '../token'\n\ninterface AuthContextValue<TAuth = unknown> {\n session: GauSession<ProviderIds<TAuth>>\n signIn: (provider: ProviderIds<TAuth>, options?: { redirectTo?: string }) => Promise<void>\n linkAccount: (provider: ProviderIds<TAuth>, options?: { redirectTo?: string }) => Promise<void>\n unlinkAccount: (provider: ProviderIds<TAuth>) => Promise<void>\n signOut: () => Promise<void>\n}\n\nconst AUTH_CONTEXT_KEY = Symbol('gau-auth')\n\nexport function createSvelteAuth<const TAuth = unknown>({\n baseUrl = '/api/auth',\n scheme = 'gau',\n redirectTo: defaultRedirectTo,\n}: {\n baseUrl?: string\n scheme?: string\n redirectTo?: string\n} = {}) {\n type CurrentSession = GauSession<ProviderIds<TAuth>>\n let session = $state<CurrentSession>({ ...NULL_SESSION, providers: [] })\n\n async function fetchSession() {\n if (!BROWSER) {\n session = { ...NULL_SESSION, providers: [] }\n return\n }\n\n const token = getSessionToken()\n const headers = token ? { Authorization: `Bearer ${token}` } : undefined\n const res = await fetch(`${baseUrl}/session`, token ? { headers } : { credentials: 'include' })\n\n const contentType = res.headers.get('content-type')\n if (contentType?.includes('application/json')) {\n session = await res.json()\n }\n else {\n session = {\n ...NULL_SESSION,\n providers: [] as ProviderIds<TAuth>[],\n }\n }\n }\n\n async function signIn(provider: ProviderIds<TAuth>, { redirectTo }: { redirectTo?: string } = {}) {\n let finalRedirectTo = redirectTo ?? defaultRedirectTo\n if (isTauri) {\n await signInWithTauri(provider as string, baseUrl, scheme, finalRedirectTo)\n }\n else {\n if (!finalRedirectTo && BROWSER)\n finalRedirectTo = window.location.origin\n\n const query = finalRedirectTo ? `?redirectTo=${encodeURIComponent(finalRedirectTo)}` : ''\n window.location.href = `${baseUrl}/${provider as string}${query}`\n }\n }\n\n async function linkAccount(provider: ProviderIds<TAuth>, { redirectTo }: { redirectTo?: string } = {}) {\n if (isTauri) {\n await linkAccountWithTauri(provider as string, baseUrl, scheme, redirectTo)\n return\n }\n\n let finalRedirectTo = redirectTo ?? defaultRedirectTo\n if (!finalRedirectTo && BROWSER)\n finalRedirectTo = window.location.href\n\n const query = finalRedirectTo ? `?redirectTo=${encodeURIComponent(finalRedirectTo)}` : ''\n const linkUrl = `${baseUrl}/link/${provider as string}${query}${query ? '&' : '?'}redirect=false`\n\n const token = getSessionToken()\n\n const fetchOptions: RequestInit = token\n ? { headers: { Authorization: `Bearer ${token}` } }\n : { credentials: 'include' }\n\n const res = await fetch(linkUrl, fetchOptions)\n if (res.redirected) {\n window.location.href = res.url\n }\n else {\n try {\n const data = await res.json()\n if (data.url)\n window.location.href = data.url\n }\n catch (e) {\n console.error('Failed to parse response from link endpoint', e)\n }\n }\n }\n\n async function unlinkAccount(provider: ProviderIds<TAuth>) {\n const token = getSessionToken()\n const fetchOptions: RequestInit = token\n ? { headers: { Authorization: `Bearer ${token}` } }\n : { credentials: 'include' }\n\n const res = await fetch(`${baseUrl}/unlink/${provider as string}`, {\n method: 'POST',\n ...fetchOptions,\n })\n\n if (res.ok)\n await fetchSession()\n else\n console.error('Failed to unlink account', await res.json())\n }\n\n async function signOut() {\n clearSessionToken()\n const token = getSessionToken()\n const headers = token ? { Authorization: `Bearer ${token}` } : undefined\n await fetch(`${baseUrl}/signout`, token ? { method: 'POST', headers } : { method: 'POST', credentials: 'include' })\n await fetchSession()\n }\n\n if (BROWSER) {\n const hash = new URL(window.location.href).hash.substring(1)\n const params = new URLSearchParams(hash)\n const tokenFromUrl = params.get('token')\n\n if (tokenFromUrl) {\n storeSessionToken(tokenFromUrl)\n void (async () => {\n try {\n // @ts-expect-error - SvelteKit-only\n const { replaceState } = await import('$app/navigation')\n await replaceState(window.location.pathname + window.location.search, {})\n }\n catch {\n window.history.replaceState(null, '', window.location.pathname + window.location.search)\n }\n await fetchSession()\n })()\n }\n else {\n fetchSession()\n }\n\n if (isTauri) {\n setupTauriListener(async (url) => {\n handleTauriDeepLink(url, baseUrl, scheme, async (token) => {\n storeSessionToken(token)\n await fetchSession()\n })\n })\n }\n }\n\n const contextValue: AuthContextValue<TAuth> = {\n get session() {\n return session\n },\n signIn: signIn as (provider: ProviderIds<TAuth>, options?: { redirectTo?: string }) => Promise<void>,\n linkAccount: linkAccount as (provider: ProviderIds<TAuth>, options?: { redirectTo?: string }) => Promise<void>,\n unlinkAccount: unlinkAccount as (provider: ProviderIds<TAuth>) => Promise<void>,\n signOut,\n }\n\n setContext(AUTH_CONTEXT_KEY, contextValue)\n}\n\nexport function useAuth<const TAuth = unknown>(): AuthContextValue<TAuth> {\n const context = getContext<AuthContextValue<TAuth>>(AUTH_CONTEXT_KEY)\n if (!context)\n throw new Error('useAuth must be used within an AuthProvider')\n\n return context\n}\n","import type { SerializeOptions } from 'cookie'\nimport { parse, serialize } from 'cookie'\n\nexport const DEFAULT_COOKIE_SERIALIZE_OPTIONS: SerializeOptions = {\n path: '/',\n sameSite: 'lax',\n secure: true,\n httpOnly: true,\n}\n\nexport type Cookie = [string, string, SerializeOptions]\n\nexport function parseCookies(cookieHeader: string | null | undefined): Map<string, string> {\n const cookies = new Map<string, string>()\n if (cookieHeader) {\n const parsed = parse(cookieHeader)\n for (const name in parsed)\n cookies.set(name, parsed[name]!)\n }\n return cookies\n}\n\nexport class Cookies {\n #new: Cookie[] = []\n\n constructor(\n private readonly requestCookies: Map<string, string>,\n private readonly defaultOptions: SerializeOptions,\n ) {}\n\n get(name: string): string | undefined {\n return this.requestCookies.get(name)\n }\n\n set(name: string, value: string, options?: SerializeOptions): void {\n const combinedOptions = { ...this.defaultOptions, ...options }\n this.#new.push([name, value, combinedOptions])\n }\n\n delete(name: string, options?: Omit<SerializeOptions, 'expires' | 'maxAge'>): void {\n this.set(name, '', { ...options, expires: new Date(0), maxAge: 0 })\n }\n\n toHeaders(): Headers {\n const headers = new Headers()\n for (const [name, value, options] of this.#new)\n headers.append('Set-Cookie', serialize(name, value, options))\n\n return headers\n }\n}\n\nexport const CSRF_COOKIE_NAME = '__gau-csrf-token'\nexport const SESSION_COOKIE_NAME = '__gau-session-token'\nexport const SESSION_STRATEGY_COOKIE_NAME = '__gau-session-strategy'\nexport const LINKING_TOKEN_COOKIE_NAME = '__gau-linking-token'\nexport const PKCE_COOKIE_NAME = '__gau-pkce-code-verifier'\nexport const CALLBACK_URI_COOKIE_NAME = '__gau-callback-uri'\n\nexport const CSRF_MAX_AGE = 60 * 10 // 10 minutes\n","/// <reference types=\"node\" />\nimport {\n createJWTSignatureMessage,\n encodeJWT,\n JWSRegisteredHeaders,\n JWTRegisteredClaims,\n parseJWT,\n} from '@oslojs/jwt'\nimport { AuthError } from '../core/index'\nimport { constantTimeEqual, deriveKeysFromSecret, rawToDer } from './utils'\n\nexport type SupportedAlgorithm = 'ES256' | 'HS256'\n\ninterface CommonSignOptions {\n /** Time-to-live in seconds (exp claim). If omitted the token will not expire. */\n ttl?: number\n}\n\nexport type SignOptions\n = | ({ algorithm?: 'ES256', privateKey?: CryptoKey, secret?: string }\n & CommonSignOptions & { iss?: string, aud?: string | string[], sub?: string })\n | ({ algorithm: 'HS256', secret?: string | Uint8Array, privateKey?: never }\n & CommonSignOptions & { iss?: string, aud?: string | string[], sub?: string })\n\n/**\n * Create a signed JWT.\n * Defaults to ES256 when a privateKey is supplied. Falls back to HS256 when a secret is supplied.\n */\nexport async function sign<T extends Record<string, unknown>>(payload: T, options: SignOptions = {}): Promise<string> {\n let { algorithm = 'ES256', ttl, iss, aud, sub, privateKey, secret } = options\n\n if (algorithm === 'ES256') {\n if (!privateKey) {\n if (typeof secret !== 'string')\n throw new AuthError('Missing secret for ES256 signing. It must be a base64url-encoded string.');\n\n ({ privateKey } = await deriveKeysFromSecret(secret))\n }\n }\n else if (algorithm === 'HS256' && !secret) {\n throw new AuthError('Missing secret for HS256 signing')\n }\n\n const now = Math.floor(Date.now() / 1000)\n\n const jwtPayload: Record<string, unknown> = { iat: now, iss, aud, sub, ...payload }\n\n if (ttl != null && ttl > 0)\n jwtPayload.exp = now + ttl\n\n const isHS256 = algorithm === 'HS256'\n const alg: SupportedAlgorithm = isHS256 ? 'HS256' : 'ES256'\n\n const headerJSON = JSON.stringify({ alg, typ: 'JWT' })\n const payloadJSON = JSON.stringify(jwtPayload)\n\n const signatureMessage = createJWTSignatureMessage(headerJSON, payloadJSON)\n\n let signature: Uint8Array\n\n if (isHS256) {\n // HS256 (HMAC-SHA256)\n const secretBytes = typeof secret === 'string'\n ? new TextEncoder().encode(secret)\n : secret\n\n const cryptoKey = await crypto.subtle.importKey(\n 'raw',\n secretBytes as BufferSource,\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n )\n\n signature = new Uint8Array(await crypto.subtle.sign('HMAC', cryptoKey, signatureMessage as BufferSource))\n }\n else {\n // ES256 (ECDSA-SHA256)\n // Runtimes like Bun's return the raw (r||s) signature directly, not DER-encoded.\n signature = new Uint8Array(\n await crypto.subtle.sign(\n { name: 'ECDSA', hash: 'SHA-256' },\n privateKey!,\n signatureMessage as BufferSource,\n ),\n )\n }\n\n return encodeJWT(headerJSON, payloadJSON, signature)\n}\n\nexport type VerifyOptions\n = | { algorithm?: 'ES256', publicKey?: CryptoKey, secret?: string, iss?: string, aud?: string | string[] }\n | { algorithm: 'HS256', secret?: string | Uint8Array, publicKey?: never, iss?: string, aud?: string | string[] }\n\n/**\n * Verify a JWT and return its payload when the signature is valid.\n * The algorithm is inferred from options – ES256 by default.\n * Throws when verification fails or the token is expired.\n */\nexport async function verify<T = Record<string, unknown>>(token: string, options: VerifyOptions): Promise<T> {\n let { algorithm = 'ES256', publicKey, secret, iss, aud } = options\n\n if (algorithm === 'ES256') {\n if (!publicKey) {\n if (typeof secret !== 'string')\n throw new AuthError('Missing secret for ES256 verification. Must be a base64url-encoded string.');\n\n ({ publicKey } = await deriveKeysFromSecret(secret))\n }\n }\n\n if (algorithm === 'HS256' && !secret)\n throw new AuthError('Missing secret for HS256 verification')\n\n const [header, payload, signature, signatureMessage] = parseJWT(token)\n\n const headerParams = new JWSRegisteredHeaders(header)\n const headerAlg = headerParams.algorithm()\n\n let validSignature = false\n\n // HS256 verification path\n if (algorithm === 'HS256') {\n if (headerAlg !== 'HS256')\n throw new Error(`JWT algorithm is \"${headerAlg}\", but verifier was configured for \"HS256\"`)\n\n const secretBytes = typeof secret === 'string'\n ? new TextEncoder().encode(secret)\n : secret\n\n const cryptoKey = await crypto.subtle.importKey(\n 'raw',\n secretBytes as BufferSource,\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n )\n\n const expectedSig = new Uint8Array(await crypto.subtle.sign('HMAC', cryptoKey, signatureMessage as BufferSource))\n validSignature = constantTimeEqual(expectedSig, new Uint8Array(signature))\n }\n // ES256 verification path (default)\n else {\n if (headerAlg !== 'ES256')\n throw new AuthError(`JWT algorithm is \"${headerAlg}\", but verifier was configured for \"ES256\"`)\n\n const signatureBytes = new Uint8Array(signature)\n\n // Runtimes like Node.js return DER-encoded signatures. Others (Bun) return raw (r||s).\n // We try DER first, as it's more common in Node environments.\n validSignature = await crypto.subtle.verify(\n { name: 'ECDSA', hash: 'SHA-256' },\n publicKey!,\n signatureBytes as BufferSource,\n signatureMessage as BufferSource,\n )\n\n if (!validSignature && signatureBytes.length === 64) {\n // If DER verification fails and the signature is 64 bytes, it might be a raw signature.\n // Convert it to DER and try again.\n try {\n const derSig = rawToDer(signatureBytes)\n validSignature = await crypto.subtle.verify(\n { name: 'ECDSA', hash: 'SHA-256' },\n publicKey!,\n derSig as BufferSource,\n signatureMessage as BufferSource,\n )\n }\n catch {\n // rawToDer can throw if the signature is not 64 bytes, but we already checked.\n // This catch is for other unexpected errors.\n validSignature = false\n }\n }\n }\n\n if (!validSignature)\n throw new AuthError('Invalid JWT signature')\n\n const claims = new JWTRegisteredClaims(payload)\n if (claims.hasExpiration() && !claims.verifyExpiration())\n throw new AuthError('JWT expired')\n if (claims.hasNotBefore() && !claims.verifyNotBefore())\n throw new AuthError('JWT not yet valid')\n if (iss && (payload as any).iss !== iss)\n throw new AuthError('Invalid JWT issuer')\n\n if (aud) {\n const expectedAudience = Array.isArray(aud) ? aud : [aud]\n const tokenAudience = (payload as any).aud\n ? (Array.isArray((payload as any).aud) ? (payload as any).aud : [(payload as any).aud])\n : []\n\n if (!expectedAudience.some(audValue => tokenAudience.includes(audValue)))\n throw new AuthError('Invalid JWT audience')\n }\n\n return payload as T\n}\n","import { generateCodeVerifier, generateState } from 'arctic'\n\nexport function createOAuthUris() {\n const state = generateState()\n const codeVerifier = generateCodeVerifier()\n\n return {\n state,\n codeVerifier,\n }\n}\n","export interface RequestLike {\n /** Absolute or relative URL */\n readonly url: string\n /** Upper-case HTTP method (e.g. `GET`) */\n readonly method: string\n /** All HTTP headers – mutable so adapters can append */\n readonly headers: Headers\n /** Lazily parse the body as JSON */\n json: <T = unknown>() => Promise<T>\n /** Raw text body */\n text: () => Promise<string>\n /** FormData helper (for `application/x-www-form-urlencoded` or `multipart/form-data`) */\n formData: () => Promise<FormData>\n}\n\nexport interface ResponseLike {\n readonly status: number\n readonly headers: Headers\n readonly body?: BodyInit | null\n json: <T = unknown>() => Promise<T>\n text: () => Promise<string>\n}\n\nexport interface User {\n id: string\n name?: string | null\n email?: string | null\n emailVerified?: boolean | null\n image?: string | null\n}\n\nexport interface Session {\n id: string\n sub: string\n [key: string]: unknown\n}\n\nexport interface GauSession<TProviders extends string = string> {\n user: User | null\n session: Session | null\n accounts?: Account[] | null\n providers?: TProviders[]\n}\n\nexport const NULL_SESSION = {\n user: null,\n session: null,\n accounts: null,\n} as const\n\nexport interface NewUser extends Omit<User, 'id' | 'accounts'> {\n id?: string\n}\n\nexport interface Account {\n userId: string\n provider: string\n providerAccountId: string\n type?: string // e.g. \"oauth\"\n accessToken?: string | null\n refreshToken?: string | null\n expiresAt?: number | null // epoch seconds\n idToken?: string | null\n scope?: string | null\n tokenType?: string | null\n sessionState?: string | null\n}\n\nexport interface NewAccount extends Account {}\n\nexport interface Adapter {\n getUser: (id: string) => Promise<User | null>\n getUserByEmail: (email: string) => Promise<User | null>\n getUserByAccount: (provider: string, providerAccountId: string) => Promise<User | null>\n getAccounts: (userId: string) => Promise<Account[]>\n getUserAndAccounts: (userId: string) => Promise<{ user: User, accounts: Account[] } | null>\n createUser: (data: NewUser) => Promise<User>\n linkAccount: (data: NewAccount) => Promise<void>\n unlinkAccount: (provider: string, providerAccountId: string) => Promise<void>\n updateUser: (data: Partial<User> & { id: string }) => Promise<User>\n deleteUser: (id: string) => Promise<void>\n}\n\nexport class AuthError extends Error {\n override readonly cause?: unknown\n constructor(message: string, cause?: unknown) {\n super(message)\n this.name = 'AuthError'\n this.cause = cause\n }\n}\n\nexport function json<T>(data: T, init: ResponseInit = {}): Response {\n const headers = new Headers(init.headers)\n if (!headers.has('Content-Type'))\n headers.set('Content-Type', 'application/json; charset=utf-8')\n return new Response(JSON.stringify(data), { ...init, headers })\n}\n\nexport function redirect(url: string, status: 302 | 303 = 302): Response {\n return new Response(null, {\n status,\n headers: {\n Location: url,\n },\n })\n}\n\nexport * from './cookies'\nexport * from './createAuth'\nexport * from './handler'\n","import { listen } from '@tauri-apps/api/event'\nimport { BROWSER } from 'esm-env'\nimport { getSessionToken } from '../../client/token'\n\nexport const isTauri = BROWSER && '__TAURI_INTERNALS__' in window\n\nexport async function signInWithTauri(\n provider: string,\n baseUrl: string,\n scheme: string = 'gau',\n redirectOverride?: string,\n) {\n if (!isTauri)\n return\n\n const { platform } = await import('@tauri-apps/plugin-os')\n const { open } = await import('@tauri-apps/plugin-shell')\n\n const currentPlatform = platform() // platform is NO LONGER an async function\n let redirectTo: string\n\n if (redirectOverride)\n redirectTo = redirectOverride\n else if (currentPlatform === 'android' || currentPlatform === 'ios')\n redirectTo = new URL(baseUrl).origin\n else\n redirectTo = `${scheme}://oauth/callback`\n\n const authUrl = `${baseUrl}/${provider}?redirectTo=${encodeURIComponent(redirectTo)}`\n await open(authUrl)\n}\n\nexport function setupTauriListener(handler: (url: string) => Promise<void>) {\n if (!isTauri)\n return\n\n listen<string>('deep-link', async (event) => {\n await handler(event.payload)\n }).catch(console.error)\n}\n\nexport function handleTauriDeepLink(url: string, baseUrl: string, scheme: string, onToken: (token: string) => void) {\n const parsed = new URL(url)\n if (parsed.protocol !== `${scheme}:` && parsed.origin !== new URL(baseUrl).origin)\n return\n\n const params = new URLSearchParams(parsed.hash.substring(1))\n const token = params.get('token')\n if (token)\n onToken(token)\n}\n\nexport async function linkAccountWithTauri(\n provider: string,\n baseUrl: string,\n scheme: string = 'gau',\n redirectOverride?: string,\n) {\n if (!isTauri)\n return\n\n const { platform } = await import('@tauri-apps/plugin-os')\n const { open } = await import('@tauri-apps/plugin-shell')\n\n const currentPlatform = platform()\n let redirectTo: string\n\n if (redirectOverride)\n redirectTo = redirectOverride\n else if (currentPlatform === 'android' || currentPlatform === 'ios')\n redirectTo = new URL(baseUrl).origin\n else\n redirectTo = `${scheme}://oauth/callback`\n\n const token = getSessionToken()\n if (!token) {\n console.error('No session token found, cannot link account.')\n return\n }\n\n const query = `?redirectTo=${encodeURIComponent(redirectTo)}&token=${encodeURIComponent(token)}`\n const linkUrl = `${baseUrl}/link/${provider}${query}`\n await open(linkUrl)\n}\n","import { BROWSER } from 'esm-env'\n\nexport function storeSessionToken(token: string) {\n if (!BROWSER)\n return\n try {\n localStorage.setItem('gau-token', token)\n document.cookie = `__gau-session-token=${token}; path=/; max-age=31536000; samesite=lax; secure`\n }\n catch {}\n}\n\nexport function getSessionToken(): string | null {\n if (!BROWSER)\n return null\n return localStorage.getItem('gau-token')\n}\n\nexport function clearSessionToken() {\n if (!BROWSER)\n return\n try {\n localStorage.removeItem('gau-token')\n document.cookie = `__gau-session-token=; path=/; max-age=0`\n }\n catch {}\n}\n"],"mappings":"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","names":["BROWSER","BROWSER","BROWSER","BROWSER"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/client/svelte/index.svelte.ts","../../../../src/core/cookies.ts","../../../../src/jwt/jwt.ts","../../../../src/oauth/utils.ts","../../../../src/core/index.ts","../../../../src/runtimes/tauri/index.ts","../../../../src/client/token.ts"],"sourcesContent":["import type { GauSession, ProviderIds } from '../../core'\nimport { BROWSER } from 'esm-env'\nimport { getContext, setContext } from 'svelte'\nimport { NULL_SESSION } from '../../core'\nimport { handleTauriDeepLink, isTauri, linkAccountWithTauri, setupTauriListener, signInWithTauri } from '../../runtimes/tauri'\nimport { clearSessionToken, getSessionToken, storeSessionToken } from '../token'\n\ninterface AuthContextValue<TAuth = unknown> {\n session: GauSession<ProviderIds<TAuth>>\n signIn: (provider: ProviderIds<TAuth>, options?: { redirectTo?: string }) => Promise<void>\n linkAccount: (provider: ProviderIds<TAuth>, options?: { redirectTo?: string }) => Promise<void>\n unlinkAccount: (provider: ProviderIds<TAuth>) => Promise<void>\n signOut: () => Promise<void>\n}\n\nconst AUTH_CONTEXT_KEY = Symbol('gau-auth')\n\nexport function createSvelteAuth<const TAuth = unknown>({\n baseUrl = '/api/auth',\n scheme = 'gau',\n redirectTo: defaultRedirectTo,\n}: {\n baseUrl?: string\n scheme?: string\n redirectTo?: string\n} = {}) {\n type CurrentSession = GauSession<ProviderIds<TAuth>>\n let session = $state<CurrentSession>({ ...NULL_SESSION, providers: [] })\n\n async function fetchSession() {\n if (!BROWSER) {\n session = { ...NULL_SESSION, providers: [] }\n return\n }\n\n const token = getSessionToken()\n const headers = token ? { Authorization: `Bearer ${token}` } : undefined\n const res = await fetch(`${baseUrl}/session`, token ? { headers } : { credentials: 'include' })\n\n const contentType = res.headers.get('content-type')\n if (contentType?.includes('application/json')) {\n session = await res.json()\n }\n else {\n session = {\n ...NULL_SESSION,\n providers: [] as ProviderIds<TAuth>[],\n }\n }\n }\n\n async function signIn(provider: ProviderIds<TAuth>, { redirectTo }: { redirectTo?: string } = {}) {\n let finalRedirectTo = redirectTo ?? defaultRedirectTo\n if (isTauri) {\n await signInWithTauri(provider as string, baseUrl, scheme, finalRedirectTo)\n }\n else {\n if (!finalRedirectTo && BROWSER)\n finalRedirectTo = window.location.origin\n\n const query = finalRedirectTo ? `?redirectTo=${encodeURIComponent(finalRedirectTo)}` : ''\n window.location.href = `${baseUrl}/${provider as string}${query}`\n }\n }\n\n async function linkAccount(provider: ProviderIds<TAuth>, { redirectTo }: { redirectTo?: string } = {}) {\n if (isTauri) {\n await linkAccountWithTauri(provider as string, baseUrl, scheme, redirectTo)\n return\n }\n\n let finalRedirectTo = redirectTo ?? defaultRedirectTo\n if (!finalRedirectTo && BROWSER)\n finalRedirectTo = window.location.href\n\n const query = finalRedirectTo ? `?redirectTo=${encodeURIComponent(finalRedirectTo)}` : ''\n const linkUrl = `${baseUrl}/link/${provider as string}${query}${query ? '&' : '?'}redirect=false`\n\n const token = getSessionToken()\n\n const fetchOptions: RequestInit = token\n ? { headers: { Authorization: `Bearer ${token}` } }\n : { credentials: 'include' }\n\n const res = await fetch(linkUrl, fetchOptions)\n if (res.redirected) {\n window.location.href = res.url\n }\n else {\n try {\n const data = await res.json()\n if (data.url)\n window.location.href = data.url\n }\n catch (e) {\n console.error('Failed to parse response from link endpoint', e)\n }\n }\n }\n\n async function unlinkAccount(provider: ProviderIds<TAuth>) {\n const token = getSessionToken()\n const fetchOptions: RequestInit = token\n ? { headers: { Authorization: `Bearer ${token}` } }\n : { credentials: 'include' }\n\n const res = await fetch(`${baseUrl}/unlink/${provider as string}`, {\n method: 'POST',\n ...fetchOptions,\n })\n\n if (res.ok)\n await fetchSession()\n else\n console.error('Failed to unlink account', await res.json())\n }\n\n async function signOut() {\n clearSessionToken()\n const token = getSessionToken()\n const headers = token ? { Authorization: `Bearer ${token}` } : undefined\n await fetch(`${baseUrl}/signout`, token ? { method: 'POST', headers } : { method: 'POST', credentials: 'include' })\n await fetchSession()\n }\n\n if (BROWSER) {\n const hash = new URL(window.location.href).hash.substring(1)\n const params = new URLSearchParams(hash)\n const tokenFromUrl = params.get('token')\n\n if (tokenFromUrl) {\n storeSessionToken(tokenFromUrl)\n void (async () => {\n try {\n // @ts-expect-error - SvelteKit-only\n const { replaceState } = await import('$app/navigation')\n await replaceState(window.location.pathname + window.location.search, {})\n }\n catch {\n window.history.replaceState(null, '', window.location.pathname + window.location.search)\n }\n await fetchSession()\n })()\n }\n else {\n fetchSession()\n }\n }\n\n $effect(() => {\n if (!BROWSER || !isTauri)\n return\n\n let cleanup: (() => void) | void\n let disposed = false\n\n setupTauriListener(async (url) => {\n handleTauriDeepLink(url, baseUrl, scheme, async (token) => {\n storeSessionToken(token)\n await fetchSession()\n })\n }).then((unlisten) => {\n if (disposed)\n unlisten?.()\n else\n cleanup = unlisten\n })\n\n return () => {\n disposed = true\n cleanup?.()\n }\n })\n\n const contextValue: AuthContextValue<TAuth> = {\n get session() {\n return session\n },\n signIn: signIn as (provider: ProviderIds<TAuth>, options?: { redirectTo?: string }) => Promise<void>,\n linkAccount: linkAccount as (provider: ProviderIds<TAuth>, options?: { redirectTo?: string }) => Promise<void>,\n unlinkAccount: unlinkAccount as (provider: ProviderIds<TAuth>) => Promise<void>,\n signOut,\n }\n\n setContext(AUTH_CONTEXT_KEY, contextValue)\n}\n\nexport function useAuth<const TAuth = unknown>(): AuthContextValue<TAuth> {\n const context = getContext<AuthContextValue<TAuth>>(AUTH_CONTEXT_KEY)\n if (!context)\n throw new Error('useAuth must be used within an AuthProvider')\n\n return context\n}\n","import type { SerializeOptions } from 'cookie'\nimport { parse, serialize } from 'cookie'\n\nexport const DEFAULT_COOKIE_SERIALIZE_OPTIONS: SerializeOptions = {\n path: '/',\n sameSite: 'lax',\n secure: true,\n httpOnly: true,\n}\n\nexport type Cookie = [string, string, SerializeOptions]\n\nexport function parseCookies(cookieHeader: string | null | undefined): Map<string, string> {\n const cookies = new Map<string, string>()\n if (cookieHeader) {\n const parsed = parse(cookieHeader)\n for (const name in parsed)\n cookies.set(name, parsed[name]!)\n }\n return cookies\n}\n\nexport class Cookies {\n #new: Cookie[] = []\n\n constructor(\n private readonly requestCookies: Map<string, string>,\n private readonly defaultOptions: SerializeOptions,\n ) {}\n\n get(name: string): string | undefined {\n return this.requestCookies.get(name)\n }\n\n set(name: string, value: string, options?: SerializeOptions): void {\n const combinedOptions = { ...this.defaultOptions, ...options }\n this.#new.push([name, value, combinedOptions])\n }\n\n delete(name: string, options?: Omit<SerializeOptions, 'expires' | 'maxAge'>): void {\n this.set(name, '', { ...options, expires: new Date(0), maxAge: 0 })\n }\n\n toHeaders(): Headers {\n const headers = new Headers()\n for (const [name, value, options] of this.#new)\n headers.append('Set-Cookie', serialize(name, value, options))\n\n return headers\n }\n}\n\nexport const CSRF_COOKIE_NAME = '__gau-csrf-token'\nexport const SESSION_COOKIE_NAME = '__gau-session-token'\nexport const SESSION_STRATEGY_COOKIE_NAME = '__gau-session-strategy'\nexport const LINKING_TOKEN_COOKIE_NAME = '__gau-linking-token'\nexport const PKCE_COOKIE_NAME = '__gau-pkce-code-verifier'\nexport const CALLBACK_URI_COOKIE_NAME = '__gau-callback-uri'\n\nexport const CSRF_MAX_AGE = 60 * 10 // 10 minutes\n","/// <reference types=\"node\" />\nimport {\n createJWTSignatureMessage,\n encodeJWT,\n JWSRegisteredHeaders,\n JWTRegisteredClaims,\n parseJWT,\n} from '@oslojs/jwt'\nimport { AuthError } from '../core/index'\nimport { constantTimeEqual, deriveKeysFromSecret, rawToDer } from './utils'\n\nexport type SupportedAlgorithm = 'ES256' | 'HS256'\n\ninterface CommonSignOptions {\n /** Time-to-live in seconds (exp claim). If omitted the token will not expire. */\n ttl?: number\n}\n\nexport type SignOptions\n = | ({ algorithm?: 'ES256', privateKey?: CryptoKey, secret?: string }\n & CommonSignOptions & { iss?: string, aud?: string | string[], sub?: string })\n | ({ algorithm: 'HS256', secret?: string | Uint8Array, privateKey?: never }\n & CommonSignOptions & { iss?: string, aud?: string | string[], sub?: string })\n\n/**\n * Create a signed JWT.\n * Defaults to ES256 when a privateKey is supplied. Falls back to HS256 when a secret is supplied.\n */\nexport async function sign<T extends Record<string, unknown>>(payload: T, options: SignOptions = {}): Promise<string> {\n let { algorithm = 'ES256', ttl, iss, aud, sub, privateKey, secret } = options\n\n if (algorithm === 'ES256') {\n if (!privateKey) {\n if (typeof secret !== 'string')\n throw new AuthError('Missing secret for ES256 signing. It must be a base64url-encoded string.');\n\n ({ privateKey } = await deriveKeysFromSecret(secret))\n }\n }\n else if (algorithm === 'HS256' && !secret) {\n throw new AuthError('Missing secret for HS256 signing')\n }\n\n const now = Math.floor(Date.now() / 1000)\n\n const jwtPayload: Record<string, unknown> = { iat: now, iss, aud, sub, ...payload }\n\n if (ttl != null && ttl > 0)\n jwtPayload.exp = now + ttl\n\n const isHS256 = algorithm === 'HS256'\n const alg: SupportedAlgorithm = isHS256 ? 'HS256' : 'ES256'\n\n const headerJSON = JSON.stringify({ alg, typ: 'JWT' })\n const payloadJSON = JSON.stringify(jwtPayload)\n\n const signatureMessage = createJWTSignatureMessage(headerJSON, payloadJSON)\n\n let signature: Uint8Array\n\n if (isHS256) {\n // HS256 (HMAC-SHA256)\n const secretBytes = typeof secret === 'string'\n ? new TextEncoder().encode(secret)\n : secret\n\n const cryptoKey = await crypto.subtle.importKey(\n 'raw',\n secretBytes as BufferSource,\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n )\n\n signature = new Uint8Array(await crypto.subtle.sign('HMAC', cryptoKey, signatureMessage as BufferSource))\n }\n else {\n // ES256 (ECDSA-SHA256)\n // Runtimes like Bun's return the raw (r||s) signature directly, not DER-encoded.\n signature = new Uint8Array(\n await crypto.subtle.sign(\n { name: 'ECDSA', hash: 'SHA-256' },\n privateKey!,\n signatureMessage as BufferSource,\n ),\n )\n }\n\n return encodeJWT(headerJSON, payloadJSON, signature)\n}\n\nexport type VerifyOptions\n = | { algorithm?: 'ES256', publicKey?: CryptoKey, secret?: string, iss?: string, aud?: string | string[] }\n | { algorithm: 'HS256', secret?: string | Uint8Array, publicKey?: never, iss?: string, aud?: string | string[] }\n\n/**\n * Verify a JWT and return its payload when the signature is valid.\n * The algorithm is inferred from options – ES256 by default.\n * Throws when verification fails or the token is expired.\n */\nexport async function verify<T = Record<string, unknown>>(token: string, options: VerifyOptions): Promise<T> {\n let { algorithm = 'ES256', publicKey, secret, iss, aud } = options\n\n if (algorithm === 'ES256') {\n if (!publicKey) {\n if (typeof secret !== 'string')\n throw new AuthError('Missing secret for ES256 verification. Must be a base64url-encoded string.');\n\n ({ publicKey } = await deriveKeysFromSecret(secret))\n }\n }\n\n if (algorithm === 'HS256' && !secret)\n throw new AuthError('Missing secret for HS256 verification')\n\n const [header, payload, signature, signatureMessage] = parseJWT(token)\n\n const headerParams = new JWSRegisteredHeaders(header)\n const headerAlg = headerParams.algorithm()\n\n let validSignature = false\n\n // HS256 verification path\n if (algorithm === 'HS256') {\n if (headerAlg !== 'HS256')\n throw new Error(`JWT algorithm is \"${headerAlg}\", but verifier was configured for \"HS256\"`)\n\n const secretBytes = typeof secret === 'string'\n ? new TextEncoder().encode(secret)\n : secret\n\n const cryptoKey = await crypto.subtle.importKey(\n 'raw',\n secretBytes as BufferSource,\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n )\n\n const expectedSig = new Uint8Array(await crypto.subtle.sign('HMAC', cryptoKey, signatureMessage as BufferSource))\n validSignature = constantTimeEqual(expectedSig, new Uint8Array(signature))\n }\n // ES256 verification path (default)\n else {\n if (headerAlg !== 'ES256')\n throw new AuthError(`JWT algorithm is \"${headerAlg}\", but verifier was configured for \"ES256\"`)\n\n const signatureBytes = new Uint8Array(signature)\n\n // Runtimes like Node.js return DER-encoded signatures. Others (Bun) return raw (r||s).\n // We try DER first, as it's more common in Node environments.\n validSignature = await crypto.subtle.verify(\n { name: 'ECDSA', hash: 'SHA-256' },\n publicKey!,\n signatureBytes as BufferSource,\n signatureMessage as BufferSource,\n )\n\n if (!validSignature && signatureBytes.length === 64) {\n // If DER verification fails and the signature is 64 bytes, it might be a raw signature.\n // Convert it to DER and try again.\n try {\n const derSig = rawToDer(signatureBytes)\n validSignature = await crypto.subtle.verify(\n { name: 'ECDSA', hash: 'SHA-256' },\n publicKey!,\n derSig as BufferSource,\n signatureMessage as BufferSource,\n )\n }\n catch {\n // rawToDer can throw if the signature is not 64 bytes, but we already checked.\n // This catch is for other unexpected errors.\n validSignature = false\n }\n }\n }\n\n if (!validSignature)\n throw new AuthError('Invalid JWT signature')\n\n const claims = new JWTRegisteredClaims(payload)\n if (claims.hasExpiration() && !claims.verifyExpiration())\n throw new AuthError('JWT expired')\n if (claims.hasNotBefore() && !claims.verifyNotBefore())\n throw new AuthError('JWT not yet valid')\n if (iss && (payload as any).iss !== iss)\n throw new AuthError('Invalid JWT issuer')\n\n if (aud) {\n const expectedAudience = Array.isArray(aud) ? aud : [aud]\n const tokenAudience = (payload as any).aud\n ? (Array.isArray((payload as any).aud) ? (payload as any).aud : [(payload as any).aud])\n : []\n\n if (!expectedAudience.some(audValue => tokenAudience.includes(audValue)))\n throw new AuthError('Invalid JWT audience')\n }\n\n return payload as T\n}\n","import { generateCodeVerifier, generateState } from 'arctic'\n\nexport function createOAuthUris() {\n const state = generateState()\n const codeVerifier = generateCodeVerifier()\n\n return {\n state,\n codeVerifier,\n }\n}\n","export interface RequestLike {\n /** Absolute or relative URL */\n readonly url: string\n /** Upper-case HTTP method (e.g. `GET`) */\n readonly method: string\n /** All HTTP headers – mutable so adapters can append */\n readonly headers: Headers\n /** Lazily parse the body as JSON */\n json: <T = unknown>() => Promise<T>\n /** Raw text body */\n text: () => Promise<string>\n /** FormData helper (for `application/x-www-form-urlencoded` or `multipart/form-data`) */\n formData: () => Promise<FormData>\n}\n\nexport interface ResponseLike {\n readonly status: number\n readonly headers: Headers\n readonly body?: BodyInit | null\n json: <T = unknown>() => Promise<T>\n text: () => Promise<string>\n}\n\nexport interface User {\n id: string\n name?: string | null\n email?: string | null\n emailVerified?: boolean | null\n image?: string | null\n}\n\nexport interface Session {\n id: string\n sub: string\n [key: string]: unknown\n}\n\nexport interface GauSession<TProviders extends string = string> {\n user: User | null\n session: Session | null\n accounts?: Account[] | null\n providers?: TProviders[]\n}\n\nexport const NULL_SESSION = {\n user: null,\n session: null,\n accounts: null,\n} as const\n\nexport interface NewUser extends Omit<User, 'id' | 'accounts'> {\n id?: string\n}\n\nexport interface Account {\n userId: string\n provider: string\n providerAccountId: string\n type?: string // e.g. \"oauth\"\n accessToken?: string | null\n refreshToken?: string | null\n expiresAt?: number | null // epoch seconds\n idToken?: string | null\n scope?: string | null\n tokenType?: string | null\n sessionState?: string | null\n}\n\nexport interface NewAccount extends Account {}\n\nexport interface Adapter {\n getUser: (id: string) => Promise<User | null>\n getUserByEmail: (email: string) => Promise<User | null>\n getUserByAccount: (provider: string, providerAccountId: string) => Promise<User | null>\n getAccounts: (userId: string) => Promise<Account[]>\n getUserAndAccounts: (userId: string) => Promise<{ user: User, accounts: Account[] } | null>\n createUser: (data: NewUser) => Promise<User>\n linkAccount: (data: NewAccount) => Promise<void>\n unlinkAccount: (provider: string, providerAccountId: string) => Promise<void>\n updateUser: (data: Partial<User> & { id: string }) => Promise<User>\n deleteUser: (id: string) => Promise<void>\n}\n\nexport class AuthError extends Error {\n override readonly cause?: unknown\n constructor(message: string, cause?: unknown) {\n super(message)\n this.name = 'AuthError'\n this.cause = cause\n }\n}\n\nexport function json<T>(data: T, init: ResponseInit = {}): Response {\n const headers = new Headers(init.headers)\n if (!headers.has('Content-Type'))\n headers.set('Content-Type', 'application/json; charset=utf-8')\n return new Response(JSON.stringify(data), { ...init, headers })\n}\n\nexport function redirect(url: string, status: 302 | 303 = 302): Response {\n return new Response(null, {\n status,\n headers: {\n Location: url,\n },\n })\n}\n\nexport * from './cookies'\nexport * from './createAuth'\nexport * from './handler'\n","import { BROWSER } from 'esm-env'\nimport { getSessionToken } from '../../client/token'\n\nexport const isTauri = BROWSER && '__TAURI_INTERNALS__' in window\n\nexport async function signInWithTauri(\n provider: string,\n baseUrl: string,\n scheme: string = 'gau',\n redirectOverride?: string,\n) {\n if (!isTauri)\n return\n\n const { platform } = await import('@tauri-apps/plugin-os')\n const { open } = await import('@tauri-apps/plugin-shell')\n\n const currentPlatform = platform() // platform is NO LONGER an async function\n let redirectTo: string\n\n if (redirectOverride)\n redirectTo = redirectOverride\n else if (currentPlatform === 'android' || currentPlatform === 'ios')\n redirectTo = new URL(baseUrl).origin\n else\n redirectTo = `${scheme}://oauth/callback`\n\n const authUrl = `${baseUrl}/${provider}?redirectTo=${encodeURIComponent(redirectTo)}`\n await open(authUrl)\n}\n\nexport async function setupTauriListener(\n handler: (url: string) => Promise<void>,\n): Promise<(() => void) | void> {\n if (!isTauri)\n return\n\n const { listen } = await import('@tauri-apps/api/event')\n try {\n const unlisten = await listen<string>('deep-link', async (event) => {\n await handler(event.payload)\n })\n return unlisten\n }\n catch (err) {\n console.error(err)\n }\n}\n\nexport function handleTauriDeepLink(url: string, baseUrl: string, scheme: string, onToken: (token: string) => void) {\n const parsed = new URL(url)\n if (parsed.protocol !== `${scheme}:` && parsed.origin !== new URL(baseUrl).origin)\n return\n\n const params = new URLSearchParams(parsed.hash.substring(1))\n const token = params.get('token')\n if (token)\n onToken(token)\n}\n\nexport async function linkAccountWithTauri(\n provider: string,\n baseUrl: string,\n scheme: string = 'gau',\n redirectOverride?: string,\n) {\n if (!isTauri)\n return\n\n const { platform } = await import('@tauri-apps/plugin-os')\n const { open } = await import('@tauri-apps/plugin-shell')\n\n const currentPlatform = platform()\n let redirectTo: string\n\n if (redirectOverride)\n redirectTo = redirectOverride\n else if (currentPlatform === 'android' || currentPlatform === 'ios')\n redirectTo = new URL(baseUrl).origin\n else\n redirectTo = `${scheme}://oauth/callback`\n\n const token = getSessionToken()\n if (!token) {\n console.error('No session token found, cannot link account.')\n return\n }\n\n const query = `?redirectTo=${encodeURIComponent(redirectTo)}&token=${encodeURIComponent(token)}`\n const linkUrl = `${baseUrl}/link/${provider}${query}`\n await open(linkUrl)\n}\n","import { BROWSER } from 'esm-env'\n\nexport function storeSessionToken(token: string) {\n if (!BROWSER)\n return\n try {\n localStorage.setItem('gau-token', token)\n document.cookie = `__gau-session-token=${token}; path=/; max-age=31536000; samesite=lax; secure`\n }\n catch {}\n}\n\nexport function getSessionToken(): string | null {\n if (!BROWSER)\n return null\n return localStorage.getItem('gau-token')\n}\n\nexport function clearSessionToken() {\n if (!BROWSER)\n return\n try {\n localStorage.removeItem('gau-token')\n document.cookie = `__gau-session-token=; path=/; max-age=0`\n }\n catch {}\n}\n"],"mappings":"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","names":["BROWSER","BROWSER","BROWSER","BROWSER"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{handleTauriDeepLink as o,isTauri as r,linkAccountWithTauri as m,setupTauriListener as p,signInWithTauri as t}from"../../chunk-
|
|
1
|
+
import{handleTauriDeepLink as o,isTauri as r,linkAccountWithTauri as m,setupTauriListener as p,signInWithTauri as t}from"../../chunk-LEYZAXTW.js";export{o as handleTauriDeepLink,r as isTauri,m as linkAccountWithTauri,p as setupTauriListener,t as signInWithTauri};//# sourceMappingURL=index.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const isTauri: boolean;
|
|
2
2
|
export declare function signInWithTauri(provider: string, baseUrl: string, scheme?: string, redirectOverride?: string): Promise<void>;
|
|
3
|
-
export declare function setupTauriListener(handler: (url: string) => Promise<void>): void
|
|
3
|
+
export declare function setupTauriListener(handler: (url: string) => Promise<void>): Promise<(() => void) | void>;
|
|
4
4
|
export declare function handleTauriDeepLink(url: string, baseUrl: string, scheme: string, onToken: (token: string) => void): void;
|
|
5
5
|
export declare function linkAccountWithTauri(provider: string, baseUrl: string, scheme?: string, redirectOverride?: string): Promise<void>;
|
|
6
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/runtimes/tauri/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/runtimes/tauri/index.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,OAAO,SAA6C,CAAA;AAEjE,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAc,EACtB,gBAAgB,CAAC,EAAE,MAAM,iBAoB1B;AAED,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GACtC,OAAO,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,CAc9B;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,QASjH;AAED,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAc,EACtB,gBAAgB,CAAC,EAAE,MAAM,iBA2B1B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{handleTauriDeepLink as o,isTauri as r,linkAccountWithTauri as m,setupTauriListener as p,signInWithTauri as t}from"../../../chunk-
|
|
1
|
+
import{handleTauriDeepLink as o,isTauri as r,linkAccountWithTauri as m,setupTauriListener as p,signInWithTauri as t}from"../../../chunk-LEYZAXTW.js";export{o as handleTauriDeepLink,r as isTauri,m as linkAccountWithTauri,p as setupTauriListener,t as signInWithTauri};//# sourceMappingURL=index.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CreateAuthOptions } from '../core';
|
|
1
|
+
import type { CreateAuthOptions, GauSession } from '../core';
|
|
2
2
|
import type { OAuthProvider } from '../oauth';
|
|
3
3
|
import { createAuth } from '../core';
|
|
4
4
|
type AuthInstance<TProviders extends OAuthProvider<any>[]> = ReturnType<typeof createAuth<TProviders>>;
|
|
@@ -19,5 +19,19 @@ export declare function SolidAuth<const TProviders extends OAuthProvider<any>[]>
|
|
|
19
19
|
POST: (event: any) => Promise<import("..").ResponseLike>;
|
|
20
20
|
OPTIONS: (event: any) => Promise<import("..").ResponseLike>;
|
|
21
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* Creates a SolidStart-compatible getSession resolver to validate a session from a Request.
|
|
24
|
+
* This mirrors the SvelteKit integration behaviour and supports both Cookie and Authorization headers.
|
|
25
|
+
*/
|
|
26
|
+
export declare function createSolidStartGetSession<const TProviders extends OAuthProvider<any>[]>(auth: AuthInstance<TProviders>): (request: Request) => Promise<GauSession<TProviders[number] extends infer T ? T extends TProviders[number] ? T extends OAuthProvider<infer T_1 extends string> ? T_1 : never : never : never>>;
|
|
27
|
+
/**
|
|
28
|
+
* SolidStart middleware factory to attach `locals.getSession` and optionally preload the session.
|
|
29
|
+
*
|
|
30
|
+
* Usage:
|
|
31
|
+
* onRequest: [authMiddleware(true, auth)]
|
|
32
|
+
* onRequest: [authMiddleware(['/protected', '/dashboard'], auth)]
|
|
33
|
+
* onRequest: [authMiddleware(false, auth)]
|
|
34
|
+
*/
|
|
35
|
+
export declare function authMiddleware<const TProviders extends OAuthProvider<any>[]>(pathsToPreLoad: string[] | boolean, optionsOrAuth: CreateAuthOptions<TProviders> | AuthInstance<TProviders>): (event: any) => Promise<void>;
|
|
22
36
|
export {};
|
|
23
37
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/solidstart/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/solidstart/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAe,MAAM,SAAS,CAAA;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAE7C,OAAO,EAAE,UAAU,EAAkE,MAAM,SAAS,CAAA;AAEpG,KAAK,YAAY,CAAC,UAAU,SAAS,aAAa,CAAC,GAAG,CAAC,EAAE,IAAI,UAAU,CAAC,OAAO,UAAU,CAAC,UAAU,CAAC,CAAC,CAAA;AAEtG;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,KAAK,CAAC,UAAU,SAAS,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,aAAa,EAAE,iBAAiB,CAAC,UAAU,CAAC,GAAG,YAAY,CAAC,UAAU,CAAC;;;;EAiB/I;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,CAAC,UAAU,SAAS,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,YAAY,CAAC,UAAU,CAAC,kMA6BvH;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,CAAC,UAAU,SAAS,aAAa,CAAC,GAAG,CAAC,EAAE,EAC1E,cAAc,EAAE,MAAM,EAAE,GAAG,OAAO,EAClC,aAAa,EAAE,iBAAiB,CAAC,UAAU,CAAC,GAAG,YAAY,CAAC,UAAU,CAAC,iCAuBxE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{NULL_SESSION as e,SESSION_COOKIE_NAME as r,createAuth as t,createHandler as n,parseCookies as o}from"../../chunk-BU67DYGK.js";import s from"process";function i(e){const r="providerMap"in e&&"signJWT"in e?e:t(e);r.development="development"===s.env.NODE_ENV;const o=n(r),i=e=>o(e.request);return{GET:i,POST:i,OPTIONS:i}}function a(t){return async function(n){let s=o(n.headers.get("Cookie")).get(r);if(!s){const e=n.headers.get("Authorization");e?.startsWith("Bearer ")&&(s=e.substring(7))}const i=Array.from(t.providerMap.keys());if(!s)return{...e,providers:i};try{const r=await t.validateSession(s);return r?{...r,providers:i}:{...e,providers:i}}catch{return{...e,providers:i}}}}function c(e,r){const n=a("providerMap"in r&&"signJWT"in r?r:t(r));return async r=>{const t=new URL(r.request.url);if("boolean"==typeof e?e:e.includes(t.pathname)){const e=await n(r.request);return void(r.locals.getSession=async()=>e)}r.locals.getSession=()=>n(r.request)}}export{i as SolidAuth,c as authMiddleware,a as createSolidStartGetSession};//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/solidstart/index.ts"],"sourcesContent":["import type { CreateAuthOptions } from '../core'\nimport type { OAuthProvider } from '../oauth'\nimport process from 'node:process'\nimport { createAuth, createHandler } from '../core'\n\ntype AuthInstance<TProviders extends OAuthProvider<any>[]> = ReturnType<typeof createAuth<TProviders>>\n\n/**\n * Creates GET and POST handlers for SolidStart.\n *\n * @example\n * ```ts\n * // src/routes/api/auth/[...auth].ts\n * import { SolidAuth } from '@rttnd/gau/solid-start'\n * import { authOptions } from '~/server/auth'\n *\n * export const { GET, POST } = SolidAuth(authOptions)\n * ```\n */\nexport function SolidAuth<const TProviders extends OAuthProvider<any>[]>(optionsOrAuth: CreateAuthOptions<TProviders> | AuthInstance<TProviders>) {\n // TODO: Duck-type to check if we have an instance or raw options\n const isInstance = 'providerMap' in optionsOrAuth && 'signJWT' in optionsOrAuth\n\n const auth = isInstance\n ? (optionsOrAuth as AuthInstance<TProviders>)\n : createAuth(optionsOrAuth as CreateAuthOptions<TProviders>)\n\n auth.development = process.env.NODE_ENV === 'development'\n\n const handler = createHandler(auth)\n const solidHandler = (event: any) => handler(event.request)\n return {\n GET: solidHandler,\n POST: solidHandler,\n OPTIONS: solidHandler,\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/solidstart/index.ts"],"sourcesContent":["import type { CreateAuthOptions, GauSession, ProviderIds } from '../core'\nimport type { OAuthProvider } from '../oauth'\nimport process from 'node:process'\nimport { createAuth, createHandler, NULL_SESSION, parseCookies, SESSION_COOKIE_NAME } from '../core'\n\ntype AuthInstance<TProviders extends OAuthProvider<any>[]> = ReturnType<typeof createAuth<TProviders>>\n\n/**\n * Creates GET and POST handlers for SolidStart.\n *\n * @example\n * ```ts\n * // src/routes/api/auth/[...auth].ts\n * import { SolidAuth } from '@rttnd/gau/solid-start'\n * import { authOptions } from '~/server/auth'\n *\n * export const { GET, POST } = SolidAuth(authOptions)\n * ```\n */\nexport function SolidAuth<const TProviders extends OAuthProvider<any>[]>(optionsOrAuth: CreateAuthOptions<TProviders> | AuthInstance<TProviders>) {\n // TODO: Duck-type to check if we have an instance or raw options\n const isInstance = 'providerMap' in optionsOrAuth && 'signJWT' in optionsOrAuth\n\n const auth = isInstance\n ? (optionsOrAuth as AuthInstance<TProviders>)\n : createAuth(optionsOrAuth as CreateAuthOptions<TProviders>)\n\n auth.development = process.env.NODE_ENV === 'development'\n\n const handler = createHandler(auth)\n const solidHandler = (event: any) => handler(event.request)\n return {\n GET: solidHandler,\n POST: solidHandler,\n OPTIONS: solidHandler,\n }\n}\n\n/**\n * Creates a SolidStart-compatible getSession resolver to validate a session from a Request.\n * This mirrors the SvelteKit integration behaviour and supports both Cookie and Authorization headers.\n */\nexport function createSolidStartGetSession<const TProviders extends OAuthProvider<any>[]>(auth: AuthInstance<TProviders>) {\n return async function getSessionFromRequest(\n request: Request,\n ): Promise<GauSession<ProviderIds<AuthInstance<TProviders>>>> {\n const requestCookies = parseCookies(request.headers.get('Cookie'))\n let sessionToken = requestCookies.get(SESSION_COOKIE_NAME)\n\n if (!sessionToken) {\n const authHeader = request.headers.get('Authorization')\n if (authHeader?.startsWith('Bearer '))\n sessionToken = authHeader.substring(7)\n }\n\n const providers = Array.from(auth.providerMap.keys()) as ProviderIds<AuthInstance<TProviders>>[]\n\n if (!sessionToken)\n return { ...NULL_SESSION, providers }\n\n try {\n const validated = await auth.validateSession(sessionToken)\n if (!validated)\n return { ...NULL_SESSION, providers }\n\n return { ...validated, providers }\n }\n catch {\n return { ...NULL_SESSION, providers }\n }\n }\n}\n\n/**\n * SolidStart middleware factory to attach `locals.getSession` and optionally preload the session.\n *\n * Usage:\n * onRequest: [authMiddleware(true, auth)]\n * onRequest: [authMiddleware(['/protected', '/dashboard'], auth)]\n * onRequest: [authMiddleware(false, auth)]\n */\nexport function authMiddleware<const TProviders extends OAuthProvider<any>[]>(\n pathsToPreLoad: string[] | boolean,\n optionsOrAuth: CreateAuthOptions<TProviders> | AuthInstance<TProviders>,\n) {\n const isInstance = 'providerMap' in optionsOrAuth && 'signJWT' in optionsOrAuth\n const auth = isInstance\n ? (optionsOrAuth as AuthInstance<TProviders>)\n : createAuth(optionsOrAuth as CreateAuthOptions<TProviders>)\n\n const getSessionFromRequest = createSolidStartGetSession(auth)\n\n return async (event: any) => {\n const url = new URL(event.request.url)\n const shouldPreload = typeof pathsToPreLoad === 'boolean'\n ? pathsToPreLoad\n : pathsToPreLoad.includes(url.pathname)\n\n if (shouldPreload) {\n const preloaded = await getSessionFromRequest(event.request)\n event.locals.getSession = async () => preloaded\n return\n }\n\n event.locals.getSession = () => getSessionFromRequest(event.request)\n }\n}\n"],"mappings":";;;;;;;;;AAEA,OAAO,aAAa;AAiBb,SAAS,UAAyD,eAAyE;AAEhJ,QAAM,aAAa,iBAAiB,iBAAiB,aAAa;AAElE,QAAM,OAAO,aACR,gBACD,WAAW,aAA8C;AAE7D,OAAK,cAAc,QAAQ,IAAI,aAAa;AAE5C,QAAM,UAAU,cAAc,IAAI;AAClC,QAAM,eAAe,CAAC,UAAe,QAAQ,MAAM,OAAO;AAC1D,SAAO;AAAA,IACL,KAAK;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,EACX;AACF;AAMO,SAAS,2BAA0E,MAAgC;AACxH,SAAO,eAAe,sBACpB,SAC4D;AAC5D,UAAM,iBAAiB,aAAa,QAAQ,QAAQ,IAAI,QAAQ,CAAC;AACjE,QAAI,eAAe,eAAe,IAAI,mBAAmB;AAEzD,QAAI,CAAC,cAAc;AACjB,YAAM,aAAa,QAAQ,QAAQ,IAAI,eAAe;AACtD,UAAI,YAAY,WAAW,SAAS;AAClC,uBAAe,WAAW,UAAU,CAAC;AAAA,IACzC;AAEA,UAAM,YAAY,MAAM,KAAK,KAAK,YAAY,KAAK,CAAC;AAEpD,QAAI,CAAC;AACH,aAAO,EAAE,GAAG,cAAc,UAAU;AAEtC,QAAI;AACF,YAAM,YAAY,MAAM,KAAK,gBAAgB,YAAY;AACzD,UAAI,CAAC;AACH,eAAO,EAAE,GAAG,cAAc,UAAU;AAEtC,aAAO,EAAE,GAAG,WAAW,UAAU;AAAA,IACnC,QACM;AACJ,aAAO,EAAE,GAAG,cAAc,UAAU;AAAA,IACtC;AAAA,EACF;AACF;AAUO,SAAS,eACd,gBACA,eACA;AACA,QAAM,aAAa,iBAAiB,iBAAiB,aAAa;AAClE,QAAM,OAAO,aACR,gBACD,WAAW,aAA8C;AAE7D,QAAM,wBAAwB,2BAA2B,IAAI;AAE7D,SAAO,OAAO,UAAe;AAC3B,UAAM,MAAM,IAAI,IAAI,MAAM,QAAQ,GAAG;AACrC,UAAM,gBAAgB,OAAO,mBAAmB,YAC5C,iBACA,eAAe,SAAS,IAAI,QAAQ;AAExC,QAAI,eAAe;AACjB,YAAM,YAAY,MAAM,sBAAsB,MAAM,OAAO;AAC3D,YAAM,OAAO,aAAa,YAAY;AACtC;AAAA,IACF;AAEA,UAAM,OAAO,aAAa,MAAM,sBAAsB,MAAM,OAAO;AAAA,EACrE;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rttnd/gau",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.3.
|
|
5
|
-
"packageManager": "bun@1.2.
|
|
4
|
+
"version": "0.3.4",
|
|
5
|
+
"packageManager": "bun@1.2.20",
|
|
6
6
|
"description": "gau is a delightful auth library",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"homepage": "https://github.com/Rettend/gau#readme",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"import": "./dist/src/cli/index.js"
|
|
42
42
|
},
|
|
43
43
|
"./client/solid": {
|
|
44
|
-
"
|
|
45
|
-
"
|
|
44
|
+
"solid": "./dist/src/client/solid/index.jsx",
|
|
45
|
+
"types": "./dist/src/client/solid/index.d.ts"
|
|
46
46
|
},
|
|
47
47
|
"./client/svelte": {
|
|
48
48
|
"types": "./dist/src/client/svelte/index.svelte.d.ts",
|
|
@@ -140,17 +140,17 @@
|
|
|
140
140
|
"esm-env": "^1.2.2"
|
|
141
141
|
},
|
|
142
142
|
"devDependencies": {
|
|
143
|
-
"@antfu/eslint-config": "^5.1
|
|
144
|
-
"@libsql/client": "^0.
|
|
143
|
+
"@antfu/eslint-config": "^5.2.1",
|
|
144
|
+
"@libsql/client": "^0.15.10",
|
|
145
145
|
"@types/better-sqlite3": "^7.6.13",
|
|
146
|
-
"@types/bun": "^1.2.
|
|
147
|
-
"@types/node": "^24.1
|
|
146
|
+
"@types/bun": "^1.2.20",
|
|
147
|
+
"@types/node": "^24.2.1",
|
|
148
148
|
"@vitest/coverage-v8": "^3.2.4",
|
|
149
149
|
"@vitest/ui": "^3.2.4",
|
|
150
150
|
"better-sqlite3": "^12.2.0",
|
|
151
|
-
"bumpp": "^10.2.
|
|
151
|
+
"bumpp": "^10.2.3",
|
|
152
152
|
"drizzle-kit": "^0.31.4",
|
|
153
|
-
"eslint": "^9.
|
|
153
|
+
"eslint": "^9.33.0",
|
|
154
154
|
"vitest": "^3.2.4"
|
|
155
155
|
}
|
|
156
156
|
}
|
package/dist/chunk-7WBYR3Q6.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{listen as o}from"@tauri-apps/api/event";import{BROWSER as n}from"esm-env";import{BROWSER as t}from"esm-env";var a=n&&"__TAURI_INTERNALS__"in window;async function i(o,n,t="gau",i){if(!a)return;const{platform:e}=await import("@tauri-apps/plugin-os"),{open:r}=await import("@tauri-apps/plugin-shell"),c=e();let p;p=i||("android"===c||"ios"===c?new URL(n).origin:`${t}://oauth/callback`);const s=`${n}/${o}?redirectTo=${encodeURIComponent(p)}`;await r(s)}function e(n){a&&o("deep-link",async o=>{await n(o.payload)}).catch(console.error)}function r(o,n,t,a){const i=new URL(o);if(i.protocol!==`${t}:`&&i.origin!==new URL(n).origin)return;const e=new URLSearchParams(i.hash.substring(1)).get("token");e&&a(e)}async function c(o,n,i="gau",e){if(!a)return;const{platform:r}=await import("@tauri-apps/plugin-os"),{open:c}=await import("@tauri-apps/plugin-shell"),p=r();let s;s=e||("android"===p||"ios"===p?new URL(n).origin:`${i}://oauth/callback`);const l=t?localStorage.getItem("gau-token"):null;if(!l)return void console.error("No session token found, cannot link account.");const u=`${n}/link/${o}${`?redirectTo=${encodeURIComponent(s)}&token=${encodeURIComponent(l)}`}`;await c(u)}export{a as isTauri,i as signInWithTauri,e as setupTauriListener,r as handleTauriDeepLink,c as linkAccountWithTauri};//# sourceMappingURL=chunk-7WBYR3Q6.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runtimes/tauri/index.ts","../src/client/token.ts"],"sourcesContent":["import { listen } from '@tauri-apps/api/event'\nimport { BROWSER } from 'esm-env'\nimport { getSessionToken } from '../../client/token'\n\nexport const isTauri = BROWSER && '__TAURI_INTERNALS__' in window\n\nexport async function signInWithTauri(\n provider: string,\n baseUrl: string,\n scheme: string = 'gau',\n redirectOverride?: string,\n) {\n if (!isTauri)\n return\n\n const { platform } = await import('@tauri-apps/plugin-os')\n const { open } = await import('@tauri-apps/plugin-shell')\n\n const currentPlatform = platform() // platform is NO LONGER an async function\n let redirectTo: string\n\n if (redirectOverride)\n redirectTo = redirectOverride\n else if (currentPlatform === 'android' || currentPlatform === 'ios')\n redirectTo = new URL(baseUrl).origin\n else\n redirectTo = `${scheme}://oauth/callback`\n\n const authUrl = `${baseUrl}/${provider}?redirectTo=${encodeURIComponent(redirectTo)}`\n await open(authUrl)\n}\n\nexport function setupTauriListener(handler: (url: string) => Promise<void>) {\n if (!isTauri)\n return\n\n listen<string>('deep-link', async (event) => {\n await handler(event.payload)\n }).catch(console.error)\n}\n\nexport function handleTauriDeepLink(url: string, baseUrl: string, scheme: string, onToken: (token: string) => void) {\n const parsed = new URL(url)\n if (parsed.protocol !== `${scheme}:` && parsed.origin !== new URL(baseUrl).origin)\n return\n\n const params = new URLSearchParams(parsed.hash.substring(1))\n const token = params.get('token')\n if (token)\n onToken(token)\n}\n\nexport async function linkAccountWithTauri(\n provider: string,\n baseUrl: string,\n scheme: string = 'gau',\n redirectOverride?: string,\n) {\n if (!isTauri)\n return\n\n const { platform } = await import('@tauri-apps/plugin-os')\n const { open } = await import('@tauri-apps/plugin-shell')\n\n const currentPlatform = platform()\n let redirectTo: string\n\n if (redirectOverride)\n redirectTo = redirectOverride\n else if (currentPlatform === 'android' || currentPlatform === 'ios')\n redirectTo = new URL(baseUrl).origin\n else\n redirectTo = `${scheme}://oauth/callback`\n\n const token = getSessionToken()\n if (!token) {\n console.error('No session token found, cannot link account.')\n return\n }\n\n const query = `?redirectTo=${encodeURIComponent(redirectTo)}&token=${encodeURIComponent(token)}`\n const linkUrl = `${baseUrl}/link/${provider}${query}`\n await open(linkUrl)\n}\n","import { BROWSER } from 'esm-env'\n\nexport function storeSessionToken(token: string) {\n if (!BROWSER)\n return\n try {\n localStorage.setItem('gau-token', token)\n document.cookie = `__gau-session-token=${token}; path=/; max-age=31536000; samesite=lax; secure`\n }\n catch {}\n}\n\nexport function getSessionToken(): string | null {\n if (!BROWSER)\n return null\n return localStorage.getItem('gau-token')\n}\n\nexport function clearSessionToken() {\n if (!BROWSER)\n return\n try {\n localStorage.removeItem('gau-token')\n document.cookie = `__gau-session-token=; path=/; max-age=0`\n }\n catch {}\n}\n"],"mappings":";AAAA,SAAS,cAAc;AACvB,SAAS,WAAAA,gBAAe;;;ACDxB,SAAS,eAAe;AAYjB,SAAS,kBAAiC;AAC/C,MAAI,CAAC;AACH,WAAO;AACT,SAAO,aAAa,QAAQ,WAAW;AACzC;;;ADZO,IAAM,UAAUC,YAAW,yBAAyB;AAE3D,eAAsB,gBACpB,UACA,SACA,SAAiB,OACjB,kBACA;AACA,MAAI,CAAC;AACH;AAEF,QAAM,EAAE,SAAS,IAAI,MAAM,OAAO,uBAAuB;AACzD,QAAM,EAAE,KAAK,IAAI,MAAM,OAAO,0BAA0B;AAExD,QAAM,kBAAkB,SAAS;AACjC,MAAI;AAEJ,MAAI;AACF,iBAAa;AAAA,WACN,oBAAoB,aAAa,oBAAoB;AAC5D,iBAAa,IAAI,IAAI,OAAO,EAAE;AAAA;AAE9B,iBAAa,GAAG,MAAM;AAExB,QAAM,UAAU,GAAG,OAAO,IAAI,QAAQ,eAAe,mBAAmB,UAAU,CAAC;AACnF,QAAM,KAAK,OAAO;AACpB;AAEO,SAAS,mBAAmB,SAAyC;AAC1E,MAAI,CAAC;AACH;AAEF,SAAe,aAAa,OAAO,UAAU;AAC3C,UAAM,QAAQ,MAAM,OAAO;AAAA,EAC7B,CAAC,EAAE,MAAM,QAAQ,KAAK;AACxB;AAEO,SAAS,oBAAoB,KAAa,SAAiB,QAAgB,SAAkC;AAClH,QAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,MAAI,OAAO,aAAa,GAAG,MAAM,OAAO,OAAO,WAAW,IAAI,IAAI,OAAO,EAAE;AACzE;AAEF,QAAM,SAAS,IAAI,gBAAgB,OAAO,KAAK,UAAU,CAAC,CAAC;AAC3D,QAAM,QAAQ,OAAO,IAAI,OAAO;AAChC,MAAI;AACF,YAAQ,KAAK;AACjB;AAEA,eAAsB,qBACpB,UACA,SACA,SAAiB,OACjB,kBACA;AACA,MAAI,CAAC;AACH;AAEF,QAAM,EAAE,SAAS,IAAI,MAAM,OAAO,uBAAuB;AACzD,QAAM,EAAE,KAAK,IAAI,MAAM,OAAO,0BAA0B;AAExD,QAAM,kBAAkB,SAAS;AACjC,MAAI;AAEJ,MAAI;AACF,iBAAa;AAAA,WACN,oBAAoB,aAAa,oBAAoB;AAC5D,iBAAa,IAAI,IAAI,OAAO,EAAE;AAAA;AAE9B,iBAAa,GAAG,MAAM;AAExB,QAAM,QAAQ,gBAAgB;AAC9B,MAAI,CAAC,OAAO;AACV,YAAQ,MAAM,8CAA8C;AAC5D;AAAA,EACF;AAEA,QAAM,QAAQ,eAAe,mBAAmB,UAAU,CAAC,UAAU,mBAAmB,KAAK,CAAC;AAC9F,QAAM,UAAU,GAAG,OAAO,SAAS,QAAQ,GAAG,KAAK;AACnD,QAAM,KAAK,OAAO;AACpB;","names":["BROWSER","BROWSER"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{createContext as o,createResource as e,onMount as n,useContext as t}from"solid-js";import{isServer as i}from"solid-js/web";import{parse as r,serialize as a}from"cookie";import{createJWTSignatureMessage as c,encodeJWT as s,JWSRegisteredHeaders as l,JWTRegisteredClaims as u,parseJWT as d}from"@oslojs/jwt";import{generateCodeVerifier as p,generateState as h}from"arctic";var m={user:null,session:null,accounts:null};import{listen as w}from"@tauri-apps/api/event";import{BROWSER as f}from"esm-env";import{BROWSER as g}from"esm-env";function k(o){if(g)try{localStorage.setItem("gau-token",o),document.cookie=`__gau-session-token=${o}; path=/; max-age=31536000; samesite=lax; secure`}catch{}}function v(){return g?localStorage.getItem("gau-token"):null}var R=f&&"__TAURI_INTERNALS__"in window;var y=o();function U(o){const t=o.scheme??"gau",r=o.baseUrl??"/api/auth",[a,{refetch:c}]=e(async()=>{if(i)return{...m,providers:[]};const o=v(),e=o?{Authorization:`Bearer ${o}`}:void 0,n=await fetch(`${r}/session`,o?{headers:e}:{credentials:"include"}),t=n.headers.get("content-type");return t?.includes("application/json")?n.json():{...m,providers:[]}},{initialValue:{...m,providers:[]}});return n(()=>{if(!R){const o=new URL(window.location.href).hash.substring(1),e=new URLSearchParams(o).get("token");e&&(k(e),c(),window.history.replaceState(null,"",window.location.pathname+window.location.search))}var o;R&&(o=async o=>{!function(o,e,n,t){const i=new URL(o);if(i.protocol!==`${n}:`&&i.origin!==new URL(e).origin)return;const r=new URLSearchParams(i.hash.substring(1)).get("token");r&&t(r)}(o,r,t,o=>{k(o),c()})},R&&w("deep-link",async e=>{await o(e.payload)}).catch(console.error))}),React.createElement(y.Provider,{value:{session:a,signIn:async function(e,{redirectTo:n}={}){let a=n??o.redirectTo;if(R)await async function(o,e,n="gau",t){if(!R)return;const{platform:i}=await import("@tauri-apps/plugin-os"),{open:r}=await import("@tauri-apps/plugin-shell"),a=i();let c;c=t||("android"===a||"ios"===a?new URL(e).origin:`${n}://oauth/callback`);const s=`${e}/${o}?redirectTo=${encodeURIComponent(c)}`;await r(s)}(e,r,t,a);else{a||i||(a=window.location.origin);const o=a?`?redirectTo=${encodeURIComponent(a)}`:"",n=`${r}/${e}${o}`;window.location.href=n}},linkAccount:async function(e,{redirectTo:n}={}){if(R)return void await async function(o,e,n="gau",t){if(!R)return;const{platform:i}=await import("@tauri-apps/plugin-os"),{open:r}=await import("@tauri-apps/plugin-shell"),a=i();let c;c=t||("android"===a||"ios"===a?new URL(e).origin:`${n}://oauth/callback`);const s=v();if(!s)return void console.error("No session token found, cannot link account.");const l=`${e}/link/${o}?redirectTo=${encodeURIComponent(c)}&token=${encodeURIComponent(s)}`;await r(l)}(e,r,t,n);let a=n??o.redirectTo;a||i||(a=window.location.href);const c=a?`?redirectTo=${encodeURIComponent(a)}`:"",s=`${r}/link/${e}${c}${c?"&":"?"}redirect=false`,l=v(),u=l?{headers:{Authorization:`Bearer ${l}`}}:{credentials:"include"},d=await fetch(s,u);if(d.redirected)window.location.href=d.url;else{const o=await d.json();o.url&&(window.location.href=o.url)}},unlinkAccount:async function(o){const e=v(),n=e?{headers:{Authorization:`Bearer ${e}`}}:{credentials:"include"},t=await fetch(`${r}/unlink/${o}`,{method:"POST",...n});t.ok?c():console.error("Failed to unlink account",await t.json())},signOut:async()=>{!function(){if(g)try{localStorage.removeItem("gau-token"),document.cookie="__gau-session-token=; path=/; max-age=0"}catch{}}();const o=v(),e=o?{Authorization:`Bearer ${o}`}:void 0;await fetch(`${r}/signout`,o?{method:"POST",headers:e}:{method:"POST",credentials:"include"}),c()}}},o.children)}function T(){const o=t(y);if(!o)throw new Error("useAuth must be used within an AuthProvider");return o}export{U as AuthProvider,T as useAuth};//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/client/solid/index.tsx","../../../../src/core/cookies.ts","../../../../src/jwt/jwt.ts","../../../../src/oauth/utils.ts","../../../../src/core/index.ts","../../../../src/runtimes/tauri/index.ts","../../../../src/client/token.ts"],"sourcesContent":["import type { Accessor, ParentProps } from 'solid-js'\nimport type { GauSession, ProviderIds } from '../../core'\nimport { createContext, createResource, onMount, useContext } from 'solid-js'\nimport { isServer } from 'solid-js/web'\nimport { NULL_SESSION } from '../../core'\nimport { handleTauriDeepLink, isTauri, linkAccountWithTauri, setupTauriListener, signInWithTauri } from '../../runtimes/tauri'\nimport { clearSessionToken, getSessionToken, storeSessionToken } from '../token'\n\ninterface AuthContextValue<TAuth = unknown> {\n session: Accessor<GauSession<ProviderIds<TAuth>>>\n signIn: (provider: ProviderIds<TAuth>, options?: { redirectTo?: string }) => Promise<void>\n linkAccount: (provider: ProviderIds<TAuth>, options?: { redirectTo?: string }) => Promise<void>\n unlinkAccount: (provider: ProviderIds<TAuth>) => Promise<void>\n signOut: () => Promise<void>\n}\n\nconst AuthContext = createContext<any>()\n\nexport function AuthProvider<const TAuth = unknown>(props: ParentProps & { auth?: TAuth, baseUrl?: string, scheme?: string, redirectTo?: string }) {\n const scheme = props.scheme ?? 'gau'\n const baseUrl = props.baseUrl ?? '/api/auth'\n\n const [session, { refetch }] = createResource<GauSession<ProviderIds<TAuth>>>(\n async () => {\n if (isServer)\n return { ...NULL_SESSION, providers: [] }\n\n const token = getSessionToken()\n const headers = token ? { Authorization: `Bearer ${token}` } : undefined\n const res = await fetch(`${baseUrl}/session`, token ? { headers } : { credentials: 'include' })\n\n const contentType = res.headers.get('content-type')\n if (contentType?.includes('application/json'))\n return res.json()\n\n return { ...NULL_SESSION, providers: [] as ProviderIds<TAuth>[] }\n },\n { initialValue: { ...NULL_SESSION, providers: [] } },\n )\n\n async function signIn(provider: ProviderIds<TAuth>, { redirectTo }: { redirectTo?: string } = {}) {\n let finalRedirectTo = redirectTo ?? props.redirectTo\n if (isTauri) {\n await signInWithTauri(provider as string, baseUrl, scheme, finalRedirectTo)\n }\n else {\n if (!finalRedirectTo && !isServer)\n finalRedirectTo = window.location.origin\n\n const query = finalRedirectTo ? `?redirectTo=${encodeURIComponent(finalRedirectTo)}` : ''\n const authUrl = `${baseUrl}/${provider as string}${query}`\n window.location.href = authUrl\n }\n }\n\n async function linkAccount(provider: ProviderIds<TAuth>, { redirectTo }: { redirectTo?: string } = {}) {\n if (isTauri) {\n await linkAccountWithTauri(provider as string, baseUrl, scheme, redirectTo)\n return\n }\n\n let finalRedirectTo = redirectTo ?? props.redirectTo\n if (!finalRedirectTo && !isServer)\n finalRedirectTo = window.location.href\n\n const query = finalRedirectTo ? `?redirectTo=${encodeURIComponent(finalRedirectTo)}` : ''\n const linkUrl = `${baseUrl}/link/${provider as string}${query}${query ? '&' : '?'}redirect=false`\n\n const token = getSessionToken()\n\n const fetchOptions: RequestInit = token\n ? { headers: { Authorization: `Bearer ${token}` } }\n : { credentials: 'include' }\n\n const res = await fetch(linkUrl, fetchOptions)\n if (res.redirected) {\n window.location.href = res.url\n }\n else {\n const data = await res.json()\n if (data.url)\n window.location.href = data.url\n }\n }\n\n async function unlinkAccount(provider: ProviderIds<TAuth>) {\n const token = getSessionToken()\n const fetchOptions: RequestInit = token\n ? { headers: { Authorization: `Bearer ${token}` } }\n : { credentials: 'include' }\n\n const res = await fetch(`${baseUrl}/unlink/${provider as string}`, {\n method: 'POST',\n ...fetchOptions,\n })\n\n if (res.ok)\n refetch()\n else\n console.error('Failed to unlink account', await res.json())\n }\n\n const signOut = async () => {\n clearSessionToken()\n const token = getSessionToken()\n const headers = token ? { Authorization: `Bearer ${token}` } : undefined\n await fetch(`${baseUrl}/signout`, token ? { method: 'POST', headers } : { method: 'POST', credentials: 'include' })\n refetch()\n }\n\n onMount(() => {\n if (!isTauri) {\n const hash = new URL(window.location.href).hash.substring(1)\n const params = new URLSearchParams(hash)\n const tokenParam = params.get('token')\n if (tokenParam) {\n storeSessionToken(tokenParam)\n refetch()\n window.history.replaceState(null, '', window.location.pathname + window.location.search)\n }\n }\n\n if (!isTauri)\n return\n\n setupTauriListener(async (url) => {\n handleTauriDeepLink(url, baseUrl, scheme, (token) => {\n storeSessionToken(token)\n refetch()\n })\n })\n })\n\n return (\n <AuthContext.Provider value={{ session, signIn, linkAccount, unlinkAccount, signOut }}>\n {props.children}\n </AuthContext.Provider>\n )\n}\n\nexport function useAuth<const TAuth = unknown>(): AuthContextValue<TAuth> {\n const context = useContext(AuthContext)\n if (!context)\n throw new Error('useAuth must be used within an AuthProvider')\n return context as AuthContextValue<TAuth>\n}\n","import type { SerializeOptions } from 'cookie'\nimport { parse, serialize } from 'cookie'\n\nexport const DEFAULT_COOKIE_SERIALIZE_OPTIONS: SerializeOptions = {\n path: '/',\n sameSite: 'lax',\n secure: true,\n httpOnly: true,\n}\n\nexport type Cookie = [string, string, SerializeOptions]\n\nexport function parseCookies(cookieHeader: string | null | undefined): Map<string, string> {\n const cookies = new Map<string, string>()\n if (cookieHeader) {\n const parsed = parse(cookieHeader)\n for (const name in parsed)\n cookies.set(name, parsed[name]!)\n }\n return cookies\n}\n\nexport class Cookies {\n #new: Cookie[] = []\n\n constructor(\n private readonly requestCookies: Map<string, string>,\n private readonly defaultOptions: SerializeOptions,\n ) {}\n\n get(name: string): string | undefined {\n return this.requestCookies.get(name)\n }\n\n set(name: string, value: string, options?: SerializeOptions): void {\n const combinedOptions = { ...this.defaultOptions, ...options }\n this.#new.push([name, value, combinedOptions])\n }\n\n delete(name: string, options?: Omit<SerializeOptions, 'expires' | 'maxAge'>): void {\n this.set(name, '', { ...options, expires: new Date(0), maxAge: 0 })\n }\n\n toHeaders(): Headers {\n const headers = new Headers()\n for (const [name, value, options] of this.#new)\n headers.append('Set-Cookie', serialize(name, value, options))\n\n return headers\n }\n}\n\nexport const CSRF_COOKIE_NAME = '__gau-csrf-token'\nexport const SESSION_COOKIE_NAME = '__gau-session-token'\nexport const SESSION_STRATEGY_COOKIE_NAME = '__gau-session-strategy'\nexport const LINKING_TOKEN_COOKIE_NAME = '__gau-linking-token'\nexport const PKCE_COOKIE_NAME = '__gau-pkce-code-verifier'\nexport const CALLBACK_URI_COOKIE_NAME = '__gau-callback-uri'\n\nexport const CSRF_MAX_AGE = 60 * 10 // 10 minutes\n","/// <reference types=\"node\" />\nimport {\n createJWTSignatureMessage,\n encodeJWT,\n JWSRegisteredHeaders,\n JWTRegisteredClaims,\n parseJWT,\n} from '@oslojs/jwt'\nimport { AuthError } from '../core/index'\nimport { constantTimeEqual, deriveKeysFromSecret, rawToDer } from './utils'\n\nexport type SupportedAlgorithm = 'ES256' | 'HS256'\n\ninterface CommonSignOptions {\n /** Time-to-live in seconds (exp claim). If omitted the token will not expire. */\n ttl?: number\n}\n\nexport type SignOptions\n = | ({ algorithm?: 'ES256', privateKey?: CryptoKey, secret?: string }\n & CommonSignOptions & { iss?: string, aud?: string | string[], sub?: string })\n | ({ algorithm: 'HS256', secret?: string | Uint8Array, privateKey?: never }\n & CommonSignOptions & { iss?: string, aud?: string | string[], sub?: string })\n\n/**\n * Create a signed JWT.\n * Defaults to ES256 when a privateKey is supplied. Falls back to HS256 when a secret is supplied.\n */\nexport async function sign<T extends Record<string, unknown>>(payload: T, options: SignOptions = {}): Promise<string> {\n let { algorithm = 'ES256', ttl, iss, aud, sub, privateKey, secret } = options\n\n if (algorithm === 'ES256') {\n if (!privateKey) {\n if (typeof secret !== 'string')\n throw new AuthError('Missing secret for ES256 signing. It must be a base64url-encoded string.');\n\n ({ privateKey } = await deriveKeysFromSecret(secret))\n }\n }\n else if (algorithm === 'HS256' && !secret) {\n throw new AuthError('Missing secret for HS256 signing')\n }\n\n const now = Math.floor(Date.now() / 1000)\n\n const jwtPayload: Record<string, unknown> = { iat: now, iss, aud, sub, ...payload }\n\n if (ttl != null && ttl > 0)\n jwtPayload.exp = now + ttl\n\n const isHS256 = algorithm === 'HS256'\n const alg: SupportedAlgorithm = isHS256 ? 'HS256' : 'ES256'\n\n const headerJSON = JSON.stringify({ alg, typ: 'JWT' })\n const payloadJSON = JSON.stringify(jwtPayload)\n\n const signatureMessage = createJWTSignatureMessage(headerJSON, payloadJSON)\n\n let signature: Uint8Array\n\n if (isHS256) {\n // HS256 (HMAC-SHA256)\n const secretBytes = typeof secret === 'string'\n ? new TextEncoder().encode(secret)\n : secret\n\n const cryptoKey = await crypto.subtle.importKey(\n 'raw',\n secretBytes as BufferSource,\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n )\n\n signature = new Uint8Array(await crypto.subtle.sign('HMAC', cryptoKey, signatureMessage as BufferSource))\n }\n else {\n // ES256 (ECDSA-SHA256)\n // Runtimes like Bun's return the raw (r||s) signature directly, not DER-encoded.\n signature = new Uint8Array(\n await crypto.subtle.sign(\n { name: 'ECDSA', hash: 'SHA-256' },\n privateKey!,\n signatureMessage as BufferSource,\n ),\n )\n }\n\n return encodeJWT(headerJSON, payloadJSON, signature)\n}\n\nexport type VerifyOptions\n = | { algorithm?: 'ES256', publicKey?: CryptoKey, secret?: string, iss?: string, aud?: string | string[] }\n | { algorithm: 'HS256', secret?: string | Uint8Array, publicKey?: never, iss?: string, aud?: string | string[] }\n\n/**\n * Verify a JWT and return its payload when the signature is valid.\n * The algorithm is inferred from options – ES256 by default.\n * Throws when verification fails or the token is expired.\n */\nexport async function verify<T = Record<string, unknown>>(token: string, options: VerifyOptions): Promise<T> {\n let { algorithm = 'ES256', publicKey, secret, iss, aud } = options\n\n if (algorithm === 'ES256') {\n if (!publicKey) {\n if (typeof secret !== 'string')\n throw new AuthError('Missing secret for ES256 verification. Must be a base64url-encoded string.');\n\n ({ publicKey } = await deriveKeysFromSecret(secret))\n }\n }\n\n if (algorithm === 'HS256' && !secret)\n throw new AuthError('Missing secret for HS256 verification')\n\n const [header, payload, signature, signatureMessage] = parseJWT(token)\n\n const headerParams = new JWSRegisteredHeaders(header)\n const headerAlg = headerParams.algorithm()\n\n let validSignature = false\n\n // HS256 verification path\n if (algorithm === 'HS256') {\n if (headerAlg !== 'HS256')\n throw new Error(`JWT algorithm is \"${headerAlg}\", but verifier was configured for \"HS256\"`)\n\n const secretBytes = typeof secret === 'string'\n ? new TextEncoder().encode(secret)\n : secret\n\n const cryptoKey = await crypto.subtle.importKey(\n 'raw',\n secretBytes as BufferSource,\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n )\n\n const expectedSig = new Uint8Array(await crypto.subtle.sign('HMAC', cryptoKey, signatureMessage as BufferSource))\n validSignature = constantTimeEqual(expectedSig, new Uint8Array(signature))\n }\n // ES256 verification path (default)\n else {\n if (headerAlg !== 'ES256')\n throw new AuthError(`JWT algorithm is \"${headerAlg}\", but verifier was configured for \"ES256\"`)\n\n const signatureBytes = new Uint8Array(signature)\n\n // Runtimes like Node.js return DER-encoded signatures. Others (Bun) return raw (r||s).\n // We try DER first, as it's more common in Node environments.\n validSignature = await crypto.subtle.verify(\n { name: 'ECDSA', hash: 'SHA-256' },\n publicKey!,\n signatureBytes as BufferSource,\n signatureMessage as BufferSource,\n )\n\n if (!validSignature && signatureBytes.length === 64) {\n // If DER verification fails and the signature is 64 bytes, it might be a raw signature.\n // Convert it to DER and try again.\n try {\n const derSig = rawToDer(signatureBytes)\n validSignature = await crypto.subtle.verify(\n { name: 'ECDSA', hash: 'SHA-256' },\n publicKey!,\n derSig as BufferSource,\n signatureMessage as BufferSource,\n )\n }\n catch {\n // rawToDer can throw if the signature is not 64 bytes, but we already checked.\n // This catch is for other unexpected errors.\n validSignature = false\n }\n }\n }\n\n if (!validSignature)\n throw new AuthError('Invalid JWT signature')\n\n const claims = new JWTRegisteredClaims(payload)\n if (claims.hasExpiration() && !claims.verifyExpiration())\n throw new AuthError('JWT expired')\n if (claims.hasNotBefore() && !claims.verifyNotBefore())\n throw new AuthError('JWT not yet valid')\n if (iss && (payload as any).iss !== iss)\n throw new AuthError('Invalid JWT issuer')\n\n if (aud) {\n const expectedAudience = Array.isArray(aud) ? aud : [aud]\n const tokenAudience = (payload as any).aud\n ? (Array.isArray((payload as any).aud) ? (payload as any).aud : [(payload as any).aud])\n : []\n\n if (!expectedAudience.some(audValue => tokenAudience.includes(audValue)))\n throw new AuthError('Invalid JWT audience')\n }\n\n return payload as T\n}\n","import { generateCodeVerifier, generateState } from 'arctic'\n\nexport function createOAuthUris() {\n const state = generateState()\n const codeVerifier = generateCodeVerifier()\n\n return {\n state,\n codeVerifier,\n }\n}\n","export interface RequestLike {\n /** Absolute or relative URL */\n readonly url: string\n /** Upper-case HTTP method (e.g. `GET`) */\n readonly method: string\n /** All HTTP headers – mutable so adapters can append */\n readonly headers: Headers\n /** Lazily parse the body as JSON */\n json: <T = unknown>() => Promise<T>\n /** Raw text body */\n text: () => Promise<string>\n /** FormData helper (for `application/x-www-form-urlencoded` or `multipart/form-data`) */\n formData: () => Promise<FormData>\n}\n\nexport interface ResponseLike {\n readonly status: number\n readonly headers: Headers\n readonly body?: BodyInit | null\n json: <T = unknown>() => Promise<T>\n text: () => Promise<string>\n}\n\nexport interface User {\n id: string\n name?: string | null\n email?: string | null\n emailVerified?: boolean | null\n image?: string | null\n}\n\nexport interface Session {\n id: string\n sub: string\n [key: string]: unknown\n}\n\nexport interface GauSession<TProviders extends string = string> {\n user: User | null\n session: Session | null\n accounts?: Account[] | null\n providers?: TProviders[]\n}\n\nexport const NULL_SESSION = {\n user: null,\n session: null,\n accounts: null,\n} as const\n\nexport interface NewUser extends Omit<User, 'id' | 'accounts'> {\n id?: string\n}\n\nexport interface Account {\n userId: string\n provider: string\n providerAccountId: string\n type?: string // e.g. \"oauth\"\n accessToken?: string | null\n refreshToken?: string | null\n expiresAt?: number | null // epoch seconds\n idToken?: string | null\n scope?: string | null\n tokenType?: string | null\n sessionState?: string | null\n}\n\nexport interface NewAccount extends Account {}\n\nexport interface Adapter {\n getUser: (id: string) => Promise<User | null>\n getUserByEmail: (email: string) => Promise<User | null>\n getUserByAccount: (provider: string, providerAccountId: string) => Promise<User | null>\n getAccounts: (userId: string) => Promise<Account[]>\n getUserAndAccounts: (userId: string) => Promise<{ user: User, accounts: Account[] } | null>\n createUser: (data: NewUser) => Promise<User>\n linkAccount: (data: NewAccount) => Promise<void>\n unlinkAccount: (provider: string, providerAccountId: string) => Promise<void>\n updateUser: (data: Partial<User> & { id: string }) => Promise<User>\n deleteUser: (id: string) => Promise<void>\n}\n\nexport class AuthError extends Error {\n override readonly cause?: unknown\n constructor(message: string, cause?: unknown) {\n super(message)\n this.name = 'AuthError'\n this.cause = cause\n }\n}\n\nexport function json<T>(data: T, init: ResponseInit = {}): Response {\n const headers = new Headers(init.headers)\n if (!headers.has('Content-Type'))\n headers.set('Content-Type', 'application/json; charset=utf-8')\n return new Response(JSON.stringify(data), { ...init, headers })\n}\n\nexport function redirect(url: string, status: 302 | 303 = 302): Response {\n return new Response(null, {\n status,\n headers: {\n Location: url,\n },\n })\n}\n\nexport * from './cookies'\nexport * from './createAuth'\nexport * from './handler'\n","import { listen } from '@tauri-apps/api/event'\nimport { BROWSER } from 'esm-env'\nimport { getSessionToken } from '../../client/token'\n\nexport const isTauri = BROWSER && '__TAURI_INTERNALS__' in window\n\nexport async function signInWithTauri(\n provider: string,\n baseUrl: string,\n scheme: string = 'gau',\n redirectOverride?: string,\n) {\n if (!isTauri)\n return\n\n const { platform } = await import('@tauri-apps/plugin-os')\n const { open } = await import('@tauri-apps/plugin-shell')\n\n const currentPlatform = platform() // platform is NO LONGER an async function\n let redirectTo: string\n\n if (redirectOverride)\n redirectTo = redirectOverride\n else if (currentPlatform === 'android' || currentPlatform === 'ios')\n redirectTo = new URL(baseUrl).origin\n else\n redirectTo = `${scheme}://oauth/callback`\n\n const authUrl = `${baseUrl}/${provider}?redirectTo=${encodeURIComponent(redirectTo)}`\n await open(authUrl)\n}\n\nexport function setupTauriListener(handler: (url: string) => Promise<void>) {\n if (!isTauri)\n return\n\n listen<string>('deep-link', async (event) => {\n await handler(event.payload)\n }).catch(console.error)\n}\n\nexport function handleTauriDeepLink(url: string, baseUrl: string, scheme: string, onToken: (token: string) => void) {\n const parsed = new URL(url)\n if (parsed.protocol !== `${scheme}:` && parsed.origin !== new URL(baseUrl).origin)\n return\n\n const params = new URLSearchParams(parsed.hash.substring(1))\n const token = params.get('token')\n if (token)\n onToken(token)\n}\n\nexport async function linkAccountWithTauri(\n provider: string,\n baseUrl: string,\n scheme: string = 'gau',\n redirectOverride?: string,\n) {\n if (!isTauri)\n return\n\n const { platform } = await import('@tauri-apps/plugin-os')\n const { open } = await import('@tauri-apps/plugin-shell')\n\n const currentPlatform = platform()\n let redirectTo: string\n\n if (redirectOverride)\n redirectTo = redirectOverride\n else if (currentPlatform === 'android' || currentPlatform === 'ios')\n redirectTo = new URL(baseUrl).origin\n else\n redirectTo = `${scheme}://oauth/callback`\n\n const token = getSessionToken()\n if (!token) {\n console.error('No session token found, cannot link account.')\n return\n }\n\n const query = `?redirectTo=${encodeURIComponent(redirectTo)}&token=${encodeURIComponent(token)}`\n const linkUrl = `${baseUrl}/link/${provider}${query}`\n await open(linkUrl)\n}\n","import { BROWSER } from 'esm-env'\n\nexport function storeSessionToken(token: string) {\n if (!BROWSER)\n return\n try {\n localStorage.setItem('gau-token', token)\n document.cookie = `__gau-session-token=${token}; path=/; max-age=31536000; samesite=lax; secure`\n }\n catch {}\n}\n\nexport function getSessionToken(): string | null {\n if (!BROWSER)\n return null\n return localStorage.getItem('gau-token')\n}\n\nexport function clearSessionToken() {\n if (!BROWSER)\n return\n try {\n localStorage.removeItem('gau-token')\n document.cookie = `__gau-session-token=; path=/; max-age=0`\n }\n catch {}\n}\n"],"mappings":"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","names":["BROWSER","BROWSER"]}
|