next-lite-auth 0.1.2 → 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/README.md +21 -16
- package/dist/client.d.mts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +222 -58
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +223 -59
- package/dist/client.mjs.map +1 -1
- package/dist/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +43 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +41 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +25 -23
package/README.md
CHANGED
|
@@ -14,14 +14,13 @@ Lightweight JWT auth for Next.js using static JSON users — no database require
|
|
|
14
14
|
- Next.js >= 13
|
|
15
15
|
- React >= 18
|
|
16
16
|
- TypeScript
|
|
17
|
-
- Tailwind CSS + shadcn/ui (for built-in login UI)
|
|
18
17
|
|
|
19
18
|
---
|
|
20
19
|
|
|
21
20
|
## Installation
|
|
22
21
|
|
|
23
22
|
```bash
|
|
24
|
-
pnpm add next-lite-auth
|
|
23
|
+
pnpm add next-lite-auth
|
|
25
24
|
```
|
|
26
25
|
|
|
27
26
|
---
|
|
@@ -31,21 +30,24 @@ pnpm add next-lite-auth jose
|
|
|
31
30
|
### 1. Create `auth.ts` at your project root
|
|
32
31
|
|
|
33
32
|
```ts
|
|
34
|
-
import { createLiteAuth } from "next-lite-auth";
|
|
33
|
+
import { createLiteAuth, usersFromEnv } from "next-lite-auth";
|
|
35
34
|
|
|
36
35
|
export const { handlers, middleware, getUserFromCookies } = createLiteAuth({
|
|
37
|
-
users:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
jwtSecret: process.env.JWT_SECRET!,
|
|
36
|
+
users: usersFromEnv(),
|
|
37
|
+
jwtSecret: process.env.LITE_AUTH_SECRET!,
|
|
38
|
+
enabled: process.env.LITE_AUTH_ENABLED !== "false",
|
|
41
39
|
});
|
|
42
40
|
```
|
|
43
41
|
|
|
44
42
|
```bash
|
|
45
43
|
# .env.local
|
|
46
|
-
|
|
44
|
+
LITE_AUTH_SECRET=your-random-secret-here
|
|
45
|
+
LITE_AUTH_ENABLED=true
|
|
46
|
+
LITE_AUTH_USERS=[{"email":"admin@example.com","password":"secret","role":"admin","name":"Admin"}]
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
`auth.ts` is safe to commit — credentials live only in `.env.local`.
|
|
50
|
+
|
|
49
51
|
### 2. Add one route file
|
|
50
52
|
|
|
51
53
|
```ts
|
|
@@ -77,16 +79,18 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
77
79
|
|
|
78
80
|
---
|
|
79
81
|
|
|
80
|
-
##
|
|
82
|
+
## OSS-friendly: toggle auth via env
|
|
81
83
|
|
|
82
|
-
|
|
84
|
+
If you ship an OSS project using next-lite-auth, your users can enable or disable auth with a single env variable — no code changes needed:
|
|
83
85
|
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
```bash
|
|
87
|
+
# Disable auth (open access)
|
|
88
|
+
LITE_AUTH_ENABLED=false
|
|
89
|
+
|
|
90
|
+
# Enable auth
|
|
91
|
+
LITE_AUTH_ENABLED=true
|
|
92
|
+
LITE_AUTH_USERS=[{"email":"admin@example.com","password":"secret"}]
|
|
93
|
+
LITE_AUTH_SECRET=your-secret
|
|
90
94
|
```
|
|
91
95
|
|
|
92
96
|
---
|
|
@@ -138,6 +142,7 @@ const user = await getUserFromCookies(cookies());
|
|
|
138
142
|
| Export | Description |
|
|
139
143
|
|---|---|
|
|
140
144
|
| `createLiteAuth(config)` | Factory — returns `handlers`, `middleware`, `getUserFromCookies` |
|
|
145
|
+
| `usersFromEnv()` | Reads `LITE_AUTH_USERS` env var and returns `User[]` |
|
|
141
146
|
| `handlers.GET / POST` | Catch-all route handlers |
|
|
142
147
|
| `middleware(options)` | Edge middleware for server-side route protection |
|
|
143
148
|
| `getUserFromCookies(cookies)` | Server-side session helper |
|
package/dist/client.d.mts
CHANGED
package/dist/client.d.ts
CHANGED
package/dist/client.js
CHANGED
|
@@ -33,6 +33,144 @@ var import_navigation = require("next/navigation");
|
|
|
33
33
|
// src/client/LiteLoginPage.tsx
|
|
34
34
|
var import_react = require("react");
|
|
35
35
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
36
|
+
var styles = {
|
|
37
|
+
page: {
|
|
38
|
+
minHeight: "100vh",
|
|
39
|
+
display: "flex",
|
|
40
|
+
alignItems: "center",
|
|
41
|
+
justifyContent: "center",
|
|
42
|
+
backgroundColor: "#f9fafb",
|
|
43
|
+
padding: "0 16px",
|
|
44
|
+
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
45
|
+
},
|
|
46
|
+
container: {
|
|
47
|
+
width: "100%",
|
|
48
|
+
maxWidth: "360px",
|
|
49
|
+
display: "flex",
|
|
50
|
+
flexDirection: "column",
|
|
51
|
+
gap: "24px"
|
|
52
|
+
},
|
|
53
|
+
header: {
|
|
54
|
+
textAlign: "center"
|
|
55
|
+
},
|
|
56
|
+
title: {
|
|
57
|
+
margin: "0 0 4px",
|
|
58
|
+
fontSize: "22px",
|
|
59
|
+
fontWeight: 600,
|
|
60
|
+
color: "#111827",
|
|
61
|
+
letterSpacing: "-0.01em"
|
|
62
|
+
},
|
|
63
|
+
description: {
|
|
64
|
+
margin: 0,
|
|
65
|
+
fontSize: "14px",
|
|
66
|
+
color: "#6b7280"
|
|
67
|
+
},
|
|
68
|
+
card: {
|
|
69
|
+
backgroundColor: "#ffffff",
|
|
70
|
+
border: "1px solid #e5e7eb",
|
|
71
|
+
borderRadius: "12px",
|
|
72
|
+
padding: "24px",
|
|
73
|
+
display: "flex",
|
|
74
|
+
flexDirection: "column",
|
|
75
|
+
gap: "16px",
|
|
76
|
+
boxShadow: "0 1px 3px rgba(0,0,0,0.07)"
|
|
77
|
+
},
|
|
78
|
+
error: {
|
|
79
|
+
backgroundColor: "#fef2f2",
|
|
80
|
+
border: "1px solid #fecaca",
|
|
81
|
+
borderRadius: "6px",
|
|
82
|
+
padding: "8px 12px",
|
|
83
|
+
fontSize: "13px",
|
|
84
|
+
color: "#dc2626"
|
|
85
|
+
},
|
|
86
|
+
field: {
|
|
87
|
+
display: "flex",
|
|
88
|
+
flexDirection: "column",
|
|
89
|
+
gap: "6px"
|
|
90
|
+
},
|
|
91
|
+
label: {
|
|
92
|
+
fontSize: "13px",
|
|
93
|
+
fontWeight: 500,
|
|
94
|
+
color: "#374151"
|
|
95
|
+
},
|
|
96
|
+
input: {
|
|
97
|
+
height: "36px",
|
|
98
|
+
width: "100%",
|
|
99
|
+
borderRadius: "6px",
|
|
100
|
+
border: "1px solid #d1d5db",
|
|
101
|
+
padding: "0 12px",
|
|
102
|
+
fontSize: "14px",
|
|
103
|
+
color: "#111827",
|
|
104
|
+
backgroundColor: "#fff",
|
|
105
|
+
outline: "none",
|
|
106
|
+
boxSizing: "border-box",
|
|
107
|
+
transition: "border-color 0.15s"
|
|
108
|
+
},
|
|
109
|
+
inputFocus: {
|
|
110
|
+
borderColor: "#6366f1",
|
|
111
|
+
boxShadow: "0 0 0 3px rgba(99,102,241,0.15)"
|
|
112
|
+
},
|
|
113
|
+
button: {
|
|
114
|
+
height: "36px",
|
|
115
|
+
width: "100%",
|
|
116
|
+
borderRadius: "6px",
|
|
117
|
+
border: "none",
|
|
118
|
+
backgroundColor: "#111827",
|
|
119
|
+
color: "#ffffff",
|
|
120
|
+
fontSize: "14px",
|
|
121
|
+
fontWeight: 500,
|
|
122
|
+
cursor: "pointer",
|
|
123
|
+
transition: "opacity 0.15s"
|
|
124
|
+
},
|
|
125
|
+
buttonDisabled: {
|
|
126
|
+
opacity: 0.5,
|
|
127
|
+
pointerEvents: "none"
|
|
128
|
+
},
|
|
129
|
+
footer: {
|
|
130
|
+
textAlign: "center",
|
|
131
|
+
fontSize: "12px",
|
|
132
|
+
color: "#9ca3af"
|
|
133
|
+
},
|
|
134
|
+
link: {
|
|
135
|
+
color: "#6b7280",
|
|
136
|
+
textDecoration: "underline",
|
|
137
|
+
textUnderlineOffset: "3px"
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
var darkModeCSS = `
|
|
141
|
+
@media (prefers-color-scheme: dark) {
|
|
142
|
+
.lite-auth-page { background-color: #09090b !important; }
|
|
143
|
+
.lite-auth-title { color: #fafafa !important; }
|
|
144
|
+
.lite-auth-desc { color: #a1a1aa !important; }
|
|
145
|
+
.lite-auth-card {
|
|
146
|
+
background-color: #18181b !important;
|
|
147
|
+
border-color: #27272a !important;
|
|
148
|
+
box-shadow: none !important;
|
|
149
|
+
}
|
|
150
|
+
.lite-auth-error {
|
|
151
|
+
background-color: rgba(239,68,68,0.1) !important;
|
|
152
|
+
border-color: rgba(239,68,68,0.3) !important;
|
|
153
|
+
color: #f87171 !important;
|
|
154
|
+
}
|
|
155
|
+
.lite-auth-label { color: #e4e4e7 !important; }
|
|
156
|
+
.lite-auth-input {
|
|
157
|
+
background-color: transparent !important;
|
|
158
|
+
border-color: #3f3f46 !important;
|
|
159
|
+
color: #fafafa !important;
|
|
160
|
+
}
|
|
161
|
+
.lite-auth-input::placeholder { color: #52525b !important; }
|
|
162
|
+
.lite-auth-input:focus {
|
|
163
|
+
border-color: #6366f1 !important;
|
|
164
|
+
box-shadow: 0 0 0 3px rgba(99,102,241,0.2) !important;
|
|
165
|
+
}
|
|
166
|
+
.lite-auth-btn {
|
|
167
|
+
background-color: #fafafa !important;
|
|
168
|
+
color: #09090b !important;
|
|
169
|
+
}
|
|
170
|
+
.lite-auth-footer { color: #52525b !important; }
|
|
171
|
+
.lite-auth-link { color: #71717a !important; }
|
|
172
|
+
}
|
|
173
|
+
`;
|
|
36
174
|
function LiteLoginPage({
|
|
37
175
|
title = "Sign in",
|
|
38
176
|
description = "Enter your credentials to continue"
|
|
@@ -40,6 +178,7 @@ function LiteLoginPage({
|
|
|
40
178
|
const { login } = useLiteAuth();
|
|
41
179
|
const [error, setError] = (0, import_react.useState)("");
|
|
42
180
|
const [loading, setLoading] = (0, import_react.useState)(false);
|
|
181
|
+
const [focusedField, setFocusedField] = (0, import_react.useState)(null);
|
|
43
182
|
async function handleSubmit(e) {
|
|
44
183
|
e.preventDefault();
|
|
45
184
|
setError("");
|
|
@@ -54,70 +193,97 @@ function LiteLoginPage({
|
|
|
54
193
|
setError(result.error);
|
|
55
194
|
}
|
|
56
195
|
}
|
|
57
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.
|
|
58
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
59
|
-
|
|
60
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("
|
|
65
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
66
|
-
|
|
196
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
197
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: darkModeCSS }),
|
|
198
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "lite-auth-page", style: styles.page, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.container, children: [
|
|
199
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.header, children: [
|
|
200
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "lite-auth-title", style: styles.title, children: title }),
|
|
201
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "lite-auth-desc", style: styles.description, children: description })
|
|
202
|
+
] }),
|
|
203
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "lite-auth-card", style: styles.card, children: [
|
|
204
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "lite-auth-error", style: styles.error, children: error }),
|
|
205
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { onSubmit: handleSubmit, style: { display: "flex", flexDirection: "column", gap: "16px" }, children: [
|
|
206
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.field, children: [
|
|
207
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "email", className: "lite-auth-label", style: styles.label, children: "Email" }),
|
|
208
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
209
|
+
"input",
|
|
210
|
+
{
|
|
211
|
+
id: "email",
|
|
212
|
+
name: "email",
|
|
213
|
+
type: "email",
|
|
214
|
+
required: true,
|
|
215
|
+
autoComplete: "email",
|
|
216
|
+
placeholder: "you@example.com",
|
|
217
|
+
className: "lite-auth-input",
|
|
218
|
+
style: {
|
|
219
|
+
...styles.input,
|
|
220
|
+
...focusedField === "email" ? styles.inputFocus : {}
|
|
221
|
+
},
|
|
222
|
+
onFocus: () => setFocusedField("email"),
|
|
223
|
+
onBlur: () => setFocusedField(null)
|
|
224
|
+
}
|
|
225
|
+
)
|
|
226
|
+
] }),
|
|
227
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.field, children: [
|
|
228
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "password", className: "lite-auth-label", style: styles.label, children: "Password" }),
|
|
229
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
230
|
+
"input",
|
|
231
|
+
{
|
|
232
|
+
id: "password",
|
|
233
|
+
name: "password",
|
|
234
|
+
type: "password",
|
|
235
|
+
required: true,
|
|
236
|
+
autoComplete: "current-password",
|
|
237
|
+
placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
|
238
|
+
className: "lite-auth-input",
|
|
239
|
+
style: {
|
|
240
|
+
...styles.input,
|
|
241
|
+
...focusedField === "password" ? styles.inputFocus : {}
|
|
242
|
+
},
|
|
243
|
+
onFocus: () => setFocusedField("password"),
|
|
244
|
+
onBlur: () => setFocusedField(null)
|
|
245
|
+
}
|
|
246
|
+
)
|
|
247
|
+
] }),
|
|
67
248
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
68
|
-
"
|
|
249
|
+
"button",
|
|
69
250
|
{
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
251
|
+
type: "submit",
|
|
252
|
+
disabled: loading,
|
|
253
|
+
className: "lite-auth-btn",
|
|
254
|
+
style: {
|
|
255
|
+
...styles.button,
|
|
256
|
+
...loading ? styles.buttonDisabled : {}
|
|
257
|
+
},
|
|
258
|
+
children: loading ? "Signing in\u2026" : "Sign in"
|
|
77
259
|
}
|
|
78
260
|
)
|
|
79
|
-
] })
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
{
|
|
85
|
-
id: "password",
|
|
86
|
-
name: "password",
|
|
87
|
-
type: "password",
|
|
88
|
-
required: true,
|
|
89
|
-
autoComplete: "current-password",
|
|
90
|
-
placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
|
91
|
-
className: "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
|
|
92
|
-
}
|
|
93
|
-
)
|
|
94
|
-
] }),
|
|
261
|
+
] })
|
|
262
|
+
] }),
|
|
263
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "lite-auth-footer", style: styles.footer, children: [
|
|
264
|
+
"Powered by",
|
|
265
|
+
" ",
|
|
95
266
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
96
|
-
"
|
|
267
|
+
"a",
|
|
97
268
|
{
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
269
|
+
href: "https://github.com/amide-init/next-lite-auth",
|
|
270
|
+
target: "_blank",
|
|
271
|
+
rel: "noopener noreferrer",
|
|
272
|
+
className: "lite-auth-link",
|
|
273
|
+
style: styles.link,
|
|
274
|
+
children: "next-lite-auth"
|
|
102
275
|
}
|
|
103
276
|
)
|
|
104
277
|
] })
|
|
105
|
-
] })
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
rel: "noopener noreferrer",
|
|
115
|
-
className: "underline underline-offset-4 hover:text-primary transition-colors",
|
|
116
|
-
children: "next-lite-auth"
|
|
117
|
-
}
|
|
118
|
-
)
|
|
119
|
-
] })
|
|
120
|
-
] }) });
|
|
278
|
+
] }) })
|
|
279
|
+
] });
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// src/core/matchesProtect.ts
|
|
283
|
+
function matchesProtect(patterns, pathname) {
|
|
284
|
+
return patterns.some(
|
|
285
|
+
(p) => p instanceof RegExp ? p.test(pathname) : p === "/" || pathname === p || pathname.startsWith(p + "/")
|
|
286
|
+
);
|
|
121
287
|
}
|
|
122
288
|
|
|
123
289
|
// src/client/LiteAuthProvider.tsx
|
|
@@ -155,9 +321,7 @@ function LiteAuthProvider({
|
|
|
155
321
|
setUser(null);
|
|
156
322
|
}, [logoutPath]);
|
|
157
323
|
const value = { user, loading, login, logout };
|
|
158
|
-
const isProtected = protect
|
|
159
|
-
(p) => pathname === p || pathname.startsWith(p + "/")
|
|
160
|
-
);
|
|
324
|
+
const isProtected = matchesProtect(protect, pathname);
|
|
161
325
|
if (loading) {
|
|
162
326
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LiteAuthContext.Provider, { value, children });
|
|
163
327
|
}
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/index.ts","../src/client/LiteAuthProvider.tsx","../src/client/LiteLoginPage.tsx"],"sourcesContent":["export { LiteAuthProvider, useLiteAuth } from \"./LiteAuthProvider\";\nexport { LiteLoginPage } from \"./LiteLoginPage\";\n","\"use client\";\n\nimport { createContext, useContext, useState, useEffect, useCallback, ReactNode } from \"react\";\nimport { usePathname } from \"next/navigation\";\nimport { PublicUser } from \"../core/types\";\nimport { LiteLoginPage } from \"./LiteLoginPage\";\n\ntype LiteAuthContextValue = {\n user: PublicUser | null;\n loading: boolean;\n login: (creds: { email: string; password: string }) => Promise<{ error?: string }>;\n logout: () => Promise<void>;\n};\n\nconst LiteAuthContext = createContext<LiteAuthContextValue | null>(null);\n\ntype LiteAuthProviderProps = {\n children: ReactNode;\n protect?: string[];\n loginPath?: string;\n logoutPath?: string;\n mePath?: string;\n};\n\nexport function LiteAuthProvider({\n children,\n protect = [],\n loginPath = \"/api/auth/login\",\n logoutPath = \"/api/auth/logout\",\n mePath = \"/api/auth/me\",\n}: LiteAuthProviderProps) {\n const [user, setUser] = useState<PublicUser | null>(null);\n const [loading, setLoading] = useState(true);\n const pathname = usePathname();\n\n useEffect(() => {\n fetch(mePath)\n .then((r) => r.json())\n .then(({ user }) => setUser(user ?? null))\n .catch(() => setUser(null))\n .finally(() => setLoading(false));\n }, [mePath]);\n\n const login = useCallback(\n async ({ email, password }: { email: string; password: string }) => {\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 setUser(data.user);\n return {};\n },\n [loginPath]\n );\n\n const logout = useCallback(async () => {\n await fetch(logoutPath, { method: \"POST\" });\n setUser(null);\n }, [logoutPath]);\n\n const value = { user, loading, login, logout };\n\n const isProtected = protect.some(\n (p) => pathname === p || pathname.startsWith(p + \"/\")\n );\n\n if (loading) {\n return (\n <LiteAuthContext.Provider value={value}>\n {children}\n </LiteAuthContext.Provider>\n );\n }\n\n if (!user && isProtected) {\n return (\n <LiteAuthContext.Provider value={value}>\n <LiteLoginPage />\n </LiteAuthContext.Provider>\n );\n }\n\n return (\n <LiteAuthContext.Provider value={value}>\n {children}\n </LiteAuthContext.Provider>\n );\n}\n\nexport function useLiteAuth(): LiteAuthContextValue {\n const ctx = useContext(LiteAuthContext);\n if (!ctx) throw new Error(\"useLiteAuth must be used inside <LiteAuthProvider>\");\n return ctx;\n}\n","\"use client\";\n\nimport { FormEvent, useState } from \"react\";\nimport { useLiteAuth } from \"./LiteAuthProvider\";\n\ntype LiteLoginPageProps = {\n title?: string;\n description?: string;\n};\n\nexport function LiteLoginPage({\n title = \"Sign in\",\n description = \"Enter your credentials to continue\",\n}: LiteLoginPageProps) {\n const { login } = useLiteAuth();\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n async function handleSubmit(e: FormEvent<HTMLFormElement>) {\n e.preventDefault();\n setError(\"\");\n setLoading(true);\n\n const form = e.currentTarget;\n const result = await login({\n email: (form.elements.namedItem(\"email\") as HTMLInputElement).value,\n password: (form.elements.namedItem(\"password\") as HTMLInputElement).value,\n });\n\n setLoading(false);\n\n if (result.error) {\n setError(result.error);\n }\n // no redirect needed — login() sets user in context,\n // LiteAuthProvider re-renders children automatically\n }\n\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-background px-4\">\n <div className=\"w-full max-w-sm space-y-6\">\n\n <div className=\"space-y-1 text-center\">\n <h1 className=\"text-2xl font-semibold tracking-tight\">{title}</h1>\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n </div>\n\n <div className=\"rounded-xl border bg-card text-card-foreground shadow-sm p-6 space-y-4\">\n {error && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n {error}\n </div>\n )}\n\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n <div className=\"space-y-1.5\">\n <label htmlFor=\"email\" className=\"text-sm font-medium leading-none\">\n Email\n </label>\n <input\n id=\"email\"\n name=\"email\"\n type=\"email\"\n required\n autoComplete=\"email\"\n placeholder=\"you@example.com\"\n className=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <label htmlFor=\"password\" className=\"text-sm font-medium leading-none\">\n Password\n </label>\n <input\n id=\"password\"\n name=\"password\"\n type=\"password\"\n required\n autoComplete=\"current-password\"\n placeholder=\"••••••••\"\n className=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n />\n </div>\n\n <button\n type=\"submit\"\n disabled={loading}\n className=\"inline-flex h-9 w-full items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 transition-colors\"\n >\n {loading ? \"Signing in…\" : \"Sign in\"}\n </button>\n </form>\n </div>\n\n <p className=\"text-center text-xs text-muted-foreground\">\n Powered by{\" \"}\n <a\n href=\"https://github.com/amide-init/next-lite-auth\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"underline underline-offset-4 hover:text-primary transition-colors\"\n >\n next-lite-auth\n </a>\n </p>\n\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","import_jsx_runtime","user"]}
|
|
1
|
+
{"version":3,"sources":["../src/client/index.ts","../src/client/LiteAuthProvider.tsx","../src/client/LiteLoginPage.tsx","../src/core/matchesProtect.ts"],"sourcesContent":["export { LiteAuthProvider, useLiteAuth } from \"./LiteAuthProvider\";\nexport { LiteLoginPage } from \"./LiteLoginPage\";\n","\"use client\";\n\nimport { createContext, useContext, useState, useEffect, useCallback, ReactNode } from \"react\";\nimport { usePathname } from \"next/navigation\";\nimport { PublicUser } from \"../core/types\";\nimport { LiteLoginPage } from \"./LiteLoginPage\";\nimport { matchesProtect } from \"../core/matchesProtect\";\n\ntype LiteAuthContextValue = {\n user: PublicUser | null;\n loading: boolean;\n login: (creds: { email: string; password: string }) => Promise<{ error?: string }>;\n logout: () => Promise<void>;\n};\n\nconst LiteAuthContext = createContext<LiteAuthContextValue | null>(null);\n\ntype LiteAuthProviderProps = {\n children: ReactNode;\n protect?: (string | RegExp)[];\n loginPath?: string;\n logoutPath?: string;\n mePath?: string;\n};\n\nexport function LiteAuthProvider({\n children,\n protect = [],\n loginPath = \"/api/auth/login\",\n logoutPath = \"/api/auth/logout\",\n mePath = \"/api/auth/me\",\n}: LiteAuthProviderProps) {\n const [user, setUser] = useState<PublicUser | null>(null);\n const [loading, setLoading] = useState(true);\n const pathname = usePathname();\n\n useEffect(() => {\n fetch(mePath)\n .then((r) => r.json())\n .then(({ user }) => setUser(user ?? null))\n .catch(() => setUser(null))\n .finally(() => setLoading(false));\n }, [mePath]);\n\n const login = useCallback(\n async ({ email, password }: { email: string; password: string }) => {\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 setUser(data.user);\n return {};\n },\n [loginPath]\n );\n\n const logout = useCallback(async () => {\n await fetch(logoutPath, { method: \"POST\" });\n setUser(null);\n }, [logoutPath]);\n\n const value = { user, loading, login, logout };\n\n const isProtected = matchesProtect(protect, pathname);\n\n if (loading) {\n return (\n <LiteAuthContext.Provider value={value}>\n {children}\n </LiteAuthContext.Provider>\n );\n }\n\n if (!user && isProtected) {\n return (\n <LiteAuthContext.Provider value={value}>\n <LiteLoginPage />\n </LiteAuthContext.Provider>\n );\n }\n\n return (\n <LiteAuthContext.Provider value={value}>\n {children}\n </LiteAuthContext.Provider>\n );\n}\n\nexport function useLiteAuth(): LiteAuthContextValue {\n const ctx = useContext(LiteAuthContext);\n if (!ctx) throw new Error(\"useLiteAuth must be used inside <LiteAuthProvider>\");\n return ctx;\n}\n","\"use client\";\n\nimport { CSSProperties, FormEvent, useState } from \"react\";\nimport { useLiteAuth } from \"./LiteAuthProvider\";\n\ntype LiteLoginPageProps = {\n title?: string;\n description?: string;\n};\n\nconst styles: Record<string, CSSProperties> = {\n page: {\n minHeight: \"100vh\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"#f9fafb\",\n padding: \"0 16px\",\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n },\n container: {\n width: \"100%\",\n maxWidth: \"360px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"24px\",\n },\n header: {\n textAlign: \"center\",\n },\n title: {\n margin: \"0 0 4px\",\n fontSize: \"22px\",\n fontWeight: 600,\n color: \"#111827\",\n letterSpacing: \"-0.01em\",\n },\n description: {\n margin: 0,\n fontSize: \"14px\",\n color: \"#6b7280\",\n },\n card: {\n backgroundColor: \"#ffffff\",\n border: \"1px solid #e5e7eb\",\n borderRadius: \"12px\",\n padding: \"24px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"16px\",\n boxShadow: \"0 1px 3px rgba(0,0,0,0.07)\",\n },\n error: {\n backgroundColor: \"#fef2f2\",\n border: \"1px solid #fecaca\",\n borderRadius: \"6px\",\n padding: \"8px 12px\",\n fontSize: \"13px\",\n color: \"#dc2626\",\n },\n field: {\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"6px\",\n },\n label: {\n fontSize: \"13px\",\n fontWeight: 500,\n color: \"#374151\",\n },\n input: {\n height: \"36px\",\n width: \"100%\",\n borderRadius: \"6px\",\n border: \"1px solid #d1d5db\",\n padding: \"0 12px\",\n fontSize: \"14px\",\n color: \"#111827\",\n backgroundColor: \"#fff\",\n outline: \"none\",\n boxSizing: \"border-box\",\n transition: \"border-color 0.15s\",\n },\n inputFocus: {\n borderColor: \"#6366f1\",\n boxShadow: \"0 0 0 3px rgba(99,102,241,0.15)\",\n },\n button: {\n height: \"36px\",\n width: \"100%\",\n borderRadius: \"6px\",\n border: \"none\",\n backgroundColor: \"#111827\",\n color: \"#ffffff\",\n fontSize: \"14px\",\n fontWeight: 500,\n cursor: \"pointer\",\n transition: \"opacity 0.15s\",\n },\n buttonDisabled: {\n opacity: 0.5,\n pointerEvents: \"none\",\n },\n footer: {\n textAlign: \"center\",\n fontSize: \"12px\",\n color: \"#9ca3af\",\n },\n link: {\n color: \"#6b7280\",\n textDecoration: \"underline\",\n textUnderlineOffset: \"3px\",\n },\n};\n\nconst darkModeCSS = `\n @media (prefers-color-scheme: dark) {\n .lite-auth-page { background-color: #09090b !important; }\n .lite-auth-title { color: #fafafa !important; }\n .lite-auth-desc { color: #a1a1aa !important; }\n .lite-auth-card {\n background-color: #18181b !important;\n border-color: #27272a !important;\n box-shadow: none !important;\n }\n .lite-auth-error {\n background-color: rgba(239,68,68,0.1) !important;\n border-color: rgba(239,68,68,0.3) !important;\n color: #f87171 !important;\n }\n .lite-auth-label { color: #e4e4e7 !important; }\n .lite-auth-input {\n background-color: transparent !important;\n border-color: #3f3f46 !important;\n color: #fafafa !important;\n }\n .lite-auth-input::placeholder { color: #52525b !important; }\n .lite-auth-input:focus {\n border-color: #6366f1 !important;\n box-shadow: 0 0 0 3px rgba(99,102,241,0.2) !important;\n }\n .lite-auth-btn {\n background-color: #fafafa !important;\n color: #09090b !important;\n }\n .lite-auth-footer { color: #52525b !important; }\n .lite-auth-link { color: #71717a !important; }\n }\n`;\n\nexport function LiteLoginPage({\n title = \"Sign in\",\n description = \"Enter your credentials to continue\",\n}: LiteLoginPageProps) {\n const { login } = useLiteAuth();\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n const [focusedField, setFocusedField] = useState<string | null>(null);\n\n async function handleSubmit(e: FormEvent<HTMLFormElement>) {\n e.preventDefault();\n setError(\"\");\n setLoading(true);\n\n const form = e.currentTarget;\n const result = await login({\n email: (form.elements.namedItem(\"email\") as HTMLInputElement).value,\n password: (form.elements.namedItem(\"password\") as HTMLInputElement).value,\n });\n\n setLoading(false);\n\n if (result.error) {\n setError(result.error);\n }\n }\n\n return (\n <>\n <style>{darkModeCSS}</style>\n <div className=\"lite-auth-page\" style={styles.page}>\n <div style={styles.container}>\n <div style={styles.header}>\n <h1 className=\"lite-auth-title\" style={styles.title}>{title}</h1>\n <p className=\"lite-auth-desc\" style={styles.description}>{description}</p>\n </div>\n\n <div className=\"lite-auth-card\" style={styles.card}>\n {error && (\n <div className=\"lite-auth-error\" style={styles.error}>{error}</div>\n )}\n\n <form onSubmit={handleSubmit} style={{ display: \"flex\", flexDirection: \"column\", gap: \"16px\" }}>\n <div style={styles.field}>\n <label htmlFor=\"email\" className=\"lite-auth-label\" style={styles.label}>Email</label>\n <input\n id=\"email\"\n name=\"email\"\n type=\"email\"\n required\n autoComplete=\"email\"\n placeholder=\"you@example.com\"\n className=\"lite-auth-input\"\n style={{\n ...styles.input,\n ...(focusedField === \"email\" ? styles.inputFocus : {}),\n }}\n onFocus={() => setFocusedField(\"email\")}\n onBlur={() => setFocusedField(null)}\n />\n </div>\n\n <div style={styles.field}>\n <label htmlFor=\"password\" className=\"lite-auth-label\" style={styles.label}>Password</label>\n <input\n id=\"password\"\n name=\"password\"\n type=\"password\"\n required\n autoComplete=\"current-password\"\n placeholder=\"••••••••\"\n className=\"lite-auth-input\"\n style={{\n ...styles.input,\n ...(focusedField === \"password\" ? styles.inputFocus : {}),\n }}\n onFocus={() => setFocusedField(\"password\")}\n onBlur={() => setFocusedField(null)}\n />\n </div>\n\n <button\n type=\"submit\"\n disabled={loading}\n className=\"lite-auth-btn\"\n style={{\n ...styles.button,\n ...(loading ? styles.buttonDisabled : {}),\n }}\n >\n {loading ? \"Signing in…\" : \"Sign in\"}\n </button>\n </form>\n </div>\n\n <p className=\"lite-auth-footer\" style={styles.footer}>\n Powered by{\" \"}\n <a\n href=\"https://github.com/amide-init/next-lite-auth\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"lite-auth-link\"\n style={styles.link}\n >\n next-lite-auth\n </a>\n </p>\n </div>\n </div>\n </>\n );\n}\n","export function matchesProtect(patterns: (string | RegExp)[], pathname: string): boolean {\n return patterns.some((p) =>\n p instanceof RegExp\n ? p.test(pathname)\n : p === \"/\" || pathname === p || pathname.startsWith(p + \"/\")\n );\n}\n"],"mappings":"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","names":["import_react","import_jsx_runtime","user"]}
|
package/dist/client.mjs
CHANGED
|
@@ -4,7 +4,145 @@ import { usePathname } from "next/navigation";
|
|
|
4
4
|
|
|
5
5
|
// src/client/LiteLoginPage.tsx
|
|
6
6
|
import { useState } from "react";
|
|
7
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
var styles = {
|
|
9
|
+
page: {
|
|
10
|
+
minHeight: "100vh",
|
|
11
|
+
display: "flex",
|
|
12
|
+
alignItems: "center",
|
|
13
|
+
justifyContent: "center",
|
|
14
|
+
backgroundColor: "#f9fafb",
|
|
15
|
+
padding: "0 16px",
|
|
16
|
+
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
17
|
+
},
|
|
18
|
+
container: {
|
|
19
|
+
width: "100%",
|
|
20
|
+
maxWidth: "360px",
|
|
21
|
+
display: "flex",
|
|
22
|
+
flexDirection: "column",
|
|
23
|
+
gap: "24px"
|
|
24
|
+
},
|
|
25
|
+
header: {
|
|
26
|
+
textAlign: "center"
|
|
27
|
+
},
|
|
28
|
+
title: {
|
|
29
|
+
margin: "0 0 4px",
|
|
30
|
+
fontSize: "22px",
|
|
31
|
+
fontWeight: 600,
|
|
32
|
+
color: "#111827",
|
|
33
|
+
letterSpacing: "-0.01em"
|
|
34
|
+
},
|
|
35
|
+
description: {
|
|
36
|
+
margin: 0,
|
|
37
|
+
fontSize: "14px",
|
|
38
|
+
color: "#6b7280"
|
|
39
|
+
},
|
|
40
|
+
card: {
|
|
41
|
+
backgroundColor: "#ffffff",
|
|
42
|
+
border: "1px solid #e5e7eb",
|
|
43
|
+
borderRadius: "12px",
|
|
44
|
+
padding: "24px",
|
|
45
|
+
display: "flex",
|
|
46
|
+
flexDirection: "column",
|
|
47
|
+
gap: "16px",
|
|
48
|
+
boxShadow: "0 1px 3px rgba(0,0,0,0.07)"
|
|
49
|
+
},
|
|
50
|
+
error: {
|
|
51
|
+
backgroundColor: "#fef2f2",
|
|
52
|
+
border: "1px solid #fecaca",
|
|
53
|
+
borderRadius: "6px",
|
|
54
|
+
padding: "8px 12px",
|
|
55
|
+
fontSize: "13px",
|
|
56
|
+
color: "#dc2626"
|
|
57
|
+
},
|
|
58
|
+
field: {
|
|
59
|
+
display: "flex",
|
|
60
|
+
flexDirection: "column",
|
|
61
|
+
gap: "6px"
|
|
62
|
+
},
|
|
63
|
+
label: {
|
|
64
|
+
fontSize: "13px",
|
|
65
|
+
fontWeight: 500,
|
|
66
|
+
color: "#374151"
|
|
67
|
+
},
|
|
68
|
+
input: {
|
|
69
|
+
height: "36px",
|
|
70
|
+
width: "100%",
|
|
71
|
+
borderRadius: "6px",
|
|
72
|
+
border: "1px solid #d1d5db",
|
|
73
|
+
padding: "0 12px",
|
|
74
|
+
fontSize: "14px",
|
|
75
|
+
color: "#111827",
|
|
76
|
+
backgroundColor: "#fff",
|
|
77
|
+
outline: "none",
|
|
78
|
+
boxSizing: "border-box",
|
|
79
|
+
transition: "border-color 0.15s"
|
|
80
|
+
},
|
|
81
|
+
inputFocus: {
|
|
82
|
+
borderColor: "#6366f1",
|
|
83
|
+
boxShadow: "0 0 0 3px rgba(99,102,241,0.15)"
|
|
84
|
+
},
|
|
85
|
+
button: {
|
|
86
|
+
height: "36px",
|
|
87
|
+
width: "100%",
|
|
88
|
+
borderRadius: "6px",
|
|
89
|
+
border: "none",
|
|
90
|
+
backgroundColor: "#111827",
|
|
91
|
+
color: "#ffffff",
|
|
92
|
+
fontSize: "14px",
|
|
93
|
+
fontWeight: 500,
|
|
94
|
+
cursor: "pointer",
|
|
95
|
+
transition: "opacity 0.15s"
|
|
96
|
+
},
|
|
97
|
+
buttonDisabled: {
|
|
98
|
+
opacity: 0.5,
|
|
99
|
+
pointerEvents: "none"
|
|
100
|
+
},
|
|
101
|
+
footer: {
|
|
102
|
+
textAlign: "center",
|
|
103
|
+
fontSize: "12px",
|
|
104
|
+
color: "#9ca3af"
|
|
105
|
+
},
|
|
106
|
+
link: {
|
|
107
|
+
color: "#6b7280",
|
|
108
|
+
textDecoration: "underline",
|
|
109
|
+
textUnderlineOffset: "3px"
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
var darkModeCSS = `
|
|
113
|
+
@media (prefers-color-scheme: dark) {
|
|
114
|
+
.lite-auth-page { background-color: #09090b !important; }
|
|
115
|
+
.lite-auth-title { color: #fafafa !important; }
|
|
116
|
+
.lite-auth-desc { color: #a1a1aa !important; }
|
|
117
|
+
.lite-auth-card {
|
|
118
|
+
background-color: #18181b !important;
|
|
119
|
+
border-color: #27272a !important;
|
|
120
|
+
box-shadow: none !important;
|
|
121
|
+
}
|
|
122
|
+
.lite-auth-error {
|
|
123
|
+
background-color: rgba(239,68,68,0.1) !important;
|
|
124
|
+
border-color: rgba(239,68,68,0.3) !important;
|
|
125
|
+
color: #f87171 !important;
|
|
126
|
+
}
|
|
127
|
+
.lite-auth-label { color: #e4e4e7 !important; }
|
|
128
|
+
.lite-auth-input {
|
|
129
|
+
background-color: transparent !important;
|
|
130
|
+
border-color: #3f3f46 !important;
|
|
131
|
+
color: #fafafa !important;
|
|
132
|
+
}
|
|
133
|
+
.lite-auth-input::placeholder { color: #52525b !important; }
|
|
134
|
+
.lite-auth-input:focus {
|
|
135
|
+
border-color: #6366f1 !important;
|
|
136
|
+
box-shadow: 0 0 0 3px rgba(99,102,241,0.2) !important;
|
|
137
|
+
}
|
|
138
|
+
.lite-auth-btn {
|
|
139
|
+
background-color: #fafafa !important;
|
|
140
|
+
color: #09090b !important;
|
|
141
|
+
}
|
|
142
|
+
.lite-auth-footer { color: #52525b !important; }
|
|
143
|
+
.lite-auth-link { color: #71717a !important; }
|
|
144
|
+
}
|
|
145
|
+
`;
|
|
8
146
|
function LiteLoginPage({
|
|
9
147
|
title = "Sign in",
|
|
10
148
|
description = "Enter your credentials to continue"
|
|
@@ -12,6 +150,7 @@ function LiteLoginPage({
|
|
|
12
150
|
const { login } = useLiteAuth();
|
|
13
151
|
const [error, setError] = useState("");
|
|
14
152
|
const [loading, setLoading] = useState(false);
|
|
153
|
+
const [focusedField, setFocusedField] = useState(null);
|
|
15
154
|
async function handleSubmit(e) {
|
|
16
155
|
e.preventDefault();
|
|
17
156
|
setError("");
|
|
@@ -26,70 +165,97 @@ function LiteLoginPage({
|
|
|
26
165
|
setError(result.error);
|
|
27
166
|
}
|
|
28
167
|
}
|
|
29
|
-
return /* @__PURE__ */
|
|
30
|
-
/* @__PURE__ */
|
|
31
|
-
|
|
32
|
-
/* @__PURE__ */
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
/* @__PURE__ */ jsxs("
|
|
37
|
-
/* @__PURE__ */
|
|
38
|
-
|
|
168
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
169
|
+
/* @__PURE__ */ jsx("style", { children: darkModeCSS }),
|
|
170
|
+
/* @__PURE__ */ jsx("div", { className: "lite-auth-page", style: styles.page, children: /* @__PURE__ */ jsxs("div", { style: styles.container, children: [
|
|
171
|
+
/* @__PURE__ */ jsxs("div", { style: styles.header, children: [
|
|
172
|
+
/* @__PURE__ */ jsx("h1", { className: "lite-auth-title", style: styles.title, children: title }),
|
|
173
|
+
/* @__PURE__ */ jsx("p", { className: "lite-auth-desc", style: styles.description, children: description })
|
|
174
|
+
] }),
|
|
175
|
+
/* @__PURE__ */ jsxs("div", { className: "lite-auth-card", style: styles.card, children: [
|
|
176
|
+
error && /* @__PURE__ */ jsx("div", { className: "lite-auth-error", style: styles.error, children: error }),
|
|
177
|
+
/* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, style: { display: "flex", flexDirection: "column", gap: "16px" }, children: [
|
|
178
|
+
/* @__PURE__ */ jsxs("div", { style: styles.field, children: [
|
|
179
|
+
/* @__PURE__ */ jsx("label", { htmlFor: "email", className: "lite-auth-label", style: styles.label, children: "Email" }),
|
|
180
|
+
/* @__PURE__ */ jsx(
|
|
181
|
+
"input",
|
|
182
|
+
{
|
|
183
|
+
id: "email",
|
|
184
|
+
name: "email",
|
|
185
|
+
type: "email",
|
|
186
|
+
required: true,
|
|
187
|
+
autoComplete: "email",
|
|
188
|
+
placeholder: "you@example.com",
|
|
189
|
+
className: "lite-auth-input",
|
|
190
|
+
style: {
|
|
191
|
+
...styles.input,
|
|
192
|
+
...focusedField === "email" ? styles.inputFocus : {}
|
|
193
|
+
},
|
|
194
|
+
onFocus: () => setFocusedField("email"),
|
|
195
|
+
onBlur: () => setFocusedField(null)
|
|
196
|
+
}
|
|
197
|
+
)
|
|
198
|
+
] }),
|
|
199
|
+
/* @__PURE__ */ jsxs("div", { style: styles.field, children: [
|
|
200
|
+
/* @__PURE__ */ jsx("label", { htmlFor: "password", className: "lite-auth-label", style: styles.label, children: "Password" }),
|
|
201
|
+
/* @__PURE__ */ jsx(
|
|
202
|
+
"input",
|
|
203
|
+
{
|
|
204
|
+
id: "password",
|
|
205
|
+
name: "password",
|
|
206
|
+
type: "password",
|
|
207
|
+
required: true,
|
|
208
|
+
autoComplete: "current-password",
|
|
209
|
+
placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
|
210
|
+
className: "lite-auth-input",
|
|
211
|
+
style: {
|
|
212
|
+
...styles.input,
|
|
213
|
+
...focusedField === "password" ? styles.inputFocus : {}
|
|
214
|
+
},
|
|
215
|
+
onFocus: () => setFocusedField("password"),
|
|
216
|
+
onBlur: () => setFocusedField(null)
|
|
217
|
+
}
|
|
218
|
+
)
|
|
219
|
+
] }),
|
|
39
220
|
/* @__PURE__ */ jsx(
|
|
40
|
-
"
|
|
221
|
+
"button",
|
|
41
222
|
{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
223
|
+
type: "submit",
|
|
224
|
+
disabled: loading,
|
|
225
|
+
className: "lite-auth-btn",
|
|
226
|
+
style: {
|
|
227
|
+
...styles.button,
|
|
228
|
+
...loading ? styles.buttonDisabled : {}
|
|
229
|
+
},
|
|
230
|
+
children: loading ? "Signing in\u2026" : "Sign in"
|
|
49
231
|
}
|
|
50
232
|
)
|
|
51
|
-
] })
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
{
|
|
57
|
-
id: "password",
|
|
58
|
-
name: "password",
|
|
59
|
-
type: "password",
|
|
60
|
-
required: true,
|
|
61
|
-
autoComplete: "current-password",
|
|
62
|
-
placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
|
63
|
-
className: "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
|
|
64
|
-
}
|
|
65
|
-
)
|
|
66
|
-
] }),
|
|
233
|
+
] })
|
|
234
|
+
] }),
|
|
235
|
+
/* @__PURE__ */ jsxs("p", { className: "lite-auth-footer", style: styles.footer, children: [
|
|
236
|
+
"Powered by",
|
|
237
|
+
" ",
|
|
67
238
|
/* @__PURE__ */ jsx(
|
|
68
|
-
"
|
|
239
|
+
"a",
|
|
69
240
|
{
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
241
|
+
href: "https://github.com/amide-init/next-lite-auth",
|
|
242
|
+
target: "_blank",
|
|
243
|
+
rel: "noopener noreferrer",
|
|
244
|
+
className: "lite-auth-link",
|
|
245
|
+
style: styles.link,
|
|
246
|
+
children: "next-lite-auth"
|
|
74
247
|
}
|
|
75
248
|
)
|
|
76
249
|
] })
|
|
77
|
-
] })
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
rel: "noopener noreferrer",
|
|
87
|
-
className: "underline underline-offset-4 hover:text-primary transition-colors",
|
|
88
|
-
children: "next-lite-auth"
|
|
89
|
-
}
|
|
90
|
-
)
|
|
91
|
-
] })
|
|
92
|
-
] }) });
|
|
250
|
+
] }) })
|
|
251
|
+
] });
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// src/core/matchesProtect.ts
|
|
255
|
+
function matchesProtect(patterns, pathname) {
|
|
256
|
+
return patterns.some(
|
|
257
|
+
(p) => p instanceof RegExp ? p.test(pathname) : p === "/" || pathname === p || pathname.startsWith(p + "/")
|
|
258
|
+
);
|
|
93
259
|
}
|
|
94
260
|
|
|
95
261
|
// src/client/LiteAuthProvider.tsx
|
|
@@ -127,9 +293,7 @@ function LiteAuthProvider({
|
|
|
127
293
|
setUser(null);
|
|
128
294
|
}, [logoutPath]);
|
|
129
295
|
const value = { user, loading, login, logout };
|
|
130
|
-
const isProtected = protect
|
|
131
|
-
(p) => pathname === p || pathname.startsWith(p + "/")
|
|
132
|
-
);
|
|
296
|
+
const isProtected = matchesProtect(protect, pathname);
|
|
133
297
|
if (loading) {
|
|
134
298
|
return /* @__PURE__ */ jsx2(LiteAuthContext.Provider, { value, children });
|
|
135
299
|
}
|
package/dist/client.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/LiteAuthProvider.tsx","../src/client/LiteLoginPage.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext, useState, useEffect, useCallback, ReactNode } from \"react\";\nimport { usePathname } from \"next/navigation\";\nimport { PublicUser } from \"../core/types\";\nimport { LiteLoginPage } from \"./LiteLoginPage\";\n\ntype LiteAuthContextValue = {\n user: PublicUser | null;\n loading: boolean;\n login: (creds: { email: string; password: string }) => Promise<{ error?: string }>;\n logout: () => Promise<void>;\n};\n\nconst LiteAuthContext = createContext<LiteAuthContextValue | null>(null);\n\ntype LiteAuthProviderProps = {\n children: ReactNode;\n protect?: string[];\n loginPath?: string;\n logoutPath?: string;\n mePath?: string;\n};\n\nexport function LiteAuthProvider({\n children,\n protect = [],\n loginPath = \"/api/auth/login\",\n logoutPath = \"/api/auth/logout\",\n mePath = \"/api/auth/me\",\n}: LiteAuthProviderProps) {\n const [user, setUser] = useState<PublicUser | null>(null);\n const [loading, setLoading] = useState(true);\n const pathname = usePathname();\n\n useEffect(() => {\n fetch(mePath)\n .then((r) => r.json())\n .then(({ user }) => setUser(user ?? null))\n .catch(() => setUser(null))\n .finally(() => setLoading(false));\n }, [mePath]);\n\n const login = useCallback(\n async ({ email, password }: { email: string; password: string }) => {\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 setUser(data.user);\n return {};\n },\n [loginPath]\n );\n\n const logout = useCallback(async () => {\n await fetch(logoutPath, { method: \"POST\" });\n setUser(null);\n }, [logoutPath]);\n\n const value = { user, loading, login, logout };\n\n const isProtected = protect.some(\n (p) => pathname === p || pathname.startsWith(p + \"/\")\n );\n\n if (loading) {\n return (\n <LiteAuthContext.Provider value={value}>\n {children}\n </LiteAuthContext.Provider>\n );\n }\n\n if (!user && isProtected) {\n return (\n <LiteAuthContext.Provider value={value}>\n <LiteLoginPage />\n </LiteAuthContext.Provider>\n );\n }\n\n return (\n <LiteAuthContext.Provider value={value}>\n {children}\n </LiteAuthContext.Provider>\n );\n}\n\nexport function useLiteAuth(): LiteAuthContextValue {\n const ctx = useContext(LiteAuthContext);\n if (!ctx) throw new Error(\"useLiteAuth must be used inside <LiteAuthProvider>\");\n return ctx;\n}\n","\"use client\";\n\nimport { FormEvent, useState } from \"react\";\nimport { useLiteAuth } from \"./LiteAuthProvider\";\n\ntype LiteLoginPageProps = {\n title?: string;\n description?: string;\n};\n\nexport function LiteLoginPage({\n title = \"Sign in\",\n description = \"Enter your credentials to continue\",\n}: LiteLoginPageProps) {\n const { login } = useLiteAuth();\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n async function handleSubmit(e: FormEvent<HTMLFormElement>) {\n e.preventDefault();\n setError(\"\");\n setLoading(true);\n\n const form = e.currentTarget;\n const result = await login({\n email: (form.elements.namedItem(\"email\") as HTMLInputElement).value,\n password: (form.elements.namedItem(\"password\") as HTMLInputElement).value,\n });\n\n setLoading(false);\n\n if (result.error) {\n setError(result.error);\n }\n // no redirect needed — login() sets user in context,\n // LiteAuthProvider re-renders children automatically\n }\n\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-background px-4\">\n <div className=\"w-full max-w-sm space-y-6\">\n\n <div className=\"space-y-1 text-center\">\n <h1 className=\"text-2xl font-semibold tracking-tight\">{title}</h1>\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n </div>\n\n <div className=\"rounded-xl border bg-card text-card-foreground shadow-sm p-6 space-y-4\">\n {error && (\n <div className=\"rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n {error}\n </div>\n )}\n\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n <div className=\"space-y-1.5\">\n <label htmlFor=\"email\" className=\"text-sm font-medium leading-none\">\n Email\n </label>\n <input\n id=\"email\"\n name=\"email\"\n type=\"email\"\n required\n autoComplete=\"email\"\n placeholder=\"you@example.com\"\n className=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <label htmlFor=\"password\" className=\"text-sm font-medium leading-none\">\n Password\n </label>\n <input\n id=\"password\"\n name=\"password\"\n type=\"password\"\n required\n autoComplete=\"current-password\"\n placeholder=\"••••••••\"\n className=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n />\n </div>\n\n <button\n type=\"submit\"\n disabled={loading}\n className=\"inline-flex h-9 w-full items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 transition-colors\"\n >\n {loading ? \"Signing in…\" : \"Sign in\"}\n </button>\n </form>\n </div>\n\n <p className=\"text-center text-xs text-muted-foreground\">\n Powered by{\" \"}\n <a\n href=\"https://github.com/amide-init/next-lite-auth\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"underline underline-offset-4 hover:text-primary transition-colors\"\n >\n next-lite-auth\n </a>\n </p>\n\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["useState","jsx","useState","user"]}
|
|
1
|
+
{"version":3,"sources":["../src/client/LiteAuthProvider.tsx","../src/client/LiteLoginPage.tsx","../src/core/matchesProtect.ts"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext, useState, useEffect, useCallback, ReactNode } from \"react\";\nimport { usePathname } from \"next/navigation\";\nimport { PublicUser } from \"../core/types\";\nimport { LiteLoginPage } from \"./LiteLoginPage\";\nimport { matchesProtect } from \"../core/matchesProtect\";\n\ntype LiteAuthContextValue = {\n user: PublicUser | null;\n loading: boolean;\n login: (creds: { email: string; password: string }) => Promise<{ error?: string }>;\n logout: () => Promise<void>;\n};\n\nconst LiteAuthContext = createContext<LiteAuthContextValue | null>(null);\n\ntype LiteAuthProviderProps = {\n children: ReactNode;\n protect?: (string | RegExp)[];\n loginPath?: string;\n logoutPath?: string;\n mePath?: string;\n};\n\nexport function LiteAuthProvider({\n children,\n protect = [],\n loginPath = \"/api/auth/login\",\n logoutPath = \"/api/auth/logout\",\n mePath = \"/api/auth/me\",\n}: LiteAuthProviderProps) {\n const [user, setUser] = useState<PublicUser | null>(null);\n const [loading, setLoading] = useState(true);\n const pathname = usePathname();\n\n useEffect(() => {\n fetch(mePath)\n .then((r) => r.json())\n .then(({ user }) => setUser(user ?? null))\n .catch(() => setUser(null))\n .finally(() => setLoading(false));\n }, [mePath]);\n\n const login = useCallback(\n async ({ email, password }: { email: string; password: string }) => {\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 setUser(data.user);\n return {};\n },\n [loginPath]\n );\n\n const logout = useCallback(async () => {\n await fetch(logoutPath, { method: \"POST\" });\n setUser(null);\n }, [logoutPath]);\n\n const value = { user, loading, login, logout };\n\n const isProtected = matchesProtect(protect, pathname);\n\n if (loading) {\n return (\n <LiteAuthContext.Provider value={value}>\n {children}\n </LiteAuthContext.Provider>\n );\n }\n\n if (!user && isProtected) {\n return (\n <LiteAuthContext.Provider value={value}>\n <LiteLoginPage />\n </LiteAuthContext.Provider>\n );\n }\n\n return (\n <LiteAuthContext.Provider value={value}>\n {children}\n </LiteAuthContext.Provider>\n );\n}\n\nexport function useLiteAuth(): LiteAuthContextValue {\n const ctx = useContext(LiteAuthContext);\n if (!ctx) throw new Error(\"useLiteAuth must be used inside <LiteAuthProvider>\");\n return ctx;\n}\n","\"use client\";\n\nimport { CSSProperties, FormEvent, useState } from \"react\";\nimport { useLiteAuth } from \"./LiteAuthProvider\";\n\ntype LiteLoginPageProps = {\n title?: string;\n description?: string;\n};\n\nconst styles: Record<string, CSSProperties> = {\n page: {\n minHeight: \"100vh\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"#f9fafb\",\n padding: \"0 16px\",\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n },\n container: {\n width: \"100%\",\n maxWidth: \"360px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"24px\",\n },\n header: {\n textAlign: \"center\",\n },\n title: {\n margin: \"0 0 4px\",\n fontSize: \"22px\",\n fontWeight: 600,\n color: \"#111827\",\n letterSpacing: \"-0.01em\",\n },\n description: {\n margin: 0,\n fontSize: \"14px\",\n color: \"#6b7280\",\n },\n card: {\n backgroundColor: \"#ffffff\",\n border: \"1px solid #e5e7eb\",\n borderRadius: \"12px\",\n padding: \"24px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"16px\",\n boxShadow: \"0 1px 3px rgba(0,0,0,0.07)\",\n },\n error: {\n backgroundColor: \"#fef2f2\",\n border: \"1px solid #fecaca\",\n borderRadius: \"6px\",\n padding: \"8px 12px\",\n fontSize: \"13px\",\n color: \"#dc2626\",\n },\n field: {\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"6px\",\n },\n label: {\n fontSize: \"13px\",\n fontWeight: 500,\n color: \"#374151\",\n },\n input: {\n height: \"36px\",\n width: \"100%\",\n borderRadius: \"6px\",\n border: \"1px solid #d1d5db\",\n padding: \"0 12px\",\n fontSize: \"14px\",\n color: \"#111827\",\n backgroundColor: \"#fff\",\n outline: \"none\",\n boxSizing: \"border-box\",\n transition: \"border-color 0.15s\",\n },\n inputFocus: {\n borderColor: \"#6366f1\",\n boxShadow: \"0 0 0 3px rgba(99,102,241,0.15)\",\n },\n button: {\n height: \"36px\",\n width: \"100%\",\n borderRadius: \"6px\",\n border: \"none\",\n backgroundColor: \"#111827\",\n color: \"#ffffff\",\n fontSize: \"14px\",\n fontWeight: 500,\n cursor: \"pointer\",\n transition: \"opacity 0.15s\",\n },\n buttonDisabled: {\n opacity: 0.5,\n pointerEvents: \"none\",\n },\n footer: {\n textAlign: \"center\",\n fontSize: \"12px\",\n color: \"#9ca3af\",\n },\n link: {\n color: \"#6b7280\",\n textDecoration: \"underline\",\n textUnderlineOffset: \"3px\",\n },\n};\n\nconst darkModeCSS = `\n @media (prefers-color-scheme: dark) {\n .lite-auth-page { background-color: #09090b !important; }\n .lite-auth-title { color: #fafafa !important; }\n .lite-auth-desc { color: #a1a1aa !important; }\n .lite-auth-card {\n background-color: #18181b !important;\n border-color: #27272a !important;\n box-shadow: none !important;\n }\n .lite-auth-error {\n background-color: rgba(239,68,68,0.1) !important;\n border-color: rgba(239,68,68,0.3) !important;\n color: #f87171 !important;\n }\n .lite-auth-label { color: #e4e4e7 !important; }\n .lite-auth-input {\n background-color: transparent !important;\n border-color: #3f3f46 !important;\n color: #fafafa !important;\n }\n .lite-auth-input::placeholder { color: #52525b !important; }\n .lite-auth-input:focus {\n border-color: #6366f1 !important;\n box-shadow: 0 0 0 3px rgba(99,102,241,0.2) !important;\n }\n .lite-auth-btn {\n background-color: #fafafa !important;\n color: #09090b !important;\n }\n .lite-auth-footer { color: #52525b !important; }\n .lite-auth-link { color: #71717a !important; }\n }\n`;\n\nexport function LiteLoginPage({\n title = \"Sign in\",\n description = \"Enter your credentials to continue\",\n}: LiteLoginPageProps) {\n const { login } = useLiteAuth();\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n const [focusedField, setFocusedField] = useState<string | null>(null);\n\n async function handleSubmit(e: FormEvent<HTMLFormElement>) {\n e.preventDefault();\n setError(\"\");\n setLoading(true);\n\n const form = e.currentTarget;\n const result = await login({\n email: (form.elements.namedItem(\"email\") as HTMLInputElement).value,\n password: (form.elements.namedItem(\"password\") as HTMLInputElement).value,\n });\n\n setLoading(false);\n\n if (result.error) {\n setError(result.error);\n }\n }\n\n return (\n <>\n <style>{darkModeCSS}</style>\n <div className=\"lite-auth-page\" style={styles.page}>\n <div style={styles.container}>\n <div style={styles.header}>\n <h1 className=\"lite-auth-title\" style={styles.title}>{title}</h1>\n <p className=\"lite-auth-desc\" style={styles.description}>{description}</p>\n </div>\n\n <div className=\"lite-auth-card\" style={styles.card}>\n {error && (\n <div className=\"lite-auth-error\" style={styles.error}>{error}</div>\n )}\n\n <form onSubmit={handleSubmit} style={{ display: \"flex\", flexDirection: \"column\", gap: \"16px\" }}>\n <div style={styles.field}>\n <label htmlFor=\"email\" className=\"lite-auth-label\" style={styles.label}>Email</label>\n <input\n id=\"email\"\n name=\"email\"\n type=\"email\"\n required\n autoComplete=\"email\"\n placeholder=\"you@example.com\"\n className=\"lite-auth-input\"\n style={{\n ...styles.input,\n ...(focusedField === \"email\" ? styles.inputFocus : {}),\n }}\n onFocus={() => setFocusedField(\"email\")}\n onBlur={() => setFocusedField(null)}\n />\n </div>\n\n <div style={styles.field}>\n <label htmlFor=\"password\" className=\"lite-auth-label\" style={styles.label}>Password</label>\n <input\n id=\"password\"\n name=\"password\"\n type=\"password\"\n required\n autoComplete=\"current-password\"\n placeholder=\"••••••••\"\n className=\"lite-auth-input\"\n style={{\n ...styles.input,\n ...(focusedField === \"password\" ? styles.inputFocus : {}),\n }}\n onFocus={() => setFocusedField(\"password\")}\n onBlur={() => setFocusedField(null)}\n />\n </div>\n\n <button\n type=\"submit\"\n disabled={loading}\n className=\"lite-auth-btn\"\n style={{\n ...styles.button,\n ...(loading ? styles.buttonDisabled : {}),\n }}\n >\n {loading ? \"Signing in…\" : \"Sign in\"}\n </button>\n </form>\n </div>\n\n <p className=\"lite-auth-footer\" style={styles.footer}>\n Powered by{\" \"}\n <a\n href=\"https://github.com/amide-init/next-lite-auth\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"lite-auth-link\"\n style={styles.link}\n >\n next-lite-auth\n </a>\n </p>\n </div>\n </div>\n </>\n );\n}\n","export function matchesProtect(patterns: (string | RegExp)[], pathname: string): boolean {\n return patterns.some((p) =>\n p instanceof RegExp\n ? p.test(pathname)\n : p === \"/\" || pathname === p || pathname.startsWith(p + \"/\")\n );\n}\n"],"mappings":"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","names":["useState","jsx","useState","user"]}
|
package/dist/index.d.mts
CHANGED
|
@@ -12,6 +12,7 @@ type LiteAuthConfig = {
|
|
|
12
12
|
users: User[];
|
|
13
13
|
jwtSecret: string;
|
|
14
14
|
cookieName?: string;
|
|
15
|
+
enabled?: boolean;
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
declare function createLiteAuth(config: LiteAuthConfig): {
|
|
@@ -20,10 +21,12 @@ declare function createLiteAuth(config: LiteAuthConfig): {
|
|
|
20
21
|
POST: (req: next_server.NextRequest) => Promise<next_server.NextResponse>;
|
|
21
22
|
};
|
|
22
23
|
middleware: (options: {
|
|
23
|
-
protect: string[];
|
|
24
|
+
protect: (string | RegExp)[];
|
|
24
25
|
redirectTo?: string;
|
|
25
26
|
}) => (req: next_server.NextRequest) => Promise<next_server.NextResponse>;
|
|
26
27
|
getUserFromCookies: (cookies: next_dist_server_web_spec_extension_adapters_request_cookies.ReadonlyRequestCookies) => Promise<PublicUser | null>;
|
|
27
28
|
};
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
declare function usersFromEnv(): User[];
|
|
31
|
+
|
|
32
|
+
export { type LiteAuthConfig, type PublicUser, type User, createLiteAuth, usersFromEnv };
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ type LiteAuthConfig = {
|
|
|
12
12
|
users: User[];
|
|
13
13
|
jwtSecret: string;
|
|
14
14
|
cookieName?: string;
|
|
15
|
+
enabled?: boolean;
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
declare function createLiteAuth(config: LiteAuthConfig): {
|
|
@@ -20,10 +21,12 @@ declare function createLiteAuth(config: LiteAuthConfig): {
|
|
|
20
21
|
POST: (req: next_server.NextRequest) => Promise<next_server.NextResponse>;
|
|
21
22
|
};
|
|
22
23
|
middleware: (options: {
|
|
23
|
-
protect: string[];
|
|
24
|
+
protect: (string | RegExp)[];
|
|
24
25
|
redirectTo?: string;
|
|
25
26
|
}) => (req: next_server.NextRequest) => Promise<next_server.NextResponse>;
|
|
26
27
|
getUserFromCookies: (cookies: next_dist_server_web_spec_extension_adapters_request_cookies.ReadonlyRequestCookies) => Promise<PublicUser | null>;
|
|
27
28
|
};
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
declare function usersFromEnv(): User[];
|
|
31
|
+
|
|
32
|
+
export { type LiteAuthConfig, type PublicUser, type User, createLiteAuth, usersFromEnv };
|
package/dist/index.js
CHANGED
|
@@ -20,7 +20,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
|
-
createLiteAuth: () => createLiteAuth
|
|
23
|
+
createLiteAuth: () => createLiteAuth,
|
|
24
|
+
usersFromEnv: () => usersFromEnv
|
|
24
25
|
});
|
|
25
26
|
module.exports = __toCommonJS(src_exports);
|
|
26
27
|
|
|
@@ -86,11 +87,13 @@ function makeHandlers(ctx) {
|
|
|
86
87
|
return import_server.NextResponse.json({ user });
|
|
87
88
|
}
|
|
88
89
|
async function GET(req) {
|
|
90
|
+
if (!ctx.enabled) return import_server.NextResponse.json({ user: null });
|
|
89
91
|
const action = req.nextUrl.pathname.split("/").pop();
|
|
90
92
|
if (action === "me") return me(req);
|
|
91
93
|
return import_server.NextResponse.json({ error: "Not found" }, { status: 404 });
|
|
92
94
|
}
|
|
93
95
|
async function POST(req) {
|
|
96
|
+
if (!ctx.enabled) return import_server.NextResponse.json({ ok: true });
|
|
94
97
|
const action = req.nextUrl.pathname.split("/").pop();
|
|
95
98
|
if (action === "login") return login(req);
|
|
96
99
|
if (action === "logout") return logout(req);
|
|
@@ -110,14 +113,22 @@ function getUserFromCookies(ctx) {
|
|
|
110
113
|
|
|
111
114
|
// src/middleware/index.ts
|
|
112
115
|
var import_server2 = require("next/server");
|
|
116
|
+
|
|
117
|
+
// src/core/matchesProtect.ts
|
|
118
|
+
function matchesProtect(patterns, pathname) {
|
|
119
|
+
return patterns.some(
|
|
120
|
+
(p) => p instanceof RegExp ? p.test(pathname) : p === "/" || pathname === p || pathname.startsWith(p + "/")
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// src/middleware/index.ts
|
|
113
125
|
function makeMiddleware(ctx) {
|
|
114
126
|
return function middleware(options) {
|
|
115
127
|
return async function(req) {
|
|
128
|
+
if (!ctx.enabled) return import_server2.NextResponse.next();
|
|
116
129
|
const { protect, redirectTo = "/login" } = options;
|
|
117
130
|
const { pathname } = req.nextUrl;
|
|
118
|
-
const isProtected = protect
|
|
119
|
-
(pattern) => pathname === pattern || pathname.startsWith(pattern + "/")
|
|
120
|
-
);
|
|
131
|
+
const isProtected = matchesProtect(protect, pathname);
|
|
121
132
|
if (!isProtected) {
|
|
122
133
|
return import_server2.NextResponse.next();
|
|
123
134
|
}
|
|
@@ -138,7 +149,8 @@ function createLiteAuth(config) {
|
|
|
138
149
|
const ctx = {
|
|
139
150
|
users: config.users,
|
|
140
151
|
jwtSecret: config.jwtSecret,
|
|
141
|
-
cookieName: config.cookieName ?? "lite-auth-token"
|
|
152
|
+
cookieName: config.cookieName ?? "lite-auth-token",
|
|
153
|
+
enabled: config.enabled ?? true
|
|
142
154
|
};
|
|
143
155
|
return {
|
|
144
156
|
handlers: makeHandlers(ctx),
|
|
@@ -146,8 +158,33 @@ function createLiteAuth(config) {
|
|
|
146
158
|
getUserFromCookies: getUserFromCookies(ctx)
|
|
147
159
|
};
|
|
148
160
|
}
|
|
161
|
+
|
|
162
|
+
// src/core/usersFromEnv.ts
|
|
163
|
+
function usersFromEnv() {
|
|
164
|
+
const raw = process.env.LITE_AUTH_USERS;
|
|
165
|
+
if (!raw) {
|
|
166
|
+
throw new Error(
|
|
167
|
+
`[next-lite-auth] LITE_AUTH_USERS environment variable is not set. Set it to a JSON array of users, e.g.: LITE_AUTH_USERS='[{"email":"admin@example.com","password":"secret"}]'`
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
let parsed;
|
|
171
|
+
try {
|
|
172
|
+
parsed = JSON.parse(raw);
|
|
173
|
+
} catch {
|
|
174
|
+
throw new Error(
|
|
175
|
+
"[next-lite-auth] LITE_AUTH_USERS is not valid JSON. Expected a JSON array of users."
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
if (!Array.isArray(parsed)) {
|
|
179
|
+
throw new Error(
|
|
180
|
+
'[next-lite-auth] LITE_AUTH_USERS must be a JSON array, e.g.: [{"email":"admin@example.com","password":"secret"}]'
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
return parsed;
|
|
184
|
+
}
|
|
149
185
|
// Annotate the CommonJS export names for ESM import in node:
|
|
150
186
|
0 && (module.exports = {
|
|
151
|
-
createLiteAuth
|
|
187
|
+
createLiteAuth,
|
|
188
|
+
usersFromEnv
|
|
152
189
|
});
|
|
153
190
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +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 makeHandlers(ctx: LiteAuthContext) {\n async function login(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,\n });\n return res;\n }\n\n async function logout(_req: NextRequest): Promise<NextResponse> {\n const res = NextResponse.json({ ok: true });\n res.cookies.set(ctx.cookieName, \"\", { httpOnly: true, path: \"/\", maxAge: 0 });\n return res;\n }\n\n async function me(req: NextRequest): Promise<NextResponse> {\n const token = req.cookies.get(ctx.cookieName)?.value;\n if (!token) return NextResponse.json({ user: null }, { status: 401 });\n const user = await verifyToken(token, ctx.jwtSecret);\n if (!user) return NextResponse.json({ user: null }, { status: 401 });\n return NextResponse.json({ user });\n }\n\n async function GET(req: NextRequest): Promise<NextResponse> {\n const action = req.nextUrl.pathname.split(\"/\").pop();\n if (action === \"me\") return me(req);\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n\n async function POST(req: NextRequest): Promise<NextResponse> {\n const action = req.nextUrl.pathname.split(\"/\").pop();\n if (action === \"login\") return login(req);\n if (action === \"logout\") return logout(req);\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n\n return { GET, POST };\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 { makeHandlers, 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: makeHandlers(ctx),\n middleware: makeMiddleware(ctx),\n getUserFromCookies: getUserFromCookies(ctx),\n };\n}\n"],"mappings":"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","names":["import_server"]}
|
|
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/matchesProtect.ts","../src/core/createLiteAuth.ts","../src/core/usersFromEnv.ts"],"sourcesContent":["export { createLiteAuth } from \"./core/createLiteAuth\";\nexport { usersFromEnv } from \"./core/usersFromEnv\";\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 makeHandlers(ctx: LiteAuthContext) {\n async function login(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,\n });\n return res;\n }\n\n async function logout(_req: NextRequest): Promise<NextResponse> {\n const res = NextResponse.json({ ok: true });\n res.cookies.set(ctx.cookieName, \"\", { httpOnly: true, path: \"/\", maxAge: 0 });\n return res;\n }\n\n async function me(req: NextRequest): Promise<NextResponse> {\n const token = req.cookies.get(ctx.cookieName)?.value;\n if (!token) return NextResponse.json({ user: null }, { status: 401 });\n const user = await verifyToken(token, ctx.jwtSecret);\n if (!user) return NextResponse.json({ user: null }, { status: 401 });\n return NextResponse.json({ user });\n }\n\n async function GET(req: NextRequest): Promise<NextResponse> {\n if (!ctx.enabled) return NextResponse.json({ user: null });\n const action = req.nextUrl.pathname.split(\"/\").pop();\n if (action === \"me\") return me(req);\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n\n async function POST(req: NextRequest): Promise<NextResponse> {\n if (!ctx.enabled) return NextResponse.json({ ok: true });\n const action = req.nextUrl.pathname.split(\"/\").pop();\n if (action === \"login\") return login(req);\n if (action === \"logout\") return logout(req);\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n\n return { GET, POST };\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\";\nimport { matchesProtect } from \"../core/matchesProtect\";\n\ntype MiddlewareOptions = {\n protect: (string | RegExp)[];\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 if (!ctx.enabled) return NextResponse.next();\n const { protect, redirectTo = \"/login\" } = options;\n const { pathname } = req.nextUrl;\n\n const isProtected = matchesProtect(protect, pathname);\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","export function matchesProtect(patterns: (string | RegExp)[], pathname: string): boolean {\n return patterns.some((p) =>\n p instanceof RegExp\n ? p.test(pathname)\n : p === \"/\" || pathname === p || pathname.startsWith(p + \"/\")\n );\n}\n","import { LiteAuthConfig, LiteAuthContext } from \"./types\";\nimport { makeHandlers, 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 enabled: config.enabled ?? true,\n };\n\n return {\n handlers: makeHandlers(ctx),\n middleware: makeMiddleware(ctx),\n getUserFromCookies: getUserFromCookies(ctx),\n };\n}\n","import { User } from \"./types\";\n\nexport function usersFromEnv(): User[] {\n const raw = process.env.LITE_AUTH_USERS;\n\n if (!raw) {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS environment variable is not set. \" +\n \"Set it to a JSON array of users, e.g.: \" +\n 'LITE_AUTH_USERS=\\'[{\"email\":\"admin@example.com\",\"password\":\"secret\"}]\\''\n );\n }\n\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS is not valid JSON. \" +\n \"Expected a JSON array of users.\"\n );\n }\n\n if (!Array.isArray(parsed)) {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS must be a JSON array, e.g.: \" +\n '[{\"email\":\"admin@example.com\",\"password\":\"secret\"}]'\n );\n }\n\n return parsed as User[];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,oBAA0C;;;ACA1C,kBAAmC;AAGnC,SAAS,UAAU,QAAgB;AACjC,SAAO,IAAI,YAAY,EAAE,OAAO,MAAM;AACxC;AAEA,eAAsB,UAAU,MAAkB,QAAiC;AACjF,SAAO,IAAI,oBAAQ,EAAE,GAAG,KAAK,CAAC,EAC3B,mBAAmB,EAAE,KAAK,QAAQ,CAAC,EACnC,YAAY,EACZ,kBAAkB,IAAI,EACtB,KAAK,UAAU,MAAM,CAAC;AAC3B;AAEA,eAAsB,YAAY,OAAe,QAA4C;AAC3F,MAAI;AACF,UAAM,EAAE,QAAQ,IAAI,UAAM,uBAAU,OAAO,UAAU,MAAM,CAAC;AAC5D,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ADlBO,SAAS,aAAa,KAAsB;AACjD,iBAAe,MAAM,KAAyC;AAC5D,QAAI;AACJ,QAAI;AACF,aAAO,MAAM,IAAI,KAAK;AAAA,IACxB,QAAQ;AACN,aAAO,2BAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACrE;AAEA,UAAM,EAAE,OAAO,SAAS,IAAI;AAC5B,QAAI,CAAC,SAAS,CAAC,UAAU;AACvB,aAAO,2BAAa,KAAK,EAAE,OAAO,kCAAkC,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACxF;AAEA,UAAM,OAAO,IAAI,MAAM,KAAK,CAAC,MAAM,EAAE,UAAU,SAAS,EAAE,aAAa,QAAQ;AAC/E,QAAI,CAAC,MAAM;AACT,aAAO,2BAAa,KAAK,EAAE,OAAO,sBAAsB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC5E;AAEA,UAAM,EAAE,UAAU,GAAG,GAAG,WAAW,IAAI;AACvC,UAAM,QAAQ,MAAM,UAAU,YAAY,IAAI,SAAS;AAEvD,UAAM,MAAM,2BAAa,KAAK,EAAE,MAAM,WAAW,CAAC;AAClD,QAAI,QAAQ,IAAI,IAAI,YAAY,OAAO;AAAA,MACrC,UAAU;AAAA,MACV,MAAM;AAAA,MACN,UAAU;AAAA,MACV,QAAQ,QAAQ,IAAI,aAAa;AAAA,MACjC,QAAQ,KAAK,KAAK,KAAK;AAAA,IACzB,CAAC;AACD,WAAO;AAAA,EACT;AAEA,iBAAe,OAAO,MAA0C;AAC9D,UAAM,MAAM,2BAAa,KAAK,EAAE,IAAI,KAAK,CAAC;AAC1C,QAAI,QAAQ,IAAI,IAAI,YAAY,IAAI,EAAE,UAAU,MAAM,MAAM,KAAK,QAAQ,EAAE,CAAC;AAC5E,WAAO;AAAA,EACT;AAEA,iBAAe,GAAG,KAAyC;AACzD,UAAM,QAAQ,IAAI,QAAQ,IAAI,IAAI,UAAU,GAAG;AAC/C,QAAI,CAAC,MAAO,QAAO,2BAAa,KAAK,EAAE,MAAM,KAAK,GAAG,EAAE,QAAQ,IAAI,CAAC;AACpE,UAAM,OAAO,MAAM,YAAY,OAAO,IAAI,SAAS;AACnD,QAAI,CAAC,KAAM,QAAO,2BAAa,KAAK,EAAE,MAAM,KAAK,GAAG,EAAE,QAAQ,IAAI,CAAC;AACnE,WAAO,2BAAa,KAAK,EAAE,KAAK,CAAC;AAAA,EACnC;AAEA,iBAAe,IAAI,KAAyC;AAC1D,QAAI,CAAC,IAAI,QAAS,QAAO,2BAAa,KAAK,EAAE,MAAM,KAAK,CAAC;AACzD,UAAM,SAAS,IAAI,QAAQ,SAAS,MAAM,GAAG,EAAE,IAAI;AACnD,QAAI,WAAW,KAAM,QAAO,GAAG,GAAG;AAClC,WAAO,2BAAa,KAAK,EAAE,OAAO,YAAY,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAClE;AAEA,iBAAe,KAAK,KAAyC;AAC3D,QAAI,CAAC,IAAI,QAAS,QAAO,2BAAa,KAAK,EAAE,IAAI,KAAK,CAAC;AACvD,UAAM,SAAS,IAAI,QAAQ,SAAS,MAAM,GAAG,EAAE,IAAI;AACnD,QAAI,WAAW,QAAS,QAAO,MAAM,GAAG;AACxC,QAAI,WAAW,SAAU,QAAO,OAAO,GAAG;AAC1C,WAAO,2BAAa,KAAK,EAAE,OAAO,YAAY,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAClE;AAEA,SAAO,EAAE,KAAK,KAAK;AACrB;;;AE/DO,SAAS,mBAAmB,KAAsB;AACvD,SAAO,eAAgB,SAA6D;AAClF,UAAM,QAAQ,QAAQ,IAAI,IAAI,UAAU,GAAG;AAC3C,QAAI,CAAC,MAAO,QAAO;AACnB,WAAO,YAAY,OAAO,IAAI,SAAS;AAAA,EACzC;AACF;;;ACVA,IAAAA,iBAA0C;;;ACAnC,SAAS,eAAe,UAA+B,UAA2B;AACvF,SAAO,SAAS;AAAA,IAAK,CAAC,MACpB,aAAa,SACT,EAAE,KAAK,QAAQ,IACf,MAAM,OAAO,aAAa,KAAK,SAAS,WAAW,IAAI,GAAG;AAAA,EAChE;AACF;;;ADIO,SAAS,eAAe,KAAsB;AACnD,SAAO,SAAS,WAAW,SAA4B;AACrD,WAAO,eAAgB,KAAyC;AAC9D,UAAI,CAAC,IAAI,QAAS,QAAO,4BAAa,KAAK;AAC3C,YAAM,EAAE,SAAS,aAAa,SAAS,IAAI;AAC3C,YAAM,EAAE,SAAS,IAAI,IAAI;AAEzB,YAAM,cAAc,eAAe,SAAS,QAAQ;AAEpD,UAAI,CAAC,aAAa;AAChB,eAAO,4BAAa,KAAK;AAAA,MAC3B;AAEA,YAAM,QAAQ,IAAI,QAAQ,IAAI,IAAI,UAAU,GAAG;AAC/C,UAAI,OAAO;AACT,cAAM,OAAO,MAAM,YAAY,OAAO,IAAI,SAAS;AACnD,YAAI,KAAM,QAAO,4BAAa,KAAK;AAAA,MACrC;AAEA,YAAM,WAAW,IAAI,IAAI,YAAY,IAAI,GAAG;AAC5C,eAAS,aAAa,IAAI,QAAQ,QAAQ;AAC1C,aAAO,4BAAa,SAAS,QAAQ;AAAA,IACvC;AAAA,EACF;AACF;;;AE9BO,SAAS,eAAe,QAAwB;AACrD,QAAM,MAAuB;AAAA,IAC3B,OAAO,OAAO;AAAA,IACd,WAAW,OAAO;AAAA,IAClB,YAAY,OAAO,cAAc;AAAA,IACjC,SAAS,OAAO,WAAW;AAAA,EAC7B;AAEA,SAAO;AAAA,IACL,UAAU,aAAa,GAAG;AAAA,IAC1B,YAAY,eAAe,GAAG;AAAA,IAC9B,oBAAoB,mBAAmB,GAAG;AAAA,EAC5C;AACF;;;ACfO,SAAS,eAAuB;AACrC,QAAM,MAAM,QAAQ,IAAI;AAExB,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR;AAAA,IAGF;AAAA,EACF;AAEA,MAAI;AAEJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;AAAA,EACzB,QAAQ;AACN,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAEA,MAAI,CAAC,MAAM,QAAQ,MAAM,GAAG;AAC1B,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAEA,SAAO;AACT;","names":["import_server"]}
|
package/dist/index.mjs
CHANGED
|
@@ -60,11 +60,13 @@ function makeHandlers(ctx) {
|
|
|
60
60
|
return NextResponse.json({ user });
|
|
61
61
|
}
|
|
62
62
|
async function GET(req) {
|
|
63
|
+
if (!ctx.enabled) return NextResponse.json({ user: null });
|
|
63
64
|
const action = req.nextUrl.pathname.split("/").pop();
|
|
64
65
|
if (action === "me") return me(req);
|
|
65
66
|
return NextResponse.json({ error: "Not found" }, { status: 404 });
|
|
66
67
|
}
|
|
67
68
|
async function POST(req) {
|
|
69
|
+
if (!ctx.enabled) return NextResponse.json({ ok: true });
|
|
68
70
|
const action = req.nextUrl.pathname.split("/").pop();
|
|
69
71
|
if (action === "login") return login(req);
|
|
70
72
|
if (action === "logout") return logout(req);
|
|
@@ -84,14 +86,22 @@ function getUserFromCookies(ctx) {
|
|
|
84
86
|
|
|
85
87
|
// src/middleware/index.ts
|
|
86
88
|
import { NextResponse as NextResponse2 } from "next/server";
|
|
89
|
+
|
|
90
|
+
// src/core/matchesProtect.ts
|
|
91
|
+
function matchesProtect(patterns, pathname) {
|
|
92
|
+
return patterns.some(
|
|
93
|
+
(p) => p instanceof RegExp ? p.test(pathname) : p === "/" || pathname === p || pathname.startsWith(p + "/")
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/middleware/index.ts
|
|
87
98
|
function makeMiddleware(ctx) {
|
|
88
99
|
return function middleware(options) {
|
|
89
100
|
return async function(req) {
|
|
101
|
+
if (!ctx.enabled) return NextResponse2.next();
|
|
90
102
|
const { protect, redirectTo = "/login" } = options;
|
|
91
103
|
const { pathname } = req.nextUrl;
|
|
92
|
-
const isProtected = protect
|
|
93
|
-
(pattern) => pathname === pattern || pathname.startsWith(pattern + "/")
|
|
94
|
-
);
|
|
104
|
+
const isProtected = matchesProtect(protect, pathname);
|
|
95
105
|
if (!isProtected) {
|
|
96
106
|
return NextResponse2.next();
|
|
97
107
|
}
|
|
@@ -112,7 +122,8 @@ function createLiteAuth(config) {
|
|
|
112
122
|
const ctx = {
|
|
113
123
|
users: config.users,
|
|
114
124
|
jwtSecret: config.jwtSecret,
|
|
115
|
-
cookieName: config.cookieName ?? "lite-auth-token"
|
|
125
|
+
cookieName: config.cookieName ?? "lite-auth-token",
|
|
126
|
+
enabled: config.enabled ?? true
|
|
116
127
|
};
|
|
117
128
|
return {
|
|
118
129
|
handlers: makeHandlers(ctx),
|
|
@@ -120,7 +131,32 @@ function createLiteAuth(config) {
|
|
|
120
131
|
getUserFromCookies: getUserFromCookies(ctx)
|
|
121
132
|
};
|
|
122
133
|
}
|
|
134
|
+
|
|
135
|
+
// src/core/usersFromEnv.ts
|
|
136
|
+
function usersFromEnv() {
|
|
137
|
+
const raw = process.env.LITE_AUTH_USERS;
|
|
138
|
+
if (!raw) {
|
|
139
|
+
throw new Error(
|
|
140
|
+
`[next-lite-auth] LITE_AUTH_USERS environment variable is not set. Set it to a JSON array of users, e.g.: LITE_AUTH_USERS='[{"email":"admin@example.com","password":"secret"}]'`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
let parsed;
|
|
144
|
+
try {
|
|
145
|
+
parsed = JSON.parse(raw);
|
|
146
|
+
} catch {
|
|
147
|
+
throw new Error(
|
|
148
|
+
"[next-lite-auth] LITE_AUTH_USERS is not valid JSON. Expected a JSON array of users."
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
if (!Array.isArray(parsed)) {
|
|
152
|
+
throw new Error(
|
|
153
|
+
'[next-lite-auth] LITE_AUTH_USERS must be a JSON array, e.g.: [{"email":"admin@example.com","password":"secret"}]'
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
return parsed;
|
|
157
|
+
}
|
|
123
158
|
export {
|
|
124
|
-
createLiteAuth
|
|
159
|
+
createLiteAuth,
|
|
160
|
+
usersFromEnv
|
|
125
161
|
};
|
|
126
162
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +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 makeHandlers(ctx: LiteAuthContext) {\n async function login(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,\n });\n return res;\n }\n\n async function logout(_req: NextRequest): Promise<NextResponse> {\n const res = NextResponse.json({ ok: true });\n res.cookies.set(ctx.cookieName, \"\", { httpOnly: true, path: \"/\", maxAge: 0 });\n return res;\n }\n\n async function me(req: NextRequest): Promise<NextResponse> {\n const token = req.cookies.get(ctx.cookieName)?.value;\n if (!token) return NextResponse.json({ user: null }, { status: 401 });\n const user = await verifyToken(token, ctx.jwtSecret);\n if (!user) return NextResponse.json({ user: null }, { status: 401 });\n return NextResponse.json({ user });\n }\n\n async function GET(req: NextRequest): Promise<NextResponse> {\n const action = req.nextUrl.pathname.split(\"/\").pop();\n if (action === \"me\") return me(req);\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n\n async function POST(req: NextRequest): Promise<NextResponse> {\n const action = req.nextUrl.pathname.split(\"/\").pop();\n if (action === \"login\") return login(req);\n if (action === \"logout\") return logout(req);\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n\n return { GET, POST };\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 { makeHandlers, 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: makeHandlers(ctx),\n middleware: makeMiddleware(ctx),\n getUserFromCookies: getUserFromCookies(ctx),\n };\n}\n"],"mappings":"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","names":["NextResponse","NextResponse"]}
|
|
1
|
+
{"version":3,"sources":["../src/server/handlers.ts","../src/server/jwt.ts","../src/server/getUserFromCookies.ts","../src/middleware/index.ts","../src/core/matchesProtect.ts","../src/core/createLiteAuth.ts","../src/core/usersFromEnv.ts"],"sourcesContent":["import { NextRequest, NextResponse } from \"next/server\";\nimport { LiteAuthContext } from \"../core/types\";\nimport { signToken, verifyToken } from \"./jwt\";\n\nexport function makeHandlers(ctx: LiteAuthContext) {\n async function login(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,\n });\n return res;\n }\n\n async function logout(_req: NextRequest): Promise<NextResponse> {\n const res = NextResponse.json({ ok: true });\n res.cookies.set(ctx.cookieName, \"\", { httpOnly: true, path: \"/\", maxAge: 0 });\n return res;\n }\n\n async function me(req: NextRequest): Promise<NextResponse> {\n const token = req.cookies.get(ctx.cookieName)?.value;\n if (!token) return NextResponse.json({ user: null }, { status: 401 });\n const user = await verifyToken(token, ctx.jwtSecret);\n if (!user) return NextResponse.json({ user: null }, { status: 401 });\n return NextResponse.json({ user });\n }\n\n async function GET(req: NextRequest): Promise<NextResponse> {\n if (!ctx.enabled) return NextResponse.json({ user: null });\n const action = req.nextUrl.pathname.split(\"/\").pop();\n if (action === \"me\") return me(req);\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n\n async function POST(req: NextRequest): Promise<NextResponse> {\n if (!ctx.enabled) return NextResponse.json({ ok: true });\n const action = req.nextUrl.pathname.split(\"/\").pop();\n if (action === \"login\") return login(req);\n if (action === \"logout\") return logout(req);\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n\n return { GET, POST };\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\";\nimport { matchesProtect } from \"../core/matchesProtect\";\n\ntype MiddlewareOptions = {\n protect: (string | RegExp)[];\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 if (!ctx.enabled) return NextResponse.next();\n const { protect, redirectTo = \"/login\" } = options;\n const { pathname } = req.nextUrl;\n\n const isProtected = matchesProtect(protect, pathname);\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","export function matchesProtect(patterns: (string | RegExp)[], pathname: string): boolean {\n return patterns.some((p) =>\n p instanceof RegExp\n ? p.test(pathname)\n : p === \"/\" || pathname === p || pathname.startsWith(p + \"/\")\n );\n}\n","import { LiteAuthConfig, LiteAuthContext } from \"./types\";\nimport { makeHandlers, 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 enabled: config.enabled ?? true,\n };\n\n return {\n handlers: makeHandlers(ctx),\n middleware: makeMiddleware(ctx),\n getUserFromCookies: getUserFromCookies(ctx),\n };\n}\n","import { User } from \"./types\";\n\nexport function usersFromEnv(): User[] {\n const raw = process.env.LITE_AUTH_USERS;\n\n if (!raw) {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS environment variable is not set. \" +\n \"Set it to a JSON array of users, e.g.: \" +\n 'LITE_AUTH_USERS=\\'[{\"email\":\"admin@example.com\",\"password\":\"secret\"}]\\''\n );\n }\n\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS is not valid JSON. \" +\n \"Expected a JSON array of users.\"\n );\n }\n\n if (!Array.isArray(parsed)) {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS must be a JSON array, e.g.: \" +\n '[{\"email\":\"admin@example.com\",\"password\":\"secret\"}]'\n );\n }\n\n return parsed as User[];\n}\n"],"mappings":"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","names":["NextResponse","NextResponse"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-lite-auth",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Lightweight JWT auth for Next.js using static JSON users (no database)",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -17,42 +17,30 @@
|
|
|
17
17
|
"require": "./dist/client.js"
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
|
-
"files": [
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
30
23
|
"peerDependencies": {
|
|
31
24
|
"next": ">=13.0.0",
|
|
32
|
-
"react": ">=18.0.0"
|
|
33
|
-
"tailwindcss": ">=3.0.0"
|
|
34
|
-
},
|
|
35
|
-
"peerDependenciesMeta": {
|
|
36
|
-
"tailwindcss": {
|
|
37
|
-
"optional": true
|
|
38
|
-
}
|
|
25
|
+
"react": ">=18.0.0"
|
|
39
26
|
},
|
|
40
27
|
"dependencies": {
|
|
41
28
|
"jose": "^5.0.0"
|
|
42
29
|
},
|
|
43
30
|
"devDependencies": {
|
|
31
|
+
"@types/node": "^25.5.2",
|
|
44
32
|
"@types/react": "^18.0.0",
|
|
45
33
|
"next": "^14.0.0",
|
|
46
34
|
"react": "^18.0.0",
|
|
47
35
|
"tsup": "^8.0.0",
|
|
48
36
|
"typescript": "^5.0.0",
|
|
49
|
-
"vitepress": "^1.0.0"
|
|
37
|
+
"vitepress": "^1.0.0",
|
|
38
|
+
"vitest": "^2.1.9"
|
|
50
39
|
},
|
|
51
40
|
"engines": {
|
|
52
41
|
"node": ">=20.0.0",
|
|
53
42
|
"pnpm": ">=9.0.0"
|
|
54
43
|
},
|
|
55
|
-
"packageManager": "pnpm@9.0.0",
|
|
56
44
|
"author": "amide-init",
|
|
57
45
|
"repository": {
|
|
58
46
|
"type": "git",
|
|
@@ -62,6 +50,20 @@
|
|
|
62
50
|
"bugs": {
|
|
63
51
|
"url": "https://github.com/amide-init/next-lite-auth/issues"
|
|
64
52
|
},
|
|
65
|
-
"keywords": [
|
|
66
|
-
|
|
67
|
-
|
|
53
|
+
"keywords": [
|
|
54
|
+
"nextjs",
|
|
55
|
+
"auth",
|
|
56
|
+
"jwt",
|
|
57
|
+
"lightweight"
|
|
58
|
+
],
|
|
59
|
+
"license": "MIT",
|
|
60
|
+
"scripts": {
|
|
61
|
+
"build": "tsup",
|
|
62
|
+
"dev": "tsup --watch",
|
|
63
|
+
"test": "vitest run",
|
|
64
|
+
"typecheck": "tsc --noEmit",
|
|
65
|
+
"docs:dev": "vitepress dev docs",
|
|
66
|
+
"docs:build": "vitepress build docs",
|
|
67
|
+
"docs:preview": "vitepress preview docs"
|
|
68
|
+
}
|
|
69
|
+
}
|