@farm.js/cli 0.1.0-beta.22 → 0.1.0-beta.24

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.
@@ -100,7 +100,7 @@ function aiChatUIFeature() {
100
100
  ],
101
101
  needsApiClient: false,
102
102
  notes: ["Open \"/integrations/ai\" to try the generated chat UI."],
103
- files: () => [componentFile("ai-chat.tsx", aiChatTemplate()), integrationPageFile("ai", "AIChat")]
103
+ files: () => [componentFile("ai-chat.tsx", aiChatTemplate()), integrationPageFile("ai", "AIChat", "ai-chat")]
104
104
  };
105
105
  }
106
106
  function supabaseAuthUIFeature() {
@@ -132,35 +132,25 @@ function workosAuthUIFeature() {
132
132
  key: input.key,
133
133
  provider: "WorkOS",
134
134
  componentName: "WorkOSAuthPanel",
135
- statusCall: "session.get",
136
- logoutCall: "logout.post",
135
+ statusCall: "session",
136
+ statusMethod: "get",
137
+ logoutCall: "logout",
138
+ logoutMethod: "post",
137
139
  loginHref: "/login?returnTo=/dashboard",
138
140
  signupHref: "/signup?returnTo=/dashboard",
139
141
  statusLabel: "Session"
140
- })), integrationPageFile("workos", "WorkOSAuthPanel")]
142
+ })), integrationPageFile("workos", "WorkOSAuthPanel", "workos-auth-panel")]
141
143
  };
142
144
  }
143
145
  function auth0AuthUIFeature() {
144
- return {
145
- name: "auth0-auth",
146
- description: "Auth0 auth UI",
147
- components: [
148
- "badge",
149
- "button",
150
- "card"
151
- ],
152
- notes: ["Open \"/integrations/auth0\" to try the generated auth UI."],
153
- files: (input) => [componentFile("auth0-auth-panel.tsx", hostedAuthTemplate({
154
- key: input.key,
155
- provider: "Auth0",
156
- componentName: "Auth0AuthPanel",
157
- statusCall: "profile.get",
158
- logoutCall: "logout.get",
159
- loginHref: "/auth/login?returnTo=/dashboard",
160
- signupHref: "/auth/signup?returnTo=/dashboard",
161
- statusLabel: "Profile"
162
- })), integrationPageFile("auth0", "Auth0AuthPanel")]
163
- };
146
+ return authRouteShellUIFeature({
147
+ provider: "auth0",
148
+ label: "Auth0",
149
+ componentName: "Auth0AuthPanel",
150
+ signInHref: "/auth/login?returnTo=/dashboard",
151
+ signUpHref: "/auth/signup?returnTo=/dashboard",
152
+ sessionHref: "/auth/profile"
153
+ });
164
154
  }
165
155
  function clerkAuthUIFeature() {
166
156
  return authRouteShellUIFeature({
@@ -239,16 +229,18 @@ function jobsUIFeature(provider) {
239
229
  function unkeyApiKeysUIFeature() {
240
230
  return {
241
231
  name: "unkey-api-keys",
242
- description: "Unkey API key console UI",
243
- components: [
244
- "badge",
245
- "button",
246
- "card",
247
- "input",
248
- "label"
249
- ],
250
- notes: ["Open \"/integrations/unkey\" to try the generated API key UI."],
251
- files: (input) => [componentFile("unkey-api-keys-console.tsx", unkeyApiKeysTemplate(input.key)), integrationPageFile("unkey", "UnkeyApiKeysConsole")]
232
+ description: "Unkey protected route UI",
233
+ components: ["badge", "card"],
234
+ needsApiClient: false,
235
+ notes: ["Open \"/integrations/unkey\" to test the generated protected API route."],
236
+ files: () => [
237
+ componentFile("unkey-api-keys-console.tsx", unkeyApiKeysTemplate()),
238
+ integrationPageFile("unkey", "UnkeyApiKeysConsole"),
239
+ {
240
+ path: path.join("src", "app", "api", "protected", "route.ts"),
241
+ source: unkeyProtectedRouteTemplate()
242
+ }
243
+ ]
252
244
  };
253
245
  }
254
246
  function billingUIFeature(input) {
@@ -278,6 +270,7 @@ function authRouteShellUIFeature(input) {
278
270
  "button",
279
271
  "card"
280
272
  ],
273
+ needsApiClient: false,
281
274
  notes: [`Open "/integrations/${input.provider}" to try the generated auth UI.`],
282
275
  files: () => [componentFile(`${input.provider}-auth-panel.tsx`, authRouteShellTemplate({
283
276
  provider: input.label,
@@ -285,7 +278,7 @@ function authRouteShellUIFeature(input) {
285
278
  signInHref: input.signInHref,
286
279
  signUpHref: input.signUpHref,
287
280
  sessionHref: input.sessionHref
288
- })), integrationPageFile(input.provider, input.componentName)]
281
+ })), integrationPageFile(input.provider, input.componentName, input.provider === "authjs" ? "authjs-auth-panel" : void 0)]
289
282
  };
290
283
  }
291
284
  function componentFile(fileName, source) {
@@ -294,11 +287,10 @@ function componentFile(fileName, source) {
294
287
  source
295
288
  };
296
289
  }
297
- function integrationPageFile(provider, componentName) {
298
- const fileName = kebabCase(componentName);
290
+ function integrationPageFile(provider, componentName, sourceFileName = kebabCase(componentName)) {
299
291
  return {
300
292
  path: path.join("src", "app", "integrations", provider, "page.tsx"),
301
- source: `import { ${componentName} } from "@/components/farm/${fileName}";
293
+ source: `import { ${componentName} } from "@/components/farm/${sourceFileName}";
302
294
 
303
295
  export default function ${componentName}Page() {
304
296
  return <${componentName} />;
@@ -455,7 +447,7 @@ const UI_DEPENDENCIES = {
455
447
  "tailwind-merge": "^3.3.1",
456
448
  tailwindcss: "^4.1.18"
457
449
  };
458
- const SHADCN_THEME_CSS = `@custom-variant dark (&:is(.dark *));
450
+ const SHADCN_THEME_CSS = `@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
459
451
 
460
452
  @theme inline {
461
453
  --color-background: var(--background);
@@ -481,7 +473,8 @@ const SHADCN_THEME_CSS = `@custom-variant dark (&:is(.dark *));
481
473
  --radius-lg: var(--radius);
482
474
  }
483
475
 
484
- :root {
476
+ :root,
477
+ [data-theme="light"] {
485
478
  --radius: 0.5rem;
486
479
  --background: oklch(1 0 0);
487
480
  --foreground: oklch(0.145 0 0);
@@ -503,7 +496,7 @@ const SHADCN_THEME_CSS = `@custom-variant dark (&:is(.dark *));
503
496
  --ring: oklch(0.708 0 0);
504
497
  }
505
498
 
506
- .dark {
499
+ [data-theme="dark"] {
507
500
  --background: oklch(0.145 0 0);
508
501
  --foreground: oklch(0.985 0 0);
509
502
  --card: oklch(0.205 0 0);
@@ -1106,12 +1099,17 @@ export function SupabaseAuthPanel() {
1106
1099
  }
1107
1100
 
1108
1101
  async function logout() {
1109
- const response = await apiClient.${key}.logout.post({ body: { returnTo: "/" } });
1110
- if (response.data?.redirectTo) {
1111
- window.location.assign(response.data.redirectTo);
1102
+ const response = await fetch("/auth/logout", {
1103
+ method: "POST",
1104
+ headers: { "content-type": "application/json" },
1105
+ body: JSON.stringify({ returnTo: "/" }),
1106
+ });
1107
+ const data = (await response.json()) as { redirectTo?: string; error?: string };
1108
+ if (data.redirectTo) {
1109
+ window.location.assign(data.redirectTo);
1112
1110
  return;
1113
1111
  }
1114
- setStatus(response.error?.message ?? "Signed out");
1112
+ setStatus(data.error ?? "Signed out");
1115
1113
  }
1116
1114
 
1117
1115
  return (
@@ -1170,7 +1168,7 @@ export function ${input.componentName}() {
1170
1168
 
1171
1169
  async function refreshStatus() {
1172
1170
  setPending(true);
1173
- const response = await apiClient.${input.key}.${input.statusCall}();
1171
+ const response = await apiClient.${input.key}.${input.statusCall}.${input.statusMethod}();
1174
1172
  if (response.error) {
1175
1173
  setStatus(response.error.message);
1176
1174
  } else {
@@ -1181,7 +1179,7 @@ export function ${input.componentName}() {
1181
1179
 
1182
1180
  async function logout() {
1183
1181
  setPending(true);
1184
- const response = await apiClient.${input.key}.${input.logoutCall}();
1182
+ const response = await apiClient.${input.key}.${input.logoutCall}.${input.logoutMethod}();
1185
1183
  if (response.data?.redirectTo) {
1186
1184
  window.location.assign(response.data.redirectTo);
1187
1185
  return;
@@ -1444,17 +1442,20 @@ import { apiClient } from "@/lib/api";
1444
1442
  export function ResendEmailConsole() {
1445
1443
  const [to, setTo] = React.useState("");
1446
1444
  const [name, setName] = React.useState("Ada");
1447
- const [templateId, setTemplateId] = React.useState("welcome");
1445
+ const templateId = "welcome" as const;
1448
1446
  const [status, setStatus] = React.useState("Idle");
1449
1447
  const [previewHtml, setPreviewHtml] = React.useState("");
1450
1448
 
1451
1449
  async function loadTemplates() {
1452
- const response = await apiClient.${key}.templates.get();
1453
- setStatus(response.error ? response.error.message : "Templates: " + (response.data ?? []).map((item) => item.id).join(", "));
1450
+ const response = await apiClient.${key}.templates();
1451
+ const templates = Array.isArray(response.data)
1452
+ ? (response.data as Array<{ id: string }>)
1453
+ : [];
1454
+ setStatus(response.error ? response.error.message : "Templates: " + templates.map((item) => item.id).join(", "));
1454
1455
  }
1455
1456
 
1456
1457
  async function preview() {
1457
- const response = await apiClient.${key}.preview.post({
1458
+ const response = await apiClient.${key}.preview({
1458
1459
  body: {
1459
1460
  templateId,
1460
1461
  data: { name },
@@ -1469,7 +1470,7 @@ export function ResendEmailConsole() {
1469
1470
  }
1470
1471
 
1471
1472
  async function send() {
1472
- const response = await apiClient.${key}.send.post({
1473
+ const response = await apiClient.${key}.send({
1473
1474
  body: {
1474
1475
  templateId,
1475
1476
  to,
@@ -1492,11 +1493,7 @@ export function ResendEmailConsole() {
1492
1493
  <CardDescription>Template previews and delivery controls.</CardDescription>
1493
1494
  </CardHeader>
1494
1495
  <CardContent className="space-y-4">
1495
- <div className="grid gap-4 sm:grid-cols-3">
1496
- <div className="space-y-2">
1497
- <Label htmlFor="templateId">Template</Label>
1498
- <Input id="templateId" value={templateId} onChange={(event) => setTemplateId(event.target.value)} />
1499
- </div>
1496
+ <div className="grid gap-4 sm:grid-cols-2">
1500
1497
  <div className="space-y-2">
1501
1498
  <Label htmlFor="to">To</Label>
1502
1499
  <Input id="to" value={to} onChange={(event) => setTo(event.target.value)} />
@@ -1621,47 +1618,11 @@ export function ${`${pascalCase(provider)}JobsConsole`}() {
1621
1618
  }
1622
1619
  `;
1623
1620
  }
1624
- function unkeyApiKeysTemplate(key) {
1625
- return `"use client";
1626
-
1627
- import * as React from "react";
1628
- import { Badge } from "@/components/ui/badge";
1629
- import { Button } from "@/components/ui/button";
1621
+ function unkeyApiKeysTemplate() {
1622
+ return `import { Badge } from "@/components/ui/badge";
1630
1623
  import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
1631
- import { Input } from "@/components/ui/input";
1632
- import { Label } from "@/components/ui/label";
1633
- import { apiClient } from "@/lib/api";
1634
1624
 
1635
1625
  export function UnkeyApiKeysConsole() {
1636
- const [name, setName] = React.useState("Development key");
1637
- const [prefix, setPrefix] = React.useState("farm");
1638
- const [apiKey, setApiKey] = React.useState("");
1639
- const [status, setStatus] = React.useState("Idle");
1640
-
1641
- async function createKey() {
1642
- const response = await apiClient.${key}.createKey.post({
1643
- body: {
1644
- name,
1645
- prefix,
1646
- },
1647
- });
1648
- if (response.error) {
1649
- setStatus(response.error.message);
1650
- return;
1651
- }
1652
- setApiKey(response.data?.key ?? "");
1653
- setStatus("Created " + (response.data?.keyId ?? "key"));
1654
- }
1655
-
1656
- async function verifyKey() {
1657
- const response = await apiClient.${key}.verifyKey.post({
1658
- body: {
1659
- key: apiKey,
1660
- },
1661
- });
1662
- setStatus(response.error ? response.error.message : response.data?.valid ? "Valid key" : "Invalid key");
1663
- }
1664
-
1665
1626
  return (
1666
1627
  <main className="min-h-screen bg-background px-6 py-12 text-foreground">
1667
1628
  <section className="mx-auto flex w-full max-w-3xl flex-col gap-6">
@@ -1671,29 +1632,16 @@ export function UnkeyApiKeysConsole() {
1671
1632
  </div>
1672
1633
  <Card>
1673
1634
  <CardHeader>
1674
- <CardTitle className="text-xl">Key console</CardTitle>
1675
- <CardDescription>API key lifecycle controls.</CardDescription>
1635
+ <CardTitle className="text-xl">Protected API</CardTitle>
1636
+ <CardDescription>Requests are verified by Unkey before the route runs.</CardDescription>
1676
1637
  </CardHeader>
1677
- <CardContent className="space-y-4">
1678
- <div className="grid gap-4 sm:grid-cols-2">
1679
- <div className="space-y-2">
1680
- <Label htmlFor="name">Name</Label>
1681
- <Input id="name" value={name} onChange={(event) => setName(event.target.value)} />
1682
- </div>
1683
- <div className="space-y-2">
1684
- <Label htmlFor="prefix">Prefix</Label>
1685
- <Input id="prefix" value={prefix} onChange={(event) => setPrefix(event.target.value)} />
1686
- </div>
1687
- </div>
1688
- <div className="space-y-2">
1689
- <Label htmlFor="apiKey">API key</Label>
1690
- <Input id="apiKey" value={apiKey} onChange={(event) => setApiKey(event.target.value)} />
1691
- </div>
1692
- <p className="rounded-md border bg-muted/30 px-3 py-2 text-sm">{status}</p>
1693
- <div className="flex flex-wrap gap-2">
1694
- <Button type="button" onClick={() => void createKey()}>Create key</Button>
1695
- <Button type="button" variant="outline" onClick={() => void verifyKey()}>Verify</Button>
1696
- </div>
1638
+ <CardContent className="space-y-3">
1639
+ <code className="block overflow-x-auto rounded-md border bg-muted/30 p-3 text-xs">
1640
+ curl http://localhost:3000/api/protected -H &quot;Authorization: Bearer YOUR_KEY&quot;
1641
+ </code>
1642
+ <p className="text-sm text-muted-foreground">
1643
+ Create and rotate keys from trusted server code or the Unkey dashboard.
1644
+ </p>
1697
1645
  </CardContent>
1698
1646
  </Card>
1699
1647
  </section>
@@ -1702,6 +1650,15 @@ export function UnkeyApiKeysConsole() {
1702
1650
  }
1703
1651
  `;
1704
1652
  }
1653
+ function unkeyProtectedRouteTemplate() {
1654
+ return `export function GET() {
1655
+ return Response.json({
1656
+ ok: true,
1657
+ message: "Valid Unkey API key.",
1658
+ });
1659
+ }
1660
+ `;
1661
+ }
1705
1662
  function pascalCase(input) {
1706
1663
  return input.split(/[^A-Za-z0-9]+/g).filter(Boolean).map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`).join("");
1707
1664
  }
@@ -1729,6 +1686,7 @@ const PROVIDERS = [
1729
1686
  "chat"
1730
1687
  ],
1731
1688
  defaultKey: "chat",
1689
+ packageName: "@farm.js/ai",
1732
1690
  fileName: "chat",
1733
1691
  exportName: "POST",
1734
1692
  description: "Vercel AI SDK chat route",
@@ -1739,7 +1697,7 @@ const PROVIDERS = [
1739
1697
  "No farm.config integration wiring is required for this route."
1740
1698
  ],
1741
1699
  ui: aiChatUIFeature(),
1742
- template: () => `import { aiChatRoute } from "@farm.js/integrations/ai";
1700
+ template: () => `import { aiChatRoute } from "@farm.js/ai";
1743
1701
 
1744
1702
  export const POST = aiChatRoute({
1745
1703
  model: "openai/gpt-4o-mini",
@@ -1755,17 +1713,19 @@ export const POST = aiChatRoute({
1755
1713
  "stripe-billing"
1756
1714
  ],
1757
1715
  defaultKey: "billing",
1716
+ packageName: "@farm.js/stripe",
1758
1717
  fileName: "stripe",
1759
1718
  exportName: "stripeIntegration",
1760
1719
  description: "Stripe billing and checkout routes",
1761
1720
  env: ["STRIPE_SECRET_KEY", "STRIPE_WEBHOOK_SECRET"],
1762
- template: () => `import { stripe } from "@farm.js/integrations/stripe";
1721
+ template: () => `import type { FarmIntegrationLogEvent } from "@farm.js/core";
1722
+ import { stripe } from "@farm.js/stripe";
1763
1723
 
1764
1724
  export const stripeIntegration = stripe({
1765
1725
  secretKey: process.env.STRIPE_SECRET_KEY,
1766
1726
  webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,
1767
1727
  products: [],
1768
- log(event) {
1728
+ log(event: FarmIntegrationLogEvent) {
1769
1729
  console.log("[stripe]", event.phase, event.route?.path || "none");
1770
1730
  },
1771
1731
  });
@@ -1776,6 +1736,7 @@ export const stripeIntegration = stripe({
1776
1736
  provider: "supabase",
1777
1737
  aliases: ["auth-supabase", "supabase-auth"],
1778
1738
  defaultKey: "auth",
1739
+ packageName: "@farm.js/supabase",
1779
1740
  fileName: "supabase",
1780
1741
  exportName: "supabaseIntegration",
1781
1742
  description: "Supabase auth routes and middleware",
@@ -1785,7 +1746,7 @@ export const stripeIntegration = stripe({
1785
1746
  "APP_BASE_URL"
1786
1747
  ],
1787
1748
  ui: supabaseAuthUIFeature(),
1788
- template: () => `import { supabase } from "@farm.js/integrations/supabase";
1749
+ template: () => `import { supabase } from "@farm.js/supabase";
1789
1750
 
1790
1751
  export const supabaseIntegration = supabase({
1791
1752
  callbackUrl: \`\${process.env.APP_BASE_URL || "http://localhost:3000"}/auth/callback\`,
@@ -1804,6 +1765,7 @@ export const supabaseIntegration = supabase({
1804
1765
  provider: "workos",
1805
1766
  aliases: ["auth-workos", "workos-auth"],
1806
1767
  defaultKey: "auth",
1768
+ packageName: "@farm.js/workos",
1807
1769
  fileName: "workos",
1808
1770
  exportName: "workosIntegration",
1809
1771
  description: "WorkOS auth routes and protected route middleware",
@@ -1813,7 +1775,7 @@ export const supabaseIntegration = supabase({
1813
1775
  "WORKOS_COOKIE_PASSWORD"
1814
1776
  ],
1815
1777
  ui: workosAuthUIFeature(),
1816
- template: () => `import { workos } from "@farm.js/integrations/workos";
1778
+ template: () => `import { workos } from "@farm.js/workos";
1817
1779
 
1818
1780
  export const workosIntegration = workos({
1819
1781
  protectedRoutes: ["/dashboard(.*)"],
@@ -1827,6 +1789,7 @@ export const workosIntegration = workos({
1827
1789
  provider: "auth0",
1828
1790
  aliases: ["auth-auth0", "auth0-auth"],
1829
1791
  defaultKey: "auth",
1792
+ packageName: "@farm.js/auth0",
1830
1793
  fileName: "auth0",
1831
1794
  exportName: "auth0Integration",
1832
1795
  description: "Auth0 login, callback, logout, and profile routes",
@@ -1837,7 +1800,7 @@ export const workosIntegration = workos({
1837
1800
  "AUTH0_SECRET"
1838
1801
  ],
1839
1802
  ui: auth0AuthUIFeature(),
1840
- template: () => `import { auth0 } from "@farm.js/integrations/auth0";
1803
+ template: () => `import { auth0 } from "@farm.js/auth0";
1841
1804
 
1842
1805
  export const auth0Integration = auth0({
1843
1806
  callbackUrl: \`\${process.env.APP_BASE_URL || "http://localhost:3000"}/auth/callback\`,
@@ -1852,12 +1815,14 @@ export const auth0Integration = auth0({
1852
1815
  provider: "clerk",
1853
1816
  aliases: ["auth-clerk", "clerk-auth"],
1854
1817
  defaultKey: "auth",
1818
+ packageName: "@farm.js/clerk",
1855
1819
  fileName: "clerk",
1856
1820
  exportName: "clerkIntegration",
1857
1821
  description: "Clerk auth provider and protected route middleware",
1858
1822
  env: ["NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY", "CLERK_SECRET_KEY"],
1823
+ dependencies: { "@clerk/react": "^6.1.0" },
1859
1824
  ui: clerkAuthUIFeature(),
1860
- template: () => `import { clerk } from "@farm.js/integrations/clerk";
1825
+ template: () => `import { clerk } from "@farm.js/clerk";
1861
1826
 
1862
1827
  export const clerkIntegration = clerk({
1863
1828
  signInUrl: "/sign-in",
@@ -1873,6 +1838,7 @@ export const clerkIntegration = clerk({
1873
1838
  provider: "resend",
1874
1839
  aliases: ["email", "resend-email"],
1875
1840
  defaultKey: "email",
1841
+ packageName: "@farm.js/email",
1876
1842
  fileName: "resend",
1877
1843
  exportName: "resendIntegration",
1878
1844
  description: "Resend email send, preview, schedule, and webhook routes",
@@ -1883,7 +1849,7 @@ export const clerkIntegration = clerk({
1883
1849
  ],
1884
1850
  ui: resendEmailUIFeature(),
1885
1851
  template: () => `import { createElement } from "react";
1886
- import { resend, template } from "@farm.js/integrations/email";
1852
+ import { resend, template } from "@farm.js/email";
1887
1853
 
1888
1854
  function WelcomeEmail(props: { name: string }) {
1889
1855
  return createElement("div", null, \`Welcome \${props.name}\`);
@@ -1922,6 +1888,7 @@ export const resendIntegration = resend({
1922
1888
  provider: "jobs-inngest",
1923
1889
  aliases: ["inngest", "jobs"],
1924
1890
  defaultKey: "jobs",
1891
+ packageName: "@farm.js/jobs",
1925
1892
  fileName: "jobs-inngest",
1926
1893
  exportName: "jobsIntegration",
1927
1894
  description: "Jobs integration backed by Inngest",
@@ -1932,7 +1899,7 @@ export const resendIntegration = resend({
1932
1899
  ],
1933
1900
  notes: ["Add tasks to jobTasks before using the generated jobs API."],
1934
1901
  ui: jobsUIFeature("inngest"),
1935
- template: () => `import { defineTasks, inngest, jobs } from "@farm.js/integrations/jobs";
1902
+ template: () => `import { defineTasks, inngest, jobs } from "@farm.js/jobs";
1936
1903
 
1937
1904
  export const jobTasks = defineTasks({});
1938
1905
 
@@ -1957,6 +1924,7 @@ export const jobsIntegration = jobs({
1957
1924
  "jobs-triggerdev"
1958
1925
  ],
1959
1926
  defaultKey: "jobs",
1927
+ packageName: "@farm.js/jobs",
1960
1928
  fileName: "jobs-trigger",
1961
1929
  exportName: "jobsIntegration",
1962
1930
  description: "Jobs integration backed by Trigger.dev",
@@ -1967,7 +1935,7 @@ export const jobsIntegration = jobs({
1967
1935
  ],
1968
1936
  notes: ["Add tasks to jobTasks before using the generated jobs API."],
1969
1937
  ui: jobsUIFeature("trigger"),
1970
- template: () => `import { defineTasks, jobs, trigger } from "@farm.js/integrations/jobs";
1938
+ template: () => `import { defineTasks, jobs, trigger } from "@farm.js/jobs";
1971
1939
 
1972
1940
  export const jobTasks = defineTasks({});
1973
1941
 
@@ -1988,6 +1956,7 @@ export const jobsIntegration = jobs({
1988
1956
  provider: "polar",
1989
1957
  aliases: ["polar-billing", "billing-polar"],
1990
1958
  defaultKey: "billing",
1959
+ packageName: "@farm.js/polar",
1991
1960
  fileName: "polar",
1992
1961
  exportName: "polarIntegration",
1993
1962
  description: "Polar billing and checkout routes",
@@ -1999,9 +1968,9 @@ export const jobsIntegration = jobs({
1999
1968
  notes: ["Replace resolveBillingOwner with your app user or organization lookup."],
2000
1969
  ui: polarBillingUIFeature(),
2001
1970
  template: () => `import type { FarmIntegrationHandlerContext } from "@farm.js/core";
2002
- import { polar } from "@farm.js/integrations/polar";
1971
+ import { polar } from "@farm.js/polar";
2003
1972
 
2004
- async function resolveBillingOwner(_context: FarmIntegrationHandlerContext) {
1973
+ function resolveBillingOwner(_context: FarmIntegrationHandlerContext): never {
2005
1974
  throw new Error("Configure Polar billing owner resolution for your app.");
2006
1975
  }
2007
1976
 
@@ -2029,6 +1998,7 @@ export const polarIntegration = polar({
2029
1998
  provider: "autumn",
2030
1999
  aliases: ["autumn-billing", "billing-autumn"],
2031
2000
  defaultKey: "billing",
2001
+ packageName: "@farm.js/autumn",
2032
2002
  fileName: "autumn",
2033
2003
  exportName: "autumnIntegration",
2034
2004
  description: "Autumn billing and checkout routes",
@@ -2040,9 +2010,9 @@ export const polarIntegration = polar({
2040
2010
  notes: ["Replace resolveBillingOwner with your app user or organization lookup."],
2041
2011
  ui: autumnBillingUIFeature(),
2042
2012
  template: () => `import type { FarmIntegrationHandlerContext } from "@farm.js/core";
2043
- import { autumn } from "@farm.js/integrations/autumn";
2013
+ import { autumn } from "@farm.js/autumn";
2044
2014
 
2045
- async function resolveBillingOwner(_context: FarmIntegrationHandlerContext) {
2015
+ function resolveBillingOwner(_context: FarmIntegrationHandlerContext): never {
2046
2016
  throw new Error("Configure Autumn billing owner resolution for your app.");
2047
2017
  }
2048
2018
 
@@ -2069,6 +2039,7 @@ export const autumnIntegration = autumn({
2069
2039
  provider: "better-auth",
2070
2040
  aliases: ["betterauth", "auth-better-auth"],
2071
2041
  defaultKey: "auth",
2042
+ packageName: "@farm.js/better-auth",
2072
2043
  fileName: "better-auth",
2073
2044
  exportName: "betterAuthIntegration",
2074
2045
  description: "Better Auth route adapter",
@@ -2123,7 +2094,7 @@ better-auth.sqlite-wal
2123
2094
  }
2124
2095
  ],
2125
2096
  ui: betterAuthUIFeature(),
2126
- template: () => `import { betterAuth } from "@farm.js/integrations/better-auth";
2097
+ template: () => `import { betterAuth } from "@farm.js/better-auth";
2127
2098
  import { auth } from "../auth.ts";
2128
2099
 
2129
2100
  export const betterAuthIntegration = betterAuth({
@@ -2142,13 +2113,45 @@ export const betterAuthIntegration = betterAuth({
2142
2113
  "next-auth"
2143
2114
  ],
2144
2115
  defaultKey: "auth",
2116
+ packageName: "@farm.js/authjs",
2145
2117
  fileName: "authjs",
2146
2118
  exportName: "authjsIntegration",
2147
2119
  description: "Auth.js route adapter",
2148
- env: [],
2149
- notes: ["This template expects src/lib/auth.ts to export an Auth.js instance named auth."],
2120
+ env: [
2121
+ "AUTH_SECRET",
2122
+ "AUTH_GITHUB_ID",
2123
+ "AUTH_GITHUB_SECRET"
2124
+ ],
2125
+ dependencies: { "@auth/core": "0.34.3" },
2126
+ setupFiles: [{
2127
+ path: "src/lib/auth.ts",
2128
+ source: () => `import { Auth } from "@auth/core";
2129
+ import GitHub from "@auth/core/providers/github";
2130
+
2131
+ const config = {
2132
+ providers: [
2133
+ GitHub({
2134
+ clientId: process.env.AUTH_GITHUB_ID!,
2135
+ clientSecret: process.env.AUTH_GITHUB_SECRET!,
2136
+ }),
2137
+ ],
2138
+ secret: process.env.AUTH_SECRET,
2139
+ trustHost: true,
2140
+ };
2141
+
2142
+ const handler = (request: Request) => Auth(request, config);
2143
+
2144
+ export const auth = {
2145
+ handlers: {
2146
+ GET: handler,
2147
+ POST: handler,
2148
+ },
2149
+ };
2150
+ `
2151
+ }],
2152
+ notes: ["The generated Auth.js instance uses GitHub OAuth through @auth/core; add or replace providers in src/lib/auth.ts."],
2150
2153
  ui: authjsUIFeature(),
2151
- template: () => `import { authjs } from "@farm.js/integrations/authjs";
2154
+ template: () => `import { authjs } from "@farm.js/authjs";
2152
2155
  import { auth } from "../auth.ts";
2153
2156
 
2154
2157
  export const authjsIntegration = authjs({
@@ -2168,6 +2171,7 @@ export const authjsIntegration = authjs({
2168
2171
  "unkey-api-keys"
2169
2172
  ],
2170
2173
  defaultKey: "apiKeys",
2174
+ packageName: "@farm.js/unkey",
2171
2175
  fileName: "unkey",
2172
2176
  exportName: "unkeyIntegration",
2173
2177
  description: "Unkey API key creation, verification, and route protection",
@@ -2177,7 +2181,7 @@ export const authjsIntegration = authjs({
2177
2181
  "UNKEY_BASE_URL"
2178
2182
  ],
2179
2183
  ui: unkeyApiKeysUIFeature(),
2180
- template: () => `import { unkey } from "@farm.js/integrations/unkey";
2184
+ template: () => `import { unkey } from "@farm.js/unkey";
2181
2185
 
2182
2186
  export const unkeyIntegration = unkey({
2183
2187
  rootKey: process.env.UNKEY_ROOT_KEY,
@@ -2194,6 +2198,7 @@ export const unkeyIntegration = unkey({
2194
2198
  function listFarmIntegrationProviders() {
2195
2199
  return PROVIDERS.map((provider) => ({
2196
2200
  name: provider.provider,
2201
+ packageName: provider.packageName,
2197
2202
  aliases: [...provider.aliases],
2198
2203
  defaultKey: provider.defaultKey,
2199
2204
  description: provider.description,
@@ -2429,7 +2434,7 @@ async function updatePackageJson(input) {
2429
2434
  const devDependencies = missingDependencies(manifest, input.definition.devDependencies);
2430
2435
  manifest.dependencies = {
2431
2436
  ...manifest.dependencies,
2432
- ...hasPackageDependency(manifest, "@farm.js/integrations") ? {} : { "@farm.js/integrations": getFarmIntegrationsVersion(manifest) },
2437
+ ...hasPackageDependency(manifest, input.definition.packageName) ? {} : { [input.definition.packageName]: getFarmIntegrationVersion(manifest) },
2433
2438
  ...dependencies
2434
2439
  };
2435
2440
  if (Object.keys(devDependencies).length) manifest.devDependencies = {
@@ -2512,8 +2517,10 @@ function findFarmConfig(root) {
2512
2517
  function hasPackageDependency(manifest, dependency) {
2513
2518
  return dependency in (manifest.dependencies || {}) || dependency in (manifest.devDependencies || {}) || dependency in (manifest.peerDependencies || {}) || dependency in (manifest.optionalDependencies || {});
2514
2519
  }
2515
- function getFarmIntegrationsVersion(manifest) {
2516
- 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";
2520
+ function getFarmIntegrationVersion(manifest) {
2521
+ const farmCoreVersion = manifest.dependencies?.["@farm.js/core"] ?? manifest.devDependencies?.["@farm.js/core"] ?? manifest.peerDependencies?.["@farm.js/core"] ?? manifest.optionalDependencies?.["@farm.js/core"];
2522
+ if (!farmCoreVersion) return "latest";
2523
+ return farmCoreVersion.startsWith("workspace:") ? "workspace:*" : farmCoreVersion;
2517
2524
  }
2518
2525
  function toImportPath(relativePath) {
2519
2526
  const normalized = relativePath.split(path.sep).join("/");
@@ -2525,4 +2532,4 @@ function escapeRegExp(input) {
2525
2532
  //#endregion
2526
2533
  export { listFarmIntegrationProviders as n, addFarmIntegration as t };
2527
2534
 
2528
- //# sourceMappingURL=add-integration-CdVfiPjG.mjs.map
2535
+ //# sourceMappingURL=add-integration-7hf9WI7e.mjs.map