peta-auth 0.1.3 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/elysia.d.mts CHANGED
@@ -1,7 +1,16 @@
1
- import { r as SessionOptions, t as IronSession } from "./session-z20gaFVT.mjs";
1
+ import { r as SessionOptions, t as IronSession } from "./session-0bF8_7Ui.mjs";
2
2
  import { Elysia } from "elysia";
3
3
 
4
4
  //#region src/elysia.d.ts
5
+ /**
6
+ * Elysia plugin that provides a session via the `session` store property.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * app.use(session({ password: "...", cookieName: "my-session" }))
11
+ * app.get("/me", ({ session }) => session)
12
+ * ```
13
+ */
5
14
  declare function session<T extends Record<string, unknown> = Record<string, unknown>>(options: SessionOptions): Elysia<"", {
6
15
  decorator: {};
7
16
  store: {};
@@ -34,6 +43,18 @@ declare function session<T extends Record<string, unknown> = Record<string, unkn
34
43
  standaloneSchema: {};
35
44
  response: {};
36
45
  }>;
46
+ /**
47
+ * Elysia guard (onBeforeHandle) that requires session data.
48
+ *
49
+ * Returns 401 when the session is empty.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * app.guard({ beforeHandle: requireSession() }, (app) =>
54
+ * app.get("/admin", () => "ok")
55
+ * )
56
+ * ```
57
+ */
37
58
  declare function requireSession(): (app: Elysia) => Elysia;
38
59
  declare function requireSession<K extends string>(key: K): (app: Elysia) => Elysia;
39
60
  //#endregion
package/dist/elysia.mjs CHANGED
@@ -1,14 +1,23 @@
1
- import { t as createSessionFromAdapter } from "./session-DSwf3XPH.mjs";
1
+ import { n as sessionHasData, t as createSessionFromAdapter } from "./session-BGCQ1Z1Q.mjs";
2
2
  import { parse } from "cookie";
3
3
  import { Elysia } from "elysia";
4
4
  //#region src/elysia.ts
5
+ /**
6
+ * Elysia plugin that provides a session via the `session` store property.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * app.use(session({ password: "...", cookieName: "my-session" }))
11
+ * app.get("/me", ({ session }) => session)
12
+ * ```
13
+ */
5
14
  function session(options) {
6
- return new Elysia({ name: "peta-auth" }).derive({ as: "scoped" }, async ({ headers: reqHeaders, set }) => {
7
- const cookieStr = reqHeaders instanceof Headers ? reqHeaders.get("cookie") ?? "" : reqHeaders.cookie ?? "";
15
+ return new Elysia({ name: "peta-auth" }).derive({ as: "scoped" }, async ({ headers, set }) => {
16
+ const cookieString = headers instanceof Headers ? headers.get("cookie") ?? "" : headers.cookie ?? "";
8
17
  return { session: await createSessionFromAdapter({
9
- getCookie: (name) => parse(cookieStr)[name],
10
- setCookie: (v) => {
11
- set.headers["Set-Cookie"] = v;
18
+ getCookie: (name) => parse(cookieString)[name],
19
+ setCookie: (value) => {
20
+ set.headers["Set-Cookie"] = value;
12
21
  }
13
22
  }, options) };
14
23
  });
@@ -16,7 +25,7 @@ function session(options) {
16
25
  function requireSession(key) {
17
26
  return (app) => app.onBeforeHandle((context) => {
18
27
  const session = context.session;
19
- if (!(key ? !!session[key] : Object.keys(session).some((k) => k !== "save" && k !== "destroy" && k !== "updateConfig"))) return new Response(JSON.stringify({ error: "unauthorized" }), {
28
+ if (!sessionHasData(session, key)) return new Response(JSON.stringify({ error: "unauthorized" }), {
20
29
  status: 401,
21
30
  headers: { "Content-Type": "application/json" }
22
31
  });
@@ -0,0 +1,17 @@
1
+ //#region src/errors.ts
2
+ /**
3
+ * Typed error for peta-auth.
4
+ *
5
+ * Carries a machine-readable `code` and a human-readable `message`.
6
+ * Thrown instead of raw `new Error(...)` throughout the library.
7
+ */
8
+ var PetaAuthError = class extends Error {
9
+ code;
10
+ constructor(code, message) {
11
+ super(message);
12
+ this.name = "PetaAuthError";
13
+ this.code = code;
14
+ }
15
+ };
16
+ //#endregion
17
+ export { PetaAuthError as t };
package/dist/hono.d.mts CHANGED
@@ -1,12 +1,33 @@
1
- import { r as SessionOptions, t as IronSession } from "./session-z20gaFVT.mjs";
1
+ import { r as SessionOptions, t as IronSession } from "./session-0bF8_7Ui.mjs";
2
2
  import { MiddlewareHandler } from "hono";
3
3
 
4
4
  //#region src/hono.d.ts
5
+ /**
6
+ * Hono middleware that creates a session and makes it available
7
+ * via `c.var.session`.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * app.use("*", session({ password: "...", cookieName: "my-session" }))
12
+ * app.get("/me", (c) => c.json(c.var.session))
13
+ * ```
14
+ */
5
15
  declare function session<T extends Record<string, unknown> = Record<string, unknown>>(options: SessionOptions): MiddlewareHandler<{
6
16
  Variables: {
7
17
  session: T & IronSession;
8
18
  };
9
19
  }>;
20
+ /**
21
+ * Hono middleware that guards a route by requiring session data.
22
+ *
23
+ * Returns 401 when the session is empty.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * app.use("/admin", requireSession())
28
+ * app.use("/admin", requireSession("role"))
29
+ * ```
30
+ */
10
31
  declare function requireSession(): MiddlewareHandler;
11
32
  declare function requireSession<K extends string>(key: K): MiddlewareHandler;
12
33
  //#endregion
package/dist/hono.mjs CHANGED
@@ -1,12 +1,22 @@
1
- import { t as createSessionFromAdapter } from "./session-DSwf3XPH.mjs";
1
+ import { n as sessionHasData, t as createSessionFromAdapter } from "./session-BGCQ1Z1Q.mjs";
2
2
  import { parse } from "cookie";
3
3
  import { createMiddleware } from "hono/factory";
4
4
  //#region src/hono.ts
5
+ /**
6
+ * Hono middleware that creates a session and makes it available
7
+ * via `c.var.session`.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * app.use("*", session({ password: "...", cookieName: "my-session" }))
12
+ * app.get("/me", (c) => c.json(c.var.session))
13
+ * ```
14
+ */
5
15
  function session(options) {
6
16
  return createMiddleware(async (c, next) => {
7
17
  c.set("session", await createSessionFromAdapter({
8
18
  getCookie: (name) => parse(c.req.header("cookie") ?? "")[name],
9
- setCookie: (v) => c.res.headers.append("Set-Cookie", v)
19
+ setCookie: (value) => c.res.headers.append("Set-Cookie", value)
10
20
  }, options));
11
21
  await next();
12
22
  });
@@ -14,7 +24,7 @@ function session(options) {
14
24
  function requireSession(key) {
15
25
  return createMiddleware(async (c, next) => {
16
26
  const s = c.var.session;
17
- if (!(key ? !!s[key] : Object.keys(s).some((k) => k !== "save" && k !== "destroy" && k !== "updateConfig"))) return c.json({ error: "unauthorized" }, 401);
27
+ if (!sessionHasData(s, key)) return c.json({ error: "unauthorized" }, 401);
18
28
  await next();
19
29
  });
20
30
  }
package/dist/index.d.mts CHANGED
@@ -1,27 +1,81 @@
1
- import { n as sealData, r as unsealData, t as Password } from "./crypto-Ln_Mj_zp.mjs";
2
- import { i as createSessionFromAdapter, n as SessionAdapter, r as SessionOptions, t as IronSession } from "./session-z20gaFVT.mjs";
1
+ import { n as sealData, r as unsealData, t as Password } from "./crypto-DR-ETdLZ.mjs";
2
+ import { i as createSessionFromAdapter, n as SessionAdapter, r as SessionOptions, t as IronSession } from "./session-0bF8_7Ui.mjs";
3
3
  import { CSRFOptions, generateCsrf, validateCsrf } from "./csrf.mjs";
4
4
  import { JWTOptions, signJWT, verifyJWT } from "./jwt.mjs";
5
5
 
6
+ //#region src/errors.d.ts
7
+ /**
8
+ * Typed error for peta-auth.
9
+ *
10
+ * Carries a machine-readable `code` and a human-readable `message`.
11
+ * Thrown instead of raw `new Error(...)` throughout the library.
12
+ */
13
+ declare class PetaAuthError extends Error {
14
+ readonly code: string;
15
+ constructor(code: string, message: string);
16
+ }
17
+ //#endregion
6
18
  //#region src/password.d.ts
7
19
  interface HashOptions {
8
- cost?: number;
20
+ /** Memory cost in KiB (default: 19456 = 19 MiB). */
21
+ memoryCost?: number;
22
+ /** Time cost (iterations) (default: 2). */
23
+ timeCost?: number;
24
+ /** Parallelism (default: 1). */
25
+ parallelism?: number;
9
26
  }
27
+ /**
28
+ * Hash a password with argon2id.
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * const hash = await hashPassword("my-password")
33
+ * ```
34
+ */
10
35
  declare function hashPassword(password: string, options?: HashOptions): Promise<string>;
36
+ /**
37
+ * Verify a password against an argon2id hash.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * const ok = await verifyPassword(hash, "my-password")
42
+ * ```
43
+ */
11
44
  declare function verifyPassword(hash: string, password: string): Promise<boolean>;
12
45
  //#endregion
13
46
  //#region src/reset-password.d.ts
47
+ /** Options for password reset token generation. */
14
48
  interface PasswordResetOptions {
49
+ /** Password(s) used to sign the reset token. */
15
50
  password: Password;
16
- exp?: number;
51
+ /** Token lifetime in seconds (default 1 hour). */
52
+ expiresIn?: number;
17
53
  }
54
+ /**
55
+ * Create a password-reset token for a user.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * const token = await createPasswordResetToken(userId, { password: "..." })
60
+ * ```
61
+ */
18
62
  declare function createPasswordResetToken(userId: string, options: PasswordResetOptions): Promise<string>;
63
+ /**
64
+ * Verify a password-reset token.
65
+ *
66
+ * Returns the user ID when the token is valid, or `null` if expired/invalid.
67
+ */
19
68
  declare function verifyPasswordResetToken(token: string, password: Password): Promise<{
20
69
  userId: string;
21
70
  } | null>;
71
+ /**
72
+ * Verify a password-reset token and apply the new password.
73
+ *
74
+ * Returns `{ userId, hash }` on success, or `null` if the token is invalid.
75
+ */
22
76
  declare function resetPassword(token: string, newPassword: string, password: Password): Promise<{
23
77
  userId: string;
24
78
  hash: string;
25
79
  } | null>;
26
80
  //#endregion
27
- export { type CSRFOptions, type IronSession, type JWTOptions, type Password, type PasswordResetOptions, type SessionAdapter, type SessionOptions, createPasswordResetToken, createSessionFromAdapter, generateCsrf, hashPassword, resetPassword, sealData, signJWT, unsealData, validateCsrf, verifyJWT, verifyPassword, verifyPasswordResetToken };
81
+ export { type CSRFOptions, type IronSession, type JWTOptions, type Password, type PasswordResetOptions, PetaAuthError, type SessionAdapter, type SessionOptions, createPasswordResetToken, createSessionFromAdapter, generateCsrf, hashPassword, resetPassword, sealData, signJWT, unsealData, validateCsrf, verifyJWT, verifyPassword, verifyPasswordResetToken };
package/dist/index.mjs CHANGED
@@ -1,31 +1,79 @@
1
- import { n as sealData, r as unsealData, t as createSessionFromAdapter } from "./session-DSwf3XPH.mjs";
1
+ import { n as sealData, r as unsealData } from "./crypto-WcFV83Nz.mjs";
2
2
  import { generateCsrf, validateCsrf } from "./csrf.mjs";
3
+ import { t as PetaAuthError } from "./errors-DxJ-WUJL.mjs";
3
4
  import { signJWT, verifyJWT } from "./jwt.mjs";
4
- import { compareSync, genSaltSync, hashSync } from "bcryptjs";
5
+ import { t as createSessionFromAdapter } from "./session-BGCQ1Z1Q.mjs";
6
+ import { hash, verify } from "@node-rs/argon2";
5
7
  //#region src/password.ts
8
+ const ARGON2_MEMORY_COST = 19456;
9
+ const ARGON2_TIME_COST = 2;
10
+ const ARGON2_PARALLELISM = 1;
11
+ /**
12
+ * Hash a password with argon2id.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const hash = await hashPassword("my-password")
17
+ * ```
18
+ */
6
19
  async function hashPassword(password, options = {}) {
7
- return hashSync(password, genSaltSync(options.cost ?? 10));
20
+ return hash(password, {
21
+ algorithm: 2,
22
+ memoryCost: options.memoryCost ?? ARGON2_MEMORY_COST,
23
+ timeCost: options.timeCost ?? ARGON2_TIME_COST,
24
+ parallelism: options.parallelism ?? ARGON2_PARALLELISM
25
+ });
8
26
  }
27
+ /**
28
+ * Verify a password against an argon2id hash.
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * const ok = await verifyPassword(hash, "my-password")
33
+ * ```
34
+ */
9
35
  async function verifyPassword(hash, password) {
10
- return compareSync(password, hash);
36
+ try {
37
+ return await verify(hash, password);
38
+ } catch {
39
+ return false;
40
+ }
11
41
  }
12
42
  //#endregion
13
43
  //#region src/reset-password.ts
14
- const DEFAULT_EXPIRY = 3600;
44
+ const DEFAULT_EXPIRES_IN = 3600;
45
+ /**
46
+ * Create a password-reset token for a user.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * const token = await createPasswordResetToken(userId, { password: "..." })
51
+ * ```
52
+ */
15
53
  async function createPasswordResetToken(userId, options) {
16
54
  return signJWT({
17
55
  userId,
18
56
  purpose: "password-reset"
19
57
  }, {
20
58
  password: options.password,
21
- exp: options.exp ?? DEFAULT_EXPIRY
59
+ expiresIn: options.expiresIn ?? DEFAULT_EXPIRES_IN
22
60
  });
23
61
  }
62
+ /**
63
+ * Verify a password-reset token.
64
+ *
65
+ * Returns the user ID when the token is valid, or `null` if expired/invalid.
66
+ */
24
67
  async function verifyPasswordResetToken(token, password) {
25
68
  const payload = await verifyJWT(token, { password });
26
- if (!payload || payload.purpose !== "password-reset") return null;
69
+ if (payload?.purpose !== "password-reset") return null;
27
70
  return { userId: payload.userId };
28
71
  }
72
+ /**
73
+ * Verify a password-reset token and apply the new password.
74
+ *
75
+ * Returns `{ userId, hash }` on success, or `null` if the token is invalid.
76
+ */
29
77
  async function resetPassword(token, newPassword, password) {
30
78
  const payload = await verifyPasswordResetToken(token, password);
31
79
  if (!payload) return null;
@@ -35,4 +83,4 @@ async function resetPassword(token, newPassword, password) {
35
83
  };
36
84
  }
37
85
  //#endregion
38
- export { createPasswordResetToken, createSessionFromAdapter, generateCsrf, hashPassword, resetPassword, sealData, signJWT, unsealData, validateCsrf, verifyJWT, verifyPassword, verifyPasswordResetToken };
86
+ export { PetaAuthError, createPasswordResetToken, createSessionFromAdapter, generateCsrf, hashPassword, resetPassword, sealData, signJWT, unsealData, validateCsrf, verifyJWT, verifyPassword, verifyPasswordResetToken };
package/dist/jwt.d.mts CHANGED
@@ -1,11 +1,32 @@
1
- import { t as Password } from "./crypto-Ln_Mj_zp.mjs";
1
+ import { t as Password } from "./crypto-DR-ETdLZ.mjs";
2
2
 
3
3
  //#region src/jwt.d.ts
4
+ /** Options for JWT sign / verify operations. */
4
5
  interface JWTOptions {
6
+ /** Password used to sign the JWT. */
5
7
  password: Password;
6
- exp?: number;
8
+ /** Time-to-live in seconds from now. */
9
+ expiresIn?: number;
7
10
  }
11
+ /**
12
+ * Sign a JWT payload.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const token = await signJWT({ userId: "abc" }, { password: "my-32-char-secret...", expiresIn: 3600 })
17
+ * ```
18
+ */
8
19
  declare function signJWT(payload: Record<string, unknown>, options: JWTOptions): Promise<string>;
20
+ /**
21
+ * Verify and decode a JWT.
22
+ *
23
+ * Returns `null` when the token is invalid or expired.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const payload = await verifyJWT<{ userId: string }>(token, { password: "my-32-char-secret..." })
28
+ * ```
29
+ */
9
30
  declare function verifyJWT<T = Record<string, unknown>>(token: string, options: JWTOptions): Promise<T | null>;
10
31
  //#endregion
11
32
  export { JWTOptions, signJWT, verifyJWT };
package/dist/jwt.mjs CHANGED
@@ -1,28 +1,48 @@
1
+ import { t as normalizePassword } from "./crypto-WcFV83Nz.mjs";
2
+ import { t as PetaAuthError } from "./errors-DxJ-WUJL.mjs";
1
3
  import * as jose from "jose";
2
4
  //#region src/jwt.ts
3
- function toPasswordMap(password) {
4
- return typeof password === "string" ? { 1: password } : password;
5
- }
6
5
  function toKey(secret) {
7
6
  return new TextEncoder().encode(secret);
8
7
  }
8
+ /**
9
+ * Sign a JWT payload.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const token = await signJWT({ userId: "abc" }, { password: "my-32-char-secret...", expiresIn: 3600 })
14
+ * ```
15
+ */
9
16
  async function signJWT(payload, options) {
10
- const map = toPasswordMap(options.password);
17
+ const map = normalizePassword(options.password);
11
18
  const secret = map[Math.max(...Object.keys(map).map(Number)).toString()];
12
- if (!secret || secret.length < 32) throw new Error("peta-auth/jwt: password must be at least 32 characters");
19
+ if (!secret || secret.length < 32) throw new PetaAuthError("JWT_PASSWORD_TOO_SHORT", "peta-auth/jwt: password must be at least 32 characters");
13
20
  const jwt = new jose.SignJWT(payload).setProtectedHeader({ alg: "HS256" }).setIssuedAt();
14
- if (options.exp !== void 0) jwt.setExpirationTime(Math.floor(Date.now() / 1e3) + options.exp);
21
+ const ttl = options.expiresIn ?? 86400;
22
+ jwt.setExpirationTime(Math.floor(Date.now() / 1e3) + ttl);
15
23
  return jwt.sign(toKey(secret));
16
24
  }
25
+ /**
26
+ * Verify and decode a JWT.
27
+ *
28
+ * Returns `null` when the token is invalid or expired.
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * const payload = await verifyJWT<{ userId: string }>(token, { password: "my-32-char-secret..." })
33
+ * ```
34
+ */
17
35
  async function verifyJWT(token, options) {
18
- for (const secret of Object.values(toPasswordMap(options.password))) {
36
+ let result = null;
37
+ const passwords = normalizePassword(options.password);
38
+ for (const secret of Object.values(passwords)) {
19
39
  if (!secret) continue;
20
40
  try {
21
41
  const { payload } = await jose.jwtVerify(token, toKey(secret));
22
- return payload;
42
+ if (!result) result = payload;
23
43
  } catch {}
24
44
  }
25
- return null;
45
+ return result;
26
46
  }
27
47
  //#endregion
28
48
  export { signJWT, verifyJWT };
package/dist/nuxt.d.mts CHANGED
@@ -1,9 +1,32 @@
1
- import { r as SessionOptions, t as IronSession } from "./session-z20gaFVT.mjs";
1
+ import { r as SessionOptions, t as IronSession } from "./session-0bF8_7Ui.mjs";
2
2
  import { H3Event } from "h3";
3
3
 
4
4
  //#region src/nuxt.d.ts
5
+ /**
6
+ * Create a session from an h3 event (Nuxt / h3).
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * // In a Nuxt server handler:
11
+ * const session = await useSession(event, { password: process.env.NUXT_SESSION_PASSWORD })
12
+ * session.userId = 42
13
+ * await session.save()
14
+ * ```
15
+ */
5
16
  declare function useSession<T extends Record<string, unknown> = Record<string, unknown>>(event: H3Event, options: SessionOptions): Promise<T & IronSession>;
6
- declare function requireSession(_event: H3Event, session: IronSession): void;
7
- declare function requireSession<K extends string>(_event: H3Event, session: IronSession, key: K): void;
17
+ /**
18
+ * Guard that requires session data.
19
+ *
20
+ * Throws a 401 h3 error when the session is empty.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * const session = await useSession(event, options)
25
+ * requireSession(event, session)
26
+ * requireSession(event, session, "role") // require specific key
27
+ * ```
28
+ */
29
+ declare function requireSession(event: H3Event, session: IronSession): void;
30
+ declare function requireSession<K extends string>(event: H3Event, session: IronSession, key: K): void;
8
31
  //#endregion
9
32
  export { requireSession, useSession };
package/dist/nuxt.mjs CHANGED
@@ -1,21 +1,33 @@
1
- import { t as createSessionFromAdapter } from "./session-DSwf3XPH.mjs";
1
+ import { t as PetaAuthError } from "./errors-DxJ-WUJL.mjs";
2
+ import { n as sessionHasData, t as createSessionFromAdapter } from "./session-BGCQ1Z1Q.mjs";
2
3
  import { appendHeader, createError, getCookie } from "h3";
3
4
  //#region src/nuxt.ts
5
+ /**
6
+ * Create a session from an h3 event (Nuxt / h3).
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * // In a Nuxt server handler:
11
+ * const session = await useSession(event, { password: process.env.NUXT_SESSION_PASSWORD })
12
+ * session.userId = 42
13
+ * await session.save()
14
+ * ```
15
+ */
4
16
  function useSession(event, options) {
5
17
  const password = options.password ?? process.env.NUXT_SESSION_PASSWORD;
6
- if (!password) throw new Error("peta-auth/nuxt: NUXT_SESSION_PASSWORD is required");
18
+ if (!password) throw new PetaAuthError("MISSING_PASSWORD", "peta-auth/nuxt: NUXT_SESSION_PASSWORD is required");
7
19
  return createSessionFromAdapter({
8
20
  getCookie: (name) => getCookie(event, name),
9
21
  setCookie: (value) => appendHeader(event, "Set-Cookie", value)
10
22
  }, {
11
23
  password,
12
- cookieName: options?.cookieName ?? "nuxt-session",
13
- ttl: options?.ttl,
14
- cookieOptions: options?.cookieOptions
24
+ cookieName: options.cookieName ?? "nuxt-session",
25
+ timeToLive: options.timeToLive,
26
+ cookieOptions: options.cookieOptions
15
27
  });
16
28
  }
17
29
  function requireSession(_event, session, key) {
18
- if (!(key ? !!session[key] : Object.keys(session).some((k) => k !== "save" && k !== "destroy" && k !== "updateConfig"))) throw createError({
30
+ if (!sessionHasData(session, key)) throw createError({
19
31
  statusCode: 401,
20
32
  statusMessage: "unauthorized"
21
33
  });
@@ -1,4 +1,5 @@
1
1
  //#region src/oauth/github.d.ts
2
+ /** Configuration for GitHub OAuth. */
2
3
  interface OAuthGitHubConfig {
3
4
  clientId?: string;
4
5
  clientSecret?: string;
@@ -10,6 +11,11 @@ interface OAuthGitHubConfig {
10
11
  authorizationParams?: Record<string, string>;
11
12
  redirectURL?: string;
12
13
  }
14
+ interface GitHubTokens {
15
+ access_token: string;
16
+ scope: string;
17
+ token_type: string;
18
+ }
13
19
  interface GitHubUser {
14
20
  login: string;
15
21
  id: number;
@@ -19,11 +25,18 @@ interface GitHubUser {
19
25
  email: string | null;
20
26
  email_verified?: boolean;
21
27
  }
22
- interface GitHubTokens {
23
- access_token: string;
24
- scope: string;
25
- token_type: string;
26
- }
28
+ /**
29
+ * Define a GitHub OAuth event handler.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const handle = defineOAuthGitHubEventHandler({
34
+ * onSuccess: async ({ user, tokens }) =>
35
+ * new Response(`Welcome ${user.login}!`),
36
+ * })
37
+ * serve(handle)
38
+ * ```
39
+ */
27
40
  declare function defineOAuthGitHubEventHandler(options: {
28
41
  config?: OAuthGitHubConfig;
29
42
  onSuccess: (event: {