@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.
Files changed (173) hide show
  1. package/README.md +38 -6
  2. package/bin/create-farm-app.js +7 -2
  3. package/dist/index.js +3298 -16
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +3294 -14
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/utils.js +9 -6
  8. package/dist/utils.js.map +1 -1
  9. package/dist/utils.mjs +9 -6
  10. package/dist/utils.mjs.map +1 -1
  11. package/package.json +2 -2
  12. package/templates/_integrations/better-auth/preact/farm.config.ts +17 -0
  13. package/templates/_integrations/better-auth/preact/src/app/dashboard/page.tsx +73 -0
  14. package/templates/_integrations/better-auth/preact/src/app/layout.tsx +14 -0
  15. package/templates/_integrations/better-auth/preact/src/app/page.tsx +36 -0
  16. package/templates/_integrations/better-auth/preact/src/app/sign-in/page.tsx +10 -0
  17. package/templates/_integrations/better-auth/preact/src/app/sign-up/page.tsx +10 -0
  18. package/templates/_integrations/better-auth/preact/src/components/auth-form.tsx +92 -0
  19. package/templates/_integrations/better-auth/preact/src/components/auth-shell.tsx +16 -0
  20. package/templates/_integrations/better-auth/preact/src/lib/auth-client.ts +5 -0
  21. package/templates/_integrations/better-auth/solid/farm.config.ts +17 -0
  22. package/templates/_integrations/better-auth/solid/src/app/dashboard/page.tsx +67 -0
  23. package/templates/_integrations/better-auth/solid/src/app/layout.tsx +14 -0
  24. package/templates/_integrations/better-auth/solid/src/app/page.tsx +36 -0
  25. package/templates/_integrations/better-auth/solid/src/app/sign-in/page.tsx +10 -0
  26. package/templates/_integrations/better-auth/solid/src/app/sign-up/page.tsx +10 -0
  27. package/templates/_integrations/better-auth/solid/src/components/auth-form.tsx +91 -0
  28. package/templates/_integrations/better-auth/solid/src/components/auth-shell.tsx +16 -0
  29. package/templates/_integrations/better-auth/solid/src/lib/auth-client.ts +5 -0
  30. package/templates/_integrations/better-auth/svelte/farm.config.ts +17 -0
  31. package/templates/_integrations/better-auth/svelte/src/app/dashboard/page.svelte +62 -0
  32. package/templates/_integrations/better-auth/svelte/src/app/layout.svelte +20 -0
  33. package/templates/_integrations/better-auth/svelte/src/app/page.svelte +32 -0
  34. package/templates/_integrations/better-auth/svelte/src/app/sign-in/page.svelte +10 -0
  35. package/templates/_integrations/better-auth/svelte/src/app/sign-up/page.svelte +10 -0
  36. package/templates/_integrations/better-auth/svelte/src/components/auth-form.svelte +83 -0
  37. package/templates/_integrations/better-auth/svelte/src/components/auth-shell.svelte +16 -0
  38. package/templates/_integrations/better-auth/svelte/src/components/resource-links.svelte +47 -0
  39. package/templates/_integrations/better-auth/svelte/src/lib/auth-client.ts +5 -0
  40. package/templates/_integrations/better-auth/vue/farm.config.ts +17 -0
  41. package/templates/_integrations/better-auth/vue/src/app/dashboard/page.vue +62 -0
  42. package/templates/_integrations/better-auth/vue/src/app/layout.vue +20 -0
  43. package/templates/_integrations/better-auth/vue/src/app/page.vue +34 -0
  44. package/templates/_integrations/better-auth/vue/src/app/sign-in/page.vue +12 -0
  45. package/templates/_integrations/better-auth/vue/src/app/sign-up/page.vue +12 -0
  46. package/templates/_integrations/better-auth/vue/src/components/auth-form.vue +86 -0
  47. package/templates/_integrations/better-auth/vue/src/components/auth-shell.vue +15 -0
  48. package/templates/_integrations/better-auth/vue/src/components/resource-links.vue +43 -0
  49. package/templates/_integrations/better-auth/vue/src/lib/auth-client.ts +5 -0
  50. package/templates/_renderers/preact/farm.config.ts +12 -0
  51. package/templates/_renderers/preact/package.json +26 -0
  52. package/templates/_renderers/preact/src/app/api/greeting/route.ts +15 -0
  53. package/templates/_renderers/preact/src/app/layout.tsx +16 -0
  54. package/templates/_renderers/preact/src/app/page.tsx +66 -0
  55. package/templates/_renderers/preact/src/app/preact.css +26 -0
  56. package/templates/_renderers/preact/src/components/resource-links.tsx +71 -0
  57. package/templates/_renderers/preact/src/lib/api-client.ts +4 -0
  58. package/templates/_renderers/preact/src/lib/api.generated.ts +7 -0
  59. package/templates/_renderers/preact/tsconfig.json +25 -0
  60. package/templates/_renderers/solid/farm.config.ts +12 -0
  61. package/templates/_renderers/solid/package.json +25 -0
  62. package/templates/_renderers/solid/src/app/api/greeting/route.ts +15 -0
  63. package/templates/_renderers/solid/src/app/layout.tsx +15 -0
  64. package/templates/_renderers/solid/src/app/page.tsx +56 -0
  65. package/templates/_renderers/solid/src/app/solid.css +22 -0
  66. package/templates/_renderers/solid/src/components/resource-links.tsx +71 -0
  67. package/templates/_renderers/solid/src/lib/api-client.ts +4 -0
  68. package/templates/_renderers/solid/src/lib/api.generated.ts +7 -0
  69. package/templates/_renderers/solid/tsconfig.json +25 -0
  70. package/templates/_renderers/svelte/farm.config.ts +9 -0
  71. package/templates/_renderers/svelte/package.json +28 -0
  72. package/templates/_renderers/svelte/src/app/api/greeting/route.ts +15 -0
  73. package/templates/_renderers/svelte/src/app/layout.svelte +21 -0
  74. package/templates/_renderers/svelte/src/app/page.svelte +64 -0
  75. package/templates/_renderers/svelte/src/app/svelte.css +26 -0
  76. package/templates/_renderers/svelte/src/components/resource-links.svelte +31 -0
  77. package/templates/_renderers/svelte/src/lib/api-client.ts +4 -0
  78. package/templates/_renderers/svelte/src/lib/api.generated.ts +7 -0
  79. package/templates/_renderers/svelte/tsconfig.json +23 -0
  80. package/templates/_renderers/vue/farm.config.ts +12 -0
  81. package/templates/_renderers/vue/package.json +26 -0
  82. package/templates/_renderers/vue/src/app/api/greeting/route.ts +15 -0
  83. package/templates/_renderers/vue/src/app/layout.vue +21 -0
  84. package/templates/_renderers/vue/src/app/page.vue +69 -0
  85. package/templates/_renderers/vue/src/app/vue.css +26 -0
  86. package/templates/_renderers/vue/src/components/resource-links.vue +33 -0
  87. package/templates/_renderers/vue/src/env.d.ts +7 -0
  88. package/templates/_renderers/vue/src/lib/api-client.ts +4 -0
  89. package/templates/_renderers/vue/src/lib/api.generated.ts +7 -0
  90. package/templates/_renderers/vue/tsconfig.json +23 -0
  91. package/templates/auth/.env.example +6 -0
  92. package/templates/auth/README.md +95 -0
  93. package/templates/auth/docs.config.ts +33 -0
  94. package/templates/auth/docs.json +36 -0
  95. package/templates/auth/farm.config.ts +20 -0
  96. package/templates/auth/gitignore +10 -0
  97. package/templates/auth/package.json +34 -0
  98. package/templates/auth/pnpm-workspace.yaml +13 -0
  99. package/templates/auth/src/app/dashboard/middleware.ts +13 -0
  100. package/templates/auth/src/app/dashboard/page.tsx +140 -0
  101. package/templates/auth/src/app/docs/page.md +29 -0
  102. package/templates/auth/src/app/error.tsx +25 -0
  103. package/templates/auth/src/app/globals.css +1064 -0
  104. package/templates/auth/src/app/layout.tsx +11 -0
  105. package/templates/auth/src/app/loading.tsx +15 -0
  106. package/templates/auth/src/app/not-found.tsx +26 -0
  107. package/templates/auth/src/app/page.tsx +46 -0
  108. package/templates/auth/src/app/sign-in/page.tsx +16 -0
  109. package/templates/auth/src/app/sign-up/page.tsx +16 -0
  110. package/templates/auth/src/components/auth-form.tsx +120 -0
  111. package/templates/auth/src/components/auth-shell.tsx +21 -0
  112. package/templates/auth/src/components/resource-links.tsx +78 -0
  113. package/templates/auth/src/components/sign-out-button.tsx +45 -0
  114. package/templates/auth/src/components/site-header.tsx +46 -0
  115. package/templates/auth/tsconfig.json +20 -0
  116. package/templates/basic/docs.config.ts +33 -0
  117. package/templates/basic/docs.json +36 -0
  118. package/templates/basic/farm.config.ts +9 -0
  119. package/templates/basic/package.json +7 -3
  120. package/templates/basic/pnpm-workspace.yaml +8 -0
  121. package/templates/basic/src/app/docs/page.md +29 -0
  122. package/templates/basic/src/app/globals.css +241 -0
  123. package/templates/basic/src/app/layout.tsx +3 -5
  124. package/templates/basic/src/app/page.tsx +20 -61
  125. package/templates/basic/src/components/resource-links.tsx +78 -0
  126. package/templates/basic/tsconfig.json +4 -0
  127. package/templates/better-auth/.env.example +3 -0
  128. package/templates/better-auth/README.md +89 -0
  129. package/templates/better-auth/docs.config.ts +33 -0
  130. package/templates/better-auth/docs.json +36 -0
  131. package/templates/better-auth/farm.config.ts +38 -0
  132. package/templates/better-auth/gitignore +10 -0
  133. package/templates/better-auth/package.json +36 -0
  134. package/templates/better-auth/pnpm-workspace.yaml +13 -0
  135. package/templates/better-auth/src/app/dashboard/middleware.ts +15 -0
  136. package/templates/better-auth/src/app/dashboard/page.tsx +188 -0
  137. package/templates/better-auth/src/app/docs/page.md +29 -0
  138. package/templates/better-auth/src/app/error.tsx +25 -0
  139. package/templates/better-auth/src/app/globals.css +1064 -0
  140. package/templates/better-auth/src/app/layout.tsx +11 -0
  141. package/templates/better-auth/src/app/loading.tsx +15 -0
  142. package/templates/better-auth/src/app/not-found.tsx +26 -0
  143. package/templates/better-auth/src/app/page.tsx +50 -0
  144. package/templates/better-auth/src/app/sign-in/page.tsx +16 -0
  145. package/templates/better-auth/src/app/sign-up/page.tsx +16 -0
  146. package/templates/better-auth/src/components/auth-form.tsx +120 -0
  147. package/templates/better-auth/src/components/auth-shell.tsx +21 -0
  148. package/templates/better-auth/src/components/resource-links.tsx +78 -0
  149. package/templates/better-auth/src/components/sign-out-button.tsx +45 -0
  150. package/templates/better-auth/src/components/site-header.tsx +46 -0
  151. package/templates/better-auth/src/lib/auth-client.ts +5 -0
  152. package/templates/better-auth/src/lib/auth.ts +50 -0
  153. package/templates/better-auth/src/lib/session.ts +8 -0
  154. package/templates/better-auth/tsconfig.json +20 -0
  155. package/templates/react-compiler/README.md +62 -0
  156. package/templates/react-compiler/docs.config.ts +33 -0
  157. package/templates/react-compiler/docs.json +36 -0
  158. package/templates/react-compiler/farm.config.ts +29 -0
  159. package/templates/react-compiler/gitignore +23 -0
  160. package/templates/react-compiler/package.json +34 -0
  161. package/templates/react-compiler/pnpm-workspace.yaml +8 -0
  162. package/templates/react-compiler/public/favicon.svg +5 -0
  163. package/templates/react-compiler/scripts/verify-experiment.mjs +113 -0
  164. package/templates/react-compiler/src/app/docs/page.md +29 -0
  165. package/templates/react-compiler/src/app/globals.css +470 -0
  166. package/templates/react-compiler/src/app/layout.tsx +22 -0
  167. package/templates/react-compiler/src/app/page.tsx +47 -0
  168. package/templates/react-compiler/src/components/compiler-comparison.tsx +93 -0
  169. package/templates/react-compiler/src/components/resource-links.tsx +78 -0
  170. package/templates/react-compiler/src/farm.d.ts +74 -0
  171. package/templates/react-compiler/src/lib/api.generated.ts +10 -0
  172. package/templates/react-compiler/tsconfig.json +24 -0
  173. 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,5 @@
1
+ import { createAuthClient } from "better-auth/svelte";
2
+
3
+ export const authClient = createAuthClient({
4
+ baseURL: "",
5
+ });
@@ -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,5 @@
1
+ import { createAuthClient } from "better-auth/vue";
2
+
3
+ export const authClient = createAuthClient({
4
+ baseURL: "",
5
+ });
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from "@farm.js/core/config";
2
+ import { preact } from "@farm.js/preact";
3
+
4
+ export default defineConfig({
5
+ renderer: preact(),
6
+ theme: {
7
+ default: "dark",
8
+ },
9
+ deploy: {
10
+ target: "vercel",
11
+ },
12
+ });
@@ -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
+ }