next-lite-auth 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 aminuddin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,219 @@
1
+ # next-lite-auth
2
+
3
+ Lightweight JWT auth for Next.js using static JSON users — no database required.
4
+
5
+ > **Not for production.** Designed for demos, OSS projects, internal tools, and quick Vercel deployments.
6
+
7
+ ---
8
+
9
+ ## Requirements
10
+
11
+ - Node.js >= 20
12
+ - Next.js >= 13
13
+ - React >= 18
14
+ - TypeScript
15
+
16
+ ---
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pnpm add next-lite-auth jose
22
+ ```
23
+
24
+ ---
25
+
26
+ ## Setup
27
+
28
+ ### 1. Create your auth instance
29
+
30
+ ```ts
31
+ // lib/auth.ts
32
+ import { createLiteAuth } from "next-lite-auth";
33
+
34
+ export const auth = createLiteAuth({
35
+ users: [
36
+ { email: "admin@example.com", password: "secret", role: "admin", name: "Admin" },
37
+ { email: "user@example.com", password: "pass123", role: "user", name: "User" },
38
+ ],
39
+ jwtSecret: process.env.JWT_SECRET!,
40
+ cookieName: "lite-auth-token", // optional, this is the default
41
+ });
42
+ ```
43
+
44
+ ### 2. Add route handlers
45
+
46
+ ```ts
47
+ // app/api/auth/login/route.ts
48
+ import { auth } from "@/lib/auth";
49
+ export const POST = auth.handlers.login;
50
+
51
+ // app/api/auth/logout/route.ts
52
+ import { auth } from "@/lib/auth";
53
+ export const POST = auth.handlers.logout;
54
+
55
+ // app/api/auth/me/route.ts
56
+ import { auth } from "@/lib/auth";
57
+ export const GET = auth.handlers.me;
58
+ ```
59
+
60
+ ### 3. Add middleware
61
+
62
+ ```ts
63
+ // middleware.ts
64
+ import { auth } from "@/lib/auth";
65
+
66
+ export default auth.middleware({
67
+ protect: ["/dashboard", "/settings"],
68
+ redirectTo: "/login", // optional, default is "/login"
69
+ });
70
+
71
+ export const config = {
72
+ matcher: ["/((?!_next|api/auth).*)"],
73
+ };
74
+ ```
75
+
76
+ ### 4. Use on the client
77
+
78
+ ```tsx
79
+ "use client";
80
+
81
+ import { useLiteAuth } from "next-lite-auth/client";
82
+
83
+ export default function LoginPage() {
84
+ const { user, loading, login, logout } = useLiteAuth();
85
+
86
+ if (loading) return <p>Loading...</p>;
87
+
88
+ if (user) {
89
+ return (
90
+ <div>
91
+ <p>Hello, {user.name ?? user.email}</p>
92
+ <button onClick={logout}>Logout</button>
93
+ </div>
94
+ );
95
+ }
96
+
97
+ return (
98
+ <form
99
+ onSubmit={async (e) => {
100
+ e.preventDefault();
101
+ const form = e.currentTarget;
102
+ const result = await login({
103
+ email: form.email.value,
104
+ password: form.password.value,
105
+ });
106
+ if (result.error) alert(result.error);
107
+ }}
108
+ >
109
+ <input name="email" type="email" placeholder="Email" />
110
+ <input name="password" type="password" placeholder="Password" />
111
+ <button type="submit">Login</button>
112
+ </form>
113
+ );
114
+ }
115
+ ```
116
+
117
+ ### 5. Read user on the server
118
+
119
+ ```ts
120
+ // app/dashboard/page.tsx
121
+ import { cookies } from "next/headers";
122
+ import { auth } from "@/lib/auth";
123
+
124
+ export default async function DashboardPage() {
125
+ const user = await auth.getUserFromCookies(cookies());
126
+ return <p>Welcome, {user?.name}</p>;
127
+ }
128
+ ```
129
+
130
+ ---
131
+
132
+ ## API Reference
133
+
134
+ ### `createLiteAuth(config)`
135
+
136
+ | Option | Type | Required | Description |
137
+ |---|---|---|---|
138
+ | `users` | `User[]` | Yes | Hardcoded list of users |
139
+ | `jwtSecret` | `string` | Yes | Secret used to sign JWTs |
140
+ | `cookieName` | `string` | No | Cookie name (default: `"lite-auth-token"`) |
141
+
142
+ Returns `{ handlers, middleware, getUserFromCookies }`.
143
+
144
+ ---
145
+
146
+ ### `User` type
147
+
148
+ ```ts
149
+ type User = {
150
+ email: string;
151
+ password: string;
152
+ role?: string;
153
+ name?: string;
154
+ };
155
+ ```
156
+
157
+ ---
158
+
159
+ ### `auth.handlers`
160
+
161
+ | Handler | Method | Route |
162
+ |---|---|---|
163
+ | `login` | POST | `/api/auth/login` |
164
+ | `logout` | POST | `/api/auth/logout` |
165
+ | `me` | GET | `/api/auth/me` |
166
+
167
+ ---
168
+
169
+ ### `auth.middleware(options)`
170
+
171
+ | Option | Type | Default | Description |
172
+ |---|---|---|---|
173
+ | `protect` | `string[]` | — | Route prefixes to protect |
174
+ | `redirectTo` | `string` | `"/login"` | Where to redirect unauthenticated users |
175
+
176
+ Appends `?from=<pathname>` to the redirect URL.
177
+
178
+ ---
179
+
180
+ ### `auth.getUserFromCookies(cookies)`
181
+
182
+ Server-side helper. Accepts Next.js `cookies()` and returns the current `PublicUser` or `null`.
183
+
184
+ ---
185
+
186
+ ### `useLiteAuth(options?)`
187
+
188
+ Client hook. Fetches `/api/auth/me` on mount.
189
+
190
+ ```ts
191
+ const { user, loading, login, logout } = useLiteAuth({
192
+ loginPath: "/api/auth/login", // optional
193
+ logoutPath: "/api/auth/logout", // optional
194
+ mePath: "/api/auth/me", // optional
195
+ });
196
+ ```
197
+
198
+ | Return | Type | Description |
199
+ |---|---|---|
200
+ | `user` | `PublicUser \| null` | Current authenticated user |
201
+ | `loading` | `boolean` | True while fetching session |
202
+ | `login(creds)` | `Promise<{ error?: string }>` | Logs in and sets user state |
203
+ | `logout()` | `Promise<void>` | Clears cookie and user state |
204
+
205
+ ---
206
+
207
+ ## Non-Goals
208
+
209
+ - OAuth / social login
210
+ - Signup / registration
211
+ - Password reset
212
+ - Role-based access control
213
+ - Production-grade security
214
+
215
+ ---
216
+
217
+ ## License
218
+
219
+ MIT
@@ -0,0 +1,30 @@
1
+ type User = {
2
+ email: string;
3
+ password: string;
4
+ role?: string;
5
+ name?: string;
6
+ };
7
+ type PublicUser = Omit<User, "password">;
8
+
9
+ type LiteAuthState = {
10
+ user: PublicUser | null;
11
+ loading: boolean;
12
+ };
13
+ type LoginCredentials = {
14
+ email: string;
15
+ password: string;
16
+ };
17
+ type UseLiteAuthReturn = LiteAuthState & {
18
+ login: (credentials: LoginCredentials) => Promise<{
19
+ error?: string;
20
+ }>;
21
+ logout: () => Promise<void>;
22
+ };
23
+ type UseLiteAuthOptions = {
24
+ loginPath?: string;
25
+ logoutPath?: string;
26
+ mePath?: string;
27
+ };
28
+ declare function useLiteAuth(options?: UseLiteAuthOptions): UseLiteAuthReturn;
29
+
30
+ export { useLiteAuth };
@@ -0,0 +1,30 @@
1
+ type User = {
2
+ email: string;
3
+ password: string;
4
+ role?: string;
5
+ name?: string;
6
+ };
7
+ type PublicUser = Omit<User, "password">;
8
+
9
+ type LiteAuthState = {
10
+ user: PublicUser | null;
11
+ loading: boolean;
12
+ };
13
+ type LoginCredentials = {
14
+ email: string;
15
+ password: string;
16
+ };
17
+ type UseLiteAuthReturn = LiteAuthState & {
18
+ login: (credentials: LoginCredentials) => Promise<{
19
+ error?: string;
20
+ }>;
21
+ logout: () => Promise<void>;
22
+ };
23
+ type UseLiteAuthOptions = {
24
+ loginPath?: string;
25
+ logoutPath?: string;
26
+ mePath?: string;
27
+ };
28
+ declare function useLiteAuth(options?: UseLiteAuthOptions): UseLiteAuthReturn;
29
+
30
+ export { useLiteAuth };
package/dist/client.js ADDED
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/client/index.ts
21
+ var client_exports = {};
22
+ __export(client_exports, {
23
+ useLiteAuth: () => useLiteAuth
24
+ });
25
+ module.exports = __toCommonJS(client_exports);
26
+
27
+ // src/client/useLiteAuth.ts
28
+ var import_react = require("react");
29
+ function useLiteAuth(options = {}) {
30
+ const {
31
+ loginPath = "/api/auth/login",
32
+ logoutPath = "/api/auth/logout",
33
+ mePath = "/api/auth/me"
34
+ } = options;
35
+ const [state, setState] = (0, import_react.useState)({ user: null, loading: true });
36
+ (0, import_react.useEffect)(() => {
37
+ fetch(mePath).then((r) => r.json()).then(({ user }) => setState({ user: user ?? null, loading: false })).catch(() => setState({ user: null, loading: false }));
38
+ }, [mePath]);
39
+ const login = (0, import_react.useCallback)(
40
+ async ({ email, password }) => {
41
+ const res = await fetch(loginPath, {
42
+ method: "POST",
43
+ headers: { "Content-Type": "application/json" },
44
+ body: JSON.stringify({ email, password })
45
+ });
46
+ const data = await res.json();
47
+ if (!res.ok) return { error: data.error ?? "Login failed" };
48
+ setState({ user: data.user, loading: false });
49
+ return {};
50
+ },
51
+ [loginPath]
52
+ );
53
+ const logout = (0, import_react.useCallback)(async () => {
54
+ await fetch(logoutPath, { method: "POST" });
55
+ setState({ user: null, loading: false });
56
+ }, [logoutPath]);
57
+ return { ...state, login, logout };
58
+ }
59
+ // Annotate the CommonJS export names for ESM import in node:
60
+ 0 && (module.exports = {
61
+ useLiteAuth
62
+ });
63
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client/index.ts","../src/client/useLiteAuth.ts"],"sourcesContent":["export { useLiteAuth } from \"./useLiteAuth\";\n","\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport { PublicUser } from \"../core/types\";\n\ntype LiteAuthState = {\n user: PublicUser | null;\n loading: boolean;\n};\n\ntype LoginCredentials = {\n email: string;\n password: string;\n};\n\ntype UseLiteAuthReturn = LiteAuthState & {\n login: (credentials: LoginCredentials) => Promise<{ error?: string }>;\n logout: () => Promise<void>;\n};\n\ntype UseLiteAuthOptions = {\n loginPath?: string;\n logoutPath?: string;\n mePath?: string;\n};\n\nexport function useLiteAuth(options: UseLiteAuthOptions = {}): UseLiteAuthReturn {\n const {\n loginPath = \"/api/auth/login\",\n logoutPath = \"/api/auth/logout\",\n mePath = \"/api/auth/me\",\n } = options;\n\n const [state, setState] = useState<LiteAuthState>({ user: null, loading: true });\n\n useEffect(() => {\n fetch(mePath)\n .then((r) => r.json())\n .then(({ user }) => setState({ user: user ?? null, loading: false }))\n .catch(() => setState({ user: null, loading: false }));\n }, [mePath]);\n\n const login = useCallback(\n async ({ email, password }: LoginCredentials) => {\n const res = await fetch(loginPath, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ email, password }),\n });\n const data = await res.json();\n if (!res.ok) return { error: data.error ?? \"Login failed\" };\n setState({ user: data.user, loading: false });\n return {};\n },\n [loginPath]\n );\n\n const logout = useCallback(async () => {\n await fetch(logoutPath, { method: \"POST\" });\n setState({ user: null, loading: false });\n }, [logoutPath]);\n\n return { ...state, login, logout };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,mBAAiD;AAwB1C,SAAS,YAAY,UAA8B,CAAC,GAAsB;AAC/E,QAAM;AAAA,IACJ,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,SAAS;AAAA,EACX,IAAI;AAEJ,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAwB,EAAE,MAAM,MAAM,SAAS,KAAK,CAAC;AAE/E,8BAAU,MAAM;AACd,UAAM,MAAM,EACT,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,EACpB,KAAK,CAAC,EAAE,KAAK,MAAM,SAAS,EAAE,MAAM,QAAQ,MAAM,SAAS,MAAM,CAAC,CAAC,EACnE,MAAM,MAAM,SAAS,EAAE,MAAM,MAAM,SAAS,MAAM,CAAC,CAAC;AAAA,EACzD,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,YAAQ;AAAA,IACZ,OAAO,EAAE,OAAO,SAAS,MAAwB;AAC/C,YAAM,MAAM,MAAM,MAAM,WAAW;AAAA,QACjC,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,OAAO,SAAS,CAAC;AAAA,MAC1C,CAAC;AACD,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAI,CAAC,IAAI,GAAI,QAAO,EAAE,OAAO,KAAK,SAAS,eAAe;AAC1D,eAAS,EAAE,MAAM,KAAK,MAAM,SAAS,MAAM,CAAC;AAC5C,aAAO,CAAC;AAAA,IACV;AAAA,IACA,CAAC,SAAS;AAAA,EACZ;AAEA,QAAM,aAAS,0BAAY,YAAY;AACrC,UAAM,MAAM,YAAY,EAAE,QAAQ,OAAO,CAAC;AAC1C,aAAS,EAAE,MAAM,MAAM,SAAS,MAAM,CAAC;AAAA,EACzC,GAAG,CAAC,UAAU,CAAC;AAEf,SAAO,EAAE,GAAG,OAAO,OAAO,OAAO;AACnC;","names":[]}
@@ -0,0 +1,36 @@
1
+ // src/client/useLiteAuth.ts
2
+ import { useState, useEffect, useCallback } from "react";
3
+ function useLiteAuth(options = {}) {
4
+ const {
5
+ loginPath = "/api/auth/login",
6
+ logoutPath = "/api/auth/logout",
7
+ mePath = "/api/auth/me"
8
+ } = options;
9
+ const [state, setState] = useState({ user: null, loading: true });
10
+ useEffect(() => {
11
+ fetch(mePath).then((r) => r.json()).then(({ user }) => setState({ user: user ?? null, loading: false })).catch(() => setState({ user: null, loading: false }));
12
+ }, [mePath]);
13
+ const login = useCallback(
14
+ async ({ email, password }) => {
15
+ const res = await fetch(loginPath, {
16
+ method: "POST",
17
+ headers: { "Content-Type": "application/json" },
18
+ body: JSON.stringify({ email, password })
19
+ });
20
+ const data = await res.json();
21
+ if (!res.ok) return { error: data.error ?? "Login failed" };
22
+ setState({ user: data.user, loading: false });
23
+ return {};
24
+ },
25
+ [loginPath]
26
+ );
27
+ const logout = useCallback(async () => {
28
+ await fetch(logoutPath, { method: "POST" });
29
+ setState({ user: null, loading: false });
30
+ }, [logoutPath]);
31
+ return { ...state, login, logout };
32
+ }
33
+ export {
34
+ useLiteAuth
35
+ };
36
+ //# sourceMappingURL=client.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client/useLiteAuth.ts"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport { PublicUser } from \"../core/types\";\n\ntype LiteAuthState = {\n user: PublicUser | null;\n loading: boolean;\n};\n\ntype LoginCredentials = {\n email: string;\n password: string;\n};\n\ntype UseLiteAuthReturn = LiteAuthState & {\n login: (credentials: LoginCredentials) => Promise<{ error?: string }>;\n logout: () => Promise<void>;\n};\n\ntype UseLiteAuthOptions = {\n loginPath?: string;\n logoutPath?: string;\n mePath?: string;\n};\n\nexport function useLiteAuth(options: UseLiteAuthOptions = {}): UseLiteAuthReturn {\n const {\n loginPath = \"/api/auth/login\",\n logoutPath = \"/api/auth/logout\",\n mePath = \"/api/auth/me\",\n } = options;\n\n const [state, setState] = useState<LiteAuthState>({ user: null, loading: true });\n\n useEffect(() => {\n fetch(mePath)\n .then((r) => r.json())\n .then(({ user }) => setState({ user: user ?? null, loading: false }))\n .catch(() => setState({ user: null, loading: false }));\n }, [mePath]);\n\n const login = useCallback(\n async ({ email, password }: LoginCredentials) => {\n const res = await fetch(loginPath, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ email, password }),\n });\n const data = await res.json();\n if (!res.ok) return { error: data.error ?? \"Login failed\" };\n setState({ user: data.user, loading: false });\n return {};\n },\n [loginPath]\n );\n\n const logout = useCallback(async () => {\n await fetch(logoutPath, { method: \"POST\" });\n setState({ user: null, loading: false });\n }, [logoutPath]);\n\n return { ...state, login, logout };\n}\n"],"mappings":";AAEA,SAAS,UAAU,WAAW,mBAAmB;AAwB1C,SAAS,YAAY,UAA8B,CAAC,GAAsB;AAC/E,QAAM;AAAA,IACJ,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,SAAS;AAAA,EACX,IAAI;AAEJ,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,EAAE,MAAM,MAAM,SAAS,KAAK,CAAC;AAE/E,YAAU,MAAM;AACd,UAAM,MAAM,EACT,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,EACpB,KAAK,CAAC,EAAE,KAAK,MAAM,SAAS,EAAE,MAAM,QAAQ,MAAM,SAAS,MAAM,CAAC,CAAC,EACnE,MAAM,MAAM,SAAS,EAAE,MAAM,MAAM,SAAS,MAAM,CAAC,CAAC;AAAA,EACzD,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,QAAQ;AAAA,IACZ,OAAO,EAAE,OAAO,SAAS,MAAwB;AAC/C,YAAM,MAAM,MAAM,MAAM,WAAW;AAAA,QACjC,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,OAAO,SAAS,CAAC;AAAA,MAC1C,CAAC;AACD,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAI,CAAC,IAAI,GAAI,QAAO,EAAE,OAAO,KAAK,SAAS,eAAe;AAC1D,eAAS,EAAE,MAAM,KAAK,MAAM,SAAS,MAAM,CAAC;AAC5C,aAAO,CAAC;AAAA,IACV;AAAA,IACA,CAAC,SAAS;AAAA,EACZ;AAEA,QAAM,SAAS,YAAY,YAAY;AACrC,UAAM,MAAM,YAAY,EAAE,QAAQ,OAAO,CAAC;AAC1C,aAAS,EAAE,MAAM,MAAM,SAAS,MAAM,CAAC;AAAA,EACzC,GAAG,CAAC,UAAU,CAAC;AAEf,SAAO,EAAE,GAAG,OAAO,OAAO,OAAO;AACnC;","names":[]}
@@ -0,0 +1,30 @@
1
+ import * as next_dist_server_web_spec_extension_adapters_request_cookies from 'next/dist/server/web/spec-extension/adapters/request-cookies';
2
+ import * as next_server from 'next/server';
3
+
4
+ type User = {
5
+ email: string;
6
+ password: string;
7
+ role?: string;
8
+ name?: string;
9
+ };
10
+ type PublicUser = Omit<User, "password">;
11
+ type LiteAuthConfig = {
12
+ users: User[];
13
+ jwtSecret: string;
14
+ cookieName?: string;
15
+ };
16
+
17
+ declare function createLiteAuth(config: LiteAuthConfig): {
18
+ handlers: {
19
+ login: (req: next_server.NextRequest) => Promise<next_server.NextResponse>;
20
+ logout: (_req: next_server.NextRequest) => Promise<next_server.NextResponse>;
21
+ me: (req: next_server.NextRequest) => Promise<next_server.NextResponse>;
22
+ };
23
+ middleware: (options: {
24
+ protect: string[];
25
+ redirectTo?: string;
26
+ }) => (req: next_server.NextRequest) => Promise<next_server.NextResponse>;
27
+ getUserFromCookies: (cookies: next_dist_server_web_spec_extension_adapters_request_cookies.ReadonlyRequestCookies) => Promise<PublicUser | null>;
28
+ };
29
+
30
+ export { type LiteAuthConfig, type PublicUser, type User, createLiteAuth };
@@ -0,0 +1,30 @@
1
+ import * as next_dist_server_web_spec_extension_adapters_request_cookies from 'next/dist/server/web/spec-extension/adapters/request-cookies';
2
+ import * as next_server from 'next/server';
3
+
4
+ type User = {
5
+ email: string;
6
+ password: string;
7
+ role?: string;
8
+ name?: string;
9
+ };
10
+ type PublicUser = Omit<User, "password">;
11
+ type LiteAuthConfig = {
12
+ users: User[];
13
+ jwtSecret: string;
14
+ cookieName?: string;
15
+ };
16
+
17
+ declare function createLiteAuth(config: LiteAuthConfig): {
18
+ handlers: {
19
+ login: (req: next_server.NextRequest) => Promise<next_server.NextResponse>;
20
+ logout: (_req: next_server.NextRequest) => Promise<next_server.NextResponse>;
21
+ me: (req: next_server.NextRequest) => Promise<next_server.NextResponse>;
22
+ };
23
+ middleware: (options: {
24
+ protect: string[];
25
+ redirectTo?: string;
26
+ }) => (req: next_server.NextRequest) => Promise<next_server.NextResponse>;
27
+ getUserFromCookies: (cookies: next_dist_server_web_spec_extension_adapters_request_cookies.ReadonlyRequestCookies) => Promise<PublicUser | null>;
28
+ };
29
+
30
+ export { type LiteAuthConfig, type PublicUser, type User, createLiteAuth };
package/dist/index.js ADDED
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ createLiteAuth: () => createLiteAuth
24
+ });
25
+ module.exports = __toCommonJS(src_exports);
26
+
27
+ // src/server/handlers.ts
28
+ var import_server = require("next/server");
29
+
30
+ // src/server/jwt.ts
31
+ var import_jose = require("jose");
32
+ function getSecret(secret) {
33
+ return new TextEncoder().encode(secret);
34
+ }
35
+ async function signToken(user, secret) {
36
+ return new import_jose.SignJWT({ ...user }).setProtectedHeader({ alg: "HS256" }).setIssuedAt().setExpirationTime("7d").sign(getSecret(secret));
37
+ }
38
+ async function verifyToken(token, secret) {
39
+ try {
40
+ const { payload } = await (0, import_jose.jwtVerify)(token, getSecret(secret));
41
+ return payload;
42
+ } catch {
43
+ return null;
44
+ }
45
+ }
46
+
47
+ // src/server/handlers.ts
48
+ function makeLoginHandler(ctx) {
49
+ return async function loginHandler(req) {
50
+ let body;
51
+ try {
52
+ body = await req.json();
53
+ } catch {
54
+ return import_server.NextResponse.json({ error: "Invalid JSON" }, { status: 400 });
55
+ }
56
+ const { email, password } = body;
57
+ if (!email || !password) {
58
+ return import_server.NextResponse.json({ error: "Email and password are required" }, { status: 400 });
59
+ }
60
+ const user = ctx.users.find((u) => u.email === email && u.password === password);
61
+ if (!user) {
62
+ return import_server.NextResponse.json({ error: "Invalid credentials" }, { status: 401 });
63
+ }
64
+ const { password: _, ...publicUser } = user;
65
+ const token = await signToken(publicUser, ctx.jwtSecret);
66
+ const res = import_server.NextResponse.json({ user: publicUser });
67
+ res.cookies.set(ctx.cookieName, token, {
68
+ httpOnly: true,
69
+ path: "/",
70
+ sameSite: "lax",
71
+ secure: process.env.NODE_ENV === "production",
72
+ maxAge: 60 * 60 * 24 * 7
73
+ // 7 days
74
+ });
75
+ return res;
76
+ };
77
+ }
78
+ function makeLogoutHandler(ctx) {
79
+ return async function logoutHandler(_req) {
80
+ const res = import_server.NextResponse.json({ ok: true });
81
+ res.cookies.set(ctx.cookieName, "", {
82
+ httpOnly: true,
83
+ path: "/",
84
+ maxAge: 0
85
+ });
86
+ return res;
87
+ };
88
+ }
89
+ function makeMeHandler(ctx) {
90
+ return async function meHandler(req) {
91
+ const token = req.cookies.get(ctx.cookieName)?.value;
92
+ if (!token) {
93
+ return import_server.NextResponse.json({ user: null }, { status: 401 });
94
+ }
95
+ const user = await verifyToken(token, ctx.jwtSecret);
96
+ if (!user) {
97
+ return import_server.NextResponse.json({ user: null }, { status: 401 });
98
+ }
99
+ return import_server.NextResponse.json({ user });
100
+ };
101
+ }
102
+
103
+ // src/server/getUserFromCookies.ts
104
+ function getUserFromCookies(ctx) {
105
+ return async function(cookies) {
106
+ const token = cookies.get(ctx.cookieName)?.value;
107
+ if (!token) return null;
108
+ return verifyToken(token, ctx.jwtSecret);
109
+ };
110
+ }
111
+
112
+ // src/middleware/index.ts
113
+ var import_server2 = require("next/server");
114
+ function makeMiddleware(ctx) {
115
+ return function middleware(options) {
116
+ return async function(req) {
117
+ const { protect, redirectTo = "/login" } = options;
118
+ const { pathname } = req.nextUrl;
119
+ const isProtected = protect.some(
120
+ (pattern) => pathname === pattern || pathname.startsWith(pattern + "/")
121
+ );
122
+ if (!isProtected) {
123
+ return import_server2.NextResponse.next();
124
+ }
125
+ const token = req.cookies.get(ctx.cookieName)?.value;
126
+ if (token) {
127
+ const user = await verifyToken(token, ctx.jwtSecret);
128
+ if (user) return import_server2.NextResponse.next();
129
+ }
130
+ const loginUrl = new URL(redirectTo, req.url);
131
+ loginUrl.searchParams.set("from", pathname);
132
+ return import_server2.NextResponse.redirect(loginUrl);
133
+ };
134
+ };
135
+ }
136
+
137
+ // src/core/createLiteAuth.ts
138
+ function createLiteAuth(config) {
139
+ const ctx = {
140
+ users: config.users,
141
+ jwtSecret: config.jwtSecret,
142
+ cookieName: config.cookieName ?? "lite-auth-token"
143
+ };
144
+ return {
145
+ handlers: {
146
+ login: makeLoginHandler(ctx),
147
+ logout: makeLogoutHandler(ctx),
148
+ me: makeMeHandler(ctx)
149
+ },
150
+ middleware: makeMiddleware(ctx),
151
+ getUserFromCookies: getUserFromCookies(ctx)
152
+ };
153
+ }
154
+ // Annotate the CommonJS export names for ESM import in node:
155
+ 0 && (module.exports = {
156
+ createLiteAuth
157
+ });
158
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/server/handlers.ts","../src/server/jwt.ts","../src/server/getUserFromCookies.ts","../src/middleware/index.ts","../src/core/createLiteAuth.ts"],"sourcesContent":["export { createLiteAuth } from \"./core/createLiteAuth\";\nexport type { User, PublicUser, LiteAuthConfig } from \"./core/types\";\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { LiteAuthContext } from \"../core/types\";\nimport { signToken, verifyToken } from \"./jwt\";\n\nexport function makeLoginHandler(ctx: LiteAuthContext) {\n return async function loginHandler(req: NextRequest): Promise<NextResponse> {\n let body: { email?: string; password?: string };\n try {\n body = await req.json();\n } catch {\n return NextResponse.json({ error: \"Invalid JSON\" }, { status: 400 });\n }\n\n const { email, password } = body;\n if (!email || !password) {\n return NextResponse.json({ error: \"Email and password are required\" }, { status: 400 });\n }\n\n const user = ctx.users.find((u) => u.email === email && u.password === password);\n if (!user) {\n return NextResponse.json({ error: \"Invalid credentials\" }, { status: 401 });\n }\n\n const { password: _, ...publicUser } = user;\n const token = await signToken(publicUser, ctx.jwtSecret);\n\n const res = NextResponse.json({ user: publicUser });\n res.cookies.set(ctx.cookieName, token, {\n httpOnly: true,\n path: \"/\",\n sameSite: \"lax\",\n secure: process.env.NODE_ENV === \"production\",\n maxAge: 60 * 60 * 24 * 7, // 7 days\n });\n return res;\n };\n}\n\nexport function makeLogoutHandler(ctx: LiteAuthContext) {\n return async function logoutHandler(_req: NextRequest): Promise<NextResponse> {\n const res = NextResponse.json({ ok: true });\n res.cookies.set(ctx.cookieName, \"\", {\n httpOnly: true,\n path: \"/\",\n maxAge: 0,\n });\n return res;\n };\n}\n\nexport function makeMeHandler(ctx: LiteAuthContext) {\n return async function meHandler(req: NextRequest): Promise<NextResponse> {\n const token = req.cookies.get(ctx.cookieName)?.value;\n if (!token) {\n return NextResponse.json({ user: null }, { status: 401 });\n }\n\n const user = await verifyToken(token, ctx.jwtSecret);\n if (!user) {\n return NextResponse.json({ user: null }, { status: 401 });\n }\n\n return NextResponse.json({ user });\n };\n}\n","import { SignJWT, jwtVerify } from \"jose\";\nimport { PublicUser } from \"../core/types\";\n\nfunction getSecret(secret: string) {\n return new TextEncoder().encode(secret);\n}\n\nexport async function signToken(user: PublicUser, secret: string): Promise<string> {\n return new SignJWT({ ...user })\n .setProtectedHeader({ alg: \"HS256\" })\n .setIssuedAt()\n .setExpirationTime(\"7d\")\n .sign(getSecret(secret));\n}\n\nexport async function verifyToken(token: string, secret: string): Promise<PublicUser | null> {\n try {\n const { payload } = await jwtVerify(token, getSecret(secret));\n return payload as unknown as PublicUser;\n } catch {\n return null;\n }\n}\n","import { ReadonlyRequestCookies } from \"next/dist/server/web/spec-extension/adapters/request-cookies\";\nimport { LiteAuthContext, PublicUser } from \"../core/types\";\nimport { verifyToken } from \"./jwt\";\n\nexport function getUserFromCookies(ctx: LiteAuthContext) {\n return async function (cookies: ReadonlyRequestCookies): Promise<PublicUser | null> {\n const token = cookies.get(ctx.cookieName)?.value;\n if (!token) return null;\n return verifyToken(token, ctx.jwtSecret);\n };\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { LiteAuthContext } from \"../core/types\";\nimport { verifyToken } from \"../server/jwt\";\n\ntype MiddlewareOptions = {\n protect: string[];\n redirectTo?: string;\n};\n\nexport function makeMiddleware(ctx: LiteAuthContext) {\n return function middleware(options: MiddlewareOptions) {\n return async function (req: NextRequest): Promise<NextResponse> {\n const { protect, redirectTo = \"/login\" } = options;\n const { pathname } = req.nextUrl;\n\n const isProtected = protect.some(\n (pattern) => pathname === pattern || pathname.startsWith(pattern + \"/\")\n );\n\n if (!isProtected) {\n return NextResponse.next();\n }\n\n const token = req.cookies.get(ctx.cookieName)?.value;\n if (token) {\n const user = await verifyToken(token, ctx.jwtSecret);\n if (user) return NextResponse.next();\n }\n\n const loginUrl = new URL(redirectTo, req.url);\n loginUrl.searchParams.set(\"from\", pathname);\n return NextResponse.redirect(loginUrl);\n };\n };\n}\n","import { LiteAuthConfig, LiteAuthContext } from \"./types\";\nimport { makeLoginHandler, makeLogoutHandler, makeMeHandler, getUserFromCookies } from \"../server\";\nimport { makeMiddleware } from \"../middleware\";\n\nexport function createLiteAuth(config: LiteAuthConfig) {\n const ctx: LiteAuthContext = {\n users: config.users,\n jwtSecret: config.jwtSecret,\n cookieName: config.cookieName ?? \"lite-auth-token\",\n };\n\n return {\n handlers: {\n login: makeLoginHandler(ctx),\n logout: makeLogoutHandler(ctx),\n me: makeMeHandler(ctx),\n },\n middleware: makeMiddleware(ctx),\n getUserFromCookies: getUserFromCookies(ctx),\n };\n}\n"],"mappings":"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","names":["import_server"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,131 @@
1
+ // src/server/handlers.ts
2
+ import { NextResponse } from "next/server";
3
+
4
+ // src/server/jwt.ts
5
+ import { SignJWT, jwtVerify } from "jose";
6
+ function getSecret(secret) {
7
+ return new TextEncoder().encode(secret);
8
+ }
9
+ async function signToken(user, secret) {
10
+ return new SignJWT({ ...user }).setProtectedHeader({ alg: "HS256" }).setIssuedAt().setExpirationTime("7d").sign(getSecret(secret));
11
+ }
12
+ async function verifyToken(token, secret) {
13
+ try {
14
+ const { payload } = await jwtVerify(token, getSecret(secret));
15
+ return payload;
16
+ } catch {
17
+ return null;
18
+ }
19
+ }
20
+
21
+ // src/server/handlers.ts
22
+ function makeLoginHandler(ctx) {
23
+ return async function loginHandler(req) {
24
+ let body;
25
+ try {
26
+ body = await req.json();
27
+ } catch {
28
+ return NextResponse.json({ error: "Invalid JSON" }, { status: 400 });
29
+ }
30
+ const { email, password } = body;
31
+ if (!email || !password) {
32
+ return NextResponse.json({ error: "Email and password are required" }, { status: 400 });
33
+ }
34
+ const user = ctx.users.find((u) => u.email === email && u.password === password);
35
+ if (!user) {
36
+ return NextResponse.json({ error: "Invalid credentials" }, { status: 401 });
37
+ }
38
+ const { password: _, ...publicUser } = user;
39
+ const token = await signToken(publicUser, ctx.jwtSecret);
40
+ const res = NextResponse.json({ user: publicUser });
41
+ res.cookies.set(ctx.cookieName, token, {
42
+ httpOnly: true,
43
+ path: "/",
44
+ sameSite: "lax",
45
+ secure: process.env.NODE_ENV === "production",
46
+ maxAge: 60 * 60 * 24 * 7
47
+ // 7 days
48
+ });
49
+ return res;
50
+ };
51
+ }
52
+ function makeLogoutHandler(ctx) {
53
+ return async function logoutHandler(_req) {
54
+ const res = NextResponse.json({ ok: true });
55
+ res.cookies.set(ctx.cookieName, "", {
56
+ httpOnly: true,
57
+ path: "/",
58
+ maxAge: 0
59
+ });
60
+ return res;
61
+ };
62
+ }
63
+ function makeMeHandler(ctx) {
64
+ return async function meHandler(req) {
65
+ const token = req.cookies.get(ctx.cookieName)?.value;
66
+ if (!token) {
67
+ return NextResponse.json({ user: null }, { status: 401 });
68
+ }
69
+ const user = await verifyToken(token, ctx.jwtSecret);
70
+ if (!user) {
71
+ return NextResponse.json({ user: null }, { status: 401 });
72
+ }
73
+ return NextResponse.json({ user });
74
+ };
75
+ }
76
+
77
+ // src/server/getUserFromCookies.ts
78
+ function getUserFromCookies(ctx) {
79
+ return async function(cookies) {
80
+ const token = cookies.get(ctx.cookieName)?.value;
81
+ if (!token) return null;
82
+ return verifyToken(token, ctx.jwtSecret);
83
+ };
84
+ }
85
+
86
+ // src/middleware/index.ts
87
+ import { NextResponse as NextResponse2 } from "next/server";
88
+ function makeMiddleware(ctx) {
89
+ return function middleware(options) {
90
+ return async function(req) {
91
+ const { protect, redirectTo = "/login" } = options;
92
+ const { pathname } = req.nextUrl;
93
+ const isProtected = protect.some(
94
+ (pattern) => pathname === pattern || pathname.startsWith(pattern + "/")
95
+ );
96
+ if (!isProtected) {
97
+ return NextResponse2.next();
98
+ }
99
+ const token = req.cookies.get(ctx.cookieName)?.value;
100
+ if (token) {
101
+ const user = await verifyToken(token, ctx.jwtSecret);
102
+ if (user) return NextResponse2.next();
103
+ }
104
+ const loginUrl = new URL(redirectTo, req.url);
105
+ loginUrl.searchParams.set("from", pathname);
106
+ return NextResponse2.redirect(loginUrl);
107
+ };
108
+ };
109
+ }
110
+
111
+ // src/core/createLiteAuth.ts
112
+ function createLiteAuth(config) {
113
+ const ctx = {
114
+ users: config.users,
115
+ jwtSecret: config.jwtSecret,
116
+ cookieName: config.cookieName ?? "lite-auth-token"
117
+ };
118
+ return {
119
+ handlers: {
120
+ login: makeLoginHandler(ctx),
121
+ logout: makeLogoutHandler(ctx),
122
+ me: makeMeHandler(ctx)
123
+ },
124
+ middleware: makeMiddleware(ctx),
125
+ getUserFromCookies: getUserFromCookies(ctx)
126
+ };
127
+ }
128
+ export {
129
+ createLiteAuth
130
+ };
131
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/handlers.ts","../src/server/jwt.ts","../src/server/getUserFromCookies.ts","../src/middleware/index.ts","../src/core/createLiteAuth.ts"],"sourcesContent":["import { NextRequest, NextResponse } from \"next/server\";\nimport { LiteAuthContext } from \"../core/types\";\nimport { signToken, verifyToken } from \"./jwt\";\n\nexport function makeLoginHandler(ctx: LiteAuthContext) {\n return async function loginHandler(req: NextRequest): Promise<NextResponse> {\n let body: { email?: string; password?: string };\n try {\n body = await req.json();\n } catch {\n return NextResponse.json({ error: \"Invalid JSON\" }, { status: 400 });\n }\n\n const { email, password } = body;\n if (!email || !password) {\n return NextResponse.json({ error: \"Email and password are required\" }, { status: 400 });\n }\n\n const user = ctx.users.find((u) => u.email === email && u.password === password);\n if (!user) {\n return NextResponse.json({ error: \"Invalid credentials\" }, { status: 401 });\n }\n\n const { password: _, ...publicUser } = user;\n const token = await signToken(publicUser, ctx.jwtSecret);\n\n const res = NextResponse.json({ user: publicUser });\n res.cookies.set(ctx.cookieName, token, {\n httpOnly: true,\n path: \"/\",\n sameSite: \"lax\",\n secure: process.env.NODE_ENV === \"production\",\n maxAge: 60 * 60 * 24 * 7, // 7 days\n });\n return res;\n };\n}\n\nexport function makeLogoutHandler(ctx: LiteAuthContext) {\n return async function logoutHandler(_req: NextRequest): Promise<NextResponse> {\n const res = NextResponse.json({ ok: true });\n res.cookies.set(ctx.cookieName, \"\", {\n httpOnly: true,\n path: \"/\",\n maxAge: 0,\n });\n return res;\n };\n}\n\nexport function makeMeHandler(ctx: LiteAuthContext) {\n return async function meHandler(req: NextRequest): Promise<NextResponse> {\n const token = req.cookies.get(ctx.cookieName)?.value;\n if (!token) {\n return NextResponse.json({ user: null }, { status: 401 });\n }\n\n const user = await verifyToken(token, ctx.jwtSecret);\n if (!user) {\n return NextResponse.json({ user: null }, { status: 401 });\n }\n\n return NextResponse.json({ user });\n };\n}\n","import { SignJWT, jwtVerify } from \"jose\";\nimport { PublicUser } from \"../core/types\";\n\nfunction getSecret(secret: string) {\n return new TextEncoder().encode(secret);\n}\n\nexport async function signToken(user: PublicUser, secret: string): Promise<string> {\n return new SignJWT({ ...user })\n .setProtectedHeader({ alg: \"HS256\" })\n .setIssuedAt()\n .setExpirationTime(\"7d\")\n .sign(getSecret(secret));\n}\n\nexport async function verifyToken(token: string, secret: string): Promise<PublicUser | null> {\n try {\n const { payload } = await jwtVerify(token, getSecret(secret));\n return payload as unknown as PublicUser;\n } catch {\n return null;\n }\n}\n","import { ReadonlyRequestCookies } from \"next/dist/server/web/spec-extension/adapters/request-cookies\";\nimport { LiteAuthContext, PublicUser } from \"../core/types\";\nimport { verifyToken } from \"./jwt\";\n\nexport function getUserFromCookies(ctx: LiteAuthContext) {\n return async function (cookies: ReadonlyRequestCookies): Promise<PublicUser | null> {\n const token = cookies.get(ctx.cookieName)?.value;\n if (!token) return null;\n return verifyToken(token, ctx.jwtSecret);\n };\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { LiteAuthContext } from \"../core/types\";\nimport { verifyToken } from \"../server/jwt\";\n\ntype MiddlewareOptions = {\n protect: string[];\n redirectTo?: string;\n};\n\nexport function makeMiddleware(ctx: LiteAuthContext) {\n return function middleware(options: MiddlewareOptions) {\n return async function (req: NextRequest): Promise<NextResponse> {\n const { protect, redirectTo = \"/login\" } = options;\n const { pathname } = req.nextUrl;\n\n const isProtected = protect.some(\n (pattern) => pathname === pattern || pathname.startsWith(pattern + \"/\")\n );\n\n if (!isProtected) {\n return NextResponse.next();\n }\n\n const token = req.cookies.get(ctx.cookieName)?.value;\n if (token) {\n const user = await verifyToken(token, ctx.jwtSecret);\n if (user) return NextResponse.next();\n }\n\n const loginUrl = new URL(redirectTo, req.url);\n loginUrl.searchParams.set(\"from\", pathname);\n return NextResponse.redirect(loginUrl);\n };\n };\n}\n","import { LiteAuthConfig, LiteAuthContext } from \"./types\";\nimport { makeLoginHandler, makeLogoutHandler, makeMeHandler, getUserFromCookies } from \"../server\";\nimport { makeMiddleware } from \"../middleware\";\n\nexport function createLiteAuth(config: LiteAuthConfig) {\n const ctx: LiteAuthContext = {\n users: config.users,\n jwtSecret: config.jwtSecret,\n cookieName: config.cookieName ?? \"lite-auth-token\",\n };\n\n return {\n handlers: {\n login: makeLoginHandler(ctx),\n logout: makeLogoutHandler(ctx),\n me: makeMeHandler(ctx),\n },\n middleware: makeMiddleware(ctx),\n getUserFromCookies: getUserFromCookies(ctx),\n };\n}\n"],"mappings":"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","names":["NextResponse","NextResponse"]}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "next-lite-auth",
3
+ "version": "0.1.0",
4
+ "description": "Lightweight JWT auth for Next.js using static JSON users (no database)",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ },
14
+ "./client": {
15
+ "types": "./dist/client.d.ts",
16
+ "import": "./dist/client.mjs",
17
+ "require": "./dist/client.js"
18
+ }
19
+ },
20
+ "files": ["dist"],
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "dev": "tsup --watch",
24
+ "typecheck": "tsc --noEmit",
25
+ "prepublishOnly": "pnpm build",
26
+ "docs:dev": "vitepress dev docs",
27
+ "docs:build": "vitepress build docs",
28
+ "docs:preview": "vitepress preview docs"
29
+ },
30
+ "peerDependencies": {
31
+ "next": ">=13.0.0",
32
+ "react": ">=18.0.0"
33
+ },
34
+ "dependencies": {
35
+ "jose": "^5.0.0"
36
+ },
37
+ "devDependencies": {
38
+ "@types/react": "^18.0.0",
39
+ "next": "^14.0.0",
40
+ "react": "^18.0.0",
41
+ "tsup": "^8.0.0",
42
+ "typescript": "^5.0.0",
43
+ "vitepress": "^1.0.0"
44
+ },
45
+ "engines": {
46
+ "node": ">=20.0.0",
47
+ "pnpm": ">=9.0.0"
48
+ },
49
+ "packageManager": "pnpm@9.0.0",
50
+ "author": "amide-init",
51
+ "repository": {
52
+ "type": "git",
53
+ "url": "https://github.com/amide-init/next-lite-auth.git"
54
+ },
55
+ "homepage": "https://github.com/amide-init/next-lite-auth#readme",
56
+ "bugs": {
57
+ "url": "https://github.com/amide-init/next-lite-auth/issues"
58
+ },
59
+ "keywords": ["nextjs", "auth", "jwt", "lightweight"],
60
+ "license": "MIT"
61
+ }