@farm.js/cli 0.1.0-beta.23 → 0.1.0-beta.25

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.
@@ -123,7 +123,7 @@ function aiChatUIFeature() {
123
123
  ],
124
124
  needsApiClient: false,
125
125
  notes: ["Open \"/integrations/ai\" to try the generated chat UI."],
126
- files: () => [componentFile("ai-chat.tsx", aiChatTemplate()), integrationPageFile("ai", "AIChat")]
126
+ files: () => [componentFile("ai-chat.tsx", aiChatTemplate()), integrationPageFile("ai", "AIChat", "ai-chat")]
127
127
  };
128
128
  }
129
129
  function supabaseAuthUIFeature() {
@@ -155,35 +155,25 @@ function workosAuthUIFeature() {
155
155
  key: input.key,
156
156
  provider: "WorkOS",
157
157
  componentName: "WorkOSAuthPanel",
158
- statusCall: "session.get",
159
- logoutCall: "logout.post",
158
+ statusCall: "session",
159
+ statusMethod: "get",
160
+ logoutCall: "logout",
161
+ logoutMethod: "post",
160
162
  loginHref: "/login?returnTo=/dashboard",
161
163
  signupHref: "/signup?returnTo=/dashboard",
162
164
  statusLabel: "Session"
163
- })), integrationPageFile("workos", "WorkOSAuthPanel")]
165
+ })), integrationPageFile("workos", "WorkOSAuthPanel", "workos-auth-panel")]
164
166
  };
165
167
  }
166
168
  function auth0AuthUIFeature() {
167
- return {
168
- name: "auth0-auth",
169
- description: "Auth0 auth UI",
170
- components: [
171
- "badge",
172
- "button",
173
- "card"
174
- ],
175
- notes: ["Open \"/integrations/auth0\" to try the generated auth UI."],
176
- files: (input) => [componentFile("auth0-auth-panel.tsx", hostedAuthTemplate({
177
- key: input.key,
178
- provider: "Auth0",
179
- componentName: "Auth0AuthPanel",
180
- statusCall: "profile.get",
181
- logoutCall: "logout.get",
182
- loginHref: "/auth/login?returnTo=/dashboard",
183
- signupHref: "/auth/signup?returnTo=/dashboard",
184
- statusLabel: "Profile"
185
- })), integrationPageFile("auth0", "Auth0AuthPanel")]
186
- };
169
+ return authRouteShellUIFeature({
170
+ provider: "auth0",
171
+ label: "Auth0",
172
+ componentName: "Auth0AuthPanel",
173
+ signInHref: "/auth/login?returnTo=/dashboard",
174
+ signUpHref: "/auth/signup?returnTo=/dashboard",
175
+ sessionHref: "/auth/profile"
176
+ });
187
177
  }
188
178
  function clerkAuthUIFeature() {
189
179
  return authRouteShellUIFeature({
@@ -262,16 +252,18 @@ function jobsUIFeature(provider) {
262
252
  function unkeyApiKeysUIFeature() {
263
253
  return {
264
254
  name: "unkey-api-keys",
265
- description: "Unkey API key console UI",
266
- components: [
267
- "badge",
268
- "button",
269
- "card",
270
- "input",
271
- "label"
272
- ],
273
- notes: ["Open \"/integrations/unkey\" to try the generated API key UI."],
274
- files: (input) => [componentFile("unkey-api-keys-console.tsx", unkeyApiKeysTemplate(input.key)), integrationPageFile("unkey", "UnkeyApiKeysConsole")]
255
+ description: "Unkey protected route UI",
256
+ components: ["badge", "card"],
257
+ needsApiClient: false,
258
+ notes: ["Open \"/integrations/unkey\" to test the generated protected API route."],
259
+ files: () => [
260
+ componentFile("unkey-api-keys-console.tsx", unkeyApiKeysTemplate()),
261
+ integrationPageFile("unkey", "UnkeyApiKeysConsole"),
262
+ {
263
+ path: node_path.default.join("src", "app", "api", "protected", "route.ts"),
264
+ source: unkeyProtectedRouteTemplate()
265
+ }
266
+ ]
275
267
  };
276
268
  }
277
269
  function billingUIFeature(input) {
@@ -301,6 +293,7 @@ function authRouteShellUIFeature(input) {
301
293
  "button",
302
294
  "card"
303
295
  ],
296
+ needsApiClient: false,
304
297
  notes: [`Open "/integrations/${input.provider}" to try the generated auth UI.`],
305
298
  files: () => [componentFile(`${input.provider}-auth-panel.tsx`, authRouteShellTemplate({
306
299
  provider: input.label,
@@ -308,7 +301,7 @@ function authRouteShellUIFeature(input) {
308
301
  signInHref: input.signInHref,
309
302
  signUpHref: input.signUpHref,
310
303
  sessionHref: input.sessionHref
311
- })), integrationPageFile(input.provider, input.componentName)]
304
+ })), integrationPageFile(input.provider, input.componentName, input.provider === "authjs" ? "authjs-auth-panel" : void 0)]
312
305
  };
313
306
  }
314
307
  function componentFile(fileName, source) {
@@ -317,11 +310,10 @@ function componentFile(fileName, source) {
317
310
  source
318
311
  };
319
312
  }
320
- function integrationPageFile(provider, componentName) {
321
- const fileName = kebabCase(componentName);
313
+ function integrationPageFile(provider, componentName, sourceFileName = kebabCase(componentName)) {
322
314
  return {
323
315
  path: node_path.default.join("src", "app", "integrations", provider, "page.tsx"),
324
- source: `import { ${componentName} } from "@/components/farm/${fileName}";
316
+ source: `import { ${componentName} } from "@/components/farm/${sourceFileName}";
325
317
 
326
318
  export default function ${componentName}Page() {
327
319
  return <${componentName} />;
@@ -478,7 +470,7 @@ const UI_DEPENDENCIES = {
478
470
  "tailwind-merge": "^3.3.1",
479
471
  tailwindcss: "^4.1.18"
480
472
  };
481
- const SHADCN_THEME_CSS = `@custom-variant dark (&:is(.dark *));
473
+ const SHADCN_THEME_CSS = `@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
482
474
 
483
475
  @theme inline {
484
476
  --color-background: var(--background);
@@ -504,7 +496,8 @@ const SHADCN_THEME_CSS = `@custom-variant dark (&:is(.dark *));
504
496
  --radius-lg: var(--radius);
505
497
  }
506
498
 
507
- :root {
499
+ :root,
500
+ [data-theme="light"] {
508
501
  --radius: 0.5rem;
509
502
  --background: oklch(1 0 0);
510
503
  --foreground: oklch(0.145 0 0);
@@ -526,7 +519,7 @@ const SHADCN_THEME_CSS = `@custom-variant dark (&:is(.dark *));
526
519
  --ring: oklch(0.708 0 0);
527
520
  }
528
521
 
529
- .dark {
522
+ [data-theme="dark"] {
530
523
  --background: oklch(0.145 0 0);
531
524
  --foreground: oklch(0.985 0 0);
532
525
  --card: oklch(0.205 0 0);
@@ -1129,12 +1122,17 @@ export function SupabaseAuthPanel() {
1129
1122
  }
1130
1123
 
1131
1124
  async function logout() {
1132
- const response = await apiClient.${key}.logout.post({ body: { returnTo: "/" } });
1133
- if (response.data?.redirectTo) {
1134
- window.location.assign(response.data.redirectTo);
1125
+ const response = await fetch("/auth/logout", {
1126
+ method: "POST",
1127
+ headers: { "content-type": "application/json" },
1128
+ body: JSON.stringify({ returnTo: "/" }),
1129
+ });
1130
+ const data = (await response.json()) as { redirectTo?: string; error?: string };
1131
+ if (data.redirectTo) {
1132
+ window.location.assign(data.redirectTo);
1135
1133
  return;
1136
1134
  }
1137
- setStatus(response.error?.message ?? "Signed out");
1135
+ setStatus(data.error ?? "Signed out");
1138
1136
  }
1139
1137
 
1140
1138
  return (
@@ -1193,7 +1191,7 @@ export function ${input.componentName}() {
1193
1191
 
1194
1192
  async function refreshStatus() {
1195
1193
  setPending(true);
1196
- const response = await apiClient.${input.key}.${input.statusCall}();
1194
+ const response = await apiClient.${input.key}.${input.statusCall}.${input.statusMethod}();
1197
1195
  if (response.error) {
1198
1196
  setStatus(response.error.message);
1199
1197
  } else {
@@ -1204,7 +1202,7 @@ export function ${input.componentName}() {
1204
1202
 
1205
1203
  async function logout() {
1206
1204
  setPending(true);
1207
- const response = await apiClient.${input.key}.${input.logoutCall}();
1205
+ const response = await apiClient.${input.key}.${input.logoutCall}.${input.logoutMethod}();
1208
1206
  if (response.data?.redirectTo) {
1209
1207
  window.location.assign(response.data.redirectTo);
1210
1208
  return;
@@ -1467,17 +1465,20 @@ import { apiClient } from "@/lib/api";
1467
1465
  export function ResendEmailConsole() {
1468
1466
  const [to, setTo] = React.useState("");
1469
1467
  const [name, setName] = React.useState("Ada");
1470
- const [templateId, setTemplateId] = React.useState("welcome");
1468
+ const templateId = "welcome" as const;
1471
1469
  const [status, setStatus] = React.useState("Idle");
1472
1470
  const [previewHtml, setPreviewHtml] = React.useState("");
1473
1471
 
1474
1472
  async function loadTemplates() {
1475
- const response = await apiClient.${key}.templates.get();
1476
- setStatus(response.error ? response.error.message : "Templates: " + (response.data ?? []).map((item) => item.id).join(", "));
1473
+ const response = await apiClient.${key}.templates();
1474
+ const templates = Array.isArray(response.data)
1475
+ ? (response.data as Array<{ id: string }>)
1476
+ : [];
1477
+ setStatus(response.error ? response.error.message : "Templates: " + templates.map((item) => item.id).join(", "));
1477
1478
  }
1478
1479
 
1479
1480
  async function preview() {
1480
- const response = await apiClient.${key}.preview.post({
1481
+ const response = await apiClient.${key}.preview({
1481
1482
  body: {
1482
1483
  templateId,
1483
1484
  data: { name },
@@ -1492,7 +1493,7 @@ export function ResendEmailConsole() {
1492
1493
  }
1493
1494
 
1494
1495
  async function send() {
1495
- const response = await apiClient.${key}.send.post({
1496
+ const response = await apiClient.${key}.send({
1496
1497
  body: {
1497
1498
  templateId,
1498
1499
  to,
@@ -1515,11 +1516,7 @@ export function ResendEmailConsole() {
1515
1516
  <CardDescription>Template previews and delivery controls.</CardDescription>
1516
1517
  </CardHeader>
1517
1518
  <CardContent className="space-y-4">
1518
- <div className="grid gap-4 sm:grid-cols-3">
1519
- <div className="space-y-2">
1520
- <Label htmlFor="templateId">Template</Label>
1521
- <Input id="templateId" value={templateId} onChange={(event) => setTemplateId(event.target.value)} />
1522
- </div>
1519
+ <div className="grid gap-4 sm:grid-cols-2">
1523
1520
  <div className="space-y-2">
1524
1521
  <Label htmlFor="to">To</Label>
1525
1522
  <Input id="to" value={to} onChange={(event) => setTo(event.target.value)} />
@@ -1644,47 +1641,11 @@ export function ${`${pascalCase(provider)}JobsConsole`}() {
1644
1641
  }
1645
1642
  `;
1646
1643
  }
1647
- function unkeyApiKeysTemplate(key) {
1648
- return `"use client";
1649
-
1650
- import * as React from "react";
1651
- import { Badge } from "@/components/ui/badge";
1652
- import { Button } from "@/components/ui/button";
1644
+ function unkeyApiKeysTemplate() {
1645
+ return `import { Badge } from "@/components/ui/badge";
1653
1646
  import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
1654
- import { Input } from "@/components/ui/input";
1655
- import { Label } from "@/components/ui/label";
1656
- import { apiClient } from "@/lib/api";
1657
1647
 
1658
1648
  export function UnkeyApiKeysConsole() {
1659
- const [name, setName] = React.useState("Development key");
1660
- const [prefix, setPrefix] = React.useState("farm");
1661
- const [apiKey, setApiKey] = React.useState("");
1662
- const [status, setStatus] = React.useState("Idle");
1663
-
1664
- async function createKey() {
1665
- const response = await apiClient.${key}.createKey.post({
1666
- body: {
1667
- name,
1668
- prefix,
1669
- },
1670
- });
1671
- if (response.error) {
1672
- setStatus(response.error.message);
1673
- return;
1674
- }
1675
- setApiKey(response.data?.key ?? "");
1676
- setStatus("Created " + (response.data?.keyId ?? "key"));
1677
- }
1678
-
1679
- async function verifyKey() {
1680
- const response = await apiClient.${key}.verifyKey.post({
1681
- body: {
1682
- key: apiKey,
1683
- },
1684
- });
1685
- setStatus(response.error ? response.error.message : response.data?.valid ? "Valid key" : "Invalid key");
1686
- }
1687
-
1688
1649
  return (
1689
1650
  <main className="min-h-screen bg-background px-6 py-12 text-foreground">
1690
1651
  <section className="mx-auto flex w-full max-w-3xl flex-col gap-6">
@@ -1694,29 +1655,16 @@ export function UnkeyApiKeysConsole() {
1694
1655
  </div>
1695
1656
  <Card>
1696
1657
  <CardHeader>
1697
- <CardTitle className="text-xl">Key console</CardTitle>
1698
- <CardDescription>API key lifecycle controls.</CardDescription>
1658
+ <CardTitle className="text-xl">Protected API</CardTitle>
1659
+ <CardDescription>Requests are verified by Unkey before the route runs.</CardDescription>
1699
1660
  </CardHeader>
1700
- <CardContent className="space-y-4">
1701
- <div className="grid gap-4 sm:grid-cols-2">
1702
- <div className="space-y-2">
1703
- <Label htmlFor="name">Name</Label>
1704
- <Input id="name" value={name} onChange={(event) => setName(event.target.value)} />
1705
- </div>
1706
- <div className="space-y-2">
1707
- <Label htmlFor="prefix">Prefix</Label>
1708
- <Input id="prefix" value={prefix} onChange={(event) => setPrefix(event.target.value)} />
1709
- </div>
1710
- </div>
1711
- <div className="space-y-2">
1712
- <Label htmlFor="apiKey">API key</Label>
1713
- <Input id="apiKey" value={apiKey} onChange={(event) => setApiKey(event.target.value)} />
1714
- </div>
1715
- <p className="rounded-md border bg-muted/30 px-3 py-2 text-sm">{status}</p>
1716
- <div className="flex flex-wrap gap-2">
1717
- <Button type="button" onClick={() => void createKey()}>Create key</Button>
1718
- <Button type="button" variant="outline" onClick={() => void verifyKey()}>Verify</Button>
1719
- </div>
1661
+ <CardContent className="space-y-3">
1662
+ <code className="block overflow-x-auto rounded-md border bg-muted/30 p-3 text-xs">
1663
+ curl http://localhost:3000/api/protected -H &quot;Authorization: Bearer YOUR_KEY&quot;
1664
+ </code>
1665
+ <p className="text-sm text-muted-foreground">
1666
+ Create and rotate keys from trusted server code or the Unkey dashboard.
1667
+ </p>
1720
1668
  </CardContent>
1721
1669
  </Card>
1722
1670
  </section>
@@ -1725,6 +1673,15 @@ export function UnkeyApiKeysConsole() {
1725
1673
  }
1726
1674
  `;
1727
1675
  }
1676
+ function unkeyProtectedRouteTemplate() {
1677
+ return `export function GET() {
1678
+ return Response.json({
1679
+ ok: true,
1680
+ message: "Valid Unkey API key.",
1681
+ });
1682
+ }
1683
+ `;
1684
+ }
1728
1685
  function pascalCase(input) {
1729
1686
  return input.split(/[^A-Za-z0-9]+/g).filter(Boolean).map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`).join("");
1730
1687
  }
@@ -1752,6 +1709,7 @@ const PROVIDERS = [
1752
1709
  "chat"
1753
1710
  ],
1754
1711
  defaultKey: "chat",
1712
+ packageName: "@farm.js/ai",
1755
1713
  fileName: "chat",
1756
1714
  exportName: "POST",
1757
1715
  description: "Vercel AI SDK chat route",
@@ -1762,7 +1720,7 @@ const PROVIDERS = [
1762
1720
  "No farm.config integration wiring is required for this route."
1763
1721
  ],
1764
1722
  ui: aiChatUIFeature(),
1765
- template: () => `import { aiChatRoute } from "@farm.js/integrations/ai";
1723
+ template: () => `import { aiChatRoute } from "@farm.js/ai";
1766
1724
 
1767
1725
  export const POST = aiChatRoute({
1768
1726
  model: "openai/gpt-4o-mini",
@@ -1778,17 +1736,19 @@ export const POST = aiChatRoute({
1778
1736
  "stripe-billing"
1779
1737
  ],
1780
1738
  defaultKey: "billing",
1739
+ packageName: "@farm.js/stripe",
1781
1740
  fileName: "stripe",
1782
1741
  exportName: "stripeIntegration",
1783
1742
  description: "Stripe billing and checkout routes",
1784
1743
  env: ["STRIPE_SECRET_KEY", "STRIPE_WEBHOOK_SECRET"],
1785
- template: () => `import { stripe } from "@farm.js/integrations/stripe";
1744
+ template: () => `import type { FarmIntegrationLogEvent } from "@farm.js/core";
1745
+ import { stripe } from "@farm.js/stripe";
1786
1746
 
1787
1747
  export const stripeIntegration = stripe({
1788
1748
  secretKey: process.env.STRIPE_SECRET_KEY,
1789
1749
  webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,
1790
1750
  products: [],
1791
- log(event) {
1751
+ log(event: FarmIntegrationLogEvent) {
1792
1752
  console.log("[stripe]", event.phase, event.route?.path || "none");
1793
1753
  },
1794
1754
  });
@@ -1799,6 +1759,7 @@ export const stripeIntegration = stripe({
1799
1759
  provider: "supabase",
1800
1760
  aliases: ["auth-supabase", "supabase-auth"],
1801
1761
  defaultKey: "auth",
1762
+ packageName: "@farm.js/supabase",
1802
1763
  fileName: "supabase",
1803
1764
  exportName: "supabaseIntegration",
1804
1765
  description: "Supabase auth routes and middleware",
@@ -1808,7 +1769,7 @@ export const stripeIntegration = stripe({
1808
1769
  "APP_BASE_URL"
1809
1770
  ],
1810
1771
  ui: supabaseAuthUIFeature(),
1811
- template: () => `import { supabase } from "@farm.js/integrations/supabase";
1772
+ template: () => `import { supabase } from "@farm.js/supabase";
1812
1773
 
1813
1774
  export const supabaseIntegration = supabase({
1814
1775
  callbackUrl: \`\${process.env.APP_BASE_URL || "http://localhost:3000"}/auth/callback\`,
@@ -1827,6 +1788,7 @@ export const supabaseIntegration = supabase({
1827
1788
  provider: "workos",
1828
1789
  aliases: ["auth-workos", "workos-auth"],
1829
1790
  defaultKey: "auth",
1791
+ packageName: "@farm.js/workos",
1830
1792
  fileName: "workos",
1831
1793
  exportName: "workosIntegration",
1832
1794
  description: "WorkOS auth routes and protected route middleware",
@@ -1836,7 +1798,7 @@ export const supabaseIntegration = supabase({
1836
1798
  "WORKOS_COOKIE_PASSWORD"
1837
1799
  ],
1838
1800
  ui: workosAuthUIFeature(),
1839
- template: () => `import { workos } from "@farm.js/integrations/workos";
1801
+ template: () => `import { workos } from "@farm.js/workos";
1840
1802
 
1841
1803
  export const workosIntegration = workos({
1842
1804
  protectedRoutes: ["/dashboard(.*)"],
@@ -1850,6 +1812,7 @@ export const workosIntegration = workos({
1850
1812
  provider: "auth0",
1851
1813
  aliases: ["auth-auth0", "auth0-auth"],
1852
1814
  defaultKey: "auth",
1815
+ packageName: "@farm.js/auth0",
1853
1816
  fileName: "auth0",
1854
1817
  exportName: "auth0Integration",
1855
1818
  description: "Auth0 login, callback, logout, and profile routes",
@@ -1860,7 +1823,7 @@ export const workosIntegration = workos({
1860
1823
  "AUTH0_SECRET"
1861
1824
  ],
1862
1825
  ui: auth0AuthUIFeature(),
1863
- template: () => `import { auth0 } from "@farm.js/integrations/auth0";
1826
+ template: () => `import { auth0 } from "@farm.js/auth0";
1864
1827
 
1865
1828
  export const auth0Integration = auth0({
1866
1829
  callbackUrl: \`\${process.env.APP_BASE_URL || "http://localhost:3000"}/auth/callback\`,
@@ -1875,12 +1838,14 @@ export const auth0Integration = auth0({
1875
1838
  provider: "clerk",
1876
1839
  aliases: ["auth-clerk", "clerk-auth"],
1877
1840
  defaultKey: "auth",
1841
+ packageName: "@farm.js/clerk",
1878
1842
  fileName: "clerk",
1879
1843
  exportName: "clerkIntegration",
1880
1844
  description: "Clerk auth provider and protected route middleware",
1881
1845
  env: ["NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY", "CLERK_SECRET_KEY"],
1846
+ dependencies: { "@clerk/react": "^6.1.0" },
1882
1847
  ui: clerkAuthUIFeature(),
1883
- template: () => `import { clerk } from "@farm.js/integrations/clerk";
1848
+ template: () => `import { clerk } from "@farm.js/clerk";
1884
1849
 
1885
1850
  export const clerkIntegration = clerk({
1886
1851
  signInUrl: "/sign-in",
@@ -1896,6 +1861,7 @@ export const clerkIntegration = clerk({
1896
1861
  provider: "resend",
1897
1862
  aliases: ["email", "resend-email"],
1898
1863
  defaultKey: "email",
1864
+ packageName: "@farm.js/email",
1899
1865
  fileName: "resend",
1900
1866
  exportName: "resendIntegration",
1901
1867
  description: "Resend email send, preview, schedule, and webhook routes",
@@ -1906,7 +1872,7 @@ export const clerkIntegration = clerk({
1906
1872
  ],
1907
1873
  ui: resendEmailUIFeature(),
1908
1874
  template: () => `import { createElement } from "react";
1909
- import { resend, template } from "@farm.js/integrations/email";
1875
+ import { resend, template } from "@farm.js/email";
1910
1876
 
1911
1877
  function WelcomeEmail(props: { name: string }) {
1912
1878
  return createElement("div", null, \`Welcome \${props.name}\`);
@@ -1945,6 +1911,7 @@ export const resendIntegration = resend({
1945
1911
  provider: "jobs-inngest",
1946
1912
  aliases: ["inngest", "jobs"],
1947
1913
  defaultKey: "jobs",
1914
+ packageName: "@farm.js/jobs",
1948
1915
  fileName: "jobs-inngest",
1949
1916
  exportName: "jobsIntegration",
1950
1917
  description: "Jobs integration backed by Inngest",
@@ -1955,7 +1922,7 @@ export const resendIntegration = resend({
1955
1922
  ],
1956
1923
  notes: ["Add tasks to jobTasks before using the generated jobs API."],
1957
1924
  ui: jobsUIFeature("inngest"),
1958
- template: () => `import { defineTasks, inngest, jobs } from "@farm.js/integrations/jobs";
1925
+ template: () => `import { defineTasks, inngest, jobs } from "@farm.js/jobs";
1959
1926
 
1960
1927
  export const jobTasks = defineTasks({});
1961
1928
 
@@ -1980,6 +1947,7 @@ export const jobsIntegration = jobs({
1980
1947
  "jobs-triggerdev"
1981
1948
  ],
1982
1949
  defaultKey: "jobs",
1950
+ packageName: "@farm.js/jobs",
1983
1951
  fileName: "jobs-trigger",
1984
1952
  exportName: "jobsIntegration",
1985
1953
  description: "Jobs integration backed by Trigger.dev",
@@ -1990,7 +1958,7 @@ export const jobsIntegration = jobs({
1990
1958
  ],
1991
1959
  notes: ["Add tasks to jobTasks before using the generated jobs API."],
1992
1960
  ui: jobsUIFeature("trigger"),
1993
- template: () => `import { defineTasks, jobs, trigger } from "@farm.js/integrations/jobs";
1961
+ template: () => `import { defineTasks, jobs, trigger } from "@farm.js/jobs";
1994
1962
 
1995
1963
  export const jobTasks = defineTasks({});
1996
1964
 
@@ -2011,6 +1979,7 @@ export const jobsIntegration = jobs({
2011
1979
  provider: "polar",
2012
1980
  aliases: ["polar-billing", "billing-polar"],
2013
1981
  defaultKey: "billing",
1982
+ packageName: "@farm.js/polar",
2014
1983
  fileName: "polar",
2015
1984
  exportName: "polarIntegration",
2016
1985
  description: "Polar billing and checkout routes",
@@ -2022,9 +1991,9 @@ export const jobsIntegration = jobs({
2022
1991
  notes: ["Replace resolveBillingOwner with your app user or organization lookup."],
2023
1992
  ui: polarBillingUIFeature(),
2024
1993
  template: () => `import type { FarmIntegrationHandlerContext } from "@farm.js/core";
2025
- import { polar } from "@farm.js/integrations/polar";
1994
+ import { polar } from "@farm.js/polar";
2026
1995
 
2027
- async function resolveBillingOwner(_context: FarmIntegrationHandlerContext) {
1996
+ function resolveBillingOwner(_context: FarmIntegrationHandlerContext): never {
2028
1997
  throw new Error("Configure Polar billing owner resolution for your app.");
2029
1998
  }
2030
1999
 
@@ -2052,6 +2021,7 @@ export const polarIntegration = polar({
2052
2021
  provider: "autumn",
2053
2022
  aliases: ["autumn-billing", "billing-autumn"],
2054
2023
  defaultKey: "billing",
2024
+ packageName: "@farm.js/autumn",
2055
2025
  fileName: "autumn",
2056
2026
  exportName: "autumnIntegration",
2057
2027
  description: "Autumn billing and checkout routes",
@@ -2063,9 +2033,9 @@ export const polarIntegration = polar({
2063
2033
  notes: ["Replace resolveBillingOwner with your app user or organization lookup."],
2064
2034
  ui: autumnBillingUIFeature(),
2065
2035
  template: () => `import type { FarmIntegrationHandlerContext } from "@farm.js/core";
2066
- import { autumn } from "@farm.js/integrations/autumn";
2036
+ import { autumn } from "@farm.js/autumn";
2067
2037
 
2068
- async function resolveBillingOwner(_context: FarmIntegrationHandlerContext) {
2038
+ function resolveBillingOwner(_context: FarmIntegrationHandlerContext): never {
2069
2039
  throw new Error("Configure Autumn billing owner resolution for your app.");
2070
2040
  }
2071
2041
 
@@ -2092,6 +2062,7 @@ export const autumnIntegration = autumn({
2092
2062
  provider: "better-auth",
2093
2063
  aliases: ["betterauth", "auth-better-auth"],
2094
2064
  defaultKey: "auth",
2065
+ packageName: "@farm.js/better-auth",
2095
2066
  fileName: "better-auth",
2096
2067
  exportName: "betterAuthIntegration",
2097
2068
  description: "Better Auth route adapter",
@@ -2146,7 +2117,7 @@ better-auth.sqlite-wal
2146
2117
  }
2147
2118
  ],
2148
2119
  ui: betterAuthUIFeature(),
2149
- template: () => `import { betterAuth } from "@farm.js/integrations/better-auth";
2120
+ template: () => `import { betterAuth } from "@farm.js/better-auth";
2150
2121
  import { auth } from "../auth.ts";
2151
2122
 
2152
2123
  export const betterAuthIntegration = betterAuth({
@@ -2165,13 +2136,45 @@ export const betterAuthIntegration = betterAuth({
2165
2136
  "next-auth"
2166
2137
  ],
2167
2138
  defaultKey: "auth",
2139
+ packageName: "@farm.js/authjs",
2168
2140
  fileName: "authjs",
2169
2141
  exportName: "authjsIntegration",
2170
2142
  description: "Auth.js route adapter",
2171
- env: [],
2172
- notes: ["This template expects src/lib/auth.ts to export an Auth.js instance named auth."],
2143
+ env: [
2144
+ "AUTH_SECRET",
2145
+ "AUTH_GITHUB_ID",
2146
+ "AUTH_GITHUB_SECRET"
2147
+ ],
2148
+ dependencies: { "@auth/core": "0.34.3" },
2149
+ setupFiles: [{
2150
+ path: "src/lib/auth.ts",
2151
+ source: () => `import { Auth } from "@auth/core";
2152
+ import GitHub from "@auth/core/providers/github";
2153
+
2154
+ const config = {
2155
+ providers: [
2156
+ GitHub({
2157
+ clientId: process.env.AUTH_GITHUB_ID!,
2158
+ clientSecret: process.env.AUTH_GITHUB_SECRET!,
2159
+ }),
2160
+ ],
2161
+ secret: process.env.AUTH_SECRET,
2162
+ trustHost: true,
2163
+ };
2164
+
2165
+ const handler = (request: Request) => Auth(request, config);
2166
+
2167
+ export const auth = {
2168
+ handlers: {
2169
+ GET: handler,
2170
+ POST: handler,
2171
+ },
2172
+ };
2173
+ `
2174
+ }],
2175
+ notes: ["The generated Auth.js instance uses GitHub OAuth through @auth/core; add or replace providers in src/lib/auth.ts."],
2173
2176
  ui: authjsUIFeature(),
2174
- template: () => `import { authjs } from "@farm.js/integrations/authjs";
2177
+ template: () => `import { authjs } from "@farm.js/authjs";
2175
2178
  import { auth } from "../auth.ts";
2176
2179
 
2177
2180
  export const authjsIntegration = authjs({
@@ -2191,6 +2194,7 @@ export const authjsIntegration = authjs({
2191
2194
  "unkey-api-keys"
2192
2195
  ],
2193
2196
  defaultKey: "apiKeys",
2197
+ packageName: "@farm.js/unkey",
2194
2198
  fileName: "unkey",
2195
2199
  exportName: "unkeyIntegration",
2196
2200
  description: "Unkey API key creation, verification, and route protection",
@@ -2200,7 +2204,7 @@ export const authjsIntegration = authjs({
2200
2204
  "UNKEY_BASE_URL"
2201
2205
  ],
2202
2206
  ui: unkeyApiKeysUIFeature(),
2203
- template: () => `import { unkey } from "@farm.js/integrations/unkey";
2207
+ template: () => `import { unkey } from "@farm.js/unkey";
2204
2208
 
2205
2209
  export const unkeyIntegration = unkey({
2206
2210
  rootKey: process.env.UNKEY_ROOT_KEY,
@@ -2217,6 +2221,7 @@ export const unkeyIntegration = unkey({
2217
2221
  function listFarmIntegrationProviders() {
2218
2222
  return PROVIDERS.map((provider) => ({
2219
2223
  name: provider.provider,
2224
+ packageName: provider.packageName,
2220
2225
  aliases: [...provider.aliases],
2221
2226
  defaultKey: provider.defaultKey,
2222
2227
  description: provider.description,
@@ -2452,7 +2457,7 @@ async function updatePackageJson(input) {
2452
2457
  const devDependencies = missingDependencies(manifest, input.definition.devDependencies);
2453
2458
  manifest.dependencies = {
2454
2459
  ...manifest.dependencies,
2455
- ...hasPackageDependency(manifest, "@farm.js/integrations") ? {} : { "@farm.js/integrations": getFarmIntegrationsVersion(manifest) },
2460
+ ...hasPackageDependency(manifest, input.definition.packageName) ? {} : { [input.definition.packageName]: getFarmIntegrationVersion(manifest) },
2456
2461
  ...dependencies
2457
2462
  };
2458
2463
  if (Object.keys(devDependencies).length) manifest.devDependencies = {
@@ -2535,8 +2540,10 @@ function findFarmConfig(root) {
2535
2540
  function hasPackageDependency(manifest, dependency) {
2536
2541
  return dependency in (manifest.dependencies || {}) || dependency in (manifest.devDependencies || {}) || dependency in (manifest.peerDependencies || {}) || dependency in (manifest.optionalDependencies || {});
2537
2542
  }
2538
- function getFarmIntegrationsVersion(manifest) {
2539
- return (manifest.dependencies?.["@farm.js/core"] ?? manifest.devDependencies?.["@farm.js/core"] ?? manifest.peerDependencies?.["@farm.js/core"] ?? manifest.optionalDependencies?.["@farm.js/core"])?.startsWith("workspace:") ? "workspace:*" : "latest";
2543
+ function getFarmIntegrationVersion(manifest) {
2544
+ const farmCoreVersion = manifest.dependencies?.["@farm.js/core"] ?? manifest.devDependencies?.["@farm.js/core"] ?? manifest.peerDependencies?.["@farm.js/core"] ?? manifest.optionalDependencies?.["@farm.js/core"];
2545
+ if (!farmCoreVersion) return "latest";
2546
+ return farmCoreVersion.startsWith("workspace:") ? "workspace:*" : farmCoreVersion;
2540
2547
  }
2541
2548
  function toImportPath(relativePath) {
2542
2549
  const normalized = relativePath.split(node_path.default.sep).join("/");
@@ -2565,4 +2572,4 @@ Object.defineProperty(exports, "listFarmIntegrationProviders", {
2565
2572
  }
2566
2573
  });
2567
2574
 
2568
- //# sourceMappingURL=add-integration-Xc0p-k-m.js.map
2575
+ //# sourceMappingURL=add-integration-D5mff3xX.js.map