@draftlab/auth 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/allow.js +26 -0
- package/dist/esm/client.js +254 -0
- package/dist/esm/core.js +597 -0
- package/dist/esm/css.d.js +0 -0
- package/dist/esm/error.js +88 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/keys.js +126 -0
- package/dist/esm/mutex.js +53 -0
- package/dist/esm/pkce.js +87 -0
- package/dist/esm/provider/apple.js +15 -0
- package/dist/esm/provider/code.js +62 -0
- package/dist/esm/provider/discord.js +15 -0
- package/dist/esm/provider/facebook.js +15 -0
- package/dist/esm/provider/github.js +15 -0
- package/dist/esm/provider/gitlab.js +15 -0
- package/dist/esm/provider/google.js +16 -0
- package/dist/esm/provider/linkedin.js +15 -0
- package/dist/esm/provider/magiclink.js +83 -0
- package/dist/esm/provider/microsoft.js +15 -0
- package/dist/esm/provider/oauth2.js +130 -0
- package/dist/esm/provider/password.js +331 -0
- package/dist/esm/provider/provider.js +18 -0
- package/dist/esm/provider/reddit.js +15 -0
- package/dist/esm/provider/slack.js +15 -0
- package/dist/esm/provider/spotify.js +15 -0
- package/dist/esm/provider/twitch.js +15 -0
- package/dist/esm/provider/vercel.js +17 -0
- package/dist/esm/random.js +40 -0
- package/dist/esm/revocation.js +27 -0
- package/dist/esm/storage/memory.js +110 -0
- package/dist/esm/storage/storage.js +56 -0
- package/dist/esm/storage/turso.js +93 -0
- package/dist/esm/storage/unstorage.js +78 -0
- package/dist/esm/subject.js +7 -0
- package/dist/esm/themes/theme.js +115 -0
- package/dist/esm/toolkit/client.js +119 -0
- package/dist/esm/toolkit/index.js +25 -0
- package/dist/esm/toolkit/providers/facebook.js +11 -0
- package/dist/esm/toolkit/providers/github.js +11 -0
- package/dist/esm/toolkit/providers/google.js +11 -0
- package/dist/esm/toolkit/providers/strategy.js +0 -0
- package/dist/esm/toolkit/storage.js +81 -0
- package/dist/esm/toolkit/utils.js +18 -0
- package/dist/esm/types.js +0 -0
- package/dist/esm/ui/base.js +478 -0
- package/dist/esm/ui/code.js +186 -0
- package/dist/esm/ui/form.js +46 -0
- package/dist/esm/ui/icon.js +242 -0
- package/dist/esm/ui/magiclink.js +158 -0
- package/dist/esm/ui/password.js +435 -0
- package/dist/esm/ui/select.js +102 -0
- package/dist/esm/util.js +59 -0
- package/dist/{allow.d.mts → types/allow.d.ts} +9 -11
- package/dist/types/allow.d.ts.map +1 -0
- package/dist/types/client.d.ts +462 -0
- package/dist/types/client.d.ts.map +1 -0
- package/dist/types/core.d.ts +113 -0
- package/dist/types/core.d.ts.map +1 -0
- package/dist/{error.d.mts → types/error.d.ts} +95 -97
- package/dist/types/error.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/{keys.d.mts → types/keys.d.ts} +20 -24
- package/dist/types/keys.d.ts.map +1 -0
- package/dist/types/mutex.d.ts +42 -0
- package/dist/types/mutex.d.ts.map +1 -0
- package/dist/{pkce.d.mts → types/pkce.d.ts} +10 -11
- package/dist/types/pkce.d.ts.map +1 -0
- package/dist/types/provider/apple.d.ts +197 -0
- package/dist/types/provider/apple.d.ts.map +1 -0
- package/dist/types/provider/code.d.ts +288 -0
- package/dist/types/provider/code.d.ts.map +1 -0
- package/dist/types/provider/discord.d.ts +206 -0
- package/dist/types/provider/discord.d.ts.map +1 -0
- package/dist/types/provider/facebook.d.ts +200 -0
- package/dist/types/provider/facebook.d.ts.map +1 -0
- package/dist/types/provider/github.d.ts +220 -0
- package/dist/types/provider/github.d.ts.map +1 -0
- package/dist/types/provider/gitlab.d.ts +180 -0
- package/dist/types/provider/gitlab.d.ts.map +1 -0
- package/dist/types/provider/google.d.ts +158 -0
- package/dist/types/provider/google.d.ts.map +1 -0
- package/dist/types/provider/linkedin.d.ts +190 -0
- package/dist/types/provider/linkedin.d.ts.map +1 -0
- package/dist/types/provider/magiclink.d.ts +141 -0
- package/dist/types/provider/magiclink.d.ts.map +1 -0
- package/dist/types/provider/microsoft.d.ts +247 -0
- package/dist/types/provider/microsoft.d.ts.map +1 -0
- package/dist/types/provider/oauth2.d.ts +229 -0
- package/dist/types/provider/oauth2.d.ts.map +1 -0
- package/dist/types/provider/password.d.ts +408 -0
- package/dist/types/provider/password.d.ts.map +1 -0
- package/dist/types/provider/provider.d.ts +226 -0
- package/dist/types/provider/provider.d.ts.map +1 -0
- package/dist/types/provider/reddit.d.ts +159 -0
- package/dist/types/provider/reddit.d.ts.map +1 -0
- package/dist/types/provider/slack.d.ts +171 -0
- package/dist/types/provider/slack.d.ts.map +1 -0
- package/dist/types/provider/spotify.d.ts +168 -0
- package/dist/types/provider/spotify.d.ts.map +1 -0
- package/dist/types/provider/twitch.d.ts +163 -0
- package/dist/types/provider/twitch.d.ts.map +1 -0
- package/dist/types/provider/vercel.d.ts +294 -0
- package/dist/types/provider/vercel.d.ts.map +1 -0
- package/dist/{random.d.mts → types/random.d.ts} +4 -6
- package/dist/types/random.d.ts.map +1 -0
- package/dist/types/revocation.d.ts +76 -0
- package/dist/types/revocation.d.ts.map +1 -0
- package/dist/{storage/memory.d.mts → types/storage/memory.d.ts} +17 -21
- package/dist/types/storage/memory.d.ts.map +1 -0
- package/dist/types/storage/storage.d.ts +177 -0
- package/dist/types/storage/storage.d.ts.map +1 -0
- package/dist/{storage/turso.d.mts → types/storage/turso.d.ts} +4 -8
- package/dist/types/storage/turso.d.ts.map +1 -0
- package/dist/{storage/unstorage.d.mts → types/storage/unstorage.d.ts} +12 -11
- package/dist/types/storage/unstorage.d.ts.map +1 -0
- package/dist/types/subject.d.ts +115 -0
- package/dist/types/subject.d.ts.map +1 -0
- package/dist/types/themes/theme.d.ts +207 -0
- package/dist/types/themes/theme.d.ts.map +1 -0
- package/dist/types/toolkit/client.d.ts +235 -0
- package/dist/types/toolkit/client.d.ts.map +1 -0
- package/dist/types/toolkit/index.d.ts +45 -0
- package/dist/types/toolkit/index.d.ts.map +1 -0
- package/dist/types/toolkit/providers/facebook.d.ts +8 -0
- package/dist/types/toolkit/providers/facebook.d.ts.map +1 -0
- package/dist/types/toolkit/providers/github.d.ts +8 -0
- package/dist/types/toolkit/providers/github.d.ts.map +1 -0
- package/dist/types/toolkit/providers/google.d.ts +8 -0
- package/dist/types/toolkit/providers/google.d.ts.map +1 -0
- package/dist/types/toolkit/providers/strategy.d.ts +38 -0
- package/dist/types/toolkit/providers/strategy.d.ts.map +1 -0
- package/dist/{toolkit/storage.d.mts → types/toolkit/storage.d.ts} +37 -39
- package/dist/types/toolkit/storage.d.ts.map +1 -0
- package/dist/{toolkit/utils.d.mts → types/toolkit/utils.d.ts} +2 -4
- package/dist/types/toolkit/utils.d.ts.map +1 -0
- package/dist/types/types.d.ts +92 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/ui/base.d.ts +18 -0
- package/dist/types/ui/base.d.ts.map +1 -0
- package/dist/types/ui/code.d.ts +43 -0
- package/dist/types/ui/code.d.ts.map +1 -0
- package/dist/types/ui/form.d.ts +24 -0
- package/dist/types/ui/form.d.ts.map +1 -0
- package/dist/types/ui/icon.d.ts +60 -0
- package/dist/types/ui/icon.d.ts.map +1 -0
- package/dist/types/ui/magiclink.d.ts +41 -0
- package/dist/types/ui/magiclink.d.ts.map +1 -0
- package/dist/types/ui/password.d.ts +43 -0
- package/dist/types/ui/password.d.ts.map +1 -0
- package/dist/types/ui/select.d.ts +33 -0
- package/dist/types/ui/select.d.ts.map +1 -0
- package/dist/{util.d.mts → types/util.d.ts} +11 -13
- package/dist/types/util.d.ts.map +1 -0
- package/package.json +10 -16
- package/dist/adapters/node.d.mts +0 -18
- package/dist/adapters/node.mjs +0 -69
- package/dist/allow.mjs +0 -63
- package/dist/client.d.mts +0 -456
- package/dist/client.mjs +0 -283
- package/dist/core.d.mts +0 -110
- package/dist/core.mjs +0 -595
- package/dist/error.mjs +0 -237
- package/dist/index.d.mts +0 -2
- package/dist/index.mjs +0 -3
- package/dist/keys.mjs +0 -146
- package/dist/mutex.d.mts +0 -44
- package/dist/mutex.mjs +0 -110
- package/dist/pkce.mjs +0 -157
- package/dist/provider/apple.d.mts +0 -111
- package/dist/provider/apple.mjs +0 -164
- package/dist/provider/code.d.mts +0 -228
- package/dist/provider/code.mjs +0 -246
- package/dist/provider/discord.d.mts +0 -146
- package/dist/provider/discord.mjs +0 -156
- package/dist/provider/facebook.d.mts +0 -142
- package/dist/provider/facebook.mjs +0 -150
- package/dist/provider/github.d.mts +0 -140
- package/dist/provider/github.mjs +0 -169
- package/dist/provider/gitlab.d.mts +0 -106
- package/dist/provider/gitlab.mjs +0 -147
- package/dist/provider/google.d.mts +0 -112
- package/dist/provider/google.mjs +0 -109
- package/dist/provider/linkedin.d.mts +0 -132
- package/dist/provider/linkedin.mjs +0 -142
- package/dist/provider/magiclink.d.mts +0 -89
- package/dist/provider/magiclink.mjs +0 -143
- package/dist/provider/microsoft.d.mts +0 -178
- package/dist/provider/microsoft.mjs +0 -177
- package/dist/provider/oauth2.d.mts +0 -176
- package/dist/provider/oauth2.mjs +0 -222
- package/dist/provider/passkey.d.mts +0 -104
- package/dist/provider/passkey.mjs +0 -320
- package/dist/provider/password.d.mts +0 -412
- package/dist/provider/password.mjs +0 -363
- package/dist/provider/provider.d.mts +0 -227
- package/dist/provider/provider.mjs +0 -44
- package/dist/provider/reddit.d.mts +0 -107
- package/dist/provider/reddit.mjs +0 -127
- package/dist/provider/slack.d.mts +0 -114
- package/dist/provider/slack.mjs +0 -138
- package/dist/provider/spotify.d.mts +0 -113
- package/dist/provider/spotify.mjs +0 -135
- package/dist/provider/totp.d.mts +0 -112
- package/dist/provider/totp.mjs +0 -191
- package/dist/provider/twitch.d.mts +0 -108
- package/dist/provider/twitch.mjs +0 -131
- package/dist/provider/vercel.d.mts +0 -177
- package/dist/provider/vercel.mjs +0 -230
- package/dist/random.mjs +0 -86
- package/dist/revocation.d.mts +0 -55
- package/dist/revocation.mjs +0 -63
- package/dist/router/context.d.mts +0 -21
- package/dist/router/context.mjs +0 -193
- package/dist/router/cookies.d.mts +0 -8
- package/dist/router/cookies.mjs +0 -13
- package/dist/router/index.d.mts +0 -21
- package/dist/router/index.mjs +0 -107
- package/dist/router/matcher.d.mts +0 -15
- package/dist/router/matcher.mjs +0 -76
- package/dist/router/middleware/cors.d.mts +0 -15
- package/dist/router/middleware/cors.mjs +0 -114
- package/dist/router/safe-request.d.mts +0 -52
- package/dist/router/safe-request.mjs +0 -160
- package/dist/router/types.d.mts +0 -67
- package/dist/router/types.mjs +0 -1
- package/dist/router/variables.d.mts +0 -12
- package/dist/router/variables.mjs +0 -20
- package/dist/storage/memory.mjs +0 -125
- package/dist/storage/storage.d.mts +0 -179
- package/dist/storage/storage.mjs +0 -104
- package/dist/storage/turso.mjs +0 -117
- package/dist/storage/unstorage.mjs +0 -103
- package/dist/subject.d.mts +0 -62
- package/dist/subject.mjs +0 -36
- package/dist/themes/theme.d.mts +0 -209
- package/dist/themes/theme.mjs +0 -120
- package/dist/toolkit/client.d.mts +0 -169
- package/dist/toolkit/client.mjs +0 -209
- package/dist/toolkit/index.d.mts +0 -9
- package/dist/toolkit/index.mjs +0 -9
- package/dist/toolkit/providers/facebook.d.mts +0 -12
- package/dist/toolkit/providers/facebook.mjs +0 -16
- package/dist/toolkit/providers/github.d.mts +0 -12
- package/dist/toolkit/providers/github.mjs +0 -16
- package/dist/toolkit/providers/google.d.mts +0 -12
- package/dist/toolkit/providers/google.mjs +0 -20
- package/dist/toolkit/providers/strategy.d.mts +0 -40
- package/dist/toolkit/providers/strategy.mjs +0 -1
- package/dist/toolkit/storage.mjs +0 -157
- package/dist/toolkit/utils.mjs +0 -30
- package/dist/types.d.mts +0 -94
- package/dist/types.mjs +0 -1
- package/dist/ui/base.d.mts +0 -30
- package/dist/ui/base.mjs +0 -407
- package/dist/ui/code.d.mts +0 -43
- package/dist/ui/code.mjs +0 -173
- package/dist/ui/form.d.mts +0 -32
- package/dist/ui/form.mjs +0 -49
- package/dist/ui/icon.d.mts +0 -58
- package/dist/ui/icon.mjs +0 -247
- package/dist/ui/magiclink.d.mts +0 -41
- package/dist/ui/magiclink.mjs +0 -152
- package/dist/ui/passkey.d.mts +0 -27
- package/dist/ui/passkey.mjs +0 -323
- package/dist/ui/password.d.mts +0 -42
- package/dist/ui/password.mjs +0 -402
- package/dist/ui/select.d.mts +0 -34
- package/dist/ui/select.mjs +0 -98
- package/dist/ui/totp.d.mts +0 -34
- package/dist/ui/totp.mjs +0 -270
- package/dist/util.mjs +0 -128
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// src/storage/turso.ts
|
|
2
|
+
import { joinKey, splitKey } from "./storage";
|
|
3
|
+
var TursoStorage = (client) => {
|
|
4
|
+
const TABLE_NAME = "__draftauth__kv_storage";
|
|
5
|
+
client.execute(`
|
|
6
|
+
CREATE TABLE IF NOT EXISTS ${TABLE_NAME} (
|
|
7
|
+
key TEXT PRIMARY KEY,
|
|
8
|
+
value TEXT NOT NULL,
|
|
9
|
+
expiry INTEGER
|
|
10
|
+
)
|
|
11
|
+
`).catch(() => console.log(`Failed to create storage table: ${TABLE_NAME}`));
|
|
12
|
+
client.execute(`
|
|
13
|
+
CREATE INDEX IF NOT EXISTS idx_${TABLE_NAME}_key_prefix
|
|
14
|
+
ON ${TABLE_NAME} (key)
|
|
15
|
+
`).catch(() => console.log(`Failed to create index prefix for table: ${TABLE_NAME}`));
|
|
16
|
+
client.execute(`
|
|
17
|
+
CREATE INDEX IF NOT EXISTS idx_${TABLE_NAME}_expiry
|
|
18
|
+
ON ${TABLE_NAME} (expiry)
|
|
19
|
+
WHERE expiry IS NOT NULL
|
|
20
|
+
`).catch(() => console.log(`Failed to create index expiry-based for table: ${TABLE_NAME}`));
|
|
21
|
+
return {
|
|
22
|
+
async get(key) {
|
|
23
|
+
const joinedKey = joinKey(key);
|
|
24
|
+
const { rows } = await client.execute({
|
|
25
|
+
sql: `SELECT value, expiry FROM ${TABLE_NAME} WHERE key = ?`,
|
|
26
|
+
args: [joinedKey]
|
|
27
|
+
});
|
|
28
|
+
const row = rows[0];
|
|
29
|
+
if (!row) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (row.expiry && row.expiry < Date.now()) {
|
|
33
|
+
await client.execute({
|
|
34
|
+
sql: `DELETE FROM ${TABLE_NAME} WHERE key = ?`,
|
|
35
|
+
args: [joinedKey]
|
|
36
|
+
});
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(row.value);
|
|
41
|
+
} catch {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
async set(key, value, expiry) {
|
|
46
|
+
const joinedKey = joinKey(key);
|
|
47
|
+
const expiryTimestamp = expiry?.getTime() ?? null;
|
|
48
|
+
try {
|
|
49
|
+
const serializedValue = JSON.stringify(value);
|
|
50
|
+
await client.execute({
|
|
51
|
+
sql: `INSERT OR REPLACE INTO ${TABLE_NAME} (key, value, expiry) VALUES (?, ?, ?)`,
|
|
52
|
+
args: [joinedKey, serializedValue, expiryTimestamp]
|
|
53
|
+
});
|
|
54
|
+
} catch {
|
|
55
|
+
throw new Error("Storage operation failed");
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
async remove(key) {
|
|
59
|
+
const joinedKey = joinKey(key);
|
|
60
|
+
await client.execute({
|
|
61
|
+
sql: `DELETE FROM ${TABLE_NAME} WHERE key = ?`,
|
|
62
|
+
args: [joinedKey]
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
async* scan(prefix) {
|
|
66
|
+
const joinedPrefix = joinKey(prefix);
|
|
67
|
+
const now = Date.now();
|
|
68
|
+
const { rows } = await client.execute({
|
|
69
|
+
sql: `
|
|
70
|
+
SELECT key, value, expiry
|
|
71
|
+
FROM ${TABLE_NAME}
|
|
72
|
+
WHERE key LIKE ?
|
|
73
|
+
AND (expiry IS NULL OR expiry >= ?)
|
|
74
|
+
ORDER BY key
|
|
75
|
+
`,
|
|
76
|
+
args: [`${joinedPrefix}%`, now]
|
|
77
|
+
});
|
|
78
|
+
for (const row of rows) {
|
|
79
|
+
try {
|
|
80
|
+
const parsedValue = JSON.parse(row.value);
|
|
81
|
+
yield [splitKey(row.key), parsedValue];
|
|
82
|
+
} catch {}
|
|
83
|
+
}
|
|
84
|
+
client.execute({
|
|
85
|
+
sql: `DELETE FROM ${TABLE_NAME} WHERE expiry IS NOT NULL AND expiry < ?`,
|
|
86
|
+
args: [now]
|
|
87
|
+
}).catch(() => {});
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
export {
|
|
92
|
+
TursoStorage
|
|
93
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// src/storage/unstorage.ts
|
|
2
|
+
import { createStorage } from "unstorage";
|
|
3
|
+
import { joinKey, splitKey } from "./storage";
|
|
4
|
+
var UnStorage = ({ driver } = {}) => {
|
|
5
|
+
const store = createStorage({
|
|
6
|
+
driver
|
|
7
|
+
});
|
|
8
|
+
return {
|
|
9
|
+
async get(key) {
|
|
10
|
+
try {
|
|
11
|
+
const keyPath = joinKey(key);
|
|
12
|
+
const entry = await store.getItem(keyPath);
|
|
13
|
+
if (!entry) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (entry.expiry && Date.now() >= entry.expiry) {
|
|
17
|
+
store.removeItem(keyPath).catch(() => {});
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
return entry.value;
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error("UnStorage get error:", error);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
async set(key, value, expiry) {
|
|
27
|
+
try {
|
|
28
|
+
const keyPath = joinKey(key);
|
|
29
|
+
const entry = {
|
|
30
|
+
value,
|
|
31
|
+
expiry: expiry ? expiry.getTime() : undefined
|
|
32
|
+
};
|
|
33
|
+
await store.setItem(keyPath, entry);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error("UnStorage set error:", error);
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
async remove(key) {
|
|
40
|
+
try {
|
|
41
|
+
const keyPath = joinKey(key);
|
|
42
|
+
await store.removeItem(keyPath);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error("UnStorage remove error:", error);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
async* scan(prefix) {
|
|
48
|
+
try {
|
|
49
|
+
const now = Date.now();
|
|
50
|
+
const prefixPath = joinKey(prefix);
|
|
51
|
+
let keys = await store.getKeys(prefixPath);
|
|
52
|
+
if (keys.length === 0) {
|
|
53
|
+
const allKeys = await store.getKeys();
|
|
54
|
+
if (allKeys.length > 0) {
|
|
55
|
+
keys = allKeys.filter((key) => key.startsWith(prefixPath));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
for (const keyPath of keys) {
|
|
59
|
+
try {
|
|
60
|
+
const entry = await store.getItem(keyPath);
|
|
61
|
+
if (!entry || !entry.value)
|
|
62
|
+
continue;
|
|
63
|
+
if (entry.expiry && now >= entry.expiry) {
|
|
64
|
+
store.removeItem(keyPath).catch(() => {});
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
yield [splitKey(keyPath), entry.value];
|
|
68
|
+
} catch {}
|
|
69
|
+
}
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error("UnStorage scan error:", error);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
export {
|
|
77
|
+
UnStorage
|
|
78
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// src/themes/theme.ts
|
|
2
|
+
var THEME_DRAFTAUTH = {
|
|
3
|
+
title: "Draft Auth",
|
|
4
|
+
radius: "none",
|
|
5
|
+
background: {
|
|
6
|
+
dark: "black",
|
|
7
|
+
light: "white"
|
|
8
|
+
},
|
|
9
|
+
primary: {
|
|
10
|
+
dark: "white",
|
|
11
|
+
light: "black"
|
|
12
|
+
},
|
|
13
|
+
font: {
|
|
14
|
+
family: "IBM Plex Sans, sans-serif"
|
|
15
|
+
},
|
|
16
|
+
css: `
|
|
17
|
+
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@100;200;300;400;500;600;700&display=swap');
|
|
18
|
+
`
|
|
19
|
+
};
|
|
20
|
+
var THEME_TERMINAL = {
|
|
21
|
+
title: "terminal",
|
|
22
|
+
radius: "none",
|
|
23
|
+
favicon: "https://www.terminal.shop/favicon.svg",
|
|
24
|
+
logo: {
|
|
25
|
+
dark: "https://www.terminal.shop/images/logo-white.svg",
|
|
26
|
+
light: "https://www.terminal.shop/images/logo-black.svg"
|
|
27
|
+
},
|
|
28
|
+
primary: "#ff5e00",
|
|
29
|
+
background: {
|
|
30
|
+
dark: "rgb(0, 0, 0)",
|
|
31
|
+
light: "rgb(255, 255, 255)"
|
|
32
|
+
},
|
|
33
|
+
font: {
|
|
34
|
+
family: "Geist Mono, monospace"
|
|
35
|
+
},
|
|
36
|
+
css: `
|
|
37
|
+
@import url('https://fonts.googleapis.com/css2?family=Geist+Mono:wght@100;200;300;400;500;600;700;800;900&display=swap');
|
|
38
|
+
`
|
|
39
|
+
};
|
|
40
|
+
var THEME_SST = {
|
|
41
|
+
title: "SST",
|
|
42
|
+
favicon: "https://sst.dev/favicon.svg",
|
|
43
|
+
logo: {
|
|
44
|
+
dark: "https://sst.dev/favicon.svg",
|
|
45
|
+
light: "https://sst.dev/favicon.svg"
|
|
46
|
+
},
|
|
47
|
+
background: {
|
|
48
|
+
dark: "#1a1a2d",
|
|
49
|
+
light: "rgb(255, 255, 255)"
|
|
50
|
+
},
|
|
51
|
+
primary: "#f3663f",
|
|
52
|
+
font: {
|
|
53
|
+
family: "Rubik, sans-serif"
|
|
54
|
+
},
|
|
55
|
+
css: `
|
|
56
|
+
@import url('https://fonts.googleapis.com/css2?family=Rubik:wght@100;200;300;400;500;600;700;800;900&display=swap');
|
|
57
|
+
`
|
|
58
|
+
};
|
|
59
|
+
var THEME_SUPABASE = {
|
|
60
|
+
title: "Supabase",
|
|
61
|
+
logo: {
|
|
62
|
+
dark: "https://supabase.com/dashboard/_next/image?url=%2Fdashboard%2Fimg%2Fsupabase-dark.svg&w=128&q=75",
|
|
63
|
+
light: "https://supabase.com/dashboard/_next/image?url=%2Fdashboard%2Fimg%2Fsupabase-light.svg&w=128&q=75"
|
|
64
|
+
},
|
|
65
|
+
background: {
|
|
66
|
+
dark: "#171717",
|
|
67
|
+
light: "#f8f8f8"
|
|
68
|
+
},
|
|
69
|
+
primary: {
|
|
70
|
+
dark: "#006239",
|
|
71
|
+
light: "#72e3ad"
|
|
72
|
+
},
|
|
73
|
+
font: {
|
|
74
|
+
family: "Varela Round, sans-serif"
|
|
75
|
+
},
|
|
76
|
+
css: `
|
|
77
|
+
@import url('https://fonts.googleapis.com/css2?family=Varela+Round:wght@100;200;300;400;500;600;700;800;900&display=swap');
|
|
78
|
+
`
|
|
79
|
+
};
|
|
80
|
+
var THEME_VERCEL = {
|
|
81
|
+
title: "Vercel",
|
|
82
|
+
logo: {
|
|
83
|
+
dark: "https://vercel.com/mktng/_next/static/media/vercel-logotype-dark.e8c0a742.svg",
|
|
84
|
+
light: "https://vercel.com/mktng/_next/static/media/vercel-logotype-light.700a8d26.svg"
|
|
85
|
+
},
|
|
86
|
+
background: {
|
|
87
|
+
dark: "black",
|
|
88
|
+
light: "white"
|
|
89
|
+
},
|
|
90
|
+
primary: {
|
|
91
|
+
dark: "white",
|
|
92
|
+
light: "black"
|
|
93
|
+
},
|
|
94
|
+
font: {
|
|
95
|
+
family: "Geist, sans-serif"
|
|
96
|
+
},
|
|
97
|
+
css: `
|
|
98
|
+
@import url('https://fonts.googleapis.com/css2?family=Geist:wght@100;200;300;400;500;600;700;800;900&display=swap');
|
|
99
|
+
`
|
|
100
|
+
};
|
|
101
|
+
var setTheme = (value) => {
|
|
102
|
+
globalThis.DRAFTAUTH_THEME = value;
|
|
103
|
+
};
|
|
104
|
+
var getTheme = () => {
|
|
105
|
+
return globalThis.DRAFTAUTH_THEME || THEME_DRAFTAUTH;
|
|
106
|
+
};
|
|
107
|
+
export {
|
|
108
|
+
setTheme,
|
|
109
|
+
getTheme,
|
|
110
|
+
THEME_VERCEL,
|
|
111
|
+
THEME_TERMINAL,
|
|
112
|
+
THEME_SUPABASE,
|
|
113
|
+
THEME_SST,
|
|
114
|
+
THEME_DRAFTAUTH
|
|
115
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// src/toolkit/client.ts
|
|
2
|
+
import { generatePKCE } from "../pkce";
|
|
3
|
+
import { createSessionStorage } from "./storage";
|
|
4
|
+
import { generateSecureRandom } from "./utils";
|
|
5
|
+
var createOAuthClient = (config) => {
|
|
6
|
+
const storage = config.storage || (typeof sessionStorage !== "undefined" ? createSessionStorage() : null);
|
|
7
|
+
if (!storage) {
|
|
8
|
+
throw new Error("No storage adapter provided. Please provide a storage adapter for server-side environments.");
|
|
9
|
+
}
|
|
10
|
+
return {
|
|
11
|
+
async authorize(provider, options) {
|
|
12
|
+
const providerConfig = config.providers[provider];
|
|
13
|
+
if (!providerConfig) {
|
|
14
|
+
throw new Error(`Provider '${String(provider)}' not configured`);
|
|
15
|
+
}
|
|
16
|
+
const pkce = await generatePKCE();
|
|
17
|
+
const state = generateSecureRandom(16);
|
|
18
|
+
await storage.set({
|
|
19
|
+
state,
|
|
20
|
+
verifier: pkce.verifier,
|
|
21
|
+
provider: String(provider),
|
|
22
|
+
nonce: options?.nonce
|
|
23
|
+
});
|
|
24
|
+
const scopes = options?.scopes || providerConfig.scopes || providerConfig.strategy.scopes;
|
|
25
|
+
const params = new URLSearchParams({
|
|
26
|
+
client_id: providerConfig.clientId,
|
|
27
|
+
redirect_uri: providerConfig.redirectUri,
|
|
28
|
+
response_type: "code",
|
|
29
|
+
scope: Array.isArray(scopes) ? scopes.join(" ") : scopes,
|
|
30
|
+
state,
|
|
31
|
+
code_challenge: pkce.challenge,
|
|
32
|
+
code_challenge_method: pkce.method,
|
|
33
|
+
...options?.params
|
|
34
|
+
});
|
|
35
|
+
const url = `${providerConfig.strategy.authorizationEndpoint}?${params.toString()}`;
|
|
36
|
+
return { url, state };
|
|
37
|
+
},
|
|
38
|
+
async handleCallback(callbackUrl) {
|
|
39
|
+
const url = new URL(callbackUrl);
|
|
40
|
+
const code = url.searchParams.get("code");
|
|
41
|
+
const state = url.searchParams.get("state");
|
|
42
|
+
const error = url.searchParams.get("error");
|
|
43
|
+
const errorDescription = url.searchParams.get("error_description");
|
|
44
|
+
if (error) {
|
|
45
|
+
throw new Error(`OAuth error: ${error}${errorDescription ? ` - ${errorDescription}` : ""}`);
|
|
46
|
+
}
|
|
47
|
+
if (!code || !state) {
|
|
48
|
+
throw new Error("Invalid callback URL: missing code or state parameter");
|
|
49
|
+
}
|
|
50
|
+
const storedState = await storage.get();
|
|
51
|
+
await storage.clear();
|
|
52
|
+
if (!storedState) {
|
|
53
|
+
throw new Error("No stored PKCE state found. OAuth flow may have expired or been tampered with.");
|
|
54
|
+
}
|
|
55
|
+
if (state !== storedState.state) {
|
|
56
|
+
throw new Error("State mismatch. Possible CSRF attack detected.");
|
|
57
|
+
}
|
|
58
|
+
const providerConfig = config.providers[storedState.provider];
|
|
59
|
+
if (!providerConfig) {
|
|
60
|
+
throw new Error(`Provider '${storedState.provider}' from callback not configured`);
|
|
61
|
+
}
|
|
62
|
+
const tokenParams = new URLSearchParams({
|
|
63
|
+
grant_type: "authorization_code",
|
|
64
|
+
code,
|
|
65
|
+
redirect_uri: providerConfig.redirectUri,
|
|
66
|
+
client_id: providerConfig.clientId,
|
|
67
|
+
client_secret: providerConfig.clientSecret,
|
|
68
|
+
code_verifier: storedState.verifier
|
|
69
|
+
});
|
|
70
|
+
const tokenResponse = await fetch(providerConfig.strategy.tokenEndpoint, {
|
|
71
|
+
method: "POST",
|
|
72
|
+
headers: {
|
|
73
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
74
|
+
Accept: "application/json"
|
|
75
|
+
},
|
|
76
|
+
body: tokenParams
|
|
77
|
+
});
|
|
78
|
+
if (!tokenResponse.ok) {
|
|
79
|
+
const errorText = await tokenResponse.text();
|
|
80
|
+
throw new Error(`Token exchange failed (${tokenResponse.status}): ${errorText}`);
|
|
81
|
+
}
|
|
82
|
+
const tokenData = await tokenResponse.json();
|
|
83
|
+
if (!tokenData.access_token) {
|
|
84
|
+
throw new Error("No access token in provider response");
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
provider: storedState.provider,
|
|
88
|
+
accessToken: tokenData.access_token,
|
|
89
|
+
refreshToken: tokenData.refresh_token,
|
|
90
|
+
expiresIn: tokenData.expires_in,
|
|
91
|
+
tokenType: tokenData.token_type,
|
|
92
|
+
idToken: tokenData.id_token
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
async getUserInfo(provider, accessToken) {
|
|
96
|
+
const providerConfig = config.providers[provider];
|
|
97
|
+
if (!providerConfig) {
|
|
98
|
+
throw new Error(`Provider '${String(provider)}' not configured`);
|
|
99
|
+
}
|
|
100
|
+
if (!providerConfig.strategy.userInfoEndpoint) {
|
|
101
|
+
throw new Error(`Provider '${String(provider)}' does not support user info endpoint`);
|
|
102
|
+
}
|
|
103
|
+
const response = await fetch(providerConfig.strategy.userInfoEndpoint, {
|
|
104
|
+
headers: {
|
|
105
|
+
Authorization: `Bearer ${accessToken}`,
|
|
106
|
+
Accept: "application/json"
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
const errorText = await response.text();
|
|
111
|
+
throw new Error(`Failed to fetch user info (${response.status}): ${errorText}`);
|
|
112
|
+
}
|
|
113
|
+
return response.json();
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
export {
|
|
118
|
+
createOAuthClient
|
|
119
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// src/toolkit/index.ts
|
|
2
|
+
import { generatePKCE } from "../pkce";
|
|
3
|
+
import { createOAuthClient } from "./client";
|
|
4
|
+
import { FacebookStrategy } from "./providers/facebook";
|
|
5
|
+
import { GitHubStrategy } from "./providers/github";
|
|
6
|
+
import { GoogleStrategy } from "./providers/google";
|
|
7
|
+
import {
|
|
8
|
+
createCookieStorage,
|
|
9
|
+
createLocalStorage,
|
|
10
|
+
createMemoryStorage,
|
|
11
|
+
createSessionStorage
|
|
12
|
+
} from "./storage";
|
|
13
|
+
import { generateSecureRandom } from "./utils";
|
|
14
|
+
export {
|
|
15
|
+
generateSecureRandom,
|
|
16
|
+
generatePKCE,
|
|
17
|
+
createSessionStorage,
|
|
18
|
+
createOAuthClient,
|
|
19
|
+
createMemoryStorage,
|
|
20
|
+
createLocalStorage,
|
|
21
|
+
createCookieStorage,
|
|
22
|
+
GoogleStrategy,
|
|
23
|
+
GitHubStrategy,
|
|
24
|
+
FacebookStrategy
|
|
25
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// src/toolkit/providers/facebook.ts
|
|
2
|
+
var FacebookStrategy = {
|
|
3
|
+
name: "facebook",
|
|
4
|
+
authorizationEndpoint: "https://www.facebook.com/v23.0/dialog/oauth",
|
|
5
|
+
tokenEndpoint: "https://graph.facebook.com/v23.0/oauth/access_token",
|
|
6
|
+
userInfoEndpoint: "https://graph.facebook.com/me?fields=id,name,email",
|
|
7
|
+
scopes: ["public_profile", "email"]
|
|
8
|
+
};
|
|
9
|
+
export {
|
|
10
|
+
FacebookStrategy
|
|
11
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// src/toolkit/providers/github.ts
|
|
2
|
+
var GitHubStrategy = {
|
|
3
|
+
name: "github",
|
|
4
|
+
authorizationEndpoint: "https://github.com/login/oauth/authorize",
|
|
5
|
+
tokenEndpoint: "https://github.com/login/oauth/access_token",
|
|
6
|
+
userInfoEndpoint: "https://api.github.com/user",
|
|
7
|
+
scopes: ["read:user", "user:email"]
|
|
8
|
+
};
|
|
9
|
+
export {
|
|
10
|
+
GitHubStrategy
|
|
11
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// src/toolkit/providers/google.ts
|
|
2
|
+
var GoogleStrategy = {
|
|
3
|
+
name: "google",
|
|
4
|
+
authorizationEndpoint: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
5
|
+
tokenEndpoint: "https://oauth2.googleapis.com/token",
|
|
6
|
+
userInfoEndpoint: "https://www.googleapis.com/oauth2/v3/userinfo",
|
|
7
|
+
scopes: ["openid", "email", "profile"]
|
|
8
|
+
};
|
|
9
|
+
export {
|
|
10
|
+
GoogleStrategy
|
|
11
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// src/toolkit/storage.ts
|
|
2
|
+
var STORAGE_KEY = "draftauth.pkce";
|
|
3
|
+
var createSessionStorage = () => ({
|
|
4
|
+
set: (data) => {
|
|
5
|
+
if (typeof sessionStorage === "undefined") {
|
|
6
|
+
throw new Error("sessionStorage is not available in this environment");
|
|
7
|
+
}
|
|
8
|
+
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(data));
|
|
9
|
+
},
|
|
10
|
+
get: () => {
|
|
11
|
+
if (typeof sessionStorage === "undefined") {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
const data = sessionStorage.getItem(STORAGE_KEY);
|
|
15
|
+
return data ? JSON.parse(data) : null;
|
|
16
|
+
},
|
|
17
|
+
clear: () => {
|
|
18
|
+
if (typeof sessionStorage === "undefined") {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
sessionStorage.removeItem(STORAGE_KEY);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
var createLocalStorage = () => ({
|
|
25
|
+
set: (data) => {
|
|
26
|
+
if (typeof localStorage === "undefined") {
|
|
27
|
+
throw new Error("localStorage is not available in this environment");
|
|
28
|
+
}
|
|
29
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
|
|
30
|
+
},
|
|
31
|
+
get: () => {
|
|
32
|
+
if (typeof localStorage === "undefined") {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const data = localStorage.getItem(STORAGE_KEY);
|
|
36
|
+
return data ? JSON.parse(data) : null;
|
|
37
|
+
},
|
|
38
|
+
clear: () => {
|
|
39
|
+
if (typeof localStorage === "undefined") {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
localStorage.removeItem(STORAGE_KEY);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
var createMemoryStorage = () => {
|
|
46
|
+
let state = null;
|
|
47
|
+
return {
|
|
48
|
+
set: (data) => {
|
|
49
|
+
state = data;
|
|
50
|
+
},
|
|
51
|
+
get: () => {
|
|
52
|
+
return state;
|
|
53
|
+
},
|
|
54
|
+
clear: () => {
|
|
55
|
+
state = null;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
var createCookieStorage = (options) => ({
|
|
60
|
+
set: async (data) => {
|
|
61
|
+
await options.setCookie(STORAGE_KEY, JSON.stringify(data), {
|
|
62
|
+
maxAge: 60 * 10,
|
|
63
|
+
httpOnly: true,
|
|
64
|
+
secure: false,
|
|
65
|
+
sameSite: "lax"
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
get: async () => {
|
|
69
|
+
const value = await options.getCookie(STORAGE_KEY);
|
|
70
|
+
return value ? JSON.parse(value) : null;
|
|
71
|
+
},
|
|
72
|
+
clear: async () => {
|
|
73
|
+
await options.deleteCookie(STORAGE_KEY);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
export {
|
|
77
|
+
createSessionStorage,
|
|
78
|
+
createMemoryStorage,
|
|
79
|
+
createLocalStorage,
|
|
80
|
+
createCookieStorage
|
|
81
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// src/toolkit/utils.ts
|
|
2
|
+
var generateSecureRandom = (length = 32) => {
|
|
3
|
+
if (length <= 0 || !Number.isInteger(length)) {
|
|
4
|
+
throw new RangeError("Length must be a positive integer");
|
|
5
|
+
}
|
|
6
|
+
const randomBytes = new Uint8Array(length);
|
|
7
|
+
crypto.getRandomValues(randomBytes);
|
|
8
|
+
let base64 = "";
|
|
9
|
+
if (typeof btoa !== "undefined") {
|
|
10
|
+
base64 = btoa(String.fromCharCode(...randomBytes));
|
|
11
|
+
} else {
|
|
12
|
+
base64 = Buffer.from(randomBytes).toString("base64");
|
|
13
|
+
}
|
|
14
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
15
|
+
};
|
|
16
|
+
export {
|
|
17
|
+
generateSecureRandom
|
|
18
|
+
};
|
|
File without changes
|