peta-auth 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -26,7 +26,7 @@ bun add elysia # for peta-auth/elysia
26
26
 
27
27
  ```ts
28
28
  import { Hono } from 'hono'
29
- import { session } from 'peta-auth/hono'
29
+ import { session, requireSession } from 'peta-auth/hono'
30
30
 
31
31
  const app = new Hono()
32
32
 
@@ -35,19 +35,18 @@ app.use('*', session({
35
35
  cookieName: 'my-session',
36
36
  }))
37
37
 
38
- app.get('/profile', (c) => {
39
- const s = c.var.session
40
- if (!s.user) return c.json({ error: 'unauthorized' }, 401)
41
- return c.json(s.user)
42
- })
43
-
44
38
  app.post('/login', async (c) => {
45
39
  const { name } = await c.req.json()
46
- Object.assign(c.var.session, { user: { name }, loggedInAt: Date.now() })
40
+ c.var.session.user = { name }
47
41
  await c.var.session.save()
48
42
  return c.json({ ok: true })
49
43
  })
50
44
 
45
+ // Everything below requireSession returns 401 if not logged in
46
+ app.use('/api/*', requireSession())
47
+
48
+ app.get('/api/profile', (c) => c.json(c.var.session.user))
49
+
51
50
  app.post('/logout', (c) => {
52
51
  c.var.session.destroy()
53
52
  return c.json({ ok: true })
@@ -60,25 +59,22 @@ Run with `bun run file.ts` — Bun auto-starts the server.
60
59
 
61
60
  ```ts
62
61
  import { Elysia } from 'elysia'
63
- import { session } from 'peta-auth/elysia'
62
+ import { session, requireSession } from 'peta-auth/elysia'
64
63
 
65
64
  new Elysia()
66
65
  .use(session({
67
66
  password: process.env.SESSION_SECRET!,
68
67
  cookieName: 'my-session',
69
68
  }))
70
- .get('/profile', ({ session: s }) =>
71
- !s.user ? Response.json({ error: 'unauthorized' }, { status: 401 })
72
- : Response.json(s.user))
73
69
  .post('/login', async ({ session: s, body }: any) => {
74
70
  s.user = { name: body.name }
75
71
  await s.save()
76
72
  return Response.json({ ok: true })
77
73
  })
78
- .post('/logout', ({ session: s }) => {
79
- s.destroy()
80
- return Response.json({ ok: true })
81
- })
74
+ .get('/public', () => Response.json({ message: 'public' }))
75
+ // Everything after requireSession is guarded
76
+ .use(requireSession())
77
+ .get('/profile', ({ session: s }) => Response.json(s.user))
82
78
  .listen(3000)
83
79
  ```
84
80
 
@@ -86,14 +82,14 @@ new Elysia()
86
82
 
87
83
  ```ts
88
84
  // server/api/profile.get.ts
89
- import { useSession } from 'peta-auth/nuxt'
85
+ import { useSession, requireSession } from 'peta-auth/nuxt'
90
86
 
91
87
  export default defineEventHandler(async (event) => {
92
88
  const session = await useSession(event, {
93
89
  password: process.env.NUXT_SESSION_PASSWORD!,
94
90
  cookieName: 'nuxt-session',
95
91
  })
96
- if (!session.user) throw createError({ statusCode: 401 })
92
+ requireSession(event, session)
97
93
  return session.user
98
94
  })
99
95
  ```
@@ -140,6 +136,33 @@ session({ password: { 1: 'old-pw', 2: 'new-pw' }, cookieName: 'my-session' })
140
136
  // new cookies use key 2, old cookies still decrypt with key 1
141
137
  ```
142
138
 
139
+ ### Typed sessions
140
+
141
+ Add a generic type parameter to get full IntelliSense on your session data:
142
+
143
+ ```ts
144
+ // Hono
145
+ app.use('*', session<{ user: { name: string }; views: number }>({ password, cookieName }))
146
+ // c.var.session.user.name → string
147
+ // c.var.session.views → number
148
+
149
+ // Elysia
150
+ app.use(session<{ user: { name: string } }>({ password, cookieName }))
151
+
152
+ // Nuxt
153
+ const session = await useSession<{ user: { name: string } }>(event, { password, cookieName })
154
+ ```
155
+
156
+ Without a generic parameter, session data defaults to `Record<string, unknown>`.
157
+
158
+ ### `requireSession()` guard
159
+
160
+ Returns 401 if the session has no user data. Works per-framework:
161
+
162
+ - **Hono**: `app.use('/protected/*', requireSession())` — middleware, path-patterned
163
+ - **Elysia**: `app.use(requireSession())` — guards all routes defined after it
164
+ - **Nuxt**: `requireSession(event, session)` — throws `createError({ statusCode: 401 })`
165
+
143
166
  ### Session object
144
167
 
145
168
  ```ts
@@ -151,14 +174,93 @@ interface IronSession {
151
174
  }
152
175
  ```
153
176
 
154
- ### Low-level
177
+ ---
178
+
179
+ ## JWT
180
+
181
+ Sign and verify HS256 JWTs using the same password infrastructure.
182
+
183
+ ```ts
184
+ import { signJWT, verifyJWT } from 'peta-auth/jwt'
185
+
186
+ // Sign
187
+ const token = await signJWT({ userId: 42, role: 'admin' }, {
188
+ password: process.env.JWT_SECRET!,
189
+ exp: 3600, // optional, seconds from now
190
+ })
191
+
192
+ // Verify
193
+ const payload = await verifyJWT<{ userId: number; role: string }>(token, {
194
+ password: process.env.JWT_SECRET!,
195
+ })
196
+ if (!payload) throw new Error('invalid or expired token')
197
+ ```
198
+
199
+ - `exp` defaults to no expiry if omitted
200
+ - Supports password rotation (tries all keys on verify, signs with highest)
201
+ - Requires password at least 32 characters
202
+
203
+ ---
204
+
205
+ ## CSRF protection
206
+
207
+ Generate and validate CSRF tokens stored in the session.
208
+
209
+ ```ts
210
+ import { generateCsrf, validateCsrf } from 'peta-auth/csrf'
211
+
212
+ // On a form page — generate token and store in session
213
+ const token = await generateCsrf(session)
214
+ await session.save()
215
+ // → render form with hidden field: <input name="_csrf" value="${token}" />
216
+
217
+ // On form submission — validate
218
+ if (!validateCsrf(session, body._csrf)) {
219
+ throw new Error('CSRF mismatch')
220
+ }
221
+ ```
222
+
223
+ - Uses `crypto.randomUUID()` for token generation
224
+ - Stores token in session under `_csrfToken` (configurable via `{ key: 'myKey' }`)
225
+ - You must call `session.save()` after `generateCsrf()`
226
+
227
+ ---
228
+
229
+ ## Password Reset
230
+
231
+ Helpers for forgot/reset password flows using short-lived JWTs.
232
+
233
+ ```ts
234
+ import { createPasswordResetToken, verifyPasswordResetToken, resetPassword } from 'peta-auth'
235
+
236
+ // Generate a token (e.g., in a "forgot password" endpoint)
237
+ const token = await createPasswordResetToken(user.email, {
238
+ password: process.env.SECRET!,
239
+ exp: 3600, // optional, default 1 hour
240
+ })
241
+ // → email token as a link: https://example.com/reset?token=${token}
242
+
243
+ // Verify a token (e.g., in a "reset password" endpoint)
244
+ const payload = await verifyPasswordResetToken(token, process.env.SECRET!)
245
+ if (!payload) throw new Error('Invalid or expired token')
246
+ // payload.userId → the email passed to createPasswordResetToken
247
+
248
+ // Combined: verify token + hash new password
249
+ const result = await resetPassword(token, newPassword, process.env.SECRET!)
250
+ if (!result) throw new Error('Invalid or expired token')
251
+ users.set(result.userId, { ...user, hash: result.hash })
252
+ ```
253
+
254
+ ---
255
+
256
+ ## Low-level
155
257
 
156
258
  ```ts
157
259
  import { createSessionFromAdapter, sealData, unsealData } from 'peta-auth'
158
260
  import { hashPassword, verifyPassword } from 'peta-auth'
159
261
  ```
160
262
 
161
- - **`createSessionFromAdapter(adapter, options)`** — takes a `SessionAdapter` (`{ getCookie, setCookie }`). Used internally by all framework adapters.
263
+ - **`createSessionFromAdapter<T>(adapter, options)`** — takes a `SessionAdapter` (`{ getCookie, setCookie }`). Used internally by all framework adapters.
162
264
  - **`sealData(data, { password, ttl? })` / `unsealData<T>(seal, { password, ttl? })`** — encrypt/decrypt arbitrary data.
163
265
  - **`hashPassword(password, { cost? })` / `verifyPassword(hash, password)`** — bcrypt hashing via `bcryptjs`. Default cost: 10.
164
266
 
@@ -186,9 +288,6 @@ const githubHandler = defineOAuthGitHubEventHandler({
186
288
  clientSecret: process.env.GITHUB_CLIENT_SECRET!,
187
289
  },
188
290
  async onSuccess({ user, tokens }) {
189
- // The user is authenticated — redirect back to your app.
190
- // To create a session, use the `request` parameter:
191
- // onSuccess({ user, tokens, request })
192
291
  return new Response(null, { status: 302, headers: { Location: '/' } })
193
292
  },
194
293
  })
@@ -223,15 +322,20 @@ async onSuccess({ user, tokens, request }) {
223
322
  Full runnable examples in [`examples/`](./examples). All work with zero config (demo password fallback built in):
224
323
 
225
324
  ```bash
226
- bun run examples/hono-basic.ts # Hono — session CRUD, views counter
227
- bun run examples/elysia-basic.ts # Elysiasession CRUD, views counter
228
- bun run examples/password-auth.ts # Honosignup + login with bcrypt
229
- bun run examples/oauth-github.ts # HonoGitHub OAuth
230
- bun run examples/oauth-google.ts # Hono — Google OAuth (PKCE)
231
- bun run examples/elysia-password.ts # Elysiasignup + login with bcrypt
232
- bun run examples/elysia-oauth-github.ts # Elysia GitHub OAuth
233
- bun run examples/elysia-oauth-google.ts # ElysiaGoogle OAuth (PKCE)
234
- cd examples/nuxt # Nuxtserver routes with useSession
325
+ bun run examples/hono-basic.ts # Hono — session CRUD, views counter
326
+ bun run examples/hono-guard.ts # HonorequireSession guard
327
+ bun run examples/elysia-basic.ts # Elysiasession CRUD, views counter
328
+ bun run examples/elysia-guard.ts # ElysiarequireSession guard
329
+ bun run examples/password-auth.ts # Hono — signup + login with bcrypt
330
+ bun run examples/password-reset.ts # Honoforgot/reset password flow
331
+ bun run examples/jwt-basic.ts # JWT sign + verify + tamper detection
332
+ bun run examples/csrf-basic.ts # HonoCSRF token form example
333
+ bun run examples/oauth-github.ts # HonoGitHub OAuth
334
+ bun run examples/oauth-google.ts # Hono — Google OAuth (PKCE)
335
+ bun run examples/elysia-password.ts # Elysia — signup + login with bcrypt
336
+ bun run examples/elysia-oauth-github.ts # Elysia — GitHub OAuth
337
+ bun run examples/elysia-oauth-google.ts # Elysia — Google OAuth (PKCE)
338
+ cd examples/nuxt # Nuxt — server routes with useSession
235
339
  ```
236
340
 
237
341
  ---
@@ -250,7 +354,7 @@ Session data is serialized, encrypted with AES-256-CBC, integrity-protected with
250
354
  ## Scripts
251
355
 
252
356
  ```bash
253
- bun test # 43 tests across 9 files
254
- bun run build # tsdown → dist/ (16 files, 24 kB)
357
+ bun test # 65 tests across 12 files
358
+ bun run build # tsdown → dist/ (21 files, 30 kB)
255
359
  bun run prepublish # build + publish
256
360
  ```
@@ -0,0 +1,19 @@
1
+ //#region src/crypto.d.ts
2
+ type PasswordsMap = Record<string, string>;
3
+ type Password = PasswordsMap | string;
4
+ declare const sealData: (data: unknown, {
5
+ password,
6
+ ttl
7
+ }: {
8
+ password: Password;
9
+ ttl?: number;
10
+ }) => Promise<string>;
11
+ declare const unsealData: <T>(seal: string, {
12
+ password,
13
+ ttl
14
+ }: {
15
+ password: Password;
16
+ ttl?: number;
17
+ }) => Promise<T>;
18
+ //#endregion
19
+ export { sealData as n, unsealData as r, Password as t };
@@ -0,0 +1,10 @@
1
+ import { t as IronSession } from "./session-z20gaFVT.mjs";
2
+
3
+ //#region src/csrf.d.ts
4
+ interface CSRFOptions {
5
+ key?: string;
6
+ }
7
+ declare function generateCsrf(session: IronSession, options?: CSRFOptions): Promise<string>;
8
+ declare function validateCsrf(session: IronSession, token: string, options?: CSRFOptions): boolean;
9
+ //#endregion
10
+ export { CSRFOptions, generateCsrf, validateCsrf };
package/dist/csrf.mjs ADDED
@@ -0,0 +1,13 @@
1
+ //#region src/csrf.ts
2
+ async function generateCsrf(session, options) {
3
+ const key = options?.key ?? "_csrfToken";
4
+ const token = crypto.randomUUID();
5
+ session[key] = token;
6
+ return token;
7
+ }
8
+ function validateCsrf(session, token, options) {
9
+ const stored = session[options?.key ?? "_csrfToken"];
10
+ return typeof stored === "string" && stored === token;
11
+ }
12
+ //#endregion
13
+ export { generateCsrf, validateCsrf };
package/dist/elysia.d.mts CHANGED
@@ -1,8 +1,8 @@
1
- import { r as SessionOptions, t as IronSession } from "./session-DYH_m3lO.mjs";
1
+ import { r as SessionOptions, t as IronSession } from "./session-z20gaFVT.mjs";
2
2
  import { Elysia } from "elysia";
3
3
 
4
4
  //#region src/elysia.d.ts
5
- declare function session(options: SessionOptions): Elysia<"", {
5
+ declare function session<T extends Record<string, unknown> = Record<string, unknown>>(options: SessionOptions): Elysia<"", {
6
6
  decorator: {};
7
7
  store: {};
8
8
  derive: {};
@@ -19,13 +19,13 @@ declare function session(options: SessionOptions): Elysia<"", {
19
19
  response: {};
20
20
  }, {}, {
21
21
  derive: {
22
- readonly session: Record<string, unknown> & IronSession;
22
+ readonly session: T & IronSession;
23
23
  };
24
24
  resolve: {};
25
25
  schema: {};
26
26
  standaloneSchema: {};
27
27
  response: import("elysia").ExtractErrorFromHandle<{
28
- readonly session: Record<string, unknown> & IronSession;
28
+ readonly session: T & IronSession;
29
29
  }>;
30
30
  }, {
31
31
  derive: {};
@@ -34,5 +34,35 @@ declare function session(options: SessionOptions): Elysia<"", {
34
34
  standaloneSchema: {};
35
35
  response: {};
36
36
  }>;
37
+ declare function requireSession(): (app: Elysia) => Elysia<"", {
38
+ decorator: {};
39
+ store: {};
40
+ derive: {};
41
+ resolve: {};
42
+ }, {
43
+ typebox: {};
44
+ error: {};
45
+ }, {
46
+ schema: {};
47
+ standaloneSchema: {};
48
+ macro: {};
49
+ macroFn: {};
50
+ parser: {};
51
+ response: {};
52
+ }, {}, {
53
+ derive: {};
54
+ resolve: {};
55
+ schema: {};
56
+ standaloneSchema: {};
57
+ response: {};
58
+ }, {
59
+ derive: {};
60
+ resolve: {};
61
+ schema: {};
62
+ standaloneSchema: {};
63
+ response: {
64
+ 200: Response;
65
+ };
66
+ }>;
37
67
  //#endregion
38
- export { session };
68
+ export { requireSession, session };
package/dist/elysia.mjs CHANGED
@@ -13,5 +13,14 @@ function session(options) {
13
13
  }, options) };
14
14
  });
15
15
  }
16
+ function requireSession() {
17
+ return (app) => app.onBeforeHandle((context) => {
18
+ const session = context.session;
19
+ if (!Object.keys(session).some((k) => k !== "save" && k !== "destroy" && k !== "updateConfig")) return new Response(JSON.stringify({ error: "unauthorized" }), {
20
+ status: 401,
21
+ headers: { "Content-Type": "application/json" }
22
+ });
23
+ });
24
+ }
16
25
  //#endregion
17
- export { session };
26
+ export { requireSession, session };
package/dist/hono.d.mts CHANGED
@@ -1,12 +1,12 @@
1
- import { r as SessionOptions, t as IronSession } from "./session-DYH_m3lO.mjs";
1
+ import { r as SessionOptions, t as IronSession } from "./session-z20gaFVT.mjs";
2
2
  import { MiddlewareHandler } from "hono";
3
3
 
4
4
  //#region src/hono.d.ts
5
- declare module 'hono' {
6
- interface ContextVariableMap {
7
- session: IronSession;
8
- }
9
- }
10
- declare function session(options: SessionOptions): MiddlewareHandler;
5
+ declare function session<T extends Record<string, unknown> = Record<string, unknown>>(options: SessionOptions): MiddlewareHandler<{
6
+ Variables: {
7
+ session: T & IronSession;
8
+ };
9
+ }>;
10
+ declare function requireSession(): MiddlewareHandler;
11
11
  //#endregion
12
- export { session };
12
+ export { requireSession, session };
package/dist/hono.mjs CHANGED
@@ -11,5 +11,12 @@ function session(options) {
11
11
  await next();
12
12
  });
13
13
  }
14
+ function requireSession() {
15
+ return createMiddleware(async (c, next) => {
16
+ const s = c.var.session;
17
+ if (!Object.keys(s).some((k) => k !== "save" && k !== "destroy" && k !== "updateConfig")) return c.json({ error: "unauthorized" }, 401);
18
+ await next();
19
+ });
20
+ }
14
21
  //#endregion
15
- export { session };
22
+ export { requireSession, session };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,7 @@
1
- import { a as Password, i as createSessionFromAdapter, n as SessionAdapter, o as sealData, r as SessionOptions, s as unsealData, t as IronSession } from "./session-DYH_m3lO.mjs";
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";
3
+ import { CSRFOptions, generateCsrf, validateCsrf } from "./csrf.mjs";
4
+ import { JWTOptions, signJWT, verifyJWT } from "./jwt.mjs";
2
5
 
3
6
  //#region src/password.d.ts
4
7
  interface HashOptions {
@@ -7,4 +10,18 @@ interface HashOptions {
7
10
  declare function hashPassword(password: string, options?: HashOptions): Promise<string>;
8
11
  declare function verifyPassword(hash: string, password: string): Promise<boolean>;
9
12
  //#endregion
10
- export { type IronSession, type Password, type SessionAdapter, type SessionOptions, createSessionFromAdapter, hashPassword, sealData, unsealData, verifyPassword };
13
+ //#region src/reset-password.d.ts
14
+ interface PasswordResetOptions {
15
+ password: Password;
16
+ exp?: number;
17
+ }
18
+ declare function createPasswordResetToken(userId: string, options: PasswordResetOptions): Promise<string>;
19
+ declare function verifyPasswordResetToken(token: string, password: Password): Promise<{
20
+ userId: string;
21
+ } | null>;
22
+ declare function resetPassword(token: string, newPassword: string, password: Password): Promise<{
23
+ userId: string;
24
+ hash: string;
25
+ } | null>;
26
+ //#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 };
package/dist/index.mjs CHANGED
@@ -1,4 +1,6 @@
1
1
  import { n as sealData, r as unsealData, t as createSessionFromAdapter } from "./session-DSwf3XPH.mjs";
2
+ import { generateCsrf, validateCsrf } from "./csrf.mjs";
3
+ import { signJWT, verifyJWT } from "./jwt.mjs";
2
4
  import { compareSync, genSaltSync, hashSync } from "bcryptjs";
3
5
  //#region src/password.ts
4
6
  async function hashPassword(password, options = {}) {
@@ -8,4 +10,29 @@ async function verifyPassword(hash, password) {
8
10
  return compareSync(password, hash);
9
11
  }
10
12
  //#endregion
11
- export { createSessionFromAdapter, hashPassword, sealData, unsealData, verifyPassword };
13
+ //#region src/reset-password.ts
14
+ const DEFAULT_EXPIRY = 3600;
15
+ async function createPasswordResetToken(userId, options) {
16
+ return signJWT({
17
+ userId,
18
+ purpose: "password-reset"
19
+ }, {
20
+ password: options.password,
21
+ exp: options.exp ?? DEFAULT_EXPIRY
22
+ });
23
+ }
24
+ async function verifyPasswordResetToken(token, password) {
25
+ const payload = await verifyJWT(token, { password });
26
+ if (!payload || payload.purpose !== "password-reset") return null;
27
+ return { userId: payload.userId };
28
+ }
29
+ async function resetPassword(token, newPassword, password) {
30
+ const payload = await verifyPasswordResetToken(token, password);
31
+ if (!payload) return null;
32
+ return {
33
+ userId: payload.userId,
34
+ hash: await hashPassword(newPassword)
35
+ };
36
+ }
37
+ //#endregion
38
+ export { createPasswordResetToken, createSessionFromAdapter, generateCsrf, hashPassword, resetPassword, sealData, signJWT, unsealData, validateCsrf, verifyJWT, verifyPassword, verifyPasswordResetToken };
package/dist/jwt.d.mts ADDED
@@ -0,0 +1,11 @@
1
+ import { t as Password } from "./crypto-Ln_Mj_zp.mjs";
2
+
3
+ //#region src/jwt.d.ts
4
+ interface JWTOptions {
5
+ password: Password;
6
+ exp?: number;
7
+ }
8
+ declare function signJWT(payload: Record<string, unknown>, options: JWTOptions): Promise<string>;
9
+ declare function verifyJWT<T = Record<string, unknown>>(token: string, options: JWTOptions): Promise<T | null>;
10
+ //#endregion
11
+ export { JWTOptions, signJWT, verifyJWT };
package/dist/jwt.mjs ADDED
@@ -0,0 +1,28 @@
1
+ import * as jose from "jose";
2
+ //#region src/jwt.ts
3
+ function toPasswordMap(password) {
4
+ return typeof password === "string" ? { 1: password } : password;
5
+ }
6
+ function toKey(secret) {
7
+ return new TextEncoder().encode(secret);
8
+ }
9
+ async function signJWT(payload, options) {
10
+ const map = toPasswordMap(options.password);
11
+ 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");
13
+ 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);
15
+ return jwt.sign(toKey(secret));
16
+ }
17
+ async function verifyJWT(token, options) {
18
+ for (const secret of Object.values(toPasswordMap(options.password))) {
19
+ if (!secret) continue;
20
+ try {
21
+ const { payload } = await jose.jwtVerify(token, toKey(secret));
22
+ return payload;
23
+ } catch {}
24
+ }
25
+ return null;
26
+ }
27
+ //#endregion
28
+ export { signJWT, verifyJWT };
package/dist/nuxt.d.mts CHANGED
@@ -1,7 +1,8 @@
1
- import { r as SessionOptions, t as IronSession } from "./session-DYH_m3lO.mjs";
1
+ import { r as SessionOptions, t as IronSession } from "./session-z20gaFVT.mjs";
2
2
  import { H3Event } from "h3";
3
3
 
4
4
  //#region src/nuxt.d.ts
5
- declare function useSession(event: H3Event, options: SessionOptions): Promise<IronSession>;
5
+ 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;
6
7
  //#endregion
7
- export { useSession };
8
+ export { requireSession, useSession };
package/dist/nuxt.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as createSessionFromAdapter } from "./session-DSwf3XPH.mjs";
2
- import { appendHeader, getCookie } from "h3";
2
+ import { appendHeader, createError, getCookie } from "h3";
3
3
  //#region src/nuxt.ts
4
4
  function useSession(event, options) {
5
5
  const password = options.password ?? process.env.NUXT_SESSION_PASSWORD;
@@ -14,5 +14,11 @@ function useSession(event, options) {
14
14
  cookieOptions: options?.cookieOptions
15
15
  });
16
16
  }
17
+ function requireSession(_event, session) {
18
+ if (!Object.keys(session).some((k) => k !== "save" && k !== "destroy" && k !== "updateConfig")) throw createError({
19
+ statusCode: 401,
20
+ statusMessage: "unauthorized"
21
+ });
22
+ }
17
23
  //#endregion
18
- export { useSession };
24
+ export { requireSession, useSession };
@@ -1,23 +1,6 @@
1
+ import { t as Password } from "./crypto-Ln_Mj_zp.mjs";
1
2
  import { SerializeOptions } from "cookie";
2
3
 
3
- //#region src/crypto.d.ts
4
- type PasswordsMap = Record<string, string>;
5
- type Password = PasswordsMap | string;
6
- declare const sealData: (data: unknown, {
7
- password,
8
- ttl
9
- }: {
10
- password: Password;
11
- ttl?: number;
12
- }) => Promise<string>;
13
- declare const unsealData: <T>(seal: string, {
14
- password,
15
- ttl
16
- }: {
17
- password: Password;
18
- ttl?: number;
19
- }) => Promise<T>;
20
- //#endregion
21
4
  //#region src/session.d.ts
22
5
  interface SessionOptions {
23
6
  password: Password;
@@ -37,4 +20,4 @@ interface SessionAdapter {
37
20
  }
38
21
  declare function createSessionFromAdapter<T extends Record<string, unknown> = Record<string, unknown>>(adapter: SessionAdapter, options: SessionOptions): Promise<T & IronSession>;
39
22
  //#endregion
40
- export { Password as a, createSessionFromAdapter as i, SessionAdapter as n, sealData as o, SessionOptions as r, unsealData as s, IronSession as t };
23
+ export { createSessionFromAdapter as i, SessionAdapter as n, SessionOptions as r, IronSession as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "peta-auth",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Encrypted cookie sessions for Bun — Hono, ElysiaJS & Nuxt adapters",
5
5
  "type": "module",
6
6
  "module": "./dist/index.mjs",
@@ -22,6 +22,14 @@
22
22
  "types": "./dist/nuxt.d.mts",
23
23
  "import": "./dist/nuxt.mjs"
24
24
  },
25
+ "./jwt": {
26
+ "types": "./dist/jwt.d.mts",
27
+ "import": "./dist/jwt.mjs"
28
+ },
29
+ "./csrf": {
30
+ "types": "./dist/csrf.d.mts",
31
+ "import": "./dist/csrf.mjs"
32
+ },
25
33
  "./oauth/github": {
26
34
  "types": "./dist/oauth/github.d.mts",
27
35
  "import": "./dist/oauth/github.mjs"
@@ -39,18 +47,20 @@
39
47
  "lint": "biome check --write .",
40
48
  "lint:ci": "biome ci .",
41
49
  "prepublish": "bun run build",
42
- "test": "bun test"
50
+ "test": "bun test",
51
+ "typecheck": "tsc --noEmit"
43
52
  },
44
53
  "dependencies": {
45
54
  "bcryptjs": "^3.0.3",
46
55
  "cookie": "^1.0.2",
47
- "iron-webcrypto": "^1.2.1"
56
+ "iron-webcrypto": "^1.2.1",
57
+ "jose": "^6.2.3"
48
58
  },
49
59
  "peerDependencies": {
50
60
  "elysia": ">=1.0.0",
51
61
  "h3": ">=1.15.0",
52
62
  "hono": ">=4.0.0",
53
- "typescript": "^5.0.0"
63
+ "typescript": "^6.0.0"
54
64
  },
55
65
  "peerDependenciesMeta": {
56
66
  "elysia": {
@@ -71,6 +81,6 @@
71
81
  "h3": "latest",
72
82
  "hono": "latest",
73
83
  "tsdown": "latest",
74
- "typescript": "^5.0.0"
84
+ "typescript": "^6.0.3"
75
85
  }
76
86
  }