@draftlab/auth 0.10.4 → 0.12.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/core.d.mts +0 -3
- package/dist/core.mjs +0 -36
- package/dist/toolkit/client.d.mts +169 -0
- package/dist/toolkit/client.mjs +209 -0
- package/dist/toolkit/index.d.mts +9 -0
- package/dist/toolkit/index.mjs +9 -0
- package/dist/toolkit/providers/facebook.d.mts +12 -0
- package/dist/toolkit/providers/facebook.mjs +16 -0
- package/dist/toolkit/providers/github.d.mts +12 -0
- package/dist/toolkit/providers/github.mjs +16 -0
- package/dist/toolkit/providers/google.d.mts +12 -0
- package/dist/toolkit/providers/google.mjs +20 -0
- package/dist/toolkit/providers/strategy.d.mts +40 -0
- package/dist/toolkit/storage.d.mts +145 -0
- package/dist/toolkit/storage.mjs +157 -0
- package/dist/toolkit/utils.d.mts +21 -0
- package/dist/toolkit/utils.mjs +30 -0
- package/package.json +3 -3
- package/dist/plugin/builder.d.mts +0 -27
- package/dist/plugin/builder.mjs +0 -93
- package/dist/plugin/manager.d.mts +0 -62
- package/dist/plugin/manager.mjs +0 -160
- package/dist/plugin/plugin.d.mts +0 -42
- package/dist/plugin/types.d.mts +0 -99
- package/dist/plugin/types.mjs +0 -13
- /package/dist/{plugin/plugin.mjs → toolkit/providers/strategy.mjs} +0 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
//#region src/toolkit/storage.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Storage adapters for PKCE state management across different runtime environments.
|
|
4
|
+
* Provides implementations for browser (sessionStorage/localStorage), server (cookies),
|
|
5
|
+
* and custom storage backends.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* PKCE state data stored during OAuth flow.
|
|
9
|
+
*/
|
|
10
|
+
interface PKCEState {
|
|
11
|
+
/** Random state parameter for CSRF protection */
|
|
12
|
+
readonly state: string;
|
|
13
|
+
/** PKCE code verifier for token exchange */
|
|
14
|
+
readonly verifier: string;
|
|
15
|
+
/** OAuth provider identifier */
|
|
16
|
+
readonly provider: string;
|
|
17
|
+
/** Optional nonce for additional security */
|
|
18
|
+
readonly nonce?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Storage interface for persisting PKCE state during OAuth flow.
|
|
22
|
+
* Implement this interface to provide custom storage backends.
|
|
23
|
+
*/
|
|
24
|
+
interface AuthStorage {
|
|
25
|
+
/**
|
|
26
|
+
* Store PKCE state data.
|
|
27
|
+
* @param state - PKCE state to persist
|
|
28
|
+
*/
|
|
29
|
+
set(state: PKCEState): void | Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Retrieve stored PKCE state data.
|
|
32
|
+
* @returns Stored state or null if not found
|
|
33
|
+
*/
|
|
34
|
+
get(): PKCEState | null | Promise<PKCEState | null>;
|
|
35
|
+
/**
|
|
36
|
+
* Clear stored PKCE state data.
|
|
37
|
+
*/
|
|
38
|
+
clear(): void | Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Creates a browser sessionStorage adapter for PKCE state.
|
|
42
|
+
* Suitable for client-side SPAs where state should only persist during the browser session.
|
|
43
|
+
*
|
|
44
|
+
* @returns AuthStorage implementation using sessionStorage
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* const storage = createSessionStorage()
|
|
49
|
+
*
|
|
50
|
+
* // Use in toolkit client
|
|
51
|
+
* const client = createOAuthClient({
|
|
52
|
+
* storage,
|
|
53
|
+
* providers: { ... }
|
|
54
|
+
* })
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
declare const createSessionStorage: () => AuthStorage;
|
|
58
|
+
/**
|
|
59
|
+
* Creates a browser localStorage adapter for PKCE state.
|
|
60
|
+
* Suitable for client-side SPAs where state should persist across browser sessions.
|
|
61
|
+
*
|
|
62
|
+
* ⚠️ Warning: localStorage persists data indefinitely. Consider using sessionStorage
|
|
63
|
+
* for better security, as it automatically clears on browser close.
|
|
64
|
+
*
|
|
65
|
+
* @returns AuthStorage implementation using localStorage
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* const storage = createLocalStorage()
|
|
70
|
+
*
|
|
71
|
+
* // Use in toolkit client
|
|
72
|
+
* const client = createOAuthClient({
|
|
73
|
+
* storage,
|
|
74
|
+
* providers: { ... }
|
|
75
|
+
* })
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
declare const createLocalStorage: () => AuthStorage;
|
|
79
|
+
/**
|
|
80
|
+
* Creates a memory-based storage adapter for PKCE state.
|
|
81
|
+
* Suitable for server-side rendering or testing environments.
|
|
82
|
+
* State is lost when the process terminates or page reloads.
|
|
83
|
+
*
|
|
84
|
+
* @returns AuthStorage implementation using in-memory storage
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* // Server-side or testing
|
|
89
|
+
* const storage = createMemoryStorage()
|
|
90
|
+
*
|
|
91
|
+
* const client = createOAuthClient({
|
|
92
|
+
* storage,
|
|
93
|
+
* providers: { ... }
|
|
94
|
+
* })
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
declare const createMemoryStorage: () => AuthStorage;
|
|
98
|
+
/**
|
|
99
|
+
* Creates a cookie-based storage adapter for PKCE state.
|
|
100
|
+
* Suitable for server-side OAuth flows (Next.js, Remix, etc.) where you need
|
|
101
|
+
* to persist state across requests.
|
|
102
|
+
*
|
|
103
|
+
* @param options - Cookie configuration options
|
|
104
|
+
* @returns AuthStorage implementation using cookies
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```ts
|
|
108
|
+
* // Next.js App Router
|
|
109
|
+
* import { cookies } from 'next/headers'
|
|
110
|
+
*
|
|
111
|
+
* const storage = createCookieStorage({
|
|
112
|
+
* getCookie: (name) => cookies().get(name)?.value ?? null,
|
|
113
|
+
* setCookie: (name, value, opts) => {
|
|
114
|
+
* cookies().set(name, value, {
|
|
115
|
+
* httpOnly: true,
|
|
116
|
+
* secure: true,
|
|
117
|
+
* sameSite: 'lax',
|
|
118
|
+
* maxAge: opts.maxAge
|
|
119
|
+
* })
|
|
120
|
+
* },
|
|
121
|
+
* deleteCookie: (name) => cookies().delete(name)
|
|
122
|
+
* })
|
|
123
|
+
*
|
|
124
|
+
* // TanStack Start
|
|
125
|
+
* import { getCookie, setCookie, deleteCookie } from '@tanstack/react-start/server'
|
|
126
|
+
*
|
|
127
|
+
* const storage = createCookieStorage({
|
|
128
|
+
* getCookie,
|
|
129
|
+
* setCookie: (name, value, opts) => setCookie(name, value, opts),
|
|
130
|
+
* deleteCookie
|
|
131
|
+
* })
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
declare const createCookieStorage: (options: {
|
|
135
|
+
getCookie: (name: string) => string | null | Promise<string | null>;
|
|
136
|
+
setCookie: (name: string, value: string, options: {
|
|
137
|
+
maxAge?: number;
|
|
138
|
+
httpOnly?: boolean;
|
|
139
|
+
secure?: boolean;
|
|
140
|
+
sameSite?: string;
|
|
141
|
+
}) => void | Promise<void>;
|
|
142
|
+
deleteCookie: (name: string) => void | Promise<void>;
|
|
143
|
+
}) => AuthStorage;
|
|
144
|
+
//#endregion
|
|
145
|
+
export { AuthStorage, PKCEState, createCookieStorage, createLocalStorage, createMemoryStorage, createSessionStorage };
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
//#region src/toolkit/storage.ts
|
|
2
|
+
const STORAGE_KEY = "draftauth.pkce";
|
|
3
|
+
/**
|
|
4
|
+
* Creates a browser sessionStorage adapter for PKCE state.
|
|
5
|
+
* Suitable for client-side SPAs where state should only persist during the browser session.
|
|
6
|
+
*
|
|
7
|
+
* @returns AuthStorage implementation using sessionStorage
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const storage = createSessionStorage()
|
|
12
|
+
*
|
|
13
|
+
* // Use in toolkit client
|
|
14
|
+
* const client = createOAuthClient({
|
|
15
|
+
* storage,
|
|
16
|
+
* providers: { ... }
|
|
17
|
+
* })
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
const createSessionStorage = () => ({
|
|
21
|
+
set: (data) => {
|
|
22
|
+
if (typeof sessionStorage === "undefined") throw new Error("sessionStorage is not available in this environment");
|
|
23
|
+
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(data));
|
|
24
|
+
},
|
|
25
|
+
get: () => {
|
|
26
|
+
if (typeof sessionStorage === "undefined") return null;
|
|
27
|
+
const data = sessionStorage.getItem(STORAGE_KEY);
|
|
28
|
+
return data ? JSON.parse(data) : null;
|
|
29
|
+
},
|
|
30
|
+
clear: () => {
|
|
31
|
+
if (typeof sessionStorage === "undefined") return;
|
|
32
|
+
sessionStorage.removeItem(STORAGE_KEY);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
/**
|
|
36
|
+
* Creates a browser localStorage adapter for PKCE state.
|
|
37
|
+
* Suitable for client-side SPAs where state should persist across browser sessions.
|
|
38
|
+
*
|
|
39
|
+
* ⚠️ Warning: localStorage persists data indefinitely. Consider using sessionStorage
|
|
40
|
+
* for better security, as it automatically clears on browser close.
|
|
41
|
+
*
|
|
42
|
+
* @returns AuthStorage implementation using localStorage
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* const storage = createLocalStorage()
|
|
47
|
+
*
|
|
48
|
+
* // Use in toolkit client
|
|
49
|
+
* const client = createOAuthClient({
|
|
50
|
+
* storage,
|
|
51
|
+
* providers: { ... }
|
|
52
|
+
* })
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
const createLocalStorage = () => ({
|
|
56
|
+
set: (data) => {
|
|
57
|
+
if (typeof localStorage === "undefined") throw new Error("localStorage is not available in this environment");
|
|
58
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
|
|
59
|
+
},
|
|
60
|
+
get: () => {
|
|
61
|
+
if (typeof localStorage === "undefined") return null;
|
|
62
|
+
const data = localStorage.getItem(STORAGE_KEY);
|
|
63
|
+
return data ? JSON.parse(data) : null;
|
|
64
|
+
},
|
|
65
|
+
clear: () => {
|
|
66
|
+
if (typeof localStorage === "undefined") return;
|
|
67
|
+
localStorage.removeItem(STORAGE_KEY);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
/**
|
|
71
|
+
* Creates a memory-based storage adapter for PKCE state.
|
|
72
|
+
* Suitable for server-side rendering or testing environments.
|
|
73
|
+
* State is lost when the process terminates or page reloads.
|
|
74
|
+
*
|
|
75
|
+
* @returns AuthStorage implementation using in-memory storage
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* // Server-side or testing
|
|
80
|
+
* const storage = createMemoryStorage()
|
|
81
|
+
*
|
|
82
|
+
* const client = createOAuthClient({
|
|
83
|
+
* storage,
|
|
84
|
+
* providers: { ... }
|
|
85
|
+
* })
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
const createMemoryStorage = () => {
|
|
89
|
+
let state = null;
|
|
90
|
+
return {
|
|
91
|
+
set: (data) => {
|
|
92
|
+
state = data;
|
|
93
|
+
},
|
|
94
|
+
get: () => {
|
|
95
|
+
return state;
|
|
96
|
+
},
|
|
97
|
+
clear: () => {
|
|
98
|
+
state = null;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Creates a cookie-based storage adapter for PKCE state.
|
|
104
|
+
* Suitable for server-side OAuth flows (Next.js, Remix, etc.) where you need
|
|
105
|
+
* to persist state across requests.
|
|
106
|
+
*
|
|
107
|
+
* @param options - Cookie configuration options
|
|
108
|
+
* @returns AuthStorage implementation using cookies
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* // Next.js App Router
|
|
113
|
+
* import { cookies } from 'next/headers'
|
|
114
|
+
*
|
|
115
|
+
* const storage = createCookieStorage({
|
|
116
|
+
* getCookie: (name) => cookies().get(name)?.value ?? null,
|
|
117
|
+
* setCookie: (name, value, opts) => {
|
|
118
|
+
* cookies().set(name, value, {
|
|
119
|
+
* httpOnly: true,
|
|
120
|
+
* secure: true,
|
|
121
|
+
* sameSite: 'lax',
|
|
122
|
+
* maxAge: opts.maxAge
|
|
123
|
+
* })
|
|
124
|
+
* },
|
|
125
|
+
* deleteCookie: (name) => cookies().delete(name)
|
|
126
|
+
* })
|
|
127
|
+
*
|
|
128
|
+
* // TanStack Start
|
|
129
|
+
* import { getCookie, setCookie, deleteCookie } from '@tanstack/react-start/server'
|
|
130
|
+
*
|
|
131
|
+
* const storage = createCookieStorage({
|
|
132
|
+
* getCookie,
|
|
133
|
+
* setCookie: (name, value, opts) => setCookie(name, value, opts),
|
|
134
|
+
* deleteCookie
|
|
135
|
+
* })
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
const createCookieStorage = (options) => ({
|
|
139
|
+
set: async (data) => {
|
|
140
|
+
await options.setCookie(STORAGE_KEY, JSON.stringify(data), {
|
|
141
|
+
maxAge: 600,
|
|
142
|
+
httpOnly: true,
|
|
143
|
+
secure: process.env.NODE_ENV === "production",
|
|
144
|
+
sameSite: "lax"
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
get: async () => {
|
|
148
|
+
const value = await options.getCookie(STORAGE_KEY);
|
|
149
|
+
return value ? JSON.parse(value) : null;
|
|
150
|
+
},
|
|
151
|
+
clear: async () => {
|
|
152
|
+
await options.deleteCookie(STORAGE_KEY);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
//#endregion
|
|
157
|
+
export { createCookieStorage, createLocalStorage, createMemoryStorage, createSessionStorage };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/toolkit/utils.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Universal utilities for the OAuth toolkit.
|
|
4
|
+
* These functions work in both browser and Node.js environments.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Generates a cryptographically secure random string using Web Crypto API.
|
|
8
|
+
* Works in both browser and Node.js environments (Node 15+).
|
|
9
|
+
*
|
|
10
|
+
* @param length - Length of random data in bytes (default: 32 for 256-bit security)
|
|
11
|
+
* @returns Base64url-encoded secure random string
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const state = generateSecureRandom(16) // 128-bit random state
|
|
16
|
+
* const token = generateSecureRandom(32) // 256-bit random token
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
declare const generateSecureRandom: (length?: number) => string;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { generateSecureRandom };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/toolkit/utils.ts
|
|
2
|
+
/**
|
|
3
|
+
* Universal utilities for the OAuth toolkit.
|
|
4
|
+
* These functions work in both browser and Node.js environments.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Generates a cryptographically secure random string using Web Crypto API.
|
|
8
|
+
* Works in both browser and Node.js environments (Node 15+).
|
|
9
|
+
*
|
|
10
|
+
* @param length - Length of random data in bytes (default: 32 for 256-bit security)
|
|
11
|
+
* @returns Base64url-encoded secure random string
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const state = generateSecureRandom(16) // 128-bit random state
|
|
16
|
+
* const token = generateSecureRandom(32) // 256-bit random token
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
const generateSecureRandom = (length = 32) => {
|
|
20
|
+
if (length <= 0 || !Number.isInteger(length)) throw new RangeError("Length must be a positive integer");
|
|
21
|
+
const randomBytes = new Uint8Array(length);
|
|
22
|
+
crypto.getRandomValues(randomBytes);
|
|
23
|
+
let base64 = "";
|
|
24
|
+
if (typeof btoa !== "undefined") base64 = btoa(String.fromCharCode(...randomBytes));
|
|
25
|
+
else base64 = Buffer.from(randomBytes).toString("base64");
|
|
26
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
export { generateSecureRandom };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@draftlab/auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Core implementation for @draftlab/auth",
|
|
6
6
|
"author": "Matheus Pergoli",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "^25.0.3",
|
|
41
41
|
"@types/qrcode": "^1.5.6",
|
|
42
|
-
"tsdown": "^0.18.
|
|
42
|
+
"tsdown": "^0.18.3",
|
|
43
43
|
"typescript": "^5.9.3",
|
|
44
44
|
"@draftlab/tsconfig": "0.1.0"
|
|
45
45
|
},
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"preact": "^10.28.1",
|
|
64
64
|
"preact-render-to-string": "^6.6.4",
|
|
65
65
|
"qrcode": "^1.5.4",
|
|
66
|
-
"@draftlab/auth-router": "0.
|
|
66
|
+
"@draftlab/auth-router": "0.5.0"
|
|
67
67
|
},
|
|
68
68
|
"engines": {
|
|
69
69
|
"node": ">=18"
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { PluginBuilder } from "./plugin.mjs";
|
|
2
|
-
|
|
3
|
-
//#region src/plugin/builder.d.ts
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Create a new plugin builder.
|
|
7
|
-
* Plugins are built using a fluent API that supports routes and lifecycle hooks.
|
|
8
|
-
*
|
|
9
|
-
* @param id - Unique identifier for the plugin
|
|
10
|
-
* @returns Plugin builder with chainable methods
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```ts
|
|
14
|
-
* const analytics = plugin("analytics")
|
|
15
|
-
* .onSuccess(async (ctx) => {
|
|
16
|
-
* await ctx.storage.set(`success:${ctx.clientID}`, ctx.subject)
|
|
17
|
-
* })
|
|
18
|
-
* .post("/stats", async (ctx) => {
|
|
19
|
-
* const stats = await ctx.pluginStorage.get("stats")
|
|
20
|
-
* return ctx.json(stats)
|
|
21
|
-
* })
|
|
22
|
-
* .build()
|
|
23
|
-
* ```
|
|
24
|
-
*/
|
|
25
|
-
declare const plugin: (id: string) => PluginBuilder;
|
|
26
|
-
//#endregion
|
|
27
|
-
export { plugin };
|
package/dist/plugin/builder.mjs
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
//#region src/plugin/builder.ts
|
|
2
|
-
/**
|
|
3
|
-
* Create a new plugin builder.
|
|
4
|
-
* Plugins are built using a fluent API that supports routes and lifecycle hooks.
|
|
5
|
-
*
|
|
6
|
-
* @param id - Unique identifier for the plugin
|
|
7
|
-
* @returns Plugin builder with chainable methods
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```ts
|
|
11
|
-
* const analytics = plugin("analytics")
|
|
12
|
-
* .onSuccess(async (ctx) => {
|
|
13
|
-
* await ctx.storage.set(`success:${ctx.clientID}`, ctx.subject)
|
|
14
|
-
* })
|
|
15
|
-
* .post("/stats", async (ctx) => {
|
|
16
|
-
* const stats = await ctx.pluginStorage.get("stats")
|
|
17
|
-
* return ctx.json(stats)
|
|
18
|
-
* })
|
|
19
|
-
* .build()
|
|
20
|
-
* ```
|
|
21
|
-
*/
|
|
22
|
-
const plugin = (id) => {
|
|
23
|
-
if (!id || typeof id !== "string") throw new Error("Plugin id must be a non-empty string");
|
|
24
|
-
const routes = [];
|
|
25
|
-
const registeredPaths = /* @__PURE__ */ new Set();
|
|
26
|
-
let initHook;
|
|
27
|
-
let authorizeHook;
|
|
28
|
-
let successHook;
|
|
29
|
-
let errorHook;
|
|
30
|
-
const validatePath = (path) => {
|
|
31
|
-
if (!path || typeof path !== "string") throw new Error("Route path must be a non-empty string");
|
|
32
|
-
if (!path.startsWith("/")) throw new Error("Route path must start with '/'");
|
|
33
|
-
};
|
|
34
|
-
return {
|
|
35
|
-
get(path, handler) {
|
|
36
|
-
validatePath(path);
|
|
37
|
-
const routeKey = `GET ${path}`;
|
|
38
|
-
if (registeredPaths.has(routeKey)) throw new Error(`Route ${routeKey} already registered in plugin '${id}'`);
|
|
39
|
-
registeredPaths.add(routeKey);
|
|
40
|
-
routes.push({
|
|
41
|
-
method: "GET",
|
|
42
|
-
path,
|
|
43
|
-
handler
|
|
44
|
-
});
|
|
45
|
-
return this;
|
|
46
|
-
},
|
|
47
|
-
post(path, handler) {
|
|
48
|
-
validatePath(path);
|
|
49
|
-
const routeKey = `POST ${path}`;
|
|
50
|
-
if (registeredPaths.has(routeKey)) throw new Error(`Route ${routeKey} already registered in plugin '${id}'`);
|
|
51
|
-
registeredPaths.add(routeKey);
|
|
52
|
-
routes.push({
|
|
53
|
-
method: "POST",
|
|
54
|
-
path,
|
|
55
|
-
handler
|
|
56
|
-
});
|
|
57
|
-
return this;
|
|
58
|
-
},
|
|
59
|
-
onInit(handler) {
|
|
60
|
-
if (initHook) throw new Error(`onInit hook already defined for plugin '${id}'`);
|
|
61
|
-
initHook = handler;
|
|
62
|
-
return this;
|
|
63
|
-
},
|
|
64
|
-
onAuthorize(handler) {
|
|
65
|
-
if (authorizeHook) throw new Error(`onAuthorize hook already defined for plugin '${id}'`);
|
|
66
|
-
authorizeHook = handler;
|
|
67
|
-
return this;
|
|
68
|
-
},
|
|
69
|
-
onSuccess(handler) {
|
|
70
|
-
if (successHook) throw new Error(`onSuccess hook already defined for plugin '${id}'`);
|
|
71
|
-
successHook = handler;
|
|
72
|
-
return this;
|
|
73
|
-
},
|
|
74
|
-
onError(handler) {
|
|
75
|
-
if (errorHook) throw new Error(`onError hook already defined for plugin '${id}'`);
|
|
76
|
-
errorHook = handler;
|
|
77
|
-
return this;
|
|
78
|
-
},
|
|
79
|
-
build() {
|
|
80
|
-
return {
|
|
81
|
-
id,
|
|
82
|
-
routes: routes.length > 0 ? routes : void 0,
|
|
83
|
-
onInit: initHook,
|
|
84
|
-
onAuthorize: authorizeHook,
|
|
85
|
-
onSuccess: successHook,
|
|
86
|
-
onError: errorHook
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
//#endregion
|
|
93
|
-
export { plugin };
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { StorageAdapter } from "../storage/storage.mjs";
|
|
2
|
-
import { Plugin } from "./types.mjs";
|
|
3
|
-
import { Router } from "@draftlab/auth-router";
|
|
4
|
-
|
|
5
|
-
//#region src/plugin/manager.d.ts
|
|
6
|
-
|
|
7
|
-
declare class PluginManager {
|
|
8
|
-
private readonly plugins;
|
|
9
|
-
private readonly storage;
|
|
10
|
-
constructor(storage: StorageAdapter);
|
|
11
|
-
/**
|
|
12
|
-
* Register a plugin
|
|
13
|
-
*/
|
|
14
|
-
register(plugin: Plugin): void;
|
|
15
|
-
/**
|
|
16
|
-
* Register multiple plugins at once
|
|
17
|
-
*/
|
|
18
|
-
registerAll(plugins: Plugin[]): void;
|
|
19
|
-
/**
|
|
20
|
-
* Get all registered plugins
|
|
21
|
-
*/
|
|
22
|
-
getAll(): Plugin[];
|
|
23
|
-
/**
|
|
24
|
-
* Get plugin by id
|
|
25
|
-
*/
|
|
26
|
-
get(id: string): Plugin | undefined;
|
|
27
|
-
/**
|
|
28
|
-
* Initialize all plugins.
|
|
29
|
-
* Called once during issuer setup.
|
|
30
|
-
* Plugins can set up initial state or validate configuration.
|
|
31
|
-
*
|
|
32
|
-
* @throws PluginError if any plugin initialization fails
|
|
33
|
-
*/
|
|
34
|
-
initialize(): Promise<void>;
|
|
35
|
-
/**
|
|
36
|
-
* Execute authorize hooks for all plugins.
|
|
37
|
-
* Called before processing an authorization request.
|
|
38
|
-
* Can validate, rate limit, or enhance the request.
|
|
39
|
-
*/
|
|
40
|
-
executeAuthorizeHooks(clientID: string, provider?: string, scopes?: string[]): Promise<void>;
|
|
41
|
-
/**
|
|
42
|
-
* Execute success hooks for all plugins.
|
|
43
|
-
* Called after successful authentication.
|
|
44
|
-
* Runs in parallel for better performance.
|
|
45
|
-
* Plugins cannot modify the response.
|
|
46
|
-
*/
|
|
47
|
-
executeSuccessHooks(clientID: string, provider: string | undefined, subject: {
|
|
48
|
-
type: string;
|
|
49
|
-
properties: Record<string, unknown>;
|
|
50
|
-
}): Promise<void>;
|
|
51
|
-
/**
|
|
52
|
-
* Execute error hooks for all plugins.
|
|
53
|
-
* Called when an authentication error occurs.
|
|
54
|
-
*/
|
|
55
|
-
executeErrorHooks(error: Error, clientID?: string, provider?: string): Promise<void>;
|
|
56
|
-
/**
|
|
57
|
-
* Setup plugin routes on a router
|
|
58
|
-
*/
|
|
59
|
-
setupRoutes(router: Router): void;
|
|
60
|
-
}
|
|
61
|
-
//#endregion
|
|
62
|
-
export { PluginManager };
|