@farm.js/create-app 0.1.0-beta.21 → 0.1.0-beta.22
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 +8 -6
- package/bin/create-farm-app.js +1 -1
- package/dist/index.js +34 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +34 -8
- package/dist/index.mjs.map +1 -1
- package/dist/utils.js +8 -6
- package/dist/utils.js.map +1 -1
- package/dist/utils.mjs +8 -6
- package/dist/utils.mjs.map +1 -1
- package/package.json +2 -2
- package/templates/auth/.env.example +6 -0
- package/templates/auth/README.md +95 -0
- package/templates/auth/farm.config.ts +11 -0
- package/templates/auth/gitignore +10 -0
- package/templates/auth/package.json +32 -0
- package/templates/auth/pnpm-workspace.yaml +13 -0
- package/templates/auth/src/app/dashboard/middleware.ts +13 -0
- package/templates/auth/src/app/dashboard/page.tsx +140 -0
- package/templates/auth/src/app/error.tsx +25 -0
- package/templates/auth/src/app/globals.css +1064 -0
- package/templates/auth/src/app/layout.tsx +11 -0
- package/templates/auth/src/app/loading.tsx +15 -0
- package/templates/auth/src/app/not-found.tsx +26 -0
- package/templates/auth/src/app/page.tsx +46 -0
- package/templates/auth/src/app/sign-in/page.tsx +16 -0
- package/templates/auth/src/app/sign-up/page.tsx +16 -0
- package/templates/auth/src/components/auth-form.tsx +120 -0
- package/templates/auth/src/components/auth-shell.tsx +21 -0
- package/templates/auth/src/components/resource-links.tsx +78 -0
- package/templates/auth/src/components/sign-out-button.tsx +45 -0
- package/templates/auth/src/components/site-header.tsx +46 -0
- package/templates/auth/tsconfig.json +20 -0
- package/templates/basic/package.json +4 -2
- package/templates/basic/pnpm-workspace.yaml +3 -0
- package/templates/basic/src/app/globals.css +241 -0
- package/templates/basic/src/app/layout.tsx +2 -4
- package/templates/basic/src/app/page.tsx +20 -61
- package/templates/basic/src/components/resource-links.tsx +78 -0
- package/templates/better-auth/.env.example +3 -0
- package/templates/better-auth/README.md +87 -0
- package/templates/better-auth/farm.config.ts +29 -0
- package/templates/better-auth/gitignore +10 -0
- package/templates/better-auth/package.json +34 -0
- package/templates/better-auth/pnpm-workspace.yaml +13 -0
- package/templates/better-auth/src/app/dashboard/middleware.ts +15 -0
- package/templates/better-auth/src/app/dashboard/page.tsx +188 -0
- package/templates/better-auth/src/app/error.tsx +25 -0
- package/templates/better-auth/src/app/globals.css +1064 -0
- package/templates/better-auth/src/app/layout.tsx +11 -0
- package/templates/better-auth/src/app/loading.tsx +15 -0
- package/templates/better-auth/src/app/not-found.tsx +26 -0
- package/templates/better-auth/src/app/page.tsx +50 -0
- package/templates/better-auth/src/app/sign-in/page.tsx +16 -0
- package/templates/better-auth/src/app/sign-up/page.tsx +16 -0
- package/templates/better-auth/src/components/auth-form.tsx +120 -0
- package/templates/better-auth/src/components/auth-shell.tsx +21 -0
- package/templates/better-auth/src/components/resource-links.tsx +78 -0
- package/templates/better-auth/src/components/sign-out-button.tsx +45 -0
- package/templates/better-auth/src/components/site-header.tsx +46 -0
- package/templates/better-auth/src/lib/auth-client.ts +5 -0
- package/templates/better-auth/src/lib/auth.ts +50 -0
- package/templates/better-auth/src/lib/session.ts +8 -0
- package/templates/better-auth/tsconfig.json +20 -0
- package/templates/basic/src/app/about/page.tsx +0 -32
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { SignOutButton } from "../../components/sign-out-button";
|
|
5
|
+
import { SiteHeader } from "../../components/site-header";
|
|
6
|
+
import { authClient } from "../../lib/auth-client";
|
|
7
|
+
|
|
8
|
+
type SessionState =
|
|
9
|
+
| { status: "loading" }
|
|
10
|
+
| { status: "unauthorized" }
|
|
11
|
+
| {
|
|
12
|
+
status: "ready";
|
|
13
|
+
session: {
|
|
14
|
+
user: {
|
|
15
|
+
createdAt: Date | string;
|
|
16
|
+
email: string;
|
|
17
|
+
name: string;
|
|
18
|
+
};
|
|
19
|
+
session: {
|
|
20
|
+
expiresAt: Date | string;
|
|
21
|
+
id: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default function DashboardPage() {
|
|
27
|
+
const [sessionState, setSessionState] = useState<SessionState>({ status: "loading" });
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
let cancelled = false;
|
|
31
|
+
|
|
32
|
+
authClient
|
|
33
|
+
.getSession()
|
|
34
|
+
.then((response) => {
|
|
35
|
+
if (cancelled) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (response.error || !response.data?.user) {
|
|
40
|
+
setSessionState({ status: "unauthorized" });
|
|
41
|
+
window.location.replace("/sign-in");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
setSessionState({
|
|
46
|
+
status: "ready",
|
|
47
|
+
session: response.data,
|
|
48
|
+
});
|
|
49
|
+
})
|
|
50
|
+
.catch(() => {
|
|
51
|
+
if (!cancelled) {
|
|
52
|
+
setSessionState({ status: "unauthorized" });
|
|
53
|
+
window.location.replace("/sign-in");
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return () => {
|
|
58
|
+
cancelled = true;
|
|
59
|
+
};
|
|
60
|
+
}, []);
|
|
61
|
+
|
|
62
|
+
if (sessionState.status === "loading") {
|
|
63
|
+
return (
|
|
64
|
+
<main className="loading-shell" aria-label="Loading account" aria-live="polite">
|
|
65
|
+
<div className="loading-block">
|
|
66
|
+
<span className="loading-label">Verifying protected session</span>
|
|
67
|
+
<div className="loading-line wide" />
|
|
68
|
+
<div className="loading-line" />
|
|
69
|
+
<div className="loading-grid">
|
|
70
|
+
<div />
|
|
71
|
+
<div />
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</main>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (sessionState.status === "unauthorized") {
|
|
79
|
+
return (
|
|
80
|
+
<main className="loading-shell" aria-label="Returning to sign in" aria-live="polite">
|
|
81
|
+
<div className="loading-block">
|
|
82
|
+
<span className="loading-label">Session unavailable</span>
|
|
83
|
+
<p className="loading-message">Returning you to the sign-in page…</p>
|
|
84
|
+
</div>
|
|
85
|
+
</main>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const { session } = sessionState;
|
|
90
|
+
const createdAt = new Date(session.user.createdAt).toLocaleDateString("en", {
|
|
91
|
+
day: "numeric",
|
|
92
|
+
month: "short",
|
|
93
|
+
year: "numeric",
|
|
94
|
+
});
|
|
95
|
+
const expiresAt = new Date(session.session.expiresAt).toLocaleString("en", {
|
|
96
|
+
day: "numeric",
|
|
97
|
+
hour: "2-digit",
|
|
98
|
+
minute: "2-digit",
|
|
99
|
+
month: "short",
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<div className="site-frame">
|
|
104
|
+
<SiteHeader user={session.user} />
|
|
105
|
+
|
|
106
|
+
<main className="dashboard-shell">
|
|
107
|
+
<div className="dashboard-heading">
|
|
108
|
+
<div>
|
|
109
|
+
<span className="section-index">PROTECTED / MIDDLEWARE VERIFIED</span>
|
|
110
|
+
<h1>Welcome back, {session.user.name}.</h1>
|
|
111
|
+
<p>Farm route middleware verified your session before this dashboard loaded.</p>
|
|
112
|
+
</div>
|
|
113
|
+
<SignOutButton />
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<section className="dashboard-grid" aria-label="Account overview">
|
|
117
|
+
<article className="account-panel">
|
|
118
|
+
<div className="panel-heading">
|
|
119
|
+
<span>Account</span>
|
|
120
|
+
<span className="status-badge">
|
|
121
|
+
<span className="status-dot" aria-hidden="true" />
|
|
122
|
+
Active
|
|
123
|
+
</span>
|
|
124
|
+
</div>
|
|
125
|
+
<dl className="detail-list">
|
|
126
|
+
<div>
|
|
127
|
+
<dt>Name</dt>
|
|
128
|
+
<dd>{session.user.name}</dd>
|
|
129
|
+
</div>
|
|
130
|
+
<div>
|
|
131
|
+
<dt>Email</dt>
|
|
132
|
+
<dd>{session.user.email}</dd>
|
|
133
|
+
</div>
|
|
134
|
+
<div>
|
|
135
|
+
<dt>Created</dt>
|
|
136
|
+
<dd>{createdAt}</dd>
|
|
137
|
+
</div>
|
|
138
|
+
</dl>
|
|
139
|
+
</article>
|
|
140
|
+
|
|
141
|
+
<article className="session-panel">
|
|
142
|
+
<div className="panel-heading">
|
|
143
|
+
<span>Current session</span>
|
|
144
|
+
<code>httpOnly cookie</code>
|
|
145
|
+
</div>
|
|
146
|
+
<dl className="detail-list">
|
|
147
|
+
<div>
|
|
148
|
+
<dt>Session ID</dt>
|
|
149
|
+
<dd className="mono truncate">{session.session.id}</dd>
|
|
150
|
+
</div>
|
|
151
|
+
<div>
|
|
152
|
+
<dt>Expires</dt>
|
|
153
|
+
<dd>{expiresAt}</dd>
|
|
154
|
+
</div>
|
|
155
|
+
<div>
|
|
156
|
+
<dt>Storage</dt>
|
|
157
|
+
<dd>Neon Postgres</dd>
|
|
158
|
+
</div>
|
|
159
|
+
</dl>
|
|
160
|
+
</article>
|
|
161
|
+
</section>
|
|
162
|
+
|
|
163
|
+
<section className="next-steps" aria-labelledby="next-steps-title">
|
|
164
|
+
<div className="section-heading compact">
|
|
165
|
+
<span className="section-index">NEXT / MAKE IT YOURS</span>
|
|
166
|
+
<h2 id="next-steps-title">The account boundary is ready for product work.</h2>
|
|
167
|
+
</div>
|
|
168
|
+
<div className="next-step-list">
|
|
169
|
+
<div>
|
|
170
|
+
<span>01</span>
|
|
171
|
+
<p>Set the production auth URL, secret, and pooled database URL in your host.</p>
|
|
172
|
+
</div>
|
|
173
|
+
<div>
|
|
174
|
+
<span>02</span>
|
|
175
|
+
<p>
|
|
176
|
+
Add GitHub or Google inside <code>src/lib/auth.ts</code> when you need OAuth.
|
|
177
|
+
</p>
|
|
178
|
+
</div>
|
|
179
|
+
<div>
|
|
180
|
+
<span>03</span>
|
|
181
|
+
<p>Build your first protected feature beside this dashboard route.</p>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
</section>
|
|
185
|
+
</main>
|
|
186
|
+
</div>
|
|
187
|
+
);
|
|
188
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ErrorProps } from "@farm.js/core";
|
|
4
|
+
|
|
5
|
+
export default function ErrorBoundary({ error, reset }: ErrorProps) {
|
|
6
|
+
const message = error instanceof Error ? error.message : "An unexpected error occurred.";
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<main className="error-shell">
|
|
10
|
+
<section className="error-panel">
|
|
11
|
+
<span className="section-index">ERROR / RECOVERABLE</span>
|
|
12
|
+
<h1>That route did not finish loading.</h1>
|
|
13
|
+
<p>{message}</p>
|
|
14
|
+
<div className="hero-actions">
|
|
15
|
+
<button className="button button-primary" onClick={reset} type="button">
|
|
16
|
+
Try again
|
|
17
|
+
</button>
|
|
18
|
+
<a className="button button-secondary" href="/">
|
|
19
|
+
Return home
|
|
20
|
+
</a>
|
|
21
|
+
</div>
|
|
22
|
+
</section>
|
|
23
|
+
</main>
|
|
24
|
+
);
|
|
25
|
+
}
|