@draftlab/auth 0.6.0 → 0.8.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.mjs +34 -3
- package/dist/plugin/builder.d.mts +18 -1
- package/dist/plugin/builder.mjs +47 -3
- package/dist/plugin/manager.d.mts +29 -0
- package/dist/plugin/manager.mjs +94 -1
- package/dist/plugin/plugin.d.mts +30 -5
- package/dist/plugin/types.d.mts +61 -2
- package/dist/ui/icon.d.mts +41 -4
- package/dist/ui/icon.mjs +196 -19
- package/dist/ui/select.mjs +27 -4
- package/package.json +1 -1
package/dist/core.mjs
CHANGED
|
@@ -187,6 +187,15 @@ const issuer = (input) => {
|
|
|
187
187
|
const authorization = await getAuthorization(ctx);
|
|
188
188
|
const currentProvider = ctx.get("provider") || "unknown";
|
|
189
189
|
if (!authorization.client_id) throw new Error("client_id is required");
|
|
190
|
+
if (manager) try {
|
|
191
|
+
const subjectProperties = properties && typeof properties === "object" ? properties : {};
|
|
192
|
+
await manager.executeSuccessHooks(authorization.client_id, currentProvider, {
|
|
193
|
+
type: currentProvider,
|
|
194
|
+
properties: subjectProperties
|
|
195
|
+
});
|
|
196
|
+
} catch (error$1) {
|
|
197
|
+
console.error("Plugin success hook failed:", error$1);
|
|
198
|
+
}
|
|
190
199
|
return await input.success({ async subject(type, properties$1, subjectOpts) {
|
|
191
200
|
const subject = subjectOpts?.subject ?? await resolveSubject(type, properties$1);
|
|
192
201
|
await successOpts?.invalidate?.(await resolveSubject(type, properties$1));
|
|
@@ -276,10 +285,21 @@ const issuer = (input) => {
|
|
|
276
285
|
storage
|
|
277
286
|
};
|
|
278
287
|
const app = new Router({ basePath: input.basePath });
|
|
279
|
-
|
|
280
|
-
|
|
288
|
+
const manager = input.plugins && input.plugins.length > 0 ? new PluginManager(input.storage) : null;
|
|
289
|
+
let pluginsInitialized = false;
|
|
290
|
+
if (manager && input.plugins) {
|
|
281
291
|
manager.registerAll(input.plugins);
|
|
282
292
|
manager.setupRoutes(app);
|
|
293
|
+
app.use(async (c, next) => {
|
|
294
|
+
if (!pluginsInitialized) try {
|
|
295
|
+
await manager.initialize();
|
|
296
|
+
pluginsInitialized = true;
|
|
297
|
+
} catch (error$1) {
|
|
298
|
+
console.error("Plugin initialization failed:", error$1);
|
|
299
|
+
return c.newResponse("Plugin initialization failed", { status: 500 });
|
|
300
|
+
}
|
|
301
|
+
return await next();
|
|
302
|
+
});
|
|
283
303
|
}
|
|
284
304
|
for (const [name, value] of Object.entries(input.providers)) {
|
|
285
305
|
const route = new Router();
|
|
@@ -498,13 +518,14 @@ const issuer = (input) => {
|
|
|
498
518
|
const audience = c.query("audience");
|
|
499
519
|
const code_challenge = c.query("code_challenge");
|
|
500
520
|
const code_challenge_method = c.query("code_challenge_method");
|
|
521
|
+
const scope = c.query("scope");
|
|
501
522
|
const authorization = {
|
|
502
523
|
response_type,
|
|
503
524
|
redirect_uri,
|
|
504
525
|
state,
|
|
505
526
|
client_id,
|
|
506
527
|
audience,
|
|
507
|
-
scope
|
|
528
|
+
scope,
|
|
508
529
|
...code_challenge && code_challenge_method && { pkce: {
|
|
509
530
|
challenge: code_challenge,
|
|
510
531
|
method: code_challenge_method
|
|
@@ -520,6 +541,10 @@ const issuer = (input) => {
|
|
|
520
541
|
redirectURI: redirect_uri,
|
|
521
542
|
audience
|
|
522
543
|
}, c.request)) throw new UnauthorizedClientError(client_id, redirect_uri);
|
|
544
|
+
if (manager) {
|
|
545
|
+
const scopes = scope ? scope.split(" ") : void 0;
|
|
546
|
+
await manager.executeAuthorizeHooks(client_id, provider, scopes);
|
|
547
|
+
}
|
|
523
548
|
await auth.set(c, "authorization", 900, authorization);
|
|
524
549
|
if (provider) return c.redirect(`${provider}/authorize`);
|
|
525
550
|
const availableProviders = Object.keys(input.providers);
|
|
@@ -527,6 +552,12 @@ const issuer = (input) => {
|
|
|
527
552
|
return auth.forward(c, await select()(Object.fromEntries(Object.entries(input.providers).map(([key, value]) => [key, value.type])), c.request));
|
|
528
553
|
});
|
|
529
554
|
app.onError(async (err, c) => {
|
|
555
|
+
if (manager) try {
|
|
556
|
+
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
557
|
+
await manager.executeErrorHooks(errorObj);
|
|
558
|
+
} catch (hookError) {
|
|
559
|
+
console.error("Plugin error hook failed:", hookError);
|
|
560
|
+
}
|
|
530
561
|
if (err instanceof UnknownStateError) return auth.forward(c, await error(err, c.request));
|
|
531
562
|
try {
|
|
532
563
|
const authorization = await getAuthorization(c);
|
|
@@ -3,7 +3,24 @@ import { PluginBuilder } from "./plugin.mjs";
|
|
|
3
3
|
//#region src/plugin/builder.d.ts
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Create a new plugin
|
|
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
|
+
* ```
|
|
7
24
|
*/
|
|
8
25
|
declare const plugin: (id: string) => PluginBuilder;
|
|
9
26
|
//#endregion
|
package/dist/plugin/builder.mjs
CHANGED
|
@@ -1,11 +1,32 @@
|
|
|
1
1
|
//#region src/plugin/builder.ts
|
|
2
2
|
/**
|
|
3
|
-
* Create a new plugin
|
|
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
|
+
* ```
|
|
4
21
|
*/
|
|
5
22
|
const plugin = (id) => {
|
|
6
23
|
if (!id || typeof id !== "string") throw new Error("Plugin id must be a non-empty string");
|
|
7
24
|
const routes = [];
|
|
8
25
|
const registeredPaths = /* @__PURE__ */ new Set();
|
|
26
|
+
let initHook;
|
|
27
|
+
let authorizeHook;
|
|
28
|
+
let successHook;
|
|
29
|
+
let errorHook;
|
|
9
30
|
const validatePath = (path) => {
|
|
10
31
|
if (!path || typeof path !== "string") throw new Error("Route path must be a non-empty string");
|
|
11
32
|
if (!path.startsWith("/")) throw new Error("Route path must start with '/'");
|
|
@@ -35,11 +56,34 @@ const plugin = (id) => {
|
|
|
35
56
|
});
|
|
36
57
|
return this;
|
|
37
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
|
+
},
|
|
38
79
|
build() {
|
|
39
|
-
if (routes.length === 0) throw new Error(`Plugin '${id}' has no routes defined`);
|
|
40
80
|
return {
|
|
41
81
|
id,
|
|
42
|
-
routes
|
|
82
|
+
routes: routes.length > 0 ? routes : void 0,
|
|
83
|
+
onInit: initHook,
|
|
84
|
+
onAuthorize: authorizeHook,
|
|
85
|
+
onSuccess: successHook,
|
|
86
|
+
onError: errorHook
|
|
43
87
|
};
|
|
44
88
|
}
|
|
45
89
|
};
|
|
@@ -24,6 +24,35 @@ declare class PluginManager {
|
|
|
24
24
|
* Get plugin by id
|
|
25
25
|
*/
|
|
26
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>;
|
|
27
56
|
/**
|
|
28
57
|
* Setup plugin routes on a router
|
|
29
58
|
*/
|
package/dist/plugin/manager.mjs
CHANGED
|
@@ -33,6 +33,99 @@ var PluginManager = class {
|
|
|
33
33
|
return this.plugins.get(id);
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
|
+
* Initialize all plugins.
|
|
37
|
+
* Called once during issuer setup.
|
|
38
|
+
* Plugins can set up initial state or validate configuration.
|
|
39
|
+
*
|
|
40
|
+
* @throws PluginError if any plugin initialization fails
|
|
41
|
+
*/
|
|
42
|
+
async initialize() {
|
|
43
|
+
for (const plugin of this.plugins.values()) {
|
|
44
|
+
if (!plugin.onInit) continue;
|
|
45
|
+
try {
|
|
46
|
+
const context = {
|
|
47
|
+
pluginId: plugin.id,
|
|
48
|
+
request: new Request("http://internal/init"),
|
|
49
|
+
now: /* @__PURE__ */ new Date(),
|
|
50
|
+
storage: this.storage
|
|
51
|
+
};
|
|
52
|
+
await plugin.onInit(context);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
throw new PluginError(`Initialization failed: ${error instanceof Error ? error.message : String(error)}`, plugin.id);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Execute authorize hooks for all plugins.
|
|
60
|
+
* Called before processing an authorization request.
|
|
61
|
+
* Can validate, rate limit, or enhance the request.
|
|
62
|
+
*/
|
|
63
|
+
async executeAuthorizeHooks(clientID, provider, scopes) {
|
|
64
|
+
for (const plugin of this.plugins.values()) {
|
|
65
|
+
if (!plugin.onAuthorize) continue;
|
|
66
|
+
try {
|
|
67
|
+
const context = {
|
|
68
|
+
pluginId: plugin.id,
|
|
69
|
+
request: new Request("http://internal/authorize"),
|
|
70
|
+
now: /* @__PURE__ */ new Date(),
|
|
71
|
+
storage: this.storage,
|
|
72
|
+
clientID,
|
|
73
|
+
provider,
|
|
74
|
+
scopes
|
|
75
|
+
};
|
|
76
|
+
await plugin.onAuthorize(context);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
throw new PluginError(`Authorization hook failed: ${error instanceof Error ? error.message : String(error)}`, plugin.id);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Execute success hooks for all plugins.
|
|
84
|
+
* Called after successful authentication.
|
|
85
|
+
* Runs in parallel for better performance.
|
|
86
|
+
* Plugins cannot modify the response.
|
|
87
|
+
*/
|
|
88
|
+
async executeSuccessHooks(clientID, provider, subject) {
|
|
89
|
+
const hooks = Array.from(this.plugins.values()).filter((p) => p.onSuccess).map(async (plugin) => {
|
|
90
|
+
const context = {
|
|
91
|
+
pluginId: plugin.id,
|
|
92
|
+
request: new Request("http://internal/success"),
|
|
93
|
+
now: /* @__PURE__ */ new Date(),
|
|
94
|
+
storage: this.storage,
|
|
95
|
+
clientID,
|
|
96
|
+
provider,
|
|
97
|
+
subject
|
|
98
|
+
};
|
|
99
|
+
return plugin.onSuccess?.(context).catch((error) => {
|
|
100
|
+
console.error(`[Plugin: ${plugin.id}] Success hook failed:`, error instanceof Error ? error.message : String(error));
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
await Promise.all(hooks);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Execute error hooks for all plugins.
|
|
107
|
+
* Called when an authentication error occurs.
|
|
108
|
+
*/
|
|
109
|
+
async executeErrorHooks(error, clientID, provider) {
|
|
110
|
+
for (const plugin of this.plugins.values()) {
|
|
111
|
+
if (!plugin.onError) continue;
|
|
112
|
+
try {
|
|
113
|
+
const context = {
|
|
114
|
+
pluginId: plugin.id,
|
|
115
|
+
request: new Request("http://internal/error"),
|
|
116
|
+
now: /* @__PURE__ */ new Date(),
|
|
117
|
+
storage: this.storage,
|
|
118
|
+
error,
|
|
119
|
+
clientID,
|
|
120
|
+
provider
|
|
121
|
+
};
|
|
122
|
+
await plugin.onError(context);
|
|
123
|
+
} catch (hookError) {
|
|
124
|
+
console.error(`[Plugin: ${plugin.id}] Error hook failed:`, hookError instanceof Error ? hookError.message : String(hookError));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
36
129
|
* Setup plugin routes on a router
|
|
37
130
|
*/
|
|
38
131
|
setupRoutes(router) {
|
|
@@ -40,7 +133,7 @@ var PluginManager = class {
|
|
|
40
133
|
for (const plugin of this.plugins.values()) {
|
|
41
134
|
if (!plugin.routes) continue;
|
|
42
135
|
for (const route of plugin.routes) {
|
|
43
|
-
const fullPath =
|
|
136
|
+
const fullPath = `/plugin/${plugin.id}${route.path}`;
|
|
44
137
|
if (registeredPaths.has(fullPath)) throw new PluginError(`Route conflict: ${fullPath} already registered`, plugin.id);
|
|
45
138
|
registeredPaths.add(fullPath);
|
|
46
139
|
const handler = async (ctx) => {
|
package/dist/plugin/plugin.d.mts
CHANGED
|
@@ -1,16 +1,41 @@
|
|
|
1
|
-
import { Plugin, PluginRouteHandler } from "./types.mjs";
|
|
1
|
+
import { Plugin, PluginAuthorizeHook, PluginErrorHook, PluginInitHook, PluginRouteHandler, PluginSuccessHook } from "./types.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/plugin/plugin.d.ts
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Plugin builder interface
|
|
6
|
+
* Plugin builder interface for creating plugins with a fluent API.
|
|
7
|
+
*
|
|
8
|
+
* The builder pattern allows for elegant plugin definition:
|
|
9
|
+
* - Chain route definitions with lifecycle hooks
|
|
10
|
+
* - Each method returns this for chaining
|
|
11
|
+
* - Build finalizes the plugin definition
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const myPlugin = plugin("my-plugin")
|
|
16
|
+
* .onInit(async (ctx) => {
|
|
17
|
+
* console.log("Plugin initialized")
|
|
18
|
+
* })
|
|
19
|
+
* .post("/action", async (ctx) => {
|
|
20
|
+
* return ctx.json({ success: true })
|
|
21
|
+
* })
|
|
22
|
+
* .build()
|
|
23
|
+
* ```
|
|
7
24
|
*/
|
|
8
25
|
interface PluginBuilder {
|
|
9
|
-
/**
|
|
26
|
+
/** Register a GET route */
|
|
10
27
|
get(path: string, handler: PluginRouteHandler): PluginBuilder;
|
|
11
|
-
/**
|
|
28
|
+
/** Register a POST route */
|
|
12
29
|
post(path: string, handler: PluginRouteHandler): PluginBuilder;
|
|
13
|
-
/**
|
|
30
|
+
/** Register initialization hook (called once during issuer setup) */
|
|
31
|
+
onInit(handler: PluginInitHook): PluginBuilder;
|
|
32
|
+
/** Register authorization hook (called before authorization request) */
|
|
33
|
+
onAuthorize(handler: PluginAuthorizeHook): PluginBuilder;
|
|
34
|
+
/** Register success hook (called after successful authentication) */
|
|
35
|
+
onSuccess(handler: PluginSuccessHook): PluginBuilder;
|
|
36
|
+
/** Register error hook (called when authentication fails) */
|
|
37
|
+
onError(handler: PluginErrorHook): PluginBuilder;
|
|
38
|
+
/** Build the final plugin */
|
|
14
39
|
build(): Plugin;
|
|
15
40
|
}
|
|
16
41
|
//#endregion
|
package/dist/plugin/types.d.mts
CHANGED
|
@@ -22,13 +22,72 @@ interface PluginRoute {
|
|
|
22
22
|
readonly handler: PluginRouteHandler;
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
25
|
+
* Lifecycle hook context provided to plugin hooks.
|
|
26
|
+
* Contains information about the current operation and access to isolated storage.
|
|
27
|
+
*/
|
|
28
|
+
interface PluginHookContext {
|
|
29
|
+
/** Unique identifier for the plugin */
|
|
30
|
+
pluginId: string;
|
|
31
|
+
/** Raw request object */
|
|
32
|
+
request: Request;
|
|
33
|
+
/** Current time for consistency across hook execution */
|
|
34
|
+
now: Date;
|
|
35
|
+
/** Storage adapter for data persistence */
|
|
36
|
+
storage: StorageAdapter;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Hook called when the issuer is being initialized.
|
|
40
|
+
* Useful for plugins that need to set up initial state or validate configuration.
|
|
41
|
+
* Should complete quickly - takes place during server startup.
|
|
42
|
+
*/
|
|
43
|
+
type PluginInitHook = (context: PluginHookContext) => Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Hook called before an authorization request is processed.
|
|
46
|
+
* Use for validation, rate limiting, or request enhancement.
|
|
47
|
+
*/
|
|
48
|
+
type PluginAuthorizeHook = (context: PluginHookContext & {
|
|
49
|
+
clientID: string;
|
|
50
|
+
provider?: string;
|
|
51
|
+
scopes?: string[];
|
|
52
|
+
}) => Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Hook called after successful authentication.
|
|
55
|
+
* Use for logging, analytics, webhooks, or side effects.
|
|
56
|
+
* Cannot modify the response - hooks run in parallel.
|
|
57
|
+
*/
|
|
58
|
+
type PluginSuccessHook = (context: PluginHookContext & {
|
|
59
|
+
clientID: string;
|
|
60
|
+
provider?: string;
|
|
61
|
+
subject: {
|
|
62
|
+
type: string;
|
|
63
|
+
properties: Record<string, unknown>;
|
|
64
|
+
};
|
|
65
|
+
}) => Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Hook called when an authentication error occurs.
|
|
68
|
+
* Use for error logging, custom error pages, or error transformation.
|
|
69
|
+
*/
|
|
70
|
+
type PluginErrorHook = (context: PluginHookContext & {
|
|
71
|
+
error: Error;
|
|
72
|
+
clientID?: string;
|
|
73
|
+
provider?: string;
|
|
74
|
+
}) => Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Main plugin interface with lifecycle hooks and storage isolation
|
|
26
77
|
*/
|
|
27
78
|
interface Plugin {
|
|
28
79
|
/** Unique plugin identifier */
|
|
29
80
|
readonly id: string;
|
|
30
81
|
/** Custom routes added by this plugin */
|
|
31
82
|
readonly routes?: readonly PluginRoute[];
|
|
83
|
+
/** Called once when the issuer initializes */
|
|
84
|
+
readonly onInit?: PluginInitHook;
|
|
85
|
+
/** Called before authorization request is processed */
|
|
86
|
+
readonly onAuthorize?: PluginAuthorizeHook;
|
|
87
|
+
/** Called after successful authentication */
|
|
88
|
+
readonly onSuccess?: PluginSuccessHook;
|
|
89
|
+
/** Called when an error occurs during authentication */
|
|
90
|
+
readonly onError?: PluginErrorHook;
|
|
32
91
|
}
|
|
33
92
|
/**
|
|
34
93
|
* Plugin error types
|
|
@@ -37,4 +96,4 @@ declare class PluginError extends Error {
|
|
|
37
96
|
constructor(message: string, pluginId: string);
|
|
38
97
|
}
|
|
39
98
|
//#endregion
|
|
40
|
-
export { Plugin, PluginContext, PluginError, PluginRoute, PluginRouteHandler };
|
|
99
|
+
export { Plugin, PluginAuthorizeHook, PluginContext, PluginError, PluginErrorHook, PluginHookContext, PluginInitHook, PluginRoute, PluginRouteHandler, PluginSuccessHook };
|
package/dist/ui/icon.d.mts
CHANGED
|
@@ -4,18 +4,55 @@ import { ComponentChildren } from "preact";
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* GitHub brand icon with official logo design.
|
|
7
|
-
* Used for GitHub authentication provider buttons and references.
|
|
8
7
|
*/
|
|
9
8
|
declare const ICON_GITHUB: () => ComponentChildren;
|
|
10
9
|
/**
|
|
11
10
|
* Google brand icon with official multicolor logo design.
|
|
12
|
-
* Used for Google authentication provider buttons and references.
|
|
13
11
|
*/
|
|
14
12
|
declare const ICON_GOOGLE: () => ComponentChildren;
|
|
15
13
|
/**
|
|
16
14
|
* Email envelope icon for email-related authentication flows.
|
|
17
|
-
* Used in email verification, password reset, and contact forms.
|
|
18
15
|
*/
|
|
19
16
|
declare const ICON_EMAIL: () => ComponentChildren;
|
|
17
|
+
/**
|
|
18
|
+
* Apple brand icon for Sign in with Apple.
|
|
19
|
+
*/
|
|
20
|
+
declare const ICON_APPLE: () => ComponentChildren;
|
|
21
|
+
/**
|
|
22
|
+
* Discord brand icon.
|
|
23
|
+
*/
|
|
24
|
+
declare const ICON_DISCORD: () => ComponentChildren;
|
|
25
|
+
/**
|
|
26
|
+
* Facebook brand icon with gradient.
|
|
27
|
+
*/
|
|
28
|
+
declare const ICON_FACEBOOK: () => ComponentChildren;
|
|
29
|
+
/**
|
|
30
|
+
* LinkedIn brand icon.
|
|
31
|
+
*/
|
|
32
|
+
declare const ICON_LINKEDIN: () => ComponentChildren;
|
|
33
|
+
/**
|
|
34
|
+
* Microsoft brand icon with four color squares.
|
|
35
|
+
*/
|
|
36
|
+
declare const ICON_MICROSOFT: () => ComponentChildren;
|
|
37
|
+
/**
|
|
38
|
+
* Slack brand icon.
|
|
39
|
+
*/
|
|
40
|
+
declare const ICON_SLACK: () => ComponentChildren;
|
|
41
|
+
/**
|
|
42
|
+
* GitLab brand icon.
|
|
43
|
+
*/
|
|
44
|
+
declare const ICON_GITLAB: () => ComponentChildren;
|
|
45
|
+
/**
|
|
46
|
+
* Reddit brand icon.
|
|
47
|
+
*/
|
|
48
|
+
declare const ICON_REDDIT: () => ComponentChildren;
|
|
49
|
+
/**
|
|
50
|
+
* Spotify brand icon.
|
|
51
|
+
*/
|
|
52
|
+
declare const ICON_SPOTIFY: () => ComponentChildren;
|
|
53
|
+
/**
|
|
54
|
+
* Twitch brand icon.
|
|
55
|
+
*/
|
|
56
|
+
declare const ICON_TWITCH: () => ComponentChildren;
|
|
20
57
|
//#endregion
|
|
21
|
-
export { ICON_EMAIL, ICON_GITHUB, ICON_GOOGLE };
|
|
58
|
+
export { ICON_APPLE, ICON_DISCORD, ICON_EMAIL, ICON_FACEBOOK, ICON_GITHUB, ICON_GITLAB, ICON_GOOGLE, ICON_LINKEDIN, ICON_MICROSOFT, ICON_REDDIT, ICON_SLACK, ICON_SPOTIFY, ICON_TWITCH };
|
package/dist/ui/icon.mjs
CHANGED
|
@@ -3,31 +3,29 @@ import { jsx, jsxs } from "preact/jsx-runtime";
|
|
|
3
3
|
//#region src/ui/icon.tsx
|
|
4
4
|
/**
|
|
5
5
|
* GitHub brand icon with official logo design.
|
|
6
|
-
* Used for GitHub authentication provider buttons and references.
|
|
7
6
|
*/
|
|
8
7
|
const ICON_GITHUB = () => /* @__PURE__ */ jsx("svg", {
|
|
9
|
-
"aria-label": "GitHub",
|
|
10
|
-
fill: "currentColor",
|
|
11
|
-
height: "250",
|
|
12
|
-
preserveAspectRatio: "xMidYMid",
|
|
13
8
|
role: "img",
|
|
14
9
|
viewBox: "0 0 256 250",
|
|
15
10
|
width: "256",
|
|
11
|
+
height: "250",
|
|
12
|
+
fill: "currentColor",
|
|
16
13
|
xmlns: "http://www.w3.org/2000/svg",
|
|
14
|
+
preserveAspectRatio: "xMidYMid",
|
|
15
|
+
"aria-label": "GitHub",
|
|
17
16
|
children: /* @__PURE__ */ jsx("path", { d: "M128.001 0C57.317 0 0 57.307 0 128.001c0 56.554 36.676 104.535 87.535 121.46 6.397 1.185 8.746-2.777 8.746-6.158 0-3.052-.12-13.135-.174-23.83-35.61 7.742-43.124-15.103-43.124-15.103-5.823-14.795-14.213-18.73-14.213-18.73-11.613-7.944.876-7.78.876-7.78 12.853.902 19.621 13.19 19.621 13.19 11.417 19.568 29.945 13.911 37.249 10.64 1.149-8.272 4.466-13.92 8.127-17.116-28.431-3.236-58.318-14.212-58.318-63.258 0-13.975 5-25.394 13.188-34.358-1.329-3.224-5.71-16.242 1.24-33.874 0 0 10.749-3.44 35.21 13.121 10.21-2.836 21.16-4.258 32.038-4.307 10.878.049 21.837 1.47 32.066 4.307 24.431-16.56 35.165-13.12 35.165-13.12 6.967 17.63 2.584 30.65 1.255 33.873 8.207 8.964 13.173 20.383 13.173 34.358 0 49.163-29.944 59.988-58.447 63.157 4.591 3.972 8.682 11.762 8.682 23.704 0 17.126-.148 30.91-.148 35.126 0 3.407 2.304 7.398 8.792 6.14C219.37 232.5 256 184.537 256 128.002 256 57.307 198.691 0 128.001 0Zm-80.06 182.34c-.282.636-1.283.827-2.194.39-.929-.417-1.45-1.284-1.15-1.922.276-.655 1.279-.838 2.205-.399.93.418 1.46 1.293 1.139 1.931Zm6.296 5.618c-.61.566-1.804.303-2.614-.591-.837-.892-.994-2.086-.375-2.66.63-.566 1.787-.301 2.626.591.838.903 1 2.088.363 2.66Zm4.32 7.188c-.785.545-2.067.034-2.86-1.104-.784-1.138-.784-2.503.017-3.05.795-.547 2.058-.055 2.861 1.075.782 1.157.782 2.522-.019 3.08Zm7.304 8.325c-.701.774-2.196.566-3.29-.49-1.119-1.032-1.43-2.496-.726-3.27.71-.776 2.213-.558 3.315.49 1.11 1.03 1.45 2.505.701 3.27Zm9.442 2.81c-.31 1.003-1.75 1.459-3.199 1.033-1.448-.439-2.395-1.613-2.103-2.626.301-1.01 1.747-1.484 3.207-1.028 1.446.436 2.396 1.602 2.095 2.622Zm10.744 1.193c.036 1.055-1.193 1.93-2.715 1.95-1.53.034-2.769-.82-2.786-1.86 0-1.065 1.202-1.932 2.733-1.958 1.522-.03 2.768.818 2.768 1.868Zm10.555-.405c.182 1.03-.875 2.088-2.387 2.37-1.485.271-2.861-.365-3.05-1.386-.184-1.056.893-2.114 2.376-2.387 1.514-.263 2.868.356 3.061 1.403Z" })
|
|
18
17
|
});
|
|
19
18
|
/**
|
|
20
19
|
* Google brand icon with official multicolor logo design.
|
|
21
|
-
* Used for Google authentication provider buttons and references.
|
|
22
20
|
*/
|
|
23
21
|
const ICON_GOOGLE = () => /* @__PURE__ */ jsxs("svg", {
|
|
24
|
-
"aria-label": "Google",
|
|
25
|
-
height: "262",
|
|
26
|
-
preserveAspectRatio: "xMidYMid",
|
|
27
22
|
role: "img",
|
|
28
|
-
viewBox: "0 0 256 262",
|
|
29
23
|
width: "256",
|
|
24
|
+
height: "262",
|
|
25
|
+
viewBox: "0 0 256 262",
|
|
30
26
|
xmlns: "http://www.w3.org/2000/svg",
|
|
27
|
+
preserveAspectRatio: "xMidYMid",
|
|
28
|
+
"aria-label": "Google",
|
|
31
29
|
children: [
|
|
32
30
|
/* @__PURE__ */ jsx("path", {
|
|
33
31
|
d: "M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622 38.755 30.023 2.685.268c24.659-22.774 38.875-56.282 38.875-96.027",
|
|
@@ -49,22 +47,201 @@ const ICON_GOOGLE = () => /* @__PURE__ */ jsxs("svg", {
|
|
|
49
47
|
});
|
|
50
48
|
/**
|
|
51
49
|
* Email envelope icon for email-related authentication flows.
|
|
52
|
-
* Used in email verification, password reset, and contact forms.
|
|
53
50
|
*/
|
|
54
51
|
const ICON_EMAIL = () => /* @__PURE__ */ jsx("svg", {
|
|
55
|
-
"aria-label": "Email",
|
|
56
|
-
fill: "none",
|
|
57
52
|
role: "img",
|
|
53
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
54
|
+
fill: "none",
|
|
55
|
+
viewBox: "0 0 24 24",
|
|
56
|
+
"stroke-width": "1.5",
|
|
58
57
|
stroke: "currentColor",
|
|
59
|
-
|
|
58
|
+
"aria-label": "Email",
|
|
59
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
60
|
+
"stroke-linecap": "round",
|
|
61
|
+
"stroke-linejoin": "round",
|
|
62
|
+
d: "M21.75 6.75v10.5a2.25 2.25 0 0 1-2.25 2.25h-15a2.25 2.25 0 0 1-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25m19.5 0v.243a2.25 2.25 0 0 1-1.07 1.916l-7.5 4.615a2.25 2.25 0 0 1-2.36 0L3.32 8.91a2.25 2.25 0 0 1-1.07-1.916V6.75"
|
|
63
|
+
})
|
|
64
|
+
});
|
|
65
|
+
/**
|
|
66
|
+
* Apple brand icon for Sign in with Apple.
|
|
67
|
+
*/
|
|
68
|
+
const ICON_APPLE = () => /* @__PURE__ */ jsx("svg", {
|
|
69
|
+
role: "img",
|
|
70
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
71
|
+
viewBox: "0 0 814 1000",
|
|
72
|
+
fill: "currentColor",
|
|
73
|
+
"aria-label": "Apple",
|
|
74
|
+
children: /* @__PURE__ */ jsx("path", { d: "M788.1 340.9c-5.8 4.5-108.2 62.2-108.2 190.5 0 148.4 130.3 200.9 134.2 202.2-.6 3.2-20.7 71.9-68.7 141.9-42.8 61.6-87.5 123.1-155.5 123.1s-85.5-39.5-164-39.5c-76.5 0-103.7 40.8-165.9 40.8s-105.6-57-155.5-127C46.7 790.7 0 663 0 541.8c0-194.4 126.4-297.5 250.8-297.5 66.1 0 121.2 43.4 162.7 43.4 39.5 0 101.1-46 176.3-46 28.5 0 130.9 2.6 198.3 99.2zm-234-181.5c31.1-36.9 53.1-88.1 53.1-139.3 0-7.1-.6-14.3-1.9-20.1-50.6 1.9-110.8 33.7-147.1 75.8-28.5 32.4-55.1 83.6-55.1 135.5 0 7.8 1.3 15.6 1.9 18.1 3.2.6 8.4 1.3 13.6 1.3 45.4 0 102.5-30.4 135.5-71.3z" })
|
|
75
|
+
});
|
|
76
|
+
/**
|
|
77
|
+
* Discord brand icon.
|
|
78
|
+
*/
|
|
79
|
+
const ICON_DISCORD = () => /* @__PURE__ */ jsx("svg", {
|
|
80
|
+
role: "img",
|
|
60
81
|
viewBox: "0 0 24 24",
|
|
61
82
|
xmlns: "http://www.w3.org/2000/svg",
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
83
|
+
fill: "currentColor",
|
|
84
|
+
"aria-label": "Discord",
|
|
85
|
+
children: /* @__PURE__ */ jsx("path", { d: "M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z" })
|
|
86
|
+
});
|
|
87
|
+
/**
|
|
88
|
+
* Facebook brand icon with gradient.
|
|
89
|
+
*/
|
|
90
|
+
const ICON_FACEBOOK = () => /* @__PURE__ */ jsxs("svg", {
|
|
91
|
+
role: "img",
|
|
92
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
93
|
+
viewBox: "0 0 36 36",
|
|
94
|
+
fill: "url(#facebook_gradient)",
|
|
95
|
+
"aria-label": "Facebook",
|
|
96
|
+
children: [
|
|
97
|
+
/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", {
|
|
98
|
+
x1: "50%",
|
|
99
|
+
x2: "50%",
|
|
100
|
+
y1: "97.078%",
|
|
101
|
+
y2: "0%",
|
|
102
|
+
id: "facebook_gradient",
|
|
103
|
+
children: [/* @__PURE__ */ jsx("stop", {
|
|
104
|
+
offset: "0%",
|
|
105
|
+
"stop-color": "#0062E0"
|
|
106
|
+
}), /* @__PURE__ */ jsx("stop", {
|
|
107
|
+
offset: "100%",
|
|
108
|
+
"stop-color": "#19AFFF"
|
|
109
|
+
})]
|
|
110
|
+
}) }),
|
|
111
|
+
/* @__PURE__ */ jsx("path", { d: "M15 35.8C6.5 34.3 0 26.9 0 18 0 8.1 8.1 0 18 0s18 8.1 18 18c0 8.9-6.5 16.3-15 17.8l-1-.8h-4l-1 .8z" }),
|
|
112
|
+
/* @__PURE__ */ jsx("path", {
|
|
113
|
+
fill: "#FFF",
|
|
114
|
+
d: "m25 23 .8-5H21v-3.5c0-1.4.5-2.5 2.7-2.5H26V7.4c-1.3-.2-2.7-.4-4-.4-4.1 0-7 2.5-7 7v4h-4.5v5H15v12.7c1 .2 2 .3 3 .3s2-.1 3-.3V23h4z"
|
|
115
|
+
})
|
|
116
|
+
]
|
|
117
|
+
});
|
|
118
|
+
/**
|
|
119
|
+
* LinkedIn brand icon.
|
|
120
|
+
*/
|
|
121
|
+
const ICON_LINKEDIN = () => /* @__PURE__ */ jsx("svg", {
|
|
122
|
+
role: "img",
|
|
123
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
124
|
+
viewBox: "0 0 24 24",
|
|
125
|
+
fill: "currentColor",
|
|
126
|
+
"aria-label": "LinkedIn",
|
|
127
|
+
children: /* @__PURE__ */ jsx("path", { d: "M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.225 0z" })
|
|
128
|
+
});
|
|
129
|
+
/**
|
|
130
|
+
* Microsoft brand icon with four color squares.
|
|
131
|
+
*/
|
|
132
|
+
const ICON_MICROSOFT = () => /* @__PURE__ */ jsxs("svg", {
|
|
133
|
+
role: "img",
|
|
134
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
135
|
+
viewBox: "0 0 23 23",
|
|
136
|
+
fill: "currentColor",
|
|
137
|
+
"aria-label": "Microsoft",
|
|
138
|
+
children: [
|
|
139
|
+
/* @__PURE__ */ jsx("rect", {
|
|
140
|
+
x: "0",
|
|
141
|
+
y: "0",
|
|
142
|
+
width: "10.58",
|
|
143
|
+
height: "10.58",
|
|
144
|
+
fill: "#F1511B"
|
|
145
|
+
}),
|
|
146
|
+
/* @__PURE__ */ jsx("rect", {
|
|
147
|
+
x: "12.42",
|
|
148
|
+
y: "0",
|
|
149
|
+
width: "10.58",
|
|
150
|
+
height: "10.58",
|
|
151
|
+
fill: "#80CC28"
|
|
152
|
+
}),
|
|
153
|
+
/* @__PURE__ */ jsx("rect", {
|
|
154
|
+
x: "0",
|
|
155
|
+
y: "12.42",
|
|
156
|
+
width: "10.58",
|
|
157
|
+
height: "10.58",
|
|
158
|
+
fill: "#00ADEF"
|
|
159
|
+
}),
|
|
160
|
+
/* @__PURE__ */ jsx("rect", {
|
|
161
|
+
x: "12.42",
|
|
162
|
+
y: "12.42",
|
|
163
|
+
width: "10.58",
|
|
164
|
+
height: "10.58",
|
|
165
|
+
fill: "#FFB900"
|
|
166
|
+
})
|
|
167
|
+
]
|
|
168
|
+
});
|
|
169
|
+
/**
|
|
170
|
+
* Slack brand icon.
|
|
171
|
+
*/
|
|
172
|
+
const ICON_SLACK = () => /* @__PURE__ */ jsx("svg", {
|
|
173
|
+
role: "img",
|
|
174
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
175
|
+
viewBox: "0 0 2447.6 2452.5",
|
|
176
|
+
fill: "currentColor",
|
|
177
|
+
"aria-label": "Slack",
|
|
178
|
+
children: /* @__PURE__ */ jsxs("g", {
|
|
179
|
+
"clip-rule": "evenodd",
|
|
180
|
+
"fill-rule": "evenodd",
|
|
181
|
+
children: [
|
|
182
|
+
/* @__PURE__ */ jsx("path", {
|
|
183
|
+
d: "m897.4 0c-135.3.1-244.8 109.9-244.7 245.2-.1 135.3 109.5 245.1 244.8 245.2h244.8v-245.1c.1-135.3-109.5-245.1-244.9-245.3.1 0 .1 0 0 0m0 654h-652.6c-135.3.1-244.9 109.9-244.8 245.2-.2 135.3 109.4 245.1 244.7 245.3h652.7c135.3-.1 244.9-109.9 244.8-245.2.1-135.4-109.5-245.2-244.8-245.3z",
|
|
184
|
+
fill: "#36c5f0"
|
|
185
|
+
}),
|
|
186
|
+
/* @__PURE__ */ jsx("path", {
|
|
187
|
+
d: "m2447.6 899.2c.1-135.3-109.5-245.1-244.8-245.2-135.3.1-244.9 109.9-244.8 245.2v245.3h244.8c135.3-.1 244.9-109.9 244.8-245.3zm-652.7 0v-654c.1-135.2-109.4-245-244.7-245.2-135.3.1-244.9 109.9-244.8 245.2v654c-.2 135.3 109.4 245.1 244.7 245.3 135.3-.1 244.9-109.9 244.8-245.3z",
|
|
188
|
+
fill: "#2eb67d"
|
|
189
|
+
}),
|
|
190
|
+
/* @__PURE__ */ jsx("path", {
|
|
191
|
+
d: "m1550.1 2452.5c135.3-.1 244.9-109.9 244.8-245.2.1-135.3-109.5-245.1-244.8-245.2h-244.8v245.2c-.1 135.2 109.5 245 244.8 245.2zm0-654.1h652.7c135.3-.1 244.9-109.9 244.8-245.2.2-135.3-109.4-245.1-244.7-245.3h-652.7c-135.3.1-244.9 109.9-244.8 245.2-.1 135.4 109.4 245.2 244.7 245.3z",
|
|
192
|
+
fill: "#ecb22e"
|
|
193
|
+
}),
|
|
194
|
+
/* @__PURE__ */ jsx("path", {
|
|
195
|
+
d: "m0 1553.2c-.1 135.3 109.5 245.1 244.8 245.2 135.3-.1 244.9-109.9 244.8-245.2v-245.2h-244.8c-135.3.1-244.9 109.9-244.8 245.2zm652.7 0v654c-.2 135.3 109.4 245.1 244.7 245.3 135.3-.1 244.9-109.9 244.8-245.2v-653.9c.2-135.3-109.4-245.1-244.7-245.3-135.4 0-244.9 109.8-244.8 245.1 0 0 0 .1 0 0",
|
|
196
|
+
fill: "#e01e5a"
|
|
197
|
+
})
|
|
198
|
+
]
|
|
66
199
|
})
|
|
67
200
|
});
|
|
201
|
+
/**
|
|
202
|
+
* GitLab brand icon.
|
|
203
|
+
*/
|
|
204
|
+
const ICON_GITLAB = () => /* @__PURE__ */ jsx("svg", {
|
|
205
|
+
role: "img",
|
|
206
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
207
|
+
viewBox: "0 0 24 24",
|
|
208
|
+
fill: "currentColor",
|
|
209
|
+
"aria-label": "GitLab",
|
|
210
|
+
children: /* @__PURE__ */ jsx("path", { d: "m23.6004 9.5927-.0337-.0862L20.3.9814a.851.851 0 0 0-.3362-.405.8748.8748 0 0 0-.9997.0539.8748.8748 0 0 0-.29.4399l-2.2055 6.748H7.5375l-2.2057-6.748a.8573.8573 0 0 0-.29-.4412.8748.8748 0 0 0-.9997-.0537.8585.8585 0 0 0-.3362.4049L.4332 9.5015l-.0325.0862a6.0657 6.0657 0 0 0 2.0119 7.0105l.0113.0087.03.0213 4.976 3.7264 2.462 1.8633 1.4995 1.1321a1.0085 1.0085 0 0 0 1.2197 0l1.4995-1.1321 2.4619-1.8633 5.006-3.7489.0125-.01a6.0682 6.0682 0 0 0 2.0094-7.003z" })
|
|
211
|
+
});
|
|
212
|
+
/**
|
|
213
|
+
* Reddit brand icon.
|
|
214
|
+
*/
|
|
215
|
+
const ICON_REDDIT = () => /* @__PURE__ */ jsx("svg", {
|
|
216
|
+
role: "img",
|
|
217
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
218
|
+
viewBox: "0 0 24 24",
|
|
219
|
+
fill: "currentColor",
|
|
220
|
+
"aria-label": "Reddit",
|
|
221
|
+
children: /* @__PURE__ */ jsx("path", { d: "M12 0C5.373 0 0 5.373 0 12c0 3.314 1.343 6.314 3.515 8.485l-2.286 2.286C.775 23.225 1.097 24 1.738 24H12c6.627 0 12-5.373 12-12S18.627 0 12 0Zm4.388 3.199c1.104 0 1.999.895 1.999 1.999 0 1.105-.895 2-1.999 2-.946 0-1.739-.657-1.947-1.539v.002c-1.147.162-2.032 1.15-2.032 2.341v.007c1.776.067 3.4.567 4.686 1.363.473-.363 1.064-.58 1.707-.58 1.547 0 2.802 1.254 2.802 2.802 0 1.117-.655 2.081-1.601 2.531-.088 3.256-3.637 5.876-7.997 5.876-4.361 0-7.905-2.617-7.998-5.87-.954-.447-1.614-1.415-1.614-2.538 0-1.548 1.255-2.802 2.803-2.802.645 0 1.239.218 1.712.585 1.275-.79 2.881-1.291 4.64-1.365v-.01c0-1.663 1.263-3.034 2.88-3.207.188-.911.993-1.595 1.959-1.595Zm-8.085 8.376c-.784 0-1.459.78-1.506 1.797-.047 1.016.64 1.429 1.426 1.429.786 0 1.371-.369 1.418-1.385.047-1.017-.553-1.841-1.338-1.841Zm7.406 0c-.786 0-1.385.824-1.338 1.841.047 1.017.634 1.385 1.418 1.385.785 0 1.473-.413 1.426-1.429-.046-1.017-.721-1.797-1.506-1.797Zm-3.703 4.013c-.974 0-1.907.048-2.77.135-.147.015-.241.168-.183.305.483 1.154 1.622 1.964 2.953 1.964 1.33 0 2.47-.81 2.953-1.964.057-.137-.037-.29-.184-.305-.863-.087-1.795-.135-2.769-.135Z" })
|
|
222
|
+
});
|
|
223
|
+
/**
|
|
224
|
+
* Spotify brand icon.
|
|
225
|
+
*/
|
|
226
|
+
const ICON_SPOTIFY = () => /* @__PURE__ */ jsx("svg", {
|
|
227
|
+
role: "img",
|
|
228
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
229
|
+
viewBox: "0 0 24 24",
|
|
230
|
+
fill: "currentColor",
|
|
231
|
+
"aria-label": "Spotify",
|
|
232
|
+
children: /* @__PURE__ */ jsx("path", { d: "M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.66 0 12 0zm5.521 17.34c-.24.359-.66.48-1.021.24-2.82-1.74-6.36-2.101-10.561-1.141-.418.122-.779-.179-.899-.539-.12-.421.18-.78.54-.9 4.56-1.021 8.52-.6 11.64 1.32.42.18.479.659.301 1.02zm1.44-3.3c-.301.42-.841.6-1.262.3-3.239-1.98-8.159-2.58-11.939-1.38-.479.12-1.02-.12-1.14-.6-.12-.48.12-1.021.6-1.141C9.6 9.9 15 10.561 18.72 12.84c.361.181.54.78.241 1.2zm.12-3.36C15.24 8.4 8.82 8.16 5.16 9.301c-.6.179-1.2-.181-1.38-.721-.18-.601.18-1.2.72-1.381 4.26-1.26 11.28-1.02 15.721 1.621.539.3.719 1.02.419 1.56-.299.421-1.02.599-1.559.3z" })
|
|
233
|
+
});
|
|
234
|
+
/**
|
|
235
|
+
* Twitch brand icon.
|
|
236
|
+
*/
|
|
237
|
+
const ICON_TWITCH = () => /* @__PURE__ */ jsx("svg", {
|
|
238
|
+
role: "img",
|
|
239
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
240
|
+
viewBox: "0 0 24 24",
|
|
241
|
+
fill: "currentColor",
|
|
242
|
+
"aria-label": "Twitch",
|
|
243
|
+
children: /* @__PURE__ */ jsx("path", { d: "M11.571 4.714h1.715v5.143H11.57zm4.715 0H18v5.143h-1.714zM6 0L1.714 4.286v15.428h5.143V24l4.286-4.286h3.428L22.286 12V0zm14.571 11.143l-3.428 3.428h-3.429l-3 3v-3H6.857V1.714h13.714Z" })
|
|
244
|
+
});
|
|
68
245
|
|
|
69
246
|
//#endregion
|
|
70
|
-
export { ICON_EMAIL, ICON_GITHUB, ICON_GOOGLE };
|
|
247
|
+
export { ICON_APPLE, ICON_DISCORD, ICON_EMAIL, ICON_FACEBOOK, ICON_GITHUB, ICON_GITLAB, ICON_GOOGLE, ICON_LINKEDIN, ICON_MICROSOFT, ICON_REDDIT, ICON_SLACK, ICON_SPOTIFY, ICON_TWITCH };
|
package/dist/ui/select.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Layout, renderToHTML } from "./base.mjs";
|
|
2
|
-
import { ICON_GITHUB, ICON_GOOGLE } from "./icon.mjs";
|
|
2
|
+
import { ICON_APPLE, ICON_DISCORD, ICON_EMAIL, ICON_FACEBOOK, ICON_GITHUB, ICON_GITLAB, ICON_GOOGLE, ICON_LINKEDIN, ICON_MICROSOFT, ICON_REDDIT, ICON_SLACK, ICON_SPOTIFY, ICON_TWITCH } from "./icon.mjs";
|
|
3
3
|
import { jsx, jsxs } from "preact/jsx-runtime";
|
|
4
4
|
|
|
5
5
|
//#region src/ui/select.tsx
|
|
@@ -7,18 +7,41 @@ import { jsx, jsxs } from "preact/jsx-runtime";
|
|
|
7
7
|
* Icon components for providers
|
|
8
8
|
*/
|
|
9
9
|
const PROVIDER_ICONS = {
|
|
10
|
+
apple: ICON_APPLE,
|
|
11
|
+
discord: ICON_DISCORD,
|
|
12
|
+
email: ICON_EMAIL,
|
|
13
|
+
facebook: ICON_FACEBOOK,
|
|
10
14
|
github: ICON_GITHUB,
|
|
11
|
-
|
|
15
|
+
gitlab: ICON_GITLAB,
|
|
16
|
+
google: ICON_GOOGLE,
|
|
17
|
+
linkedin: ICON_LINKEDIN,
|
|
18
|
+
magiclink: ICON_EMAIL,
|
|
19
|
+
microsoft: ICON_MICROSOFT,
|
|
20
|
+
password: ICON_EMAIL,
|
|
21
|
+
reddit: ICON_REDDIT,
|
|
22
|
+
slack: ICON_SLACK,
|
|
23
|
+
spotify: ICON_SPOTIFY,
|
|
24
|
+
twitch: ICON_TWITCH
|
|
12
25
|
};
|
|
13
26
|
/**
|
|
14
27
|
* Default display names for provider types
|
|
15
28
|
*/
|
|
16
29
|
const DEFAULT_DISPLAYS = {
|
|
30
|
+
apple: "Apple",
|
|
31
|
+
code: "Code",
|
|
32
|
+
discord: "Discord",
|
|
33
|
+
facebook: "Facebook",
|
|
17
34
|
github: "GitHub",
|
|
35
|
+
gitlab: "GitLab",
|
|
18
36
|
google: "Google",
|
|
19
|
-
|
|
37
|
+
linkedin: "LinkedIn",
|
|
38
|
+
microsoft: "Microsoft",
|
|
20
39
|
passkey: "Passkey",
|
|
21
|
-
password: "Password"
|
|
40
|
+
password: "Password",
|
|
41
|
+
reddit: "Reddit",
|
|
42
|
+
slack: "Slack",
|
|
43
|
+
spotify: "Spotify",
|
|
44
|
+
twitch: "Twitch"
|
|
22
45
|
};
|
|
23
46
|
/**
|
|
24
47
|
* Main provider selection component
|