@farm.js/create-app 0.1.0-beta.7 → 0.1.0-beta.71
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 +38 -6
- package/bin/create-farm-app.js +7 -2
- package/dist/index.js +3298 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3294 -14
- package/dist/index.mjs.map +1 -1
- package/dist/utils.js +9 -6
- package/dist/utils.js.map +1 -1
- package/dist/utils.mjs +9 -6
- package/dist/utils.mjs.map +1 -1
- package/package.json +2 -2
- package/templates/_integrations/better-auth/preact/farm.config.ts +17 -0
- package/templates/_integrations/better-auth/preact/src/app/dashboard/page.tsx +73 -0
- package/templates/_integrations/better-auth/preact/src/app/layout.tsx +14 -0
- package/templates/_integrations/better-auth/preact/src/app/page.tsx +36 -0
- package/templates/_integrations/better-auth/preact/src/app/sign-in/page.tsx +10 -0
- package/templates/_integrations/better-auth/preact/src/app/sign-up/page.tsx +10 -0
- package/templates/_integrations/better-auth/preact/src/components/auth-form.tsx +92 -0
- package/templates/_integrations/better-auth/preact/src/components/auth-shell.tsx +16 -0
- package/templates/_integrations/better-auth/preact/src/lib/auth-client.ts +5 -0
- package/templates/_integrations/better-auth/solid/farm.config.ts +17 -0
- package/templates/_integrations/better-auth/solid/src/app/dashboard/page.tsx +67 -0
- package/templates/_integrations/better-auth/solid/src/app/layout.tsx +14 -0
- package/templates/_integrations/better-auth/solid/src/app/page.tsx +36 -0
- package/templates/_integrations/better-auth/solid/src/app/sign-in/page.tsx +10 -0
- package/templates/_integrations/better-auth/solid/src/app/sign-up/page.tsx +10 -0
- package/templates/_integrations/better-auth/solid/src/components/auth-form.tsx +91 -0
- package/templates/_integrations/better-auth/solid/src/components/auth-shell.tsx +16 -0
- package/templates/_integrations/better-auth/solid/src/lib/auth-client.ts +5 -0
- package/templates/_integrations/better-auth/svelte/farm.config.ts +17 -0
- package/templates/_integrations/better-auth/svelte/src/app/dashboard/page.svelte +62 -0
- package/templates/_integrations/better-auth/svelte/src/app/layout.svelte +20 -0
- package/templates/_integrations/better-auth/svelte/src/app/page.svelte +32 -0
- package/templates/_integrations/better-auth/svelte/src/app/sign-in/page.svelte +10 -0
- package/templates/_integrations/better-auth/svelte/src/app/sign-up/page.svelte +10 -0
- package/templates/_integrations/better-auth/svelte/src/components/auth-form.svelte +83 -0
- package/templates/_integrations/better-auth/svelte/src/components/auth-shell.svelte +16 -0
- package/templates/_integrations/better-auth/svelte/src/components/resource-links.svelte +47 -0
- package/templates/_integrations/better-auth/svelte/src/lib/auth-client.ts +5 -0
- package/templates/_integrations/better-auth/vue/farm.config.ts +17 -0
- package/templates/_integrations/better-auth/vue/src/app/dashboard/page.vue +62 -0
- package/templates/_integrations/better-auth/vue/src/app/layout.vue +20 -0
- package/templates/_integrations/better-auth/vue/src/app/page.vue +34 -0
- package/templates/_integrations/better-auth/vue/src/app/sign-in/page.vue +12 -0
- package/templates/_integrations/better-auth/vue/src/app/sign-up/page.vue +12 -0
- package/templates/_integrations/better-auth/vue/src/components/auth-form.vue +86 -0
- package/templates/_integrations/better-auth/vue/src/components/auth-shell.vue +15 -0
- package/templates/_integrations/better-auth/vue/src/components/resource-links.vue +43 -0
- package/templates/_integrations/better-auth/vue/src/lib/auth-client.ts +5 -0
- package/templates/_renderers/preact/farm.config.ts +12 -0
- package/templates/_renderers/preact/package.json +26 -0
- package/templates/_renderers/preact/src/app/api/greeting/route.ts +15 -0
- package/templates/_renderers/preact/src/app/layout.tsx +16 -0
- package/templates/_renderers/preact/src/app/page.tsx +66 -0
- package/templates/_renderers/preact/src/app/preact.css +26 -0
- package/templates/_renderers/preact/src/components/resource-links.tsx +71 -0
- package/templates/_renderers/preact/src/lib/api-client.ts +4 -0
- package/templates/_renderers/preact/src/lib/api.generated.ts +7 -0
- package/templates/_renderers/preact/tsconfig.json +25 -0
- package/templates/_renderers/solid/farm.config.ts +12 -0
- package/templates/_renderers/solid/package.json +25 -0
- package/templates/_renderers/solid/src/app/api/greeting/route.ts +15 -0
- package/templates/_renderers/solid/src/app/layout.tsx +15 -0
- package/templates/_renderers/solid/src/app/page.tsx +56 -0
- package/templates/_renderers/solid/src/app/solid.css +22 -0
- package/templates/_renderers/solid/src/components/resource-links.tsx +71 -0
- package/templates/_renderers/solid/src/lib/api-client.ts +4 -0
- package/templates/_renderers/solid/src/lib/api.generated.ts +7 -0
- package/templates/_renderers/solid/tsconfig.json +25 -0
- package/templates/_renderers/svelte/farm.config.ts +9 -0
- package/templates/_renderers/svelte/package.json +28 -0
- package/templates/_renderers/svelte/src/app/api/greeting/route.ts +15 -0
- package/templates/_renderers/svelte/src/app/layout.svelte +21 -0
- package/templates/_renderers/svelte/src/app/page.svelte +64 -0
- package/templates/_renderers/svelte/src/app/svelte.css +26 -0
- package/templates/_renderers/svelte/src/components/resource-links.svelte +31 -0
- package/templates/_renderers/svelte/src/lib/api-client.ts +4 -0
- package/templates/_renderers/svelte/src/lib/api.generated.ts +7 -0
- package/templates/_renderers/svelte/tsconfig.json +23 -0
- package/templates/_renderers/vue/farm.config.ts +12 -0
- package/templates/_renderers/vue/package.json +26 -0
- package/templates/_renderers/vue/src/app/api/greeting/route.ts +15 -0
- package/templates/_renderers/vue/src/app/layout.vue +21 -0
- package/templates/_renderers/vue/src/app/page.vue +69 -0
- package/templates/_renderers/vue/src/app/vue.css +26 -0
- package/templates/_renderers/vue/src/components/resource-links.vue +33 -0
- package/templates/_renderers/vue/src/env.d.ts +7 -0
- package/templates/_renderers/vue/src/lib/api-client.ts +4 -0
- package/templates/_renderers/vue/src/lib/api.generated.ts +7 -0
- package/templates/_renderers/vue/tsconfig.json +23 -0
- package/templates/auth/.env.example +6 -0
- package/templates/auth/README.md +95 -0
- package/templates/auth/docs.config.ts +33 -0
- package/templates/auth/docs.json +36 -0
- package/templates/auth/farm.config.ts +20 -0
- package/templates/auth/gitignore +10 -0
- package/templates/auth/package.json +34 -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/docs/page.md +29 -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/docs.config.ts +33 -0
- package/templates/basic/docs.json +36 -0
- package/templates/basic/farm.config.ts +9 -0
- package/templates/basic/package.json +7 -3
- package/templates/basic/pnpm-workspace.yaml +8 -0
- package/templates/basic/src/app/docs/page.md +29 -0
- package/templates/basic/src/app/globals.css +241 -0
- package/templates/basic/src/app/layout.tsx +3 -5
- package/templates/basic/src/app/page.tsx +20 -61
- package/templates/basic/src/components/resource-links.tsx +78 -0
- package/templates/basic/tsconfig.json +4 -0
- package/templates/better-auth/.env.example +3 -0
- package/templates/better-auth/README.md +89 -0
- package/templates/better-auth/docs.config.ts +33 -0
- package/templates/better-auth/docs.json +36 -0
- package/templates/better-auth/farm.config.ts +38 -0
- package/templates/better-auth/gitignore +10 -0
- package/templates/better-auth/package.json +36 -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/docs/page.md +29 -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/react-compiler/README.md +62 -0
- package/templates/react-compiler/docs.config.ts +33 -0
- package/templates/react-compiler/docs.json +36 -0
- package/templates/react-compiler/farm.config.ts +29 -0
- package/templates/react-compiler/gitignore +23 -0
- package/templates/react-compiler/package.json +34 -0
- package/templates/react-compiler/pnpm-workspace.yaml +8 -0
- package/templates/react-compiler/public/favicon.svg +5 -0
- package/templates/react-compiler/scripts/verify-experiment.mjs +113 -0
- package/templates/react-compiler/src/app/docs/page.md +29 -0
- package/templates/react-compiler/src/app/globals.css +470 -0
- package/templates/react-compiler/src/app/layout.tsx +22 -0
- package/templates/react-compiler/src/app/page.tsx +47 -0
- package/templates/react-compiler/src/components/compiler-comparison.tsx +93 -0
- package/templates/react-compiler/src/components/resource-links.tsx +78 -0
- package/templates/react-compiler/src/farm.d.ts +74 -0
- package/templates/react-compiler/src/lib/api.generated.ts +10 -0
- package/templates/react-compiler/tsconfig.json +24 -0
- package/templates/basic/src/app/about/page.tsx +0 -32
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import type { Metadata } from "@farm.js/core";
|
|
3
|
+
import "./globals.css";
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = {
|
|
6
|
+
title: "FARMJS Svelte Better Auth Starter",
|
|
7
|
+
description: "Better Auth with FARMJS and Svelte",
|
|
8
|
+
icons: {
|
|
9
|
+
icon: [{ url: "/favicon.svg", type: "image/svg+xml", sizes: "any" }],
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<script lang="ts">
|
|
15
|
+
import type { Snippet } from "svelte";
|
|
16
|
+
|
|
17
|
+
let { children }: { children?: Snippet } = $props();
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
{@render children?.()}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import ResourceLinks from "../components/resource-links.svelte";
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<main class="landing-main">
|
|
6
|
+
<section class="hero-section">
|
|
7
|
+
<div class="hero-copy">
|
|
8
|
+
<div class="eyebrow-row">
|
|
9
|
+
<span>00</span>
|
|
10
|
+
<span>FARMJS / Svelte + Better Auth</span>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<h1>Connect Postgres. Start at <code>/sign-up</code>.</h1>
|
|
14
|
+
|
|
15
|
+
<div class="command-list" aria-label="Development commands">
|
|
16
|
+
<div class="command-row">
|
|
17
|
+
<span>01</span>
|
|
18
|
+
<code>cp .env.example .env.local</code>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="command-row">
|
|
21
|
+
<span>02</span>
|
|
22
|
+
<code>pnpm dev</code>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<ResourceLinks
|
|
27
|
+
className="resource-links"
|
|
28
|
+
primary={{ href: "/sign-up", label: "Get started" }}
|
|
29
|
+
/>
|
|
30
|
+
</div>
|
|
31
|
+
</section>
|
|
32
|
+
</main>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
export const hydrate = true;
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import AuthForm from "../../components/auth-form.svelte";
|
|
7
|
+
import AuthShell from "../../components/auth-shell.svelte";
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<AuthShell><AuthForm mode="sign-in" /></AuthShell>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
export const hydrate = true;
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import AuthForm from "../../components/auth-form.svelte";
|
|
7
|
+
import AuthShell from "../../components/auth-shell.svelte";
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<AuthShell><AuthForm mode="sign-up" /></AuthShell>
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { authClient } from "../lib/auth-client";
|
|
3
|
+
|
|
4
|
+
let { mode }: { mode: "sign-in" | "sign-up" } = $props();
|
|
5
|
+
const isSignUp = $derived(mode === "sign-up");
|
|
6
|
+
let pending = $state(false);
|
|
7
|
+
let error = $state<string | null>(null);
|
|
8
|
+
|
|
9
|
+
async function submit(event: SubmitEvent) {
|
|
10
|
+
event.preventDefault();
|
|
11
|
+
error = null;
|
|
12
|
+
pending = true;
|
|
13
|
+
|
|
14
|
+
const formData = new FormData(event.currentTarget as HTMLFormElement);
|
|
15
|
+
const email = String(formData.get("email") ?? "").trim();
|
|
16
|
+
const password = String(formData.get("password") ?? "");
|
|
17
|
+
const name = String(formData.get("name") ?? "").trim();
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const response = isSignUp
|
|
21
|
+
? await authClient.signUp.email({ email, name, password })
|
|
22
|
+
: await authClient.signIn.email({ email, password });
|
|
23
|
+
if (response.error) {
|
|
24
|
+
error = response.error.message ?? "We could not complete that request.";
|
|
25
|
+
pending = false;
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
window.location.assign("/dashboard");
|
|
29
|
+
} catch {
|
|
30
|
+
error = "The authentication service could not be reached. Please try again.";
|
|
31
|
+
pending = false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<div class="auth-form-panel">
|
|
37
|
+
<div class="auth-form-heading">
|
|
38
|
+
<span class="section-index">{isSignUp ? "01 / SIGN UP" : "01 / SIGN IN"}</span>
|
|
39
|
+
<h1>{isSignUp ? "Create account." : "Welcome back."}</h1>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<form class="auth-form" onsubmit={submit}>
|
|
43
|
+
{#if isSignUp}
|
|
44
|
+
<label class="field">
|
|
45
|
+
<span><small>01</small> Name</span>
|
|
46
|
+
<input autocomplete="name" minlength="2" name="name" required type="text" />
|
|
47
|
+
</label>
|
|
48
|
+
{/if}
|
|
49
|
+
<label class="field">
|
|
50
|
+
<span><small>{isSignUp ? "02" : "01"}</small> Email</span>
|
|
51
|
+
<input autocomplete="email" name="email" required type="email" />
|
|
52
|
+
</label>
|
|
53
|
+
<label class="field">
|
|
54
|
+
<span><small>{isSignUp ? "03" : "02"}</small> Password</span>
|
|
55
|
+
<input
|
|
56
|
+
autocomplete={isSignUp ? "new-password" : "current-password"}
|
|
57
|
+
minlength="8"
|
|
58
|
+
name="password"
|
|
59
|
+
required
|
|
60
|
+
type="password"
|
|
61
|
+
/>
|
|
62
|
+
</label>
|
|
63
|
+
|
|
64
|
+
{#if error}
|
|
65
|
+
<div class="form-error" role="alert">
|
|
66
|
+
<strong>Authentication failed</strong>
|
|
67
|
+
<span>{error}</span>
|
|
68
|
+
</div>
|
|
69
|
+
{/if}
|
|
70
|
+
|
|
71
|
+
<button class="button button-primary auth-submit" disabled={pending} type="submit">
|
|
72
|
+
<span>{pending ? "Please wait…" : isSignUp ? "Create account" : "Sign in"}</span>
|
|
73
|
+
<span aria-hidden="true">{pending ? "···" : "→"}</span>
|
|
74
|
+
</button>
|
|
75
|
+
</form>
|
|
76
|
+
|
|
77
|
+
<p class="auth-switch">
|
|
78
|
+
{isSignUp ? "Have an account?" : "Need an account?"}
|
|
79
|
+
<a href={isSignUp ? "/sign-in" : "/sign-up"}>
|
|
80
|
+
{isSignUp ? "Sign in →" : "Sign up →"}
|
|
81
|
+
</a>
|
|
82
|
+
</p>
|
|
83
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import ResourceLinks from "./resource-links.svelte";
|
|
4
|
+
|
|
5
|
+
let { children }: { children?: Snippet } = $props();
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<main class="auth-shell">
|
|
9
|
+
<a class="auth-home-link" href="/" aria-label="Back to starter home">
|
|
10
|
+
<span>00</span>
|
|
11
|
+
<span>FARMJS / Svelte + Better Auth</span>
|
|
12
|
+
</a>
|
|
13
|
+
|
|
14
|
+
<section class="auth-form-side">{@render children?.()}</section>
|
|
15
|
+
<ResourceLinks className="auth-resource-links" />
|
|
16
|
+
</main>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
let {
|
|
3
|
+
className,
|
|
4
|
+
primary,
|
|
5
|
+
}: {
|
|
6
|
+
className: string;
|
|
7
|
+
primary?: { href: string; label: string };
|
|
8
|
+
} = $props();
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<nav class={className} aria-label="Starter resources">
|
|
12
|
+
{#if primary}
|
|
13
|
+
<span class="resource-link-item">
|
|
14
|
+
<a class="resource-link-primary" href={primary.href}>{primary.label}</a>
|
|
15
|
+
</span>
|
|
16
|
+
{/if}
|
|
17
|
+
<span class="resource-link-item">
|
|
18
|
+
{#if primary}<span class="resource-separator" aria-hidden="true">/</span>{/if}
|
|
19
|
+
<a href="https://farm.js.dev">
|
|
20
|
+
<svg
|
|
21
|
+
class="resource-icon"
|
|
22
|
+
viewBox="0 0 24 24"
|
|
23
|
+
fill="none"
|
|
24
|
+
stroke="currentColor"
|
|
25
|
+
stroke-width="1.8"
|
|
26
|
+
stroke-linecap="round"
|
|
27
|
+
stroke-linejoin="round"
|
|
28
|
+
aria-hidden="true"
|
|
29
|
+
>
|
|
30
|
+
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" />
|
|
31
|
+
<path d="M14 2v6h6M8 13h8M8 17h6" />
|
|
32
|
+
</svg>
|
|
33
|
+
<span>Docs</span>
|
|
34
|
+
</a>
|
|
35
|
+
</span>
|
|
36
|
+
<span class="resource-link-item">
|
|
37
|
+
<span class="resource-separator" aria-hidden="true">/</span>
|
|
38
|
+
<a href="https://github.com/farming-labs/farm.js">
|
|
39
|
+
<svg class="resource-icon" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
40
|
+
<path
|
|
41
|
+
d="M12 .7a11.5 11.5 0 0 0-3.64 22.41c.58.1.79-.25.79-.56v-2.23c-3.22.7-3.9-1.37-3.9-1.37-.52-1.34-1.28-1.69-1.28-1.69-1.05-.72.08-.7.08-.7 1.16.08 1.77 1.19 1.77 1.19 1.03 1.77 2.7 1.26 3.36.96.1-.75.4-1.26.73-1.55-2.57-.29-5.27-1.29-5.27-5.68 0-1.26.45-2.28 1.18-3.09-.12-.29-.51-1.47.11-3.05 0 0 .96-.31 3.16 1.18A10.95 10.95 0 0 1 12 6.1c.98 0 1.95.13 2.87.39 2.2-1.49 3.16-1.18 3.16-1.18.62 1.58.23 2.76.11 3.05.74.81 1.18 1.83 1.18 3.09 0 4.4-2.71 5.38-5.29 5.67.42.36.79 1.07.79 2.16v3.27c0 .31.21.67.8.56A11.5 11.5 0 0 0 12 .7Z"
|
|
42
|
+
/>
|
|
43
|
+
</svg>
|
|
44
|
+
<span>GitHub</span>
|
|
45
|
+
</a>
|
|
46
|
+
</span>
|
|
47
|
+
</nav>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { betterAuth } from "@farm.js/better-auth";
|
|
2
|
+
import { defineConfig } from "@farm.js/core/config";
|
|
3
|
+
import { vue } from "@farm.js/vue";
|
|
4
|
+
import { auth } from "./src/lib/auth.ts";
|
|
5
|
+
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
renderer: vue(),
|
|
8
|
+
theme: {
|
|
9
|
+
default: "dark",
|
|
10
|
+
},
|
|
11
|
+
integrations: {
|
|
12
|
+
auth: betterAuth({ instance: auth }),
|
|
13
|
+
},
|
|
14
|
+
deploy: {
|
|
15
|
+
target: "vercel",
|
|
16
|
+
},
|
|
17
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const hydrate = true;
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script setup lang="ts">
|
|
6
|
+
import { onMounted, ref } from "vue";
|
|
7
|
+
import { authClient } from "../../lib/auth-client";
|
|
8
|
+
|
|
9
|
+
type SessionData = NonNullable<Awaited<ReturnType<typeof authClient.getSession>>["data"]>;
|
|
10
|
+
|
|
11
|
+
const session = ref<SessionData | null>(null);
|
|
12
|
+
const pending = ref(true);
|
|
13
|
+
const error = ref<string | null>(null);
|
|
14
|
+
|
|
15
|
+
onMounted(async () => {
|
|
16
|
+
const response = await authClient.getSession();
|
|
17
|
+
if (response.error || !response.data?.user) {
|
|
18
|
+
window.location.replace("/sign-in");
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
session.value = response.data;
|
|
22
|
+
pending.value = false;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
async function signOut() {
|
|
26
|
+
pending.value = true;
|
|
27
|
+
error.value = null;
|
|
28
|
+
const response = await authClient.signOut();
|
|
29
|
+
if (response.error) {
|
|
30
|
+
error.value = response.error.message ?? "Could not sign out.";
|
|
31
|
+
pending.value = false;
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
window.location.assign("/");
|
|
35
|
+
}
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<template>
|
|
39
|
+
<main v-if="!session" class="loading-shell" aria-live="polite">
|
|
40
|
+
<div class="loading-block">
|
|
41
|
+
<span class="loading-label">Verifying protected session</span>
|
|
42
|
+
<div class="loading-line wide" />
|
|
43
|
+
<div class="loading-line" />
|
|
44
|
+
</div>
|
|
45
|
+
</main>
|
|
46
|
+
|
|
47
|
+
<main v-else class="dashboard-shell">
|
|
48
|
+
<div class="dashboard-heading">
|
|
49
|
+
<div>
|
|
50
|
+
<span class="section-index">PROTECTED / MIDDLEWARE VERIFIED</span>
|
|
51
|
+
<h1>Welcome back, {{ session.user.name }}.</h1>
|
|
52
|
+
<p>{{ session.user.email }}</p>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="sign-out-control">
|
|
55
|
+
<button class="button button-secondary" :disabled="pending" @click="signOut">
|
|
56
|
+
{{ pending ? "Signing out…" : "Sign out" }}
|
|
57
|
+
</button>
|
|
58
|
+
<span v-if="error" class="inline-error">{{ error }}</span>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</main>
|
|
62
|
+
</template>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Metadata } from "@farm.js/core";
|
|
3
|
+
import "./globals.css";
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = {
|
|
6
|
+
title: "FARMJS Vue Better Auth Starter",
|
|
7
|
+
description: "Better Auth with FARMJS and Vue",
|
|
8
|
+
icons: {
|
|
9
|
+
icon: [{ url: "/favicon.svg", type: "image/svg+xml", sizes: "any" }],
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<script setup lang="ts">
|
|
15
|
+
defineOptions({ inheritAttrs: false });
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<slot />
|
|
20
|
+
</template>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import ResourceLinks from "../components/resource-links.vue";
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<main class="landing-main">
|
|
7
|
+
<section class="hero-section">
|
|
8
|
+
<div class="hero-copy">
|
|
9
|
+
<div class="eyebrow-row">
|
|
10
|
+
<span>00</span>
|
|
11
|
+
<span>FARMJS / Vue + Better Auth</span>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<h1>Connect Postgres. Start at <code>/sign-up</code>.</h1>
|
|
15
|
+
|
|
16
|
+
<div class="command-list" aria-label="Development commands">
|
|
17
|
+
<div class="command-row">
|
|
18
|
+
<span>01</span>
|
|
19
|
+
<code>cp .env.example .env.local</code>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="command-row">
|
|
22
|
+
<span>02</span>
|
|
23
|
+
<code>pnpm dev</code>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<ResourceLinks
|
|
28
|
+
class="resource-links"
|
|
29
|
+
:primary="{ href: '/sign-up', label: 'Get started' }"
|
|
30
|
+
/>
|
|
31
|
+
</div>
|
|
32
|
+
</section>
|
|
33
|
+
</main>
|
|
34
|
+
</template>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const hydrate = true;
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script setup lang="ts">
|
|
6
|
+
import AuthForm from "../../components/auth-form.vue";
|
|
7
|
+
import AuthShell from "../../components/auth-shell.vue";
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<AuthShell><AuthForm mode="sign-in" /></AuthShell>
|
|
12
|
+
</template>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const hydrate = true;
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script setup lang="ts">
|
|
6
|
+
import AuthForm from "../../components/auth-form.vue";
|
|
7
|
+
import AuthShell from "../../components/auth-shell.vue";
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<AuthShell><AuthForm mode="sign-up" /></AuthShell>
|
|
12
|
+
</template>
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, ref } from "vue";
|
|
3
|
+
import { authClient } from "../lib/auth-client";
|
|
4
|
+
|
|
5
|
+
const props = defineProps<{ mode: "sign-in" | "sign-up" }>();
|
|
6
|
+
const isSignUp = computed(() => props.mode === "sign-up");
|
|
7
|
+
const pending = ref(false);
|
|
8
|
+
const error = ref<string | null>(null);
|
|
9
|
+
|
|
10
|
+
async function submit(event: Event) {
|
|
11
|
+
event.preventDefault();
|
|
12
|
+
error.value = null;
|
|
13
|
+
pending.value = true;
|
|
14
|
+
|
|
15
|
+
const formData = new FormData(event.currentTarget as HTMLFormElement);
|
|
16
|
+
const email = String(formData.get("email") ?? "").trim();
|
|
17
|
+
const password = String(formData.get("password") ?? "");
|
|
18
|
+
const name = String(formData.get("name") ?? "").trim();
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const response = isSignUp.value
|
|
22
|
+
? await authClient.signUp.email({ email, name, password })
|
|
23
|
+
: await authClient.signIn.email({ email, password });
|
|
24
|
+
if (response.error) {
|
|
25
|
+
error.value = response.error.message ?? "We could not complete that request.";
|
|
26
|
+
pending.value = false;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
window.location.assign("/dashboard");
|
|
30
|
+
} catch {
|
|
31
|
+
error.value = "The authentication service could not be reached. Please try again.";
|
|
32
|
+
pending.value = false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<template>
|
|
38
|
+
<div class="auth-form-panel">
|
|
39
|
+
<div class="auth-form-heading">
|
|
40
|
+
<span class="section-index">{{ isSignUp ? "01 / SIGN UP" : "01 / SIGN IN" }}</span>
|
|
41
|
+
<h1>{{ isSignUp ? "Create account." : "Welcome back." }}</h1>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<form class="auth-form" @submit="submit">
|
|
45
|
+
<label v-if="isSignUp" class="field">
|
|
46
|
+
<span><small>01</small> Name</span>
|
|
47
|
+
<input autocomplete="name" minlength="2" name="name" required type="text" />
|
|
48
|
+
</label>
|
|
49
|
+
<label class="field">
|
|
50
|
+
<span
|
|
51
|
+
><small>{{ isSignUp ? "02" : "01" }}</small> Email</span
|
|
52
|
+
>
|
|
53
|
+
<input autocomplete="email" name="email" required type="email" />
|
|
54
|
+
</label>
|
|
55
|
+
<label class="field">
|
|
56
|
+
<span
|
|
57
|
+
><small>{{ isSignUp ? "03" : "02" }}</small> Password</span
|
|
58
|
+
>
|
|
59
|
+
<input
|
|
60
|
+
:autocomplete="isSignUp ? 'new-password' : 'current-password'"
|
|
61
|
+
minlength="8"
|
|
62
|
+
name="password"
|
|
63
|
+
required
|
|
64
|
+
type="password"
|
|
65
|
+
/>
|
|
66
|
+
</label>
|
|
67
|
+
|
|
68
|
+
<div v-if="error" class="form-error" role="alert">
|
|
69
|
+
<strong>Authentication failed</strong>
|
|
70
|
+
<span>{{ error }}</span>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<button class="button button-primary auth-submit" :disabled="pending" type="submit">
|
|
74
|
+
<span>{{ pending ? "Please wait…" : isSignUp ? "Create account" : "Sign in" }}</span>
|
|
75
|
+
<span aria-hidden="true">{{ pending ? "···" : "→" }}</span>
|
|
76
|
+
</button>
|
|
77
|
+
</form>
|
|
78
|
+
|
|
79
|
+
<p class="auth-switch">
|
|
80
|
+
{{ isSignUp ? "Have an account?" : "Need an account?" }}
|
|
81
|
+
<a :href="isSignUp ? '/sign-in' : '/sign-up'">
|
|
82
|
+
{{ isSignUp ? "Sign in →" : "Sign up →" }}
|
|
83
|
+
</a>
|
|
84
|
+
</p>
|
|
85
|
+
</div>
|
|
86
|
+
</template>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import ResourceLinks from "./resource-links.vue";
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<main class="auth-shell">
|
|
7
|
+
<a class="auth-home-link" href="/" aria-label="Back to starter home">
|
|
8
|
+
<span>00</span>
|
|
9
|
+
<span>FARMJS / Vue + Better Auth</span>
|
|
10
|
+
</a>
|
|
11
|
+
|
|
12
|
+
<section class="auth-form-side"><slot /></section>
|
|
13
|
+
<ResourceLinks class="auth-resource-links" />
|
|
14
|
+
</main>
|
|
15
|
+
</template>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
defineProps<{
|
|
3
|
+
primary?: { href: string; label: string };
|
|
4
|
+
}>();
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<nav aria-label="Starter resources">
|
|
9
|
+
<span v-if="primary" class="resource-link-item">
|
|
10
|
+
<a class="resource-link-primary" :href="primary.href">{{ primary.label }}</a>
|
|
11
|
+
</span>
|
|
12
|
+
<span class="resource-link-item">
|
|
13
|
+
<span v-if="primary" class="resource-separator" aria-hidden="true">/</span>
|
|
14
|
+
<a href="https://farm.js.dev">
|
|
15
|
+
<svg
|
|
16
|
+
class="resource-icon"
|
|
17
|
+
viewBox="0 0 24 24"
|
|
18
|
+
fill="none"
|
|
19
|
+
stroke="currentColor"
|
|
20
|
+
stroke-width="1.8"
|
|
21
|
+
stroke-linecap="round"
|
|
22
|
+
stroke-linejoin="round"
|
|
23
|
+
aria-hidden="true"
|
|
24
|
+
>
|
|
25
|
+
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" />
|
|
26
|
+
<path d="M14 2v6h6M8 13h8M8 17h6" />
|
|
27
|
+
</svg>
|
|
28
|
+
<span>Docs</span>
|
|
29
|
+
</a>
|
|
30
|
+
</span>
|
|
31
|
+
<span class="resource-link-item">
|
|
32
|
+
<span class="resource-separator" aria-hidden="true">/</span>
|
|
33
|
+
<a href="https://github.com/farming-labs/farm.js">
|
|
34
|
+
<svg class="resource-icon" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
35
|
+
<path
|
|
36
|
+
d="M12 .7a11.5 11.5 0 0 0-3.64 22.41c.58.1.79-.25.79-.56v-2.23c-3.22.7-3.9-1.37-3.9-1.37-.52-1.34-1.28-1.69-1.28-1.69-1.05-.72.08-.7.08-.7 1.16.08 1.77 1.19 1.77 1.19 1.03 1.77 2.7 1.26 3.36.96.1-.75.4-1.26.73-1.55-2.57-.29-5.27-1.29-5.27-5.68 0-1.26.45-2.28 1.18-3.09-.12-.29-.51-1.47.11-3.05 0 0 .96-.31 3.16 1.18A10.95 10.95 0 0 1 12 6.1c.98 0 1.95.13 2.87.39 2.2-1.49 3.16-1.18 3.16-1.18.62 1.58.23 2.76.11 3.05.74.81 1.18 1.83 1.18 3.09 0 4.4-2.71 5.38-5.29 5.67.42.36.79 1.07.79 2.16v3.27c0 .31.21.67.8.56A11.5 11.5 0 0 0 12 .7Z"
|
|
37
|
+
/>
|
|
38
|
+
</svg>
|
|
39
|
+
<span>GitHub</span>
|
|
40
|
+
</a>
|
|
41
|
+
</span>
|
|
42
|
+
</nav>
|
|
43
|
+
</template>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "farm-app",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "farm dev",
|
|
8
|
+
"build": "farm build",
|
|
9
|
+
"deploy": "farm deploy",
|
|
10
|
+
"type-check": "tsc --noEmit"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@farm.js/core": "0.1.0-beta.71",
|
|
14
|
+
"@farm.js/preact": "0.1.0-beta.31",
|
|
15
|
+
"@fontsource-variable/geist": "5.3.0",
|
|
16
|
+
"@fontsource-variable/geist-mono": "5.3.0",
|
|
17
|
+
"preact": "10.29.8",
|
|
18
|
+
"zod": "4.1.12"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@farm.js/cli": "0.1.0-beta.71",
|
|
22
|
+
"tailwindcss": "^4.0.0",
|
|
23
|
+
"typescript": "^5.3.3"
|
|
24
|
+
},
|
|
25
|
+
"packageManager": "pnpm@8.12.1"
|
|
26
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createEndpoint } from "@farm.js/core/api";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
export const POST = createEndpoint(
|
|
5
|
+
"/api/greeting",
|
|
6
|
+
{
|
|
7
|
+
method: "POST",
|
|
8
|
+
body: z.object({
|
|
9
|
+
name: z.string().trim().min(1).max(40),
|
|
10
|
+
}),
|
|
11
|
+
},
|
|
12
|
+
async ({ body }) => ({
|
|
13
|
+
message: `Hello, ${body.name}, from the FARMJS server.`,
|
|
14
|
+
}),
|
|
15
|
+
);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Metadata } from "@farm.js/core";
|
|
2
|
+
import type { ComponentChildren } from "preact";
|
|
3
|
+
import "./globals.css";
|
|
4
|
+
import "./preact.css";
|
|
5
|
+
|
|
6
|
+
export const metadata: Metadata = {
|
|
7
|
+
title: "FARMJS Preact App",
|
|
8
|
+
description: "A framework for product-integrated apps",
|
|
9
|
+
icons: {
|
|
10
|
+
icon: [{ url: "/favicon.svg", type: "image/svg+xml", sizes: "any" }],
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default function RootLayout({ children }: { children?: ComponentChildren }) {
|
|
15
|
+
return <>{children}</>;
|
|
16
|
+
}
|