@farm.js/cli 0.1.0-beta.1 → 0.1.0-beta.3
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/dist/add-integration-CdVfiPjG.mjs.map +1 -1
- package/dist/{add-integration-pp16Zr0U.js → add-integration-Xc0p-k-m.js} +2 -2
- package/dist/add-integration-Xc0p-k-m.js.map +1 -0
- package/dist/add-integration.js +1 -1
- package/dist/build.js.map +1 -1
- package/dist/index.js +10 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +9 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/dist/add-integration-pp16Zr0U.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-integration-CdVfiPjG.mjs","names":["hasPackageDependency"],"sources":["../src/ui-feature-registry.ts","../src/add-integration.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { AddFarmIntegrationResult, FarmIntegrationProvider } from \"./add-integration\";\n\ntype PackageManifest = {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n};\n\nexport interface AddFarmIntegrationUIResult {\n feature: string;\n components: string[];\n files: string[];\n}\n\nexport type ShadcnComponentName = \"badge\" | \"button\" | \"card\" | \"input\" | \"label\";\n\nexport interface UIFeatureDefinition {\n name: string;\n description: string;\n components: readonly ShadcnComponentName[];\n files(input: UIFeatureTemplateInput): readonly UIFeatureFile[];\n needsApiClient?: boolean;\n notes?: readonly string[];\n}\n\ninterface UIFeatureTemplateInput {\n key: string;\n provider: FarmIntegrationProvider;\n}\n\ninterface UIFeatureFile {\n path: string;\n source: string;\n}\n\nexport async function installUIFeature(input: {\n root: string;\n definition: { provider: FarmIntegrationProvider; ui?: UIFeatureDefinition };\n key: string;\n dryRun?: boolean;\n force?: boolean;\n skipPackageJson?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const feature = input.definition.ui;\n if (!feature) {\n input.result.notes.push(\n `No --ui feature pack is available for ${input.definition.provider} yet.`,\n );\n return;\n }\n\n input.result.ui = {\n feature: feature.name,\n components: [...feature.components],\n files: [],\n };\n input.result.notes.push(\n `Installed ${feature.description} with shadcn-style local source components.`,\n ...(feature.notes || []),\n );\n\n await ensureComponentsJson({\n root: input.root,\n dryRun: input.dryRun,\n result: input.result,\n });\n await ensureShadcnGlobals({\n root: input.root,\n dryRun: input.dryRun,\n result: input.result,\n });\n await ensureTsconfigAlias({\n root: input.root,\n dryRun: input.dryRun,\n result: input.result,\n });\n\n if (!input.skipPackageJson) {\n await updateUIPackageJson({\n root: input.root,\n dryRun: input.dryRun,\n result: input.result,\n });\n }\n\n await writeGeneratedFile({\n root: input.root,\n relativePath: path.join(\"src\", \"lib\", \"utils.ts\"),\n source: shadcnUtilsTemplate(),\n dryRun: input.dryRun,\n force: input.force,\n result: input.result,\n });\n\n for (const component of feature.components) {\n await writeGeneratedFile({\n root: input.root,\n relativePath: path.join(\"src\", \"components\", \"ui\", `${component}.tsx`),\n source: shadcnComponentTemplate(component),\n dryRun: input.dryRun,\n force: input.force,\n result: input.result,\n });\n }\n\n if (feature.needsApiClient !== false) {\n await writeGeneratedFile({\n root: input.root,\n relativePath: path.join(\"src\", \"lib\", \"api.ts\"),\n source: apiClientTemplate(),\n dryRun: input.dryRun,\n force: input.force,\n result: input.result,\n });\n }\n\n for (const file of feature.files({\n key: input.key,\n provider: input.definition.provider,\n })) {\n await writeGeneratedFile({\n root: input.root,\n relativePath: file.path,\n source: file.source,\n dryRun: input.dryRun,\n force: input.force,\n result: input.result,\n });\n }\n}\n\nexport function stripeBillingUIFeature(): UIFeatureDefinition {\n return billingUIFeature({\n provider: \"stripe\",\n label: \"Stripe\",\n });\n}\n\nexport function polarBillingUIFeature(): UIFeatureDefinition {\n return billingUIFeature({\n provider: \"polar\",\n label: \"Polar\",\n });\n}\n\nexport function autumnBillingUIFeature(): UIFeatureDefinition {\n return billingUIFeature({\n provider: \"autumn\",\n label: \"Autumn\",\n });\n}\n\nexport function aiChatUIFeature(): UIFeatureDefinition {\n return {\n name: \"ai-chat\",\n description: \"AI chat UI\",\n components: [\"badge\", \"button\", \"card\", \"input\"],\n needsApiClient: false,\n notes: ['Open \"/integrations/ai\" to try the generated chat UI.'],\n files: () => [\n componentFile(\"ai-chat.tsx\", aiChatTemplate()),\n integrationPageFile(\"ai\", \"AIChat\"),\n ],\n };\n}\n\nexport function supabaseAuthUIFeature(): UIFeatureDefinition {\n return {\n name: \"supabase-auth\",\n description: \"Supabase auth UI\",\n components: [\"badge\", \"button\", \"card\", \"input\", \"label\"],\n notes: ['Open \"/integrations/supabase\" to try the generated auth UI.'],\n files: (input) => [\n componentFile(\"supabase-auth-panel.tsx\", supabaseAuthTemplate(input.key)),\n integrationPageFile(\"supabase\", \"SupabaseAuthPanel\"),\n ],\n };\n}\n\nexport function workosAuthUIFeature(): UIFeatureDefinition {\n return {\n name: \"workos-auth\",\n description: \"WorkOS auth UI\",\n components: [\"badge\", \"button\", \"card\"],\n notes: ['Open \"/integrations/workos\" to try the generated auth UI.'],\n files: (input) => [\n componentFile(\n \"workos-auth-panel.tsx\",\n hostedAuthTemplate({\n key: input.key,\n provider: \"WorkOS\",\n componentName: \"WorkOSAuthPanel\",\n statusCall: \"session.get\",\n logoutCall: \"logout.post\",\n loginHref: \"/login?returnTo=/dashboard\",\n signupHref: \"/signup?returnTo=/dashboard\",\n statusLabel: \"Session\",\n }),\n ),\n integrationPageFile(\"workos\", \"WorkOSAuthPanel\"),\n ],\n };\n}\n\nexport function auth0AuthUIFeature(): UIFeatureDefinition {\n return {\n name: \"auth0-auth\",\n description: \"Auth0 auth UI\",\n components: [\"badge\", \"button\", \"card\"],\n notes: ['Open \"/integrations/auth0\" to try the generated auth UI.'],\n files: (input) => [\n componentFile(\n \"auth0-auth-panel.tsx\",\n hostedAuthTemplate({\n key: input.key,\n provider: \"Auth0\",\n componentName: \"Auth0AuthPanel\",\n statusCall: \"profile.get\",\n logoutCall: \"logout.get\",\n loginHref: \"/auth/login?returnTo=/dashboard\",\n signupHref: \"/auth/signup?returnTo=/dashboard\",\n statusLabel: \"Profile\",\n }),\n ),\n integrationPageFile(\"auth0\", \"Auth0AuthPanel\"),\n ],\n };\n}\n\nexport function clerkAuthUIFeature(): UIFeatureDefinition {\n return authRouteShellUIFeature({\n provider: \"clerk\",\n label: \"Clerk\",\n componentName: \"ClerkAuthPanel\",\n signInHref: \"/sign-in\",\n signUpHref: \"/sign-up\",\n sessionHref: \"/dashboard\",\n });\n}\n\nexport function betterAuthUIFeature(): UIFeatureDefinition {\n return {\n name: \"better-auth-auth\",\n description: \"Better Auth email and password UI\",\n components: [\"badge\", \"button\", \"card\", \"input\", \"label\"],\n needsApiClient: false,\n notes: ['Open \"/integrations/better-auth\" to try the generated auth UI.'],\n files: () => [\n {\n path: path.join(\"src\", \"lib\", \"auth-client.ts\"),\n source: betterAuthClientTemplate(),\n },\n componentFile(\"better-auth-panel.tsx\", betterAuthPanelTemplate()),\n integrationPageFile(\"better-auth\", \"BetterAuthPanel\"),\n ],\n };\n}\n\nexport function authjsUIFeature(): UIFeatureDefinition {\n return authRouteShellUIFeature({\n provider: \"authjs\",\n label: \"Auth.js\",\n componentName: \"AuthJsPanel\",\n signInHref: \"/api/auth/signin\",\n signUpHref: \"/api/auth/signin\",\n sessionHref: \"/api/auth/session\",\n });\n}\n\nexport function resendEmailUIFeature(): UIFeatureDefinition {\n return {\n name: \"resend-email\",\n description: \"Resend email console UI\",\n components: [\"badge\", \"button\", \"card\", \"input\", \"label\"],\n notes: ['Open \"/integrations/resend\" to try the generated email UI.'],\n files: (input) => [\n componentFile(\"resend-email-console.tsx\", resendEmailTemplate(input.key)),\n integrationPageFile(\"resend\", \"ResendEmailConsole\"),\n ],\n };\n}\n\nexport function jobsUIFeature(provider: \"inngest\" | \"trigger\"): UIFeatureDefinition {\n const label = provider === \"inngest\" ? \"Inngest\" : \"Trigger.dev\";\n\n return {\n name: `${provider}-jobs`,\n description: `${label} jobs console UI`,\n components: [\"badge\", \"button\", \"card\", \"input\", \"label\"],\n notes: [`Open \"/integrations/jobs-${provider}\" to try the generated jobs UI.`],\n files: (input) => [\n componentFile(\n `${provider}-jobs-console.tsx`,\n jobsConsoleTemplate(input.key, label, provider),\n ),\n integrationPageFile(`jobs-${provider}`, `${pascalCase(provider)}JobsConsole`),\n ],\n };\n}\n\nexport function unkeyApiKeysUIFeature(): UIFeatureDefinition {\n return {\n name: \"unkey-api-keys\",\n description: \"Unkey API key console UI\",\n components: [\"badge\", \"button\", \"card\", \"input\", \"label\"],\n notes: ['Open \"/integrations/unkey\" to try the generated API key UI.'],\n files: (input) => [\n componentFile(\"unkey-api-keys-console.tsx\", unkeyApiKeysTemplate(input.key)),\n integrationPageFile(\"unkey\", \"UnkeyApiKeysConsole\"),\n ],\n };\n}\n\nfunction billingUIFeature(input: { provider: \"stripe\" | \"polar\" | \"autumn\"; label: string }) {\n return {\n name: `${input.provider}-billing`,\n description: `${input.label} pricing and checkout UI`,\n components: [\"badge\", \"button\", \"card\"],\n notes: [\n `Open \"/integrations/${input.provider}\" to try the generated ${input.label} billing UI.`,\n ],\n files: (templateInput) => [\n componentFile(\n `${input.provider}-billing.tsx`,\n billingPricingTemplate({\n key: templateInput.key,\n provider: input.provider,\n label: input.label,\n componentName: `${pascalCase(input.provider)}Billing`,\n }),\n ),\n integrationPageFile(input.provider, `${pascalCase(input.provider)}Billing`),\n ],\n };\n}\n\nfunction authRouteShellUIFeature(input: {\n provider: \"authjs\" | \"better-auth\" | \"clerk\";\n label: string;\n componentName: string;\n signInHref: string;\n signUpHref: string;\n sessionHref: string;\n}): UIFeatureDefinition {\n return {\n name: `${input.provider}-auth`,\n description: `${input.label} auth UI`,\n components: [\"badge\", \"button\", \"card\"],\n notes: [`Open \"/integrations/${input.provider}\" to try the generated auth UI.`],\n files: () => [\n componentFile(\n `${input.provider}-auth-panel.tsx`,\n authRouteShellTemplate({\n provider: input.label,\n componentName: input.componentName,\n signInHref: input.signInHref,\n signUpHref: input.signUpHref,\n sessionHref: input.sessionHref,\n }),\n ),\n integrationPageFile(input.provider, input.componentName),\n ],\n };\n}\n\nfunction componentFile(fileName: string, source: string): UIFeatureFile {\n return {\n path: path.join(\"src\", \"components\", \"farm\", fileName),\n source,\n };\n}\n\nfunction integrationPageFile(provider: string, componentName: string): UIFeatureFile {\n const fileName = kebabCase(componentName);\n\n return {\n path: path.join(\"src\", \"app\", \"integrations\", provider, \"page.tsx\"),\n source: `import { ${componentName} } from \"@/components/farm/${fileName}\";\n\nexport default function ${componentName}Page() {\n return <${componentName} />;\n}\n`,\n };\n}\n\nasync function writeGeneratedFile(input: {\n root: string;\n relativePath: string;\n source: string;\n dryRun?: boolean;\n force?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const absolutePath = path.join(input.root, input.relativePath);\n const exists = existsSync(absolutePath);\n const source = resolveGeneratedAliases(input.source, input.relativePath);\n input.result.ui?.files.push(absolutePath);\n\n if (exists && !input.force) {\n pushResultPath(input.result.skipped, absolutePath);\n return;\n }\n\n if (!input.dryRun) {\n await mkdir(path.dirname(absolutePath), { recursive: true });\n await writeFile(absolutePath, source, \"utf8\");\n }\n\n pushResultPath(exists ? input.result.updated : input.result.created, absolutePath);\n}\n\nfunction resolveGeneratedAliases(source: string, relativePath: string) {\n const sourceDirectory = path.dirname(relativePath);\n\n return source.replace(/([\"'])@\\/([^\"']+)\\1/g, (_match, quote: string, target: string) => {\n const relativeTarget = path\n .relative(sourceDirectory, path.join(\"src\", target))\n .split(path.sep)\n .join(\"/\");\n const importPath = relativeTarget.startsWith(\".\") ? relativeTarget : `./${relativeTarget}`;\n return `${quote}${importPath}${quote}`;\n });\n}\n\nasync function ensureComponentsJson(input: {\n root: string;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const componentsJsonPath = path.join(input.root, \"components.json\");\n input.result.ui?.files.push(componentsJsonPath);\n const defaults = createComponentsJson();\n\n if (!existsSync(componentsJsonPath)) {\n if (!input.dryRun) {\n await writeFile(componentsJsonPath, `${JSON.stringify(defaults, null, 2)}\\n`, \"utf8\");\n }\n pushResultPath(input.result.created, componentsJsonPath);\n return;\n }\n\n let current: Record<string, unknown>;\n try {\n current = JSON.parse(await readFile(componentsJsonPath, \"utf8\")) as Record<string, unknown>;\n } catch {\n pushResultPath(input.result.skipped, componentsJsonPath);\n input.result.notes.push(\n \"components.json could not be parsed. Keep shadcn aliases pointed at src/components and src/lib/utils.\",\n );\n return;\n }\n\n const next = mergeComponentsJson(current, defaults);\n if (JSON.stringify(current) === JSON.stringify(next)) {\n pushResultPath(input.result.skipped, componentsJsonPath);\n return;\n }\n\n if (!input.dryRun) {\n await writeFile(componentsJsonPath, `${JSON.stringify(next, null, 2)}\\n`, \"utf8\");\n }\n pushResultPath(input.result.updated, componentsJsonPath);\n}\n\nasync function ensureShadcnGlobals(input: {\n root: string;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const globalsPath = path.join(input.root, \"src\", \"app\", \"globals.css\");\n input.result.ui?.files.push(globalsPath);\n\n if (!existsSync(globalsPath)) {\n const source = `@import \"tailwindcss\";\n\n${SHADCN_THEME_CSS}\n`;\n if (!input.dryRun) {\n await mkdir(path.dirname(globalsPath), { recursive: true });\n await writeFile(globalsPath, source, \"utf8\");\n }\n pushResultPath(input.result.created, globalsPath);\n return;\n }\n\n const source = await readFile(globalsPath, \"utf8\");\n const hasTailwindImport = source.includes('@import \"tailwindcss\"');\n const hasTheme = source.includes(\"--color-background\") || source.includes(\"--background:\");\n if (hasTailwindImport && hasTheme) {\n pushResultPath(input.result.skipped, globalsPath);\n return;\n }\n\n const nextSource = `${hasTailwindImport ? \"\" : '@import \"tailwindcss\";\\n\\n'}${source.trimEnd()}${\n hasTheme\n ? \"\\n\"\n : `\n\n${SHADCN_THEME_CSS}\n`\n }`;\n if (!input.dryRun) {\n await writeFile(globalsPath, nextSource, \"utf8\");\n }\n pushResultPath(input.result.updated, globalsPath);\n}\n\nasync function ensureTsconfigAlias(input: {\n root: string;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const tsconfigPath = path.join(input.root, \"tsconfig.json\");\n input.result.ui?.files.push(tsconfigPath);\n const defaults = {\n compilerOptions: {\n baseUrl: \".\",\n paths: {\n \"@/*\": [\"./src/*\"],\n },\n },\n };\n\n if (!existsSync(tsconfigPath)) {\n if (!input.dryRun) {\n await writeFile(tsconfigPath, `${JSON.stringify(defaults, null, 2)}\\n`, \"utf8\");\n }\n pushResultPath(input.result.created, tsconfigPath);\n return;\n }\n\n let tsconfig: Record<string, unknown>;\n try {\n tsconfig = JSON.parse(await readFile(tsconfigPath, \"utf8\")) as Record<string, unknown>;\n } catch {\n pushResultPath(input.result.skipped, tsconfigPath);\n input.result.notes.push(\n 'tsconfig.json could not be parsed. Add paths: { \"@/*\": [\"./src/*\"] } manually.',\n );\n return;\n }\n\n const compilerOptions = readObject(tsconfig.compilerOptions);\n const paths = readObject(compilerOptions.paths);\n const nextCompilerOptions = {\n ...compilerOptions,\n baseUrl: typeof compilerOptions.baseUrl === \"string\" ? compilerOptions.baseUrl : \".\",\n paths: {\n ...paths,\n \"@/*\": [\"./src/*\"],\n },\n };\n const nextTsconfig = {\n ...tsconfig,\n compilerOptions: nextCompilerOptions,\n };\n\n if (JSON.stringify(tsconfig) === JSON.stringify(nextTsconfig)) {\n pushResultPath(input.result.skipped, tsconfigPath);\n return;\n }\n\n if (!input.dryRun) {\n await writeFile(tsconfigPath, `${JSON.stringify(nextTsconfig, null, 2)}\\n`, \"utf8\");\n }\n pushResultPath(input.result.updated, tsconfigPath);\n}\n\nasync function updateUIPackageJson(input: {\n root: string;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const packageJsonPath = path.join(input.root, \"package.json\");\n input.result.ui?.files.push(packageJsonPath);\n if (!existsSync(packageJsonPath)) {\n pushResultPath(input.result.skipped, packageJsonPath);\n return;\n }\n\n const source = await readFile(packageJsonPath, \"utf8\");\n const manifest = JSON.parse(source) as PackageManifest;\n let changed = false;\n\n for (const [dependency, version] of Object.entries(UI_DEPENDENCIES)) {\n if (hasPackageDependency(manifest, dependency)) {\n continue;\n }\n\n manifest.dependencies = {\n ...manifest.dependencies,\n [dependency]: version,\n };\n changed = true;\n }\n\n if (!changed) {\n pushResultPath(input.result.skipped, packageJsonPath);\n return;\n }\n\n if (!input.dryRun) {\n await writeFile(packageJsonPath, `${JSON.stringify(manifest, null, 2)}\\n`, \"utf8\");\n }\n input.result.packageJson = packageJsonPath;\n pushResultPath(input.result.updated, packageJsonPath);\n}\n\nconst UI_DEPENDENCIES = {\n \"class-variance-authority\": \"^0.7.1\",\n clsx: \"^2.1.1\",\n \"tailwind-merge\": \"^3.3.1\",\n tailwindcss: \"^4.1.18\",\n} as const;\n\nconst SHADCN_THEME_CSS = `@custom-variant dark (&:is(.dark *));\n\n@theme inline {\n --color-background: var(--background);\n --color-foreground: var(--foreground);\n --color-card: var(--card);\n --color-card-foreground: var(--card-foreground);\n --color-popover: var(--popover);\n --color-popover-foreground: var(--popover-foreground);\n --color-primary: var(--primary);\n --color-primary-foreground: var(--primary-foreground);\n --color-secondary: var(--secondary);\n --color-secondary-foreground: var(--secondary-foreground);\n --color-muted: var(--muted);\n --color-muted-foreground: var(--muted-foreground);\n --color-accent: var(--accent);\n --color-accent-foreground: var(--accent-foreground);\n --color-destructive: var(--destructive);\n --color-border: var(--border);\n --color-input: var(--input);\n --color-ring: var(--ring);\n --radius-sm: calc(var(--radius) - 4px);\n --radius-md: calc(var(--radius) - 2px);\n --radius-lg: var(--radius);\n}\n\n:root {\n --radius: 0.5rem;\n --background: oklch(1 0 0);\n --foreground: oklch(0.145 0 0);\n --card: oklch(1 0 0);\n --card-foreground: oklch(0.145 0 0);\n --popover: oklch(1 0 0);\n --popover-foreground: oklch(0.145 0 0);\n --primary: oklch(0.205 0 0);\n --primary-foreground: oklch(0.985 0 0);\n --secondary: oklch(0.97 0 0);\n --secondary-foreground: oklch(0.205 0 0);\n --muted: oklch(0.97 0 0);\n --muted-foreground: oklch(0.556 0 0);\n --accent: oklch(0.97 0 0);\n --accent-foreground: oklch(0.205 0 0);\n --destructive: oklch(0.577 0.245 27.325);\n --border: oklch(0.922 0 0);\n --input: oklch(0.922 0 0);\n --ring: oklch(0.708 0 0);\n}\n\n.dark {\n --background: oklch(0.145 0 0);\n --foreground: oklch(0.985 0 0);\n --card: oklch(0.205 0 0);\n --card-foreground: oklch(0.985 0 0);\n --popover: oklch(0.205 0 0);\n --popover-foreground: oklch(0.985 0 0);\n --primary: oklch(0.922 0 0);\n --primary-foreground: oklch(0.205 0 0);\n --secondary: oklch(0.269 0 0);\n --secondary-foreground: oklch(0.985 0 0);\n --muted: oklch(0.269 0 0);\n --muted-foreground: oklch(0.708 0 0);\n --accent: oklch(0.269 0 0);\n --accent-foreground: oklch(0.985 0 0);\n --destructive: oklch(0.704 0.191 22.216);\n --border: oklch(1 0 0 / 10%);\n --input: oklch(1 0 0 / 15%);\n --ring: oklch(0.556 0 0);\n}\n\n@layer base {\n * {\n @apply border-border outline-ring/50;\n }\n\n body {\n @apply bg-background text-foreground;\n }\n}`;\n\nfunction createComponentsJson() {\n return {\n $schema: \"https://ui.shadcn.com/schema.json\",\n style: \"new-york\",\n rsc: true,\n tsx: true,\n tailwind: {\n config: \"\",\n css: \"src/app/globals.css\",\n baseColor: \"zinc\",\n cssVariables: true,\n },\n aliases: {\n components: \"@/components\",\n utils: \"@/lib/utils\",\n ui: \"@/components/ui\",\n lib: \"@/lib\",\n hooks: \"@/hooks\",\n },\n registries: {\n farm: {\n url: \"https://farmjs.dev/r/{name}.json\",\n },\n },\n };\n}\n\nfunction mergeComponentsJson(\n current: Record<string, unknown>,\n defaults: ReturnType<typeof createComponentsJson>,\n) {\n const aliases = readObject(current.aliases);\n const tailwind = readObject(current.tailwind);\n const registries = readObject(current.registries);\n\n return {\n ...current,\n $schema: typeof current.$schema === \"string\" ? current.$schema : defaults.$schema,\n style: typeof current.style === \"string\" ? current.style : defaults.style,\n rsc: typeof current.rsc === \"boolean\" ? current.rsc : defaults.rsc,\n tsx: typeof current.tsx === \"boolean\" ? current.tsx : defaults.tsx,\n tailwind: {\n ...defaults.tailwind,\n ...tailwind,\n },\n aliases: {\n ...defaults.aliases,\n ...aliases,\n },\n registries: {\n ...registries,\n farm: readObject(registries.farm).url ? registries.farm : defaults.registries.farm,\n },\n };\n}\n\nfunction shadcnUtilsTemplate() {\n return `import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n`;\n}\n\nfunction apiClientTemplate() {\n return `import { createIntegrations } from \"@farm.js/core/client\";\nimport type { AppIntegrations } from \"./integrations\";\n\nexport const { api, apiClient } = createIntegrations<AppIntegrations>();\n`;\n}\n\nfunction shadcnComponentTemplate(component: ShadcnComponentName) {\n switch (component) {\n case \"badge\":\n return `import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@/lib/utils\";\n\nconst badgeVariants = cva(\n \"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2\",\n {\n variants: {\n variant: {\n default: \"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80\",\n secondary: \"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n outline: \"text-foreground\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\nexport interface BadgeProps\n extends React.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof badgeVariants> {}\n\nexport function Badge({ className, variant, ...props }: BadgeProps) {\n return <div className={cn(badgeVariants({ variant }), className)} {...props} />;\n}\n\nexport { badgeVariants };\n`;\n case \"button\":\n return `import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@/lib/utils\";\n\nconst buttonVariants = cva(\n \"inline-flex h-9 items-center justify-center whitespace-nowrap rounded-md px-4 py-2 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground shadow hover:bg-primary/90\",\n secondary: \"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80\",\n outline: \"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n sm: \"h-8 rounded-md px-3 text-xs\",\n lg: \"h-10 rounded-md px-8\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {}\n\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, ...props }, ref) => {\n return (\n <button\n className={cn(buttonVariants({ variant, size, className }))}\n ref={ref}\n {...props}\n />\n );\n },\n);\nButton.displayName = \"Button\";\n\nexport { buttonVariants };\n`;\n case \"card\":\n return `import * as React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"rounded-lg border bg-card text-card-foreground shadow-sm\", className)}\n {...props}\n />\n ),\n);\nCard.displayName = \"Card\";\n\nexport const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex flex-col space-y-1.5 p-6\", className)} {...props} />\n ),\n);\nCardHeader.displayName = \"CardHeader\";\n\nexport const CardTitle = React.forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTMLHeadingElement>>(\n ({ className, ...props }, ref) => (\n <h3 ref={ref} className={cn(\"text-2xl font-semibold leading-none tracking-normal\", className)} {...props} />\n ),\n);\nCardTitle.displayName = \"CardTitle\";\n\nexport const CardDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(\n ({ className, ...props }, ref) => (\n <p ref={ref} className={cn(\"text-sm text-muted-foreground\", className)} {...props} />\n ),\n);\nCardDescription.displayName = \"CardDescription\";\n\nexport const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"p-6 pt-0\", className)} {...props} />\n ),\n);\nCardContent.displayName = \"CardContent\";\n\nexport const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex items-center p-6 pt-0\", className)} {...props} />\n ),\n);\nCardFooter.displayName = \"CardFooter\";\n`;\n case \"input\":\n return `import * as React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}\n\nexport const Input = React.forwardRef<HTMLInputElement, InputProps>(\n ({ className, type, ...props }, ref) => (\n <input\n type={type}\n className={cn(\n \"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n ref={ref}\n {...props}\n />\n ),\n);\nInput.displayName = \"Input\";\n`;\n case \"label\":\n return `import * as React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport const Label = React.forwardRef<HTMLLabelElement, React.LabelHTMLAttributes<HTMLLabelElement>>(\n ({ className, ...props }, ref) => (\n <label\n ref={ref}\n className={cn(\"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\", className)}\n {...props}\n />\n ),\n);\nLabel.displayName = \"Label\";\n`;\n }\n}\n\nfunction billingPricingTemplate(input: {\n key: string;\n provider: \"stripe\" | \"polar\" | \"autumn\";\n label: string;\n componentName: string;\n}) {\n return `\"use client\";\n\nimport * as React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Card,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from \"@/components/ui/card\";\nimport { apiClient } from \"@/lib/api\";\n\ntype BillingProduct = NonNullable<Awaited<ReturnType<typeof apiClient.${input.key}.products>>[\"data\"]>[number];\n\nexport function ${input.componentName}() {\n const [products, setProducts] = React.useState<BillingProduct[]>([]);\n const [loading, setLoading] = React.useState(true);\n const [checkingOut, setCheckingOut] = React.useState<string | null>(null);\n const [error, setError] = React.useState<string | null>(null);\n\n React.useEffect(() => {\n let active = true;\n\n async function loadProducts() {\n setLoading(true);\n setError(null);\n\n try {\n const response = await apiClient.${input.key}.products();\n if (response.error) {\n throw new Error(readErrorMessage(response.error, \"${input.label} request failed.\"));\n }\n\n if (active) {\n setProducts(Array.from(response.data ?? []));\n }\n } catch (cause) {\n if (active) {\n setError(cause instanceof Error ? cause.message : \"Could not load ${input.label} products.\");\n }\n } finally {\n if (active) {\n setLoading(false);\n }\n }\n }\n\n void loadProducts();\n\n return () => {\n active = false;\n };\n }, []);\n\n async function startCheckout(product: BillingProduct) {\n const productId = String(readProductField(product, \"id\") ?? \"\");\n if (!productId) {\n setError(\"This Stripe product is missing an id.\");\n return;\n }\n\n setCheckingOut(productId);\n setError(null);\n\n try {\n const response = await apiClient.${input.key}.checkout({\n body: {\n productId,\n successPath: \"/billing/success\",\n cancelPath: \"/integrations/${input.provider}\",\n },\n });\n if (response.error) {\n throw new Error(readErrorMessage(response.error, \"${input.label} checkout failed.\"));\n }\n\n const redirectTo = response.data?.redirectTo;\n if (!redirectTo) {\n throw new Error(\"${input.label} checkout did not return a redirect URL.\");\n }\n\n window.location.assign(redirectTo);\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : \"Could not start ${input.label} checkout.\");\n setCheckingOut(null);\n }\n }\n\n return (\n <main className=\"min-h-screen bg-background px-6 py-12 text-foreground\">\n <section className=\"mx-auto flex w-full max-w-5xl flex-col gap-8\">\n <div className=\"max-w-2xl space-y-3\">\n <Badge variant=\"secondary\">${input.label}</Badge>\n <h1 className=\"text-3xl font-semibold tracking-normal\">${input.label} billing</h1>\n <p className=\"text-sm leading-6 text-muted-foreground\">\n Plans, checkout, and customer billing actions in one place.\n </p>\n </div>\n\n {error ? (\n <div className=\"rounded-md border border-destructive/30 bg-destructive/10 px-4 py-3 text-sm text-destructive\">\n {error}\n </div>\n ) : null}\n\n {loading ? (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {Array.from({ length: 3 }).map((_, index) => (\n <Card key={index} className=\"min-h-[220px] animate-pulse\" />\n ))}\n </div>\n ) : products.length ? (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {products.map((product) => {\n const productId = String(readProductField(product, \"id\") ?? \"\");\n const fallbackName = productId || \"Product\";\n const name = String(readProductField(product, \"name\") ?? fallbackName);\n const description =\n readProductField(product, \"description\") ?? \"Connected to your Stripe catalog.\";\n\n return (\n <Card key={productId || name} className=\"flex min-h-[260px] flex-col\">\n <CardHeader>\n <CardTitle className=\"text-xl\">{name}</CardTitle>\n <CardDescription>{String(description)}</CardDescription>\n </CardHeader>\n <CardContent className=\"flex-1\">\n <div className=\"text-3xl font-semibold\">{formatProductPrice(product)}</div>\n </CardContent>\n <CardFooter>\n <Button\n className=\"w-full\"\n disabled={!productId || checkingOut === productId}\n onClick={() => void startCheckout(product)}\n >\n {checkingOut === productId ? \"Starting checkout...\" : \"Checkout\"}\n </Button>\n </CardFooter>\n </Card>\n );\n })}\n </div>\n ) : (\n <Card>\n <CardHeader>\n <CardTitle>No products yet</CardTitle>\n <CardDescription>\n Add products to the generated ${input.label} integration template or provider dashboard.\n </CardDescription>\n </CardHeader>\n </Card>\n )}\n </section>\n </main>\n );\n}\n\nfunction readProductField(product: BillingProduct, field: string) {\n return (product as Record<string, unknown>)[field];\n}\n\nfunction formatProductPrice(product: BillingProduct) {\n const amount = readProductField(product, \"amount\") ?? readProductField(product, \"unitAmount\");\n const currency = String(readProductField(product, \"currency\") ?? \"USD\").toUpperCase();\n const interval = readProductField(product, \"interval\");\n\n if (typeof amount === \"number\" && Number.isFinite(amount)) {\n const formatted = new Intl.NumberFormat(\"en\", {\n style: \"currency\",\n currency,\n }).format(amount / 100);\n\n return interval ? \\`\\${formatted}/\\${String(interval)}\\` : formatted;\n }\n\n return \"Custom\";\n}\n\nfunction readErrorMessage(error: unknown, fallback: string) {\n if (error && typeof error === \"object\" && \"message\" in error) {\n return String((error as { message?: unknown }).message);\n }\n\n return fallback;\n}\n`;\n}\n\nfunction aiChatTemplate() {\n return `\"use client\";\n\nimport * as React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Input } from \"@/components/ui/input\";\n\ntype ChatMessage = {\n role: \"user\" | \"assistant\";\n content: string;\n};\n\nexport function AIChat() {\n const [messages, setMessages] = React.useState<ChatMessage[]>([]);\n const [input, setInput] = React.useState(\"\");\n const [pending, setPending] = React.useState(false);\n const [error, setError] = React.useState<string | null>(null);\n\n async function sendMessage(event: React.FormEvent<HTMLFormElement>) {\n event.preventDefault();\n const nextInput = input.trim();\n if (!nextInput) {\n return;\n }\n\n const nextMessages: ChatMessage[] = [...messages, { role: \"user\", content: nextInput }];\n setMessages(nextMessages);\n setInput(\"\");\n setPending(true);\n setError(null);\n\n try {\n const response = await fetch(\"/api/chat\", {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n messages: nextMessages.map((message) => ({\n role: message.role,\n parts: [{ type: \"text\", text: message.content }],\n })),\n }),\n });\n\n const text = await response.text();\n if (!response.ok) {\n throw new Error(text || \"AI request failed.\");\n }\n\n setMessages([...nextMessages, { role: \"assistant\", content: text || \"Done.\" }]);\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : \"AI request failed.\");\n } finally {\n setPending(false);\n }\n }\n\n return (\n <main className=\"min-h-screen bg-background px-6 py-12 text-foreground\">\n <section className=\"mx-auto flex w-full max-w-3xl flex-col gap-6\">\n <div className=\"space-y-3\">\n <Badge variant=\"secondary\">AI</Badge>\n <h1 className=\"text-3xl font-semibold tracking-normal\">Chat</h1>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-xl\">Conversation</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"min-h-[320px] space-y-3 rounded-md border bg-muted/30 p-4\">\n {messages.length ? (\n messages.map((message, index) => (\n <div\n key={index}\n className={message.role === \"user\" ? \"ml-auto max-w-[85%] rounded-md bg-primary px-3 py-2 text-sm text-primary-foreground\" : \"max-w-[85%] rounded-md bg-background px-3 py-2 text-sm\"}\n >\n {message.content}\n </div>\n ))\n ) : (\n <p className=\"text-sm text-muted-foreground\">Start a conversation.</p>\n )}\n </div>\n\n {error ? <p className=\"text-sm text-destructive\">{error}</p> : null}\n\n <form className=\"flex gap-2\" onSubmit={sendMessage}>\n <Input\n value={input}\n onChange={(event) => setInput(event.target.value)}\n placeholder=\"Ask something...\"\n />\n <Button disabled={pending} type=\"submit\">\n {pending ? \"Sending...\" : \"Send\"}\n </Button>\n </form>\n </CardContent>\n </Card>\n </section>\n </main>\n );\n}\n`;\n}\n\nfunction supabaseAuthTemplate(key: string) {\n return `\"use client\";\n\nimport * as React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { apiClient } from \"@/lib/api\";\n\nexport function SupabaseAuthPanel() {\n const [email, setEmail] = React.useState(\"\");\n const [password, setPassword] = React.useState(\"\");\n const [mode, setMode] = React.useState<\"login\" | \"signup\">(\"login\");\n const [pending, setPending] = React.useState(false);\n const [status, setStatus] = React.useState<string | null>(null);\n\n async function submit(event: React.FormEvent<HTMLFormElement>) {\n event.preventDefault();\n setPending(true);\n setStatus(null);\n\n const response =\n mode === \"login\"\n ? await apiClient.${key}.login.post({ body: { email, password, returnTo: \"/dashboard\" } })\n : await apiClient.${key}.signup.post({ body: { email, password, returnTo: \"/dashboard\" } });\n\n if (response.error) {\n setStatus(response.error.message);\n setPending(false);\n return;\n }\n\n if (response.data?.redirectTo) {\n window.location.assign(response.data.redirectTo);\n return;\n }\n\n setStatus(response.data?.message ?? \"Check your email to continue.\");\n setPending(false);\n }\n\n async function loadSession() {\n const response = await apiClient.${key}.session.get();\n setStatus(response.error ? response.error.message : response.data?.authenticated ? \"Authenticated\" : \"No active session\");\n }\n\n async function logout() {\n const response = await apiClient.${key}.logout.post({ body: { returnTo: \"/\" } });\n if (response.data?.redirectTo) {\n window.location.assign(response.data.redirectTo);\n return;\n }\n setStatus(response.error?.message ?? \"Signed out\");\n }\n\n return (\n <main className=\"min-h-screen bg-background px-6 py-12 text-foreground\">\n <section className=\"mx-auto flex w-full max-w-xl flex-col gap-6\">\n <div className=\"space-y-3\">\n <Badge variant=\"secondary\">Supabase</Badge>\n <h1 className=\"text-3xl font-semibold tracking-normal\">Auth</h1>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-xl\">{mode === \"login\" ? \"Sign in\" : \"Create account\"}</CardTitle>\n <CardDescription>Email and password access for this app.</CardDescription>\n </CardHeader>\n <CardContent>\n <form className=\"space-y-4\" onSubmit={submit}>\n <div className=\"space-y-2\">\n <Label htmlFor=\"email\">Email</Label>\n <Input id=\"email\" value={email} onChange={(event) => setEmail(event.target.value)} type=\"email\" />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"password\">Password</Label>\n <Input id=\"password\" value={password} onChange={(event) => setPassword(event.target.value)} type=\"password\" />\n </div>\n {status ? <p className=\"text-sm text-muted-foreground\">{status}</p> : null}\n <div className=\"flex flex-wrap gap-2\">\n <Button disabled={pending} type=\"submit\">{pending ? \"Working...\" : mode === \"login\" ? \"Sign in\" : \"Sign up\"}</Button>\n <Button type=\"button\" variant=\"outline\" onClick={() => setMode(mode === \"login\" ? \"signup\" : \"login\")}>\n {mode === \"login\" ? \"Use sign up\" : \"Use sign in\"}\n </Button>\n <Button type=\"button\" variant=\"ghost\" onClick={() => void loadSession()}>Session</Button>\n <Button type=\"button\" variant=\"ghost\" onClick={() => void logout()}>Logout</Button>\n </div>\n </form>\n </CardContent>\n </Card>\n </section>\n </main>\n );\n}\n`;\n}\n\nfunction hostedAuthTemplate(input: {\n key: string;\n provider: string;\n componentName: string;\n statusCall: string;\n logoutCall: string;\n loginHref: string;\n signupHref: string;\n statusLabel: string;\n}) {\n return `\"use client\";\n\nimport * as React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { apiClient } from \"@/lib/api\";\n\nexport function ${input.componentName}() {\n const [status, setStatus] = React.useState<string>(\"Idle\");\n const [pending, setPending] = React.useState(false);\n\n async function refreshStatus() {\n setPending(true);\n const response = await apiClient.${input.key}.${input.statusCall}();\n if (response.error) {\n setStatus(response.error.message);\n } else {\n setStatus(response.data?.authenticated ? \"Authenticated\" : \"No active session\");\n }\n setPending(false);\n }\n\n async function logout() {\n setPending(true);\n const response = await apiClient.${input.key}.${input.logoutCall}();\n if (response.data?.redirectTo) {\n window.location.assign(response.data.redirectTo);\n return;\n }\n setStatus(response.error?.message ?? \"Signed out\");\n setPending(false);\n }\n\n return (\n <main className=\"min-h-screen bg-background px-6 py-12 text-foreground\">\n <section className=\"mx-auto flex w-full max-w-3xl flex-col gap-6\">\n <div className=\"space-y-3\">\n <Badge variant=\"secondary\">${input.provider}</Badge>\n <h1 className=\"text-3xl font-semibold tracking-normal\">Auth</h1>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-xl\">${input.provider} session</CardTitle>\n <CardDescription>Hosted auth, account session, and sign-out controls.</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <p className=\"rounded-md border bg-muted/30 px-3 py-2 text-sm\">{status}</p>\n <div className=\"flex flex-wrap gap-2\">\n <Button type=\"button\" onClick={() => window.location.assign(\"${input.loginHref}\")}>Sign in</Button>\n <Button type=\"button\" variant=\"outline\" onClick={() => window.location.assign(\"${input.signupHref}\")}>Sign up</Button>\n <Button type=\"button\" variant=\"ghost\" disabled={pending} onClick={() => void refreshStatus()}>Refresh</Button>\n <Button type=\"button\" variant=\"ghost\" disabled={pending} onClick={() => void logout()}>Logout</Button>\n </div>\n </CardContent>\n </Card>\n </section>\n </main>\n );\n}\n`;\n}\n\nfunction authRouteShellTemplate(input: {\n provider: string;\n componentName: string;\n signInHref: string;\n signUpHref: string;\n sessionHref: string;\n}) {\n return `\"use client\";\n\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from \"@/components/ui/card\";\n\nexport function ${input.componentName}() {\n return (\n <main className=\"min-h-screen bg-background px-6 py-12 text-foreground\">\n <section className=\"mx-auto flex w-full max-w-3xl flex-col gap-6\">\n <div className=\"space-y-3\">\n <Badge variant=\"secondary\">${input.provider}</Badge>\n <h1 className=\"text-3xl font-semibold tracking-normal\">Auth</h1>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-xl\">${input.provider} routes</CardTitle>\n <CardDescription>Account entry points and session route.</CardDescription>\n </CardHeader>\n <CardContent className=\"flex flex-wrap gap-2\">\n <Button type=\"button\" onClick={() => window.location.assign(\"${input.signInHref}\")}>Sign in</Button>\n <Button type=\"button\" variant=\"outline\" onClick={() => window.location.assign(\"${input.signUpHref}\")}>Sign up</Button>\n <Button type=\"button\" variant=\"ghost\" onClick={() => window.location.assign(\"${input.sessionHref}\")}>Session</Button>\n </CardContent>\n </Card>\n </section>\n </main>\n );\n}\n`;\n}\n\nfunction betterAuthClientTemplate() {\n return `import { createAuthClient } from \"better-auth/react\";\n\nexport const authClient = createAuthClient({\n baseURL: \"\",\n});\n`;\n}\n\nfunction betterAuthPanelTemplate() {\n return `\"use client\";\n\nimport * as React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { authClient } from \"@/lib/auth-client\";\n\ntype Mode = \"sign-in\" | \"sign-up\";\n\nexport function BetterAuthPanel() {\n const [mode, setMode] = React.useState<Mode>(\"sign-in\");\n const [pending, setPending] = React.useState(false);\n const [message, setMessage] = React.useState(\"Ready\");\n const [sessionEmail, setSessionEmail] = React.useState<string | null>(null);\n\n async function submit(event: React.FormEvent<HTMLFormElement>) {\n event.preventDefault();\n setPending(true);\n setMessage(mode === \"sign-in\" ? \"Signing in…\" : \"Creating account…\");\n\n const form = new FormData(event.currentTarget);\n const email = String(form.get(\"email\") || \"\");\n const password = String(form.get(\"password\") || \"\");\n const name = String(form.get(\"name\") || \"\");\n try {\n const response =\n mode === \"sign-in\"\n ? await authClient.signIn.email({ email, password })\n : await authClient.signUp.email({ email, password, name });\n\n if (response.error) {\n setMessage(response.error.message || \"Authentication failed.\");\n return;\n }\n\n setSessionEmail(email);\n setMessage(mode === \"sign-in\" ? \"Signed in.\" : \"Account created.\");\n } catch (cause) {\n setMessage(cause instanceof Error ? cause.message : \"Could not reach the auth server.\");\n } finally {\n setPending(false);\n }\n }\n\n async function refreshSession() {\n setPending(true);\n try {\n const response = await authClient.getSession();\n setSessionEmail(response.data?.user.email || null);\n setMessage(response.error?.message || (response.data ? \"Session active.\" : \"No active session.\"));\n } catch (cause) {\n setMessage(cause instanceof Error ? cause.message : \"Could not read the session.\");\n } finally {\n setPending(false);\n }\n }\n\n async function signOut() {\n setPending(true);\n try {\n const response = await authClient.signOut();\n if (response.error) {\n setMessage(response.error.message || \"Could not sign out.\");\n return;\n }\n setSessionEmail(null);\n setMessage(\"Signed out.\");\n } catch (cause) {\n setMessage(cause instanceof Error ? cause.message : \"Could not reach the auth server.\");\n } finally {\n setPending(false);\n }\n }\n\n return (\n <main className=\"min-h-screen bg-background px-5 py-12 text-foreground sm:px-8\">\n <section className=\"mx-auto grid w-full max-w-5xl gap-8 lg:grid-cols-[1fr_420px] lg:items-start\">\n <div className=\"space-y-5 py-4\">\n <Badge variant=\"secondary\">Better Auth × Farm.js</Badge>\n <div className=\"space-y-3\">\n <h1 className=\"max-w-xl text-4xl font-semibold tracking-tight sm:text-5xl\">\n Authentication that starts ready.\n </h1>\n <p className=\"max-w-xl text-base leading-7 text-muted-foreground\">\n Test account creation, email sign-in, session reads, and sign-out through Farm’s\n generated Better Auth integration.\n </p>\n </div>\n <div aria-live=\"polite\" className=\"border-l-2 border-primary pl-4 text-sm\">\n <p className=\"font-medium\">{message}</p>\n <p className=\"mt-1 text-muted-foreground\">\n {sessionEmail ? \\`Signed in as \\${sessionEmail}\\` : \"No authenticated user\"}\n </p>\n </div>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>{mode === \"sign-in\" ? \"Welcome back\" : \"Create an account\"}</CardTitle>\n <CardDescription>\n {mode === \"sign-in\"\n ? \"Enter your credentials to start a secure session.\"\n : \"Use an email and password to create your local account.\"}\n </CardDescription>\n </CardHeader>\n <CardContent>\n <form className=\"space-y-4\" onSubmit={submit}>\n {mode === \"sign-up\" ? (\n <div className=\"space-y-2\">\n <Label htmlFor=\"name\">Name</Label>\n <Input autoComplete=\"name\" id=\"name\" name=\"name\" required />\n </div>\n ) : null}\n <div className=\"space-y-2\">\n <Label htmlFor=\"email\">Email</Label>\n <Input autoComplete=\"email\" id=\"email\" name=\"email\" required type=\"email\" />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"password\">Password</Label>\n <Input\n autoComplete={mode === \"sign-in\" ? \"current-password\" : \"new-password\"}\n id=\"password\"\n minLength={8}\n name=\"password\"\n required\n type=\"password\"\n />\n </div>\n <Button className=\"w-full\" disabled={pending} type=\"submit\">\n {pending ? \"Working…\" : mode === \"sign-in\" ? \"Sign in\" : \"Create account\"}\n </Button>\n </form>\n\n <div className=\"mt-4 grid gap-2 sm:grid-cols-2\">\n <Button\n disabled={pending}\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setMode(mode === \"sign-in\" ? \"sign-up\" : \"sign-in\");\n setMessage(\"Ready\");\n }}\n >\n {mode === \"sign-in\" ? \"Create account\" : \"Use sign in\"}\n </Button>\n <Button disabled={pending} type=\"button\" variant=\"outline\" onClick={() => void refreshSession()}>\n Check session\n </Button>\n </div>\n <Button\n className=\"mt-2 w-full\"\n disabled={pending || !sessionEmail}\n type=\"button\"\n variant=\"ghost\"\n onClick={() => void signOut()}\n >\n Sign out\n </Button>\n </CardContent>\n </Card>\n </section>\n </main>\n );\n}\n`;\n}\n\nfunction resendEmailTemplate(key: string) {\n return `\"use client\";\n\nimport * as React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { apiClient } from \"@/lib/api\";\n\nexport function ResendEmailConsole() {\n const [to, setTo] = React.useState(\"\");\n const [name, setName] = React.useState(\"Ada\");\n const [templateId, setTemplateId] = React.useState(\"welcome\");\n const [status, setStatus] = React.useState(\"Idle\");\n const [previewHtml, setPreviewHtml] = React.useState(\"\");\n\n async function loadTemplates() {\n const response = await apiClient.${key}.templates.get();\n setStatus(response.error ? response.error.message : \"Templates: \" + (response.data ?? []).map((item) => item.id).join(\", \"));\n }\n\n async function preview() {\n const response = await apiClient.${key}.preview.post({\n body: {\n templateId,\n data: { name },\n },\n });\n if (response.error) {\n setStatus(response.error.message);\n return;\n }\n setPreviewHtml(response.data?.html ?? \"\");\n setStatus(response.data?.subject ?? \"Preview loaded\");\n }\n\n async function send() {\n const response = await apiClient.${key}.send.post({\n body: {\n templateId,\n to,\n data: { name },\n },\n });\n setStatus(response.error ? response.error.message : \"Sent \" + (response.data?.id ?? \"email\"));\n }\n\n return (\n <main className=\"min-h-screen bg-background px-6 py-12 text-foreground\">\n <section className=\"mx-auto flex w-full max-w-3xl flex-col gap-6\">\n <div className=\"space-y-3\">\n <Badge variant=\"secondary\">Resend</Badge>\n <h1 className=\"text-3xl font-semibold tracking-normal\">Email console</h1>\n </div>\n <Card>\n <CardHeader>\n <CardTitle className=\"text-xl\">Send template</CardTitle>\n <CardDescription>Template previews and delivery controls.</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid gap-4 sm:grid-cols-3\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"templateId\">Template</Label>\n <Input id=\"templateId\" value={templateId} onChange={(event) => setTemplateId(event.target.value)} />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"to\">To</Label>\n <Input id=\"to\" value={to} onChange={(event) => setTo(event.target.value)} />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"name\">Name</Label>\n <Input id=\"name\" value={name} onChange={(event) => setName(event.target.value)} />\n </div>\n </div>\n <p className=\"rounded-md border bg-muted/30 px-3 py-2 text-sm\">{status}</p>\n {previewHtml ? <div className=\"max-h-64 overflow-auto rounded-md border p-3 text-sm\" dangerouslySetInnerHTML={{ __html: previewHtml }} /> : null}\n <div className=\"flex flex-wrap gap-2\">\n <Button type=\"button\" variant=\"outline\" onClick={() => void loadTemplates()}>Templates</Button>\n <Button type=\"button\" variant=\"outline\" onClick={() => void preview()}>Preview</Button>\n <Button type=\"button\" onClick={() => void send()}>Send</Button>\n </div>\n </CardContent>\n </Card>\n </section>\n </main>\n );\n}\n`;\n}\n\nfunction jobsConsoleTemplate(key: string, label: string, provider: \"inngest\" | \"trigger\") {\n const componentName = `${pascalCase(provider)}JobsConsole`;\n\n return `\"use client\";\n\nimport * as React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { apiClient } from \"@/lib/api\";\n\ntype JobTask = {\n key: string;\n description?: string | null;\n};\n\nexport function ${componentName}() {\n const [tasks, setTasks] = React.useState<JobTask[]>([]);\n const [taskKey, setTaskKey] = React.useState(\"\");\n const [runId, setRunId] = React.useState(\"\");\n const [status, setStatus] = React.useState(\"Idle\");\n\n async function loadTasks() {\n const response = await apiClient.${key}.tasks.list();\n if (response.error) {\n setStatus(response.error.message);\n return;\n }\n const nextTasks = Array.from(response.data ?? []);\n setTasks(nextTasks);\n setTaskKey(nextTasks[0]?.key ?? \"\");\n setStatus(nextTasks.length ? \"Tasks loaded\" : \"No tasks registered yet\");\n }\n\n async function triggerTask() {\n const task = (apiClient.${key} as Record<string, any>)[taskKey];\n if (!task?.trigger) {\n setStatus(\"Select a task first.\");\n return;\n }\n const response = await task.trigger({ body: { input: {} } });\n setStatus(response.error ? response.error.message : \"Triggered \" + (response.data?.runId ?? response.data?.id ?? taskKey));\n }\n\n async function checkStatus() {\n const task = (apiClient.${key} as Record<string, any>)[taskKey];\n if (!task?.status || !runId) {\n setStatus(\"Enter a task and run id.\");\n return;\n }\n const response = await task.status({ query: { runId } });\n setStatus(response.error ? response.error.message : JSON.stringify(response.data));\n }\n\n return (\n <main className=\"min-h-screen bg-background px-6 py-12 text-foreground\">\n <section className=\"mx-auto flex w-full max-w-4xl flex-col gap-6\">\n <div className=\"space-y-3\">\n <Badge variant=\"secondary\">${label}</Badge>\n <h1 className=\"text-3xl font-semibold tracking-normal\">Jobs console</h1>\n </div>\n <Card>\n <CardHeader>\n <CardTitle className=\"text-xl\">Tasks</CardTitle>\n <CardDescription>Task runs and status checks.</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"taskKey\">Task key</Label>\n <Input id=\"taskKey\" value={taskKey} onChange={(event) => setTaskKey(event.target.value)} />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"runId\">Run id</Label>\n <Input id=\"runId\" value={runId} onChange={(event) => setRunId(event.target.value)} />\n </div>\n </div>\n <p className=\"rounded-md border bg-muted/30 px-3 py-2 text-sm\">{status}</p>\n <div className=\"flex flex-wrap gap-2\">\n <Button type=\"button\" variant=\"outline\" onClick={() => void loadTasks()}>Load tasks</Button>\n <Button type=\"button\" onClick={() => void triggerTask()}>Trigger</Button>\n <Button type=\"button\" variant=\"ghost\" onClick={() => void checkStatus()}>Status</Button>\n </div>\n {tasks.length ? (\n <div className=\"grid gap-2\">\n {tasks.map((task) => (\n <button key={task.key} className=\"rounded-md border px-3 py-2 text-left text-sm\" onClick={() => setTaskKey(task.key)} type=\"button\">\n {task.key}\n </button>\n ))}\n </div>\n ) : null}\n </CardContent>\n </Card>\n </section>\n </main>\n );\n}\n`;\n}\n\nfunction unkeyApiKeysTemplate(key: string) {\n return `\"use client\";\n\nimport * as React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { apiClient } from \"@/lib/api\";\n\nexport function UnkeyApiKeysConsole() {\n const [name, setName] = React.useState(\"Development key\");\n const [prefix, setPrefix] = React.useState(\"farm\");\n const [apiKey, setApiKey] = React.useState(\"\");\n const [status, setStatus] = React.useState(\"Idle\");\n\n async function createKey() {\n const response = await apiClient.${key}.createKey.post({\n body: {\n name,\n prefix,\n },\n });\n if (response.error) {\n setStatus(response.error.message);\n return;\n }\n setApiKey(response.data?.key ?? \"\");\n setStatus(\"Created \" + (response.data?.keyId ?? \"key\"));\n }\n\n async function verifyKey() {\n const response = await apiClient.${key}.verifyKey.post({\n body: {\n key: apiKey,\n },\n });\n setStatus(response.error ? response.error.message : response.data?.valid ? \"Valid key\" : \"Invalid key\");\n }\n\n return (\n <main className=\"min-h-screen bg-background px-6 py-12 text-foreground\">\n <section className=\"mx-auto flex w-full max-w-3xl flex-col gap-6\">\n <div className=\"space-y-3\">\n <Badge variant=\"secondary\">Unkey</Badge>\n <h1 className=\"text-3xl font-semibold tracking-normal\">API keys</h1>\n </div>\n <Card>\n <CardHeader>\n <CardTitle className=\"text-xl\">Key console</CardTitle>\n <CardDescription>API key lifecycle controls.</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"name\">Name</Label>\n <Input id=\"name\" value={name} onChange={(event) => setName(event.target.value)} />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"prefix\">Prefix</Label>\n <Input id=\"prefix\" value={prefix} onChange={(event) => setPrefix(event.target.value)} />\n </div>\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"apiKey\">API key</Label>\n <Input id=\"apiKey\" value={apiKey} onChange={(event) => setApiKey(event.target.value)} />\n </div>\n <p className=\"rounded-md border bg-muted/30 px-3 py-2 text-sm\">{status}</p>\n <div className=\"flex flex-wrap gap-2\">\n <Button type=\"button\" onClick={() => void createKey()}>Create key</Button>\n <Button type=\"button\" variant=\"outline\" onClick={() => void verifyKey()}>Verify</Button>\n </div>\n </CardContent>\n </Card>\n </section>\n </main>\n );\n}\n`;\n}\n\nfunction pascalCase(input: string) {\n return input\n .split(/[^A-Za-z0-9]+/g)\n .filter(Boolean)\n .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)\n .join(\"\");\n}\n\nfunction kebabCase(input: string) {\n return input\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .replace(/[^A-Za-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .toLowerCase();\n}\n\nfunction hasPackageDependency(manifest: PackageManifest, dependency: string) {\n return (\n dependency in (manifest.dependencies || {}) ||\n dependency in (manifest.devDependencies || {}) ||\n dependency in (manifest.peerDependencies || {}) ||\n dependency in (manifest.optionalDependencies || {})\n );\n}\n\nfunction readObject(value: unknown): Record<string, unknown> {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n\nfunction pushResultPath(list: string[], filePath: string) {\n if (!list.includes(filePath)) {\n list.push(filePath);\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n aiChatUIFeature,\n auth0AuthUIFeature,\n authjsUIFeature,\n autumnBillingUIFeature,\n betterAuthUIFeature,\n clerkAuthUIFeature,\n installUIFeature,\n jobsUIFeature,\n polarBillingUIFeature,\n resendEmailUIFeature,\n stripeBillingUIFeature,\n supabaseAuthUIFeature,\n unkeyApiKeysUIFeature,\n workosAuthUIFeature,\n type AddFarmIntegrationUIResult,\n type UIFeatureDefinition,\n} from \"./ui-feature-registry\";\n\nexport type { AddFarmIntegrationUIResult } from \"./ui-feature-registry\";\n\ntype PackageManifest = {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n};\n\nexport interface AddFarmIntegrationOptions {\n root?: string;\n provider: string;\n key?: string;\n integrationsFile?: string;\n routeFile?: string;\n ui?: boolean;\n skipPackageJson?: boolean;\n skipConfig?: boolean;\n dryRun?: boolean;\n force?: boolean;\n}\n\nexport interface AddFarmIntegrationResult {\n provider: FarmIntegrationProvider;\n key: string;\n mode?: \"integration\" | \"route\";\n integrationFile: string;\n registryFile: string;\n routeFile?: string;\n routePath?: string;\n packageJson?: string;\n configFile?: string;\n created: string[];\n updated: string[];\n skipped: string[];\n env: string[];\n notes: string[];\n ui?: AddFarmIntegrationUIResult;\n}\n\nexport type FarmIntegrationProvider =\n | \"ai\"\n | \"auth0\"\n | \"authjs\"\n | \"autumn\"\n | \"better-auth\"\n | \"clerk\"\n | \"jobs-inngest\"\n | \"jobs-trigger\"\n | \"polar\"\n | \"resend\"\n | \"stripe\"\n | \"supabase\"\n | \"unkey\"\n | \"workos\";\n\ninterface IntegrationProviderDefinition {\n provider: FarmIntegrationProvider;\n aliases: readonly string[];\n defaultKey: string;\n fileName: string;\n exportName: string;\n description: string;\n env: readonly string[];\n dependencies?: Readonly<Record<string, string>>;\n devDependencies?: Readonly<Record<string, string>>;\n setupFiles?: readonly {\n path: string;\n merge?: \"lines\";\n source(): string;\n }[];\n notes?: readonly string[];\n ui?: UIFeatureDefinition;\n template(): string;\n}\n\nconst PROVIDERS: readonly IntegrationProviderDefinition[] = [\n {\n provider: \"ai\",\n aliases: [\"ai-sdk\", \"vercel-ai\", \"vercel-ai-sdk\", \"chat\"],\n defaultKey: \"chat\",\n fileName: \"chat\",\n exportName: \"POST\",\n description: \"Vercel AI SDK chat route\",\n env: [\"AI_GATEWAY_API_KEY\"],\n notes: [\n 'Use @ai-sdk/react useChat with api: \"/api/chat\" on the client.',\n \"Replace model with any AI SDK provider model or Vercel AI Gateway model id.\",\n \"No farm.config integration wiring is required for this route.\",\n ],\n ui: aiChatUIFeature(),\n template: () => `import { aiChatRoute } from \"@farm.js/integrations/ai\";\n\nexport const POST = aiChatRoute({\n model: \"openai/gpt-4o-mini\",\n system: \"You are a helpful assistant.\",\n});\n`,\n },\n {\n provider: \"stripe\",\n aliases: [\"billing-stripe\", \"payments\", \"stripe-billing\"],\n defaultKey: \"billing\",\n fileName: \"stripe\",\n exportName: \"stripeIntegration\",\n description: \"Stripe billing and checkout routes\",\n env: [\"STRIPE_SECRET_KEY\", \"STRIPE_WEBHOOK_SECRET\"],\n template: () => `import { stripe } from \"@farm.js/integrations/stripe\";\n\nexport const stripeIntegration = stripe({\n secretKey: process.env.STRIPE_SECRET_KEY,\n webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,\n products: [],\n log(event) {\n console.log(\"[stripe]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n ui: stripeBillingUIFeature(),\n },\n {\n provider: \"supabase\",\n aliases: [\"auth-supabase\", \"supabase-auth\"],\n defaultKey: \"auth\",\n fileName: \"supabase\",\n exportName: \"supabaseIntegration\",\n description: \"Supabase auth routes and middleware\",\n env: [\"SUPABASE_URL\", \"SUPABASE_ANON_KEY\", \"APP_BASE_URL\"],\n ui: supabaseAuthUIFeature(),\n template: () => `import { supabase } from \"@farm.js/integrations/supabase\";\n\nexport const supabaseIntegration = supabase({\n callbackUrl: \\`\\${process.env.APP_BASE_URL || \"http://localhost:3000\"}/auth/callback\\`,\n protectedRoutes: [\"/dashboard(.*)\"],\n pages: {\n signIn: \"/sign-in\",\n signUp: \"/sign-up\",\n },\n log(event) {\n console.log(\"[supabase]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"workos\",\n aliases: [\"auth-workos\", \"workos-auth\"],\n defaultKey: \"auth\",\n fileName: \"workos\",\n exportName: \"workosIntegration\",\n description: \"WorkOS auth routes and protected route middleware\",\n env: [\"WORKOS_CLIENT_ID\", \"WORKOS_API_KEY\", \"WORKOS_COOKIE_PASSWORD\"],\n ui: workosAuthUIFeature(),\n template: () => `import { workos } from \"@farm.js/integrations/workos\";\n\nexport const workosIntegration = workos({\n protectedRoutes: [\"/dashboard(.*)\"],\n log(event) {\n console.log(\"[workos]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"auth0\",\n aliases: [\"auth-auth0\", \"auth0-auth\"],\n defaultKey: \"auth\",\n fileName: \"auth0\",\n exportName: \"auth0Integration\",\n description: \"Auth0 login, callback, logout, and profile routes\",\n env: [\"AUTH0_DOMAIN\", \"AUTH0_CLIENT_ID\", \"AUTH0_CLIENT_SECRET\", \"AUTH0_SECRET\"],\n ui: auth0AuthUIFeature(),\n template: () => `import { auth0 } from \"@farm.js/integrations/auth0\";\n\nexport const auth0Integration = auth0({\n callbackUrl: \\`\\${process.env.APP_BASE_URL || \"http://localhost:3000\"}/auth/callback\\`,\n protectedRoutes: [\"/dashboard(.*)\"],\n log(event) {\n console.log(\"[auth0]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"clerk\",\n aliases: [\"auth-clerk\", \"clerk-auth\"],\n defaultKey: \"auth\",\n fileName: \"clerk\",\n exportName: \"clerkIntegration\",\n description: \"Clerk auth provider and protected route middleware\",\n env: [\"NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY\", \"CLERK_SECRET_KEY\"],\n ui: clerkAuthUIFeature(),\n template: () => `import { clerk } from \"@farm.js/integrations/clerk\";\n\nexport const clerkIntegration = clerk({\n signInUrl: \"/sign-in\",\n signUpUrl: \"/sign-up\",\n protectedRoutes: [\"/dashboard(.*)\"],\n log(event) {\n console.log(\"[clerk]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"resend\",\n aliases: [\"email\", \"resend-email\"],\n defaultKey: \"email\",\n fileName: \"resend\",\n exportName: \"resendIntegration\",\n description: \"Resend email send, preview, schedule, and webhook routes\",\n env: [\"RESEND_API_KEY\", \"RESEND_FROM_EMAIL\", \"RESEND_WEBHOOK_SECRET\"],\n ui: resendEmailUIFeature(),\n template: () => `import { createElement } from \"react\";\nimport { resend, template } from \"@farm.js/integrations/email\";\n\nfunction WelcomeEmail(props: { name: string }) {\n return createElement(\"div\", null, \\`Welcome \\${props.name}\\`);\n}\n\nWelcomeEmail.PreviewProps = {\n name: \"Ada\",\n};\n\nexport const emailTemplates = {\n welcome: template(WelcomeEmail, {\n subject: ({ name }) => \\`Welcome, \\${name}\\`,\n previewText: () => \"Welcome to the app\",\n }),\n} as const;\n\nexport const resendIntegration = resend({\n apiKey: process.env.RESEND_API_KEY,\n defaults: {\n from: process.env.RESEND_FROM_EMAIL,\n replyTo: process.env.RESEND_REPLY_TO_EMAIL ?? process.env.RESEND_FROM_EMAIL,\n },\n templates: emailTemplates,\n webhooks: process.env.RESEND_WEBHOOK_SECRET\n ? {\n secret: process.env.RESEND_WEBHOOK_SECRET,\n }\n : undefined,\n log(event) {\n console.log(\"[resend]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"jobs-inngest\",\n aliases: [\"inngest\", \"jobs\"],\n defaultKey: \"jobs\",\n fileName: \"jobs-inngest\",\n exportName: \"jobsIntegration\",\n description: \"Jobs integration backed by Inngest\",\n env: [\"INNGEST_APP_ID\", \"INNGEST_EVENT_KEY\", \"INNGEST_SIGNING_KEY\"],\n notes: [\"Add tasks to jobTasks before using the generated jobs API.\"],\n ui: jobsUIFeature(\"inngest\"),\n template: () => `import { defineTasks, inngest, jobs } from \"@farm.js/integrations/jobs\";\n\nexport const jobTasks = defineTasks({});\n\nexport const jobsIntegration = jobs({\n runtime: inngest({\n appId: process.env.INNGEST_APP_ID,\n eventKey: process.env.INNGEST_EVENT_KEY,\n signingKey: process.env.INNGEST_SIGNING_KEY,\n }),\n tasks: jobTasks,\n log(event) {\n console.log(\"[jobs:inngest]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"jobs-trigger\",\n aliases: [\"trigger\", \"trigger-dev\", \"jobs-triggerdev\"],\n defaultKey: \"jobs\",\n fileName: \"jobs-trigger\",\n exportName: \"jobsIntegration\",\n description: \"Jobs integration backed by Trigger.dev\",\n env: [\"TRIGGER_PROJECT_REF\", \"TRIGGER_SECRET_KEY\", \"TRIGGER_WEBHOOK_SECRET\"],\n notes: [\"Add tasks to jobTasks before using the generated jobs API.\"],\n ui: jobsUIFeature(\"trigger\"),\n template: () => `import { defineTasks, jobs, trigger } from \"@farm.js/integrations/jobs\";\n\nexport const jobTasks = defineTasks({});\n\nexport const jobsIntegration = jobs({\n runtime: trigger({\n projectRef: process.env.TRIGGER_PROJECT_REF,\n apiKey: process.env.TRIGGER_SECRET_KEY,\n webhookSecret: process.env.TRIGGER_WEBHOOK_SECRET,\n }),\n tasks: jobTasks,\n log(event) {\n console.log(\"[jobs:trigger]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"polar\",\n aliases: [\"polar-billing\", \"billing-polar\"],\n defaultKey: \"billing\",\n fileName: \"polar\",\n exportName: \"polarIntegration\",\n description: \"Polar billing and checkout routes\",\n env: [\"POLAR_ACCESS_TOKEN\", \"POLAR_WEBHOOK_SECRET\", \"APP_BASE_URL\"],\n notes: [\"Replace resolveBillingOwner with your app user or organization lookup.\"],\n ui: polarBillingUIFeature(),\n template: () => `import type { FarmIntegrationHandlerContext } from \"@farm.js/core\";\nimport { polar } from \"@farm.js/integrations/polar\";\n\nasync function resolveBillingOwner(_context: FarmIntegrationHandlerContext) {\n throw new Error(\"Configure Polar billing owner resolution for your app.\");\n}\n\nexport const polarIntegration = polar({\n accessToken: process.env.POLAR_ACCESS_TOKEN,\n server: (process.env.POLAR_SERVER as \"sandbox\" | \"production\" | undefined) ?? \"sandbox\",\n appBaseUrl: process.env.APP_BASE_URL,\n webhooks: process.env.POLAR_WEBHOOK_SECRET\n ? {\n secret: process.env.POLAR_WEBHOOK_SECRET,\n }\n : undefined,\n billing: {\n resolveOwner: resolveBillingOwner,\n plans: {},\n products: {},\n },\n log(event) {\n console.log(\"[polar]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"autumn\",\n aliases: [\"autumn-billing\", \"billing-autumn\"],\n defaultKey: \"billing\",\n fileName: \"autumn\",\n exportName: \"autumnIntegration\",\n description: \"Autumn billing and checkout routes\",\n env: [\"AUTUMN_SECRET_KEY\", \"AUTUMN_WEBHOOK_SECRET\", \"APP_BASE_URL\"],\n notes: [\"Replace resolveBillingOwner with your app user or organization lookup.\"],\n ui: autumnBillingUIFeature(),\n template: () => `import type { FarmIntegrationHandlerContext } from \"@farm.js/core\";\nimport { autumn } from \"@farm.js/integrations/autumn\";\n\nasync function resolveBillingOwner(_context: FarmIntegrationHandlerContext) {\n throw new Error(\"Configure Autumn billing owner resolution for your app.\");\n}\n\nexport const autumnIntegration = autumn({\n secretKey: process.env.AUTUMN_SECRET_KEY,\n appBaseUrl: process.env.APP_BASE_URL,\n webhooks: process.env.AUTUMN_WEBHOOK_SECRET\n ? {\n secret: process.env.AUTUMN_WEBHOOK_SECRET,\n }\n : undefined,\n billing: {\n resolveOwner: resolveBillingOwner,\n plans: {},\n products: {},\n },\n log(event) {\n console.log(\"[autumn]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"better-auth\",\n aliases: [\"betterauth\", \"auth-better-auth\"],\n defaultKey: \"auth\",\n fileName: \"better-auth\",\n exportName: \"betterAuthIntegration\",\n description: \"Better Auth route adapter\",\n env: [\"BETTER_AUTH_SECRET\", \"BETTER_AUTH_URL\", \"BETTER_AUTH_DATABASE_PATH\"],\n dependencies: {\n \"better-auth\": \"^1.5.5\",\n \"better-sqlite3\": \"^12.6.2\",\n },\n devDependencies: {\n \"@types/better-sqlite3\": \"^7.6.13\",\n },\n notes: [\n \"The generated SQLite database is intended for local development. Configure a persistent production database before deploying.\",\n \"Set BETTER_AUTH_SECRET to a high-entropy value of at least 32 characters.\",\n ],\n setupFiles: [\n {\n path: \"src/lib/auth.ts\",\n source: () => `import Database from \"better-sqlite3\";\nimport { betterAuth as createBetterAuth } from \"better-auth\";\nimport { getMigrations } from \"better-auth/db/migration\";\n\nconst baseURL = process.env.BETTER_AUTH_URL || \"http://localhost:3000\";\nexport const auth = createBetterAuth({\n database: new Database(process.env.BETTER_AUTH_DATABASE_PATH || \"better-auth.sqlite\"),\n secret: process.env.BETTER_AUTH_SECRET,\n baseURL,\n trustedOrigins: [baseURL],\n emailAndPassword: {\n enabled: true,\n },\n});\n\nconst migrations = await getMigrations(auth.options);\nawait migrations.runMigrations();\n`,\n },\n {\n path: \".env.example\",\n merge: \"lines\",\n source: () => `BETTER_AUTH_SECRET=replace-with-at-least-32-random-characters\nBETTER_AUTH_URL=http://localhost:3000\nBETTER_AUTH_DATABASE_PATH=better-auth.sqlite\n`,\n },\n {\n path: \".gitignore\",\n merge: \"lines\",\n source: () => `better-auth.sqlite\nbetter-auth.sqlite-shm\nbetter-auth.sqlite-wal\n`,\n },\n ],\n ui: betterAuthUIFeature(),\n template: () => `import { betterAuth } from \"@farm.js/integrations/better-auth\";\nimport { auth } from \"../auth.ts\";\n\nexport const betterAuthIntegration = betterAuth({\n instance: auth,\n log(event) {\n console.log(\"[better-auth]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"authjs\",\n aliases: [\"auth-js\", \"nextauth\", \"next-auth\"],\n defaultKey: \"auth\",\n fileName: \"authjs\",\n exportName: \"authjsIntegration\",\n description: \"Auth.js route adapter\",\n env: [],\n notes: [\"This template expects src/lib/auth.ts to export an Auth.js instance named auth.\"],\n ui: authjsUIFeature(),\n template: () => `import { authjs } from \"@farm.js/integrations/authjs\";\nimport { auth } from \"../auth.ts\";\n\nexport const authjsIntegration = authjs({\n instance: auth,\n log(event) {\n console.log(\"[authjs]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"unkey\",\n aliases: [\"api-keys\", \"apikeys\", \"keys\", \"unkey-api-keys\"],\n defaultKey: \"apiKeys\",\n fileName: \"unkey\",\n exportName: \"unkeyIntegration\",\n description: \"Unkey API key creation, verification, and route protection\",\n env: [\"UNKEY_ROOT_KEY\", \"UNKEY_API_ID\", \"UNKEY_BASE_URL\"],\n ui: unkeyApiKeysUIFeature(),\n template: () => `import { unkey } from \"@farm.js/integrations/unkey\";\n\nexport const unkeyIntegration = unkey({\n rootKey: process.env.UNKEY_ROOT_KEY,\n apiId: process.env.UNKEY_API_ID,\n baseUrl: process.env.UNKEY_BASE_URL,\n protectedRoutes: [\"/api/protected(.*)\"],\n log(event) {\n console.log(\"[unkey]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n] as const;\n\nexport function listFarmIntegrationProviders() {\n return PROVIDERS.map((provider) => ({\n name: provider.provider,\n aliases: [...provider.aliases],\n defaultKey: provider.defaultKey,\n description: provider.description,\n env: [...provider.env],\n ui: provider.ui\n ? {\n feature: provider.ui.name,\n description: provider.ui.description,\n components: [...provider.ui.components],\n }\n : undefined,\n }));\n}\n\nexport async function addFarmIntegration(\n options: AddFarmIntegrationOptions,\n): Promise<AddFarmIntegrationResult> {\n const root = path.resolve(options.root || process.cwd());\n const definition = resolveProvider(options.provider);\n\n if (definition.provider === \"ai\") {\n return addAIRouteIntegration({\n root,\n definition,\n routeFile: options.routeFile,\n ui: options.ui,\n skipPackageJson: options.skipPackageJson,\n dryRun: options.dryRun,\n force: options.force,\n });\n }\n\n const key = options.key || definition.defaultKey;\n assertValidIntegrationKey(key);\n\n const registryFile = path.resolve(\n root,\n options.integrationsFile || path.join(\"src\", \"lib\", \"integrations.ts\"),\n );\n const integrationFile = path.join(\n path.dirname(registryFile),\n \"integrations\",\n `${definition.fileName}.ts`,\n );\n const result: AddFarmIntegrationResult = {\n provider: definition.provider,\n key,\n mode: \"integration\",\n integrationFile,\n registryFile,\n created: [],\n updated: [],\n skipped: [],\n env: [...definition.env],\n notes: [...(definition.notes || [])],\n };\n\n await writeIntegrationComponent({\n path: integrationFile,\n definition,\n force: options.force,\n dryRun: options.dryRun,\n result,\n });\n await writeIntegrationSetupFiles({\n root,\n definition,\n force: options.force,\n dryRun: options.dryRun,\n result,\n });\n await writeIntegrationRegistry({\n path: registryFile,\n integrationFile,\n definition,\n key,\n dryRun: options.dryRun,\n result,\n });\n\n if (!options.skipPackageJson) {\n await updatePackageJson({\n root,\n definition,\n dryRun: options.dryRun,\n result,\n });\n }\n\n if (!options.skipConfig) {\n await updateFarmConfig({\n root,\n registryFile,\n dryRun: options.dryRun,\n result,\n });\n }\n\n if (options.ui) {\n await installUIFeature({\n root,\n definition,\n key,\n dryRun: options.dryRun,\n force: options.force,\n skipPackageJson: options.skipPackageJson,\n result,\n });\n }\n\n return result;\n}\n\nasync function addAIRouteIntegration(input: {\n root: string;\n definition: IntegrationProviderDefinition;\n routeFile?: string;\n ui?: boolean;\n skipPackageJson?: boolean;\n dryRun?: boolean;\n force?: boolean;\n}): Promise<AddFarmIntegrationResult> {\n const routeFile = path.resolve(\n input.root,\n input.routeFile || path.join(\"src\", \"app\", \"api\", \"chat\", \"route.ts\"),\n );\n const result: AddFarmIntegrationResult = {\n provider: \"ai\",\n key: input.definition.defaultKey,\n mode: \"route\",\n integrationFile: routeFile,\n registryFile: \"\",\n routeFile,\n routePath: \"/api/chat\",\n created: [],\n updated: [],\n skipped: [],\n env: [...input.definition.env],\n notes: [...(input.definition.notes || [])],\n };\n\n await writeIntegrationComponent({\n path: routeFile,\n definition: input.definition,\n force: input.force,\n dryRun: input.dryRun,\n result,\n });\n\n if (!input.skipPackageJson) {\n await updatePackageJson({\n root: input.root,\n definition: input.definition,\n dryRun: input.dryRun,\n result,\n });\n }\n\n if (input.ui) {\n await installUIFeature({\n root: input.root,\n definition: input.definition,\n key: input.definition.defaultKey,\n dryRun: input.dryRun,\n force: input.force,\n skipPackageJson: input.skipPackageJson,\n result,\n });\n }\n\n return result;\n}\n\nfunction resolveProvider(input: string) {\n const normalized = input.trim().toLowerCase();\n const match = PROVIDERS.find(\n (provider) => provider.provider === normalized || provider.aliases.includes(normalized),\n );\n\n if (!match) {\n const supported = PROVIDERS.map((provider) => provider.provider).join(\", \");\n throw new Error(`Unknown integration \"${input}\". Supported integrations: ${supported}.`);\n }\n\n return match;\n}\n\nfunction assertValidIntegrationKey(key: string) {\n if (!/^[A-Za-z_$][\\w$]*$/.test(key)) {\n throw new Error(`Integration key \"${key}\" must be a valid JavaScript object property name.`);\n }\n}\n\nasync function writeIntegrationComponent(input: {\n path: string;\n definition: IntegrationProviderDefinition;\n force?: boolean;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const exists = existsSync(input.path);\n if (exists && !input.force) {\n input.result.skipped.push(input.path);\n return;\n }\n\n if (!input.dryRun) {\n await mkdir(path.dirname(input.path), { recursive: true });\n await writeFile(input.path, input.definition.template(), \"utf8\");\n }\n\n if (exists) {\n input.result.updated.push(input.path);\n } else {\n input.result.created.push(input.path);\n }\n}\n\nasync function writeIntegrationRegistry(input: {\n path: string;\n integrationFile: string;\n definition: IntegrationProviderDefinition;\n key: string;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const importPath = toImportPath(path.relative(path.dirname(input.path), input.integrationFile));\n const importLine = `import { ${input.definition.exportName} } from \"${importPath}\";`;\n const propertyLine = ` ${input.key}: ${input.definition.exportName},`;\n\n let nextSource: string;\n const exists = existsSync(input.path);\n\n if (exists) {\n const source = await readFile(input.path, \"utf8\");\n nextSource = ensureRegistryEntry(source, {\n importLine,\n propertyLine,\n key: input.key,\n exportName: input.definition.exportName,\n });\n } else {\n nextSource = `${importLine}\n\nexport const appIntegrations = {\n${propertyLine}\n} as const;\n\nexport type AppIntegrations = typeof appIntegrations;\n`;\n }\n\n if (!input.dryRun) {\n await mkdir(path.dirname(input.path), { recursive: true });\n await writeFile(input.path, nextSource, \"utf8\");\n }\n\n input.result[exists ? \"updated\" : \"created\"].push(input.path);\n}\n\nfunction ensureRegistryEntry(\n source: string,\n input: {\n importLine: string;\n propertyLine: string;\n key: string;\n exportName: string;\n },\n) {\n const keyPattern = new RegExp(`(^|\\\\n)\\\\s*${escapeRegExp(input.key)}\\\\s*:`, \"m\");\n if (keyPattern.test(source)) {\n if (source.includes(`${input.key}: ${input.exportName}`)) {\n return source.includes(input.importLine) ? source : `${input.importLine}\\n${source}`;\n }\n\n throw new Error(\n `Integration key \"${input.key}\" already exists in the app integrations registry. Pass --key to use a different key.`,\n );\n }\n\n const sourceWithImport = source.includes(input.importLine)\n ? source\n : `${input.importLine}\\n${source}`;\n const appIntegrationsPattern =\n /export\\s+const\\s+appIntegrations\\s*=\\s*\\{([\\s\\S]*?)\\}\\s*as\\s+const;/m;\n const match = sourceWithImport.match(appIntegrationsPattern);\n\n if (!match) {\n return `${sourceWithImport.trimEnd()}\n\nexport const appIntegrations = {\n${input.propertyLine}\n} as const;\n\nexport type AppIntegrations = typeof appIntegrations;\n`;\n }\n\n const body = match[1] || \"\";\n const nextBody = body.trim().length\n ? `${body.trimEnd()}\\n${input.propertyLine}\\n`\n : `\\n${input.propertyLine}\\n`;\n\n return sourceWithImport.replace(appIntegrationsPattern, () => {\n return `export const appIntegrations = {${nextBody}} as const;`;\n });\n}\n\nasync function writeIntegrationSetupFiles(input: {\n root: string;\n definition: IntegrationProviderDefinition;\n force?: boolean;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n for (const file of input.definition.setupFiles || []) {\n const absolutePath = path.join(input.root, file.path);\n const exists = existsSync(absolutePath);\n if (exists && !input.force) {\n if (file.merge === \"lines\") {\n const source = await readFile(absolutePath, \"utf8\");\n const additions = file\n .source()\n .split(/\\r?\\n/)\n .filter((line) => line && !source.split(/\\r?\\n/).includes(line));\n if (!additions.length) {\n input.result.skipped.push(absolutePath);\n continue;\n }\n\n if (!input.dryRun) {\n await writeFile(absolutePath, `${source.trimEnd()}\\n${additions.join(\"\\n\")}\\n`, \"utf8\");\n }\n input.result.updated.push(absolutePath);\n continue;\n }\n\n input.result.skipped.push(absolutePath);\n continue;\n }\n\n if (!input.dryRun) {\n await mkdir(path.dirname(absolutePath), { recursive: true });\n await writeFile(absolutePath, file.source(), \"utf8\");\n }\n\n input.result[exists ? \"updated\" : \"created\"].push(absolutePath);\n }\n}\n\nasync function updatePackageJson(input: {\n root: string;\n definition: IntegrationProviderDefinition;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const packageJsonPath = path.join(input.root, \"package.json\");\n if (!existsSync(packageJsonPath)) {\n input.result.skipped.push(packageJsonPath);\n return;\n }\n\n const source = await readFile(packageJsonPath, \"utf8\");\n const manifest = JSON.parse(source) as PackageManifest;\n\n const dependencies = missingDependencies(manifest, input.definition.dependencies);\n const devDependencies = missingDependencies(manifest, input.definition.devDependencies);\n manifest.dependencies = {\n ...manifest.dependencies,\n ...(hasPackageDependency(manifest, \"@farm.js/integrations\")\n ? {}\n : { \"@farm.js/integrations\": getFarmIntegrationsVersion(manifest) }),\n ...dependencies,\n };\n if (Object.keys(devDependencies).length) {\n manifest.devDependencies = {\n ...manifest.devDependencies,\n ...devDependencies,\n };\n }\n\n const nextSource = `${JSON.stringify(manifest, null, 2)}\\n`;\n if (source === nextSource) {\n input.result.packageJson = packageJsonPath;\n input.result.skipped.push(packageJsonPath);\n return;\n }\n\n if (!input.dryRun) {\n await writeFile(packageJsonPath, nextSource, \"utf8\");\n }\n\n input.result.packageJson = packageJsonPath;\n input.result.updated.push(packageJsonPath);\n}\n\nfunction missingDependencies(\n manifest: PackageManifest,\n dependencies: Readonly<Record<string, string>> | undefined,\n) {\n return Object.fromEntries(\n Object.entries(dependencies || {}).filter(([name]) => !hasPackageDependency(manifest, name)),\n );\n}\n\nasync function updateFarmConfig(input: {\n root: string;\n registryFile: string;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const configFile = findFarmConfig(input.root);\n\n if (!configFile) {\n const newConfigFile = path.join(input.root, \"farm.config.ts\");\n const importPath = toImportPath(path.relative(input.root, input.registryFile));\n const source = `import { defineConfig } from \"@farm.js/core\";\nimport { appIntegrations } from \"${importPath}\";\n\nexport default defineConfig({\n integrations: appIntegrations,\n});\n`;\n\n if (!input.dryRun) {\n await writeFile(newConfigFile, source, \"utf8\");\n }\n\n input.result.configFile = newConfigFile;\n input.result.created.push(newConfigFile);\n return;\n }\n\n input.result.configFile = configFile;\n const source = await readFile(configFile, \"utf8\");\n if (/\\bintegrations\\s*:/.test(source)) {\n input.result.skipped.push(configFile);\n input.result.notes.push(\n `farm.config already has an integrations field. Confirm it includes appIntegrations from ${path.relative(input.root, input.registryFile)}.`,\n );\n return;\n }\n\n const importPath = toImportPath(path.relative(path.dirname(configFile), input.registryFile));\n const importLine = `import { appIntegrations } from \"${importPath}\";`;\n const sourceWithImport = source.includes(importLine) ? source : `${importLine}\\n${source}`;\n const nextSource = insertIntegrationsConfig(sourceWithImport);\n\n if (nextSource === sourceWithImport) {\n input.result.skipped.push(configFile);\n input.result.notes.push(\n `Could not safely update ${path.relative(input.root, configFile)}. Add integrations: appIntegrations manually.`,\n );\n return;\n }\n\n if (!input.dryRun) {\n await writeFile(configFile, nextSource, \"utf8\");\n }\n\n input.result.updated.push(configFile);\n}\n\nfunction insertIntegrationsConfig(source: string) {\n const defineConfigCall = /\\bdefine(?:Farm)?Config\\s*\\(\\s*\\{/;\n if (defineConfigCall.test(source)) {\n return source.replace(defineConfigCall, (match) => {\n return `${match}\\n integrations: appIntegrations,`;\n });\n }\n\n if (/export\\s+default\\s+\\{/.test(source)) {\n return source.replace(/export\\s+default\\s+\\{/, (match) => {\n return `${match}\\n integrations: appIntegrations,`;\n });\n }\n\n return source;\n}\n\nfunction findFarmConfig(root: string) {\n const candidates = [\n \"farm.config.ts\",\n \"farm.config.mts\",\n \"farm.config.js\",\n \"farm.config.mjs\",\n \"config.ts\",\n \"config.mts\",\n \"config.js\",\n \"config.mjs\",\n ];\n for (const candidate of candidates) {\n const absolutePath = path.join(root, candidate);\n if (existsSync(absolutePath)) {\n return absolutePath;\n }\n }\n\n return null;\n}\n\nfunction hasPackageDependency(manifest: PackageManifest, dependency: string) {\n return (\n dependency in (manifest.dependencies || {}) ||\n dependency in (manifest.devDependencies || {}) ||\n dependency in (manifest.peerDependencies || {}) ||\n dependency in (manifest.optionalDependencies || {})\n );\n}\n\nfunction getFarmIntegrationsVersion(manifest: PackageManifest) {\n const farmCoreVersion =\n manifest.dependencies?.[\"@farm.js/core\"] ??\n manifest.devDependencies?.[\"@farm.js/core\"] ??\n manifest.peerDependencies?.[\"@farm.js/core\"] ??\n manifest.optionalDependencies?.[\"@farm.js/core\"];\n\n return farmCoreVersion?.startsWith(\"workspace:\") ? \"workspace:*\" : \"latest\";\n}\n\nfunction toImportPath(relativePath: string) {\n const normalized = relativePath.split(path.sep).join(\"/\");\n const withDot = normalized.startsWith(\".\") ? normalized : `./${normalized}`;\n return withDot.replace(/\\.tsx?$/, \".ts\");\n}\n\nfunction escapeRegExp(input: string) {\n return input.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"add-integration-CdVfiPjG.mjs","names":["hasPackageDependency"],"sources":["../src/ui-feature-registry.ts","../src/add-integration.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { AddFarmIntegrationResult, FarmIntegrationProvider } from \"./add-integration\";\n\ntype PackageManifest = {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n};\n\nexport interface AddFarmIntegrationUIResult {\n feature: string;\n components: string[];\n files: string[];\n}\n\nexport type ShadcnComponentName = \"badge\" | \"button\" | \"card\" | \"input\" | \"label\";\n\nexport interface UIFeatureDefinition {\n name: string;\n description: string;\n components: readonly ShadcnComponentName[];\n files(input: UIFeatureTemplateInput): readonly UIFeatureFile[];\n needsApiClient?: boolean;\n notes?: readonly string[];\n}\n\ninterface UIFeatureTemplateInput {\n key: string;\n provider: FarmIntegrationProvider;\n}\n\ninterface UIFeatureFile {\n path: string;\n source: string;\n}\n\nexport async function installUIFeature(input: {\n root: string;\n definition: { provider: FarmIntegrationProvider; ui?: UIFeatureDefinition };\n key: string;\n dryRun?: boolean;\n force?: boolean;\n skipPackageJson?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const feature = input.definition.ui;\n if (!feature) {\n input.result.notes.push(\n `No --ui feature pack is available for ${input.definition.provider} yet.`,\n );\n return;\n }\n\n input.result.ui = {\n feature: feature.name,\n components: [...feature.components],\n files: [],\n };\n input.result.notes.push(\n `Installed ${feature.description} with shadcn-style local source components.`,\n ...(feature.notes || []),\n );\n\n await ensureComponentsJson({\n root: input.root,\n dryRun: input.dryRun,\n result: input.result,\n });\n await ensureShadcnGlobals({\n root: input.root,\n dryRun: input.dryRun,\n result: input.result,\n });\n await ensureTsconfigAlias({\n root: input.root,\n dryRun: input.dryRun,\n result: input.result,\n });\n\n if (!input.skipPackageJson) {\n await updateUIPackageJson({\n root: input.root,\n dryRun: input.dryRun,\n result: input.result,\n });\n }\n\n await writeGeneratedFile({\n root: input.root,\n relativePath: path.join(\"src\", \"lib\", \"utils.ts\"),\n source: shadcnUtilsTemplate(),\n dryRun: input.dryRun,\n force: input.force,\n result: input.result,\n });\n\n for (const component of feature.components) {\n await writeGeneratedFile({\n root: input.root,\n relativePath: path.join(\"src\", \"components\", \"ui\", `${component}.tsx`),\n source: shadcnComponentTemplate(component),\n dryRun: input.dryRun,\n force: input.force,\n result: input.result,\n });\n }\n\n if (feature.needsApiClient !== false) {\n await writeGeneratedFile({\n root: input.root,\n relativePath: path.join(\"src\", \"lib\", \"api.ts\"),\n source: apiClientTemplate(),\n dryRun: input.dryRun,\n force: input.force,\n result: input.result,\n });\n }\n\n for (const file of feature.files({\n key: input.key,\n provider: input.definition.provider,\n })) {\n await writeGeneratedFile({\n root: input.root,\n relativePath: file.path,\n source: file.source,\n dryRun: input.dryRun,\n force: input.force,\n result: input.result,\n });\n }\n}\n\nexport function stripeBillingUIFeature(): UIFeatureDefinition {\n return billingUIFeature({\n provider: \"stripe\",\n label: \"Stripe\",\n });\n}\n\nexport function polarBillingUIFeature(): UIFeatureDefinition {\n return billingUIFeature({\n provider: \"polar\",\n label: \"Polar\",\n });\n}\n\nexport function autumnBillingUIFeature(): UIFeatureDefinition {\n return billingUIFeature({\n provider: \"autumn\",\n label: \"Autumn\",\n });\n}\n\nexport function aiChatUIFeature(): UIFeatureDefinition {\n return {\n name: \"ai-chat\",\n description: \"AI chat UI\",\n components: [\"badge\", \"button\", \"card\", \"input\"],\n needsApiClient: false,\n notes: ['Open \"/integrations/ai\" to try the generated chat UI.'],\n files: () => [\n componentFile(\"ai-chat.tsx\", aiChatTemplate()),\n integrationPageFile(\"ai\", \"AIChat\"),\n ],\n };\n}\n\nexport function supabaseAuthUIFeature(): UIFeatureDefinition {\n return {\n name: \"supabase-auth\",\n description: \"Supabase auth UI\",\n components: [\"badge\", \"button\", \"card\", \"input\", \"label\"],\n notes: ['Open \"/integrations/supabase\" to try the generated auth UI.'],\n files: (input) => [\n componentFile(\"supabase-auth-panel.tsx\", supabaseAuthTemplate(input.key)),\n integrationPageFile(\"supabase\", \"SupabaseAuthPanel\"),\n ],\n };\n}\n\nexport function workosAuthUIFeature(): UIFeatureDefinition {\n return {\n name: \"workos-auth\",\n description: \"WorkOS auth UI\",\n components: [\"badge\", \"button\", \"card\"],\n notes: ['Open \"/integrations/workos\" to try the generated auth UI.'],\n files: (input) => [\n componentFile(\n \"workos-auth-panel.tsx\",\n hostedAuthTemplate({\n key: input.key,\n provider: \"WorkOS\",\n componentName: \"WorkOSAuthPanel\",\n statusCall: \"session.get\",\n logoutCall: \"logout.post\",\n loginHref: \"/login?returnTo=/dashboard\",\n signupHref: \"/signup?returnTo=/dashboard\",\n statusLabel: \"Session\",\n }),\n ),\n integrationPageFile(\"workos\", \"WorkOSAuthPanel\"),\n ],\n };\n}\n\nexport function auth0AuthUIFeature(): UIFeatureDefinition {\n return {\n name: \"auth0-auth\",\n description: \"Auth0 auth UI\",\n components: [\"badge\", \"button\", \"card\"],\n notes: ['Open \"/integrations/auth0\" to try the generated auth UI.'],\n files: (input) => [\n componentFile(\n \"auth0-auth-panel.tsx\",\n hostedAuthTemplate({\n key: input.key,\n provider: \"Auth0\",\n componentName: \"Auth0AuthPanel\",\n statusCall: \"profile.get\",\n logoutCall: \"logout.get\",\n loginHref: \"/auth/login?returnTo=/dashboard\",\n signupHref: \"/auth/signup?returnTo=/dashboard\",\n statusLabel: \"Profile\",\n }),\n ),\n integrationPageFile(\"auth0\", \"Auth0AuthPanel\"),\n ],\n };\n}\n\nexport function clerkAuthUIFeature(): UIFeatureDefinition {\n return authRouteShellUIFeature({\n provider: \"clerk\",\n label: \"Clerk\",\n componentName: \"ClerkAuthPanel\",\n signInHref: \"/sign-in\",\n signUpHref: \"/sign-up\",\n sessionHref: \"/dashboard\",\n });\n}\n\nexport function betterAuthUIFeature(): UIFeatureDefinition {\n return {\n name: \"better-auth-auth\",\n description: \"Better Auth email and password UI\",\n components: [\"badge\", \"button\", \"card\", \"input\", \"label\"],\n needsApiClient: false,\n notes: ['Open \"/integrations/better-auth\" to try the generated auth UI.'],\n files: () => [\n {\n path: path.join(\"src\", \"lib\", \"auth-client.ts\"),\n source: betterAuthClientTemplate(),\n },\n componentFile(\"better-auth-panel.tsx\", betterAuthPanelTemplate()),\n integrationPageFile(\"better-auth\", \"BetterAuthPanel\"),\n ],\n };\n}\n\nexport function authjsUIFeature(): UIFeatureDefinition {\n return authRouteShellUIFeature({\n provider: \"authjs\",\n label: \"Auth.js\",\n componentName: \"AuthJsPanel\",\n signInHref: \"/api/auth/signin\",\n signUpHref: \"/api/auth/signin\",\n sessionHref: \"/api/auth/session\",\n });\n}\n\nexport function resendEmailUIFeature(): UIFeatureDefinition {\n return {\n name: \"resend-email\",\n description: \"Resend email console UI\",\n components: [\"badge\", \"button\", \"card\", \"input\", \"label\"],\n notes: ['Open \"/integrations/resend\" to try the generated email UI.'],\n files: (input) => [\n componentFile(\"resend-email-console.tsx\", resendEmailTemplate(input.key)),\n integrationPageFile(\"resend\", \"ResendEmailConsole\"),\n ],\n };\n}\n\nexport function jobsUIFeature(provider: \"inngest\" | \"trigger\"): UIFeatureDefinition {\n const label = provider === \"inngest\" ? \"Inngest\" : \"Trigger.dev\";\n\n return {\n name: `${provider}-jobs`,\n description: `${label} jobs console UI`,\n components: [\"badge\", \"button\", \"card\", \"input\", \"label\"],\n notes: [`Open \"/integrations/jobs-${provider}\" to try the generated jobs UI.`],\n files: (input) => [\n componentFile(\n `${provider}-jobs-console.tsx`,\n jobsConsoleTemplate(input.key, label, provider),\n ),\n integrationPageFile(`jobs-${provider}`, `${pascalCase(provider)}JobsConsole`),\n ],\n };\n}\n\nexport function unkeyApiKeysUIFeature(): UIFeatureDefinition {\n return {\n name: \"unkey-api-keys\",\n description: \"Unkey API key console UI\",\n components: [\"badge\", \"button\", \"card\", \"input\", \"label\"],\n notes: ['Open \"/integrations/unkey\" to try the generated API key UI.'],\n files: (input) => [\n componentFile(\"unkey-api-keys-console.tsx\", unkeyApiKeysTemplate(input.key)),\n integrationPageFile(\"unkey\", \"UnkeyApiKeysConsole\"),\n ],\n };\n}\n\nfunction billingUIFeature(input: {\n provider: \"stripe\" | \"polar\" | \"autumn\";\n label: string;\n}): UIFeatureDefinition {\n return {\n name: `${input.provider}-billing`,\n description: `${input.label} pricing and checkout UI`,\n components: [\"badge\", \"button\", \"card\"],\n notes: [\n `Open \"/integrations/${input.provider}\" to try the generated ${input.label} billing UI.`,\n ],\n files: (templateInput) => [\n componentFile(\n `${input.provider}-billing.tsx`,\n billingPricingTemplate({\n key: templateInput.key,\n provider: input.provider,\n label: input.label,\n componentName: `${pascalCase(input.provider)}Billing`,\n }),\n ),\n integrationPageFile(input.provider, `${pascalCase(input.provider)}Billing`),\n ],\n };\n}\n\nfunction authRouteShellUIFeature(input: {\n provider: \"authjs\" | \"better-auth\" | \"clerk\";\n label: string;\n componentName: string;\n signInHref: string;\n signUpHref: string;\n sessionHref: string;\n}): UIFeatureDefinition {\n return {\n name: `${input.provider}-auth`,\n description: `${input.label} auth UI`,\n components: [\"badge\", \"button\", \"card\"],\n notes: [`Open \"/integrations/${input.provider}\" to try the generated auth UI.`],\n files: () => [\n componentFile(\n `${input.provider}-auth-panel.tsx`,\n authRouteShellTemplate({\n provider: input.label,\n componentName: input.componentName,\n signInHref: input.signInHref,\n signUpHref: input.signUpHref,\n sessionHref: input.sessionHref,\n }),\n ),\n integrationPageFile(input.provider, input.componentName),\n ],\n };\n}\n\nfunction componentFile(fileName: string, source: string): UIFeatureFile {\n return {\n path: path.join(\"src\", \"components\", \"farm\", fileName),\n source,\n };\n}\n\nfunction integrationPageFile(provider: string, componentName: string): UIFeatureFile {\n const fileName = kebabCase(componentName);\n\n return {\n path: path.join(\"src\", \"app\", \"integrations\", provider, \"page.tsx\"),\n source: `import { ${componentName} } from \"@/components/farm/${fileName}\";\n\nexport default function ${componentName}Page() {\n return <${componentName} />;\n}\n`,\n };\n}\n\nasync function writeGeneratedFile(input: {\n root: string;\n relativePath: string;\n source: string;\n dryRun?: boolean;\n force?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const absolutePath = path.join(input.root, input.relativePath);\n const exists = existsSync(absolutePath);\n const source = resolveGeneratedAliases(input.source, input.relativePath);\n input.result.ui?.files.push(absolutePath);\n\n if (exists && !input.force) {\n pushResultPath(input.result.skipped, absolutePath);\n return;\n }\n\n if (!input.dryRun) {\n await mkdir(path.dirname(absolutePath), { recursive: true });\n await writeFile(absolutePath, source, \"utf8\");\n }\n\n pushResultPath(exists ? input.result.updated : input.result.created, absolutePath);\n}\n\nfunction resolveGeneratedAliases(source: string, relativePath: string) {\n const sourceDirectory = path.dirname(relativePath);\n\n return source.replace(/([\"'])@\\/([^\"']+)\\1/g, (_match, quote: string, target: string) => {\n const relativeTarget = path\n .relative(sourceDirectory, path.join(\"src\", target))\n .split(path.sep)\n .join(\"/\");\n const importPath = relativeTarget.startsWith(\".\") ? relativeTarget : `./${relativeTarget}`;\n return `${quote}${importPath}${quote}`;\n });\n}\n\nasync function ensureComponentsJson(input: {\n root: string;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const componentsJsonPath = path.join(input.root, \"components.json\");\n input.result.ui?.files.push(componentsJsonPath);\n const defaults = createComponentsJson();\n\n if (!existsSync(componentsJsonPath)) {\n if (!input.dryRun) {\n await writeFile(componentsJsonPath, `${JSON.stringify(defaults, null, 2)}\\n`, \"utf8\");\n }\n pushResultPath(input.result.created, componentsJsonPath);\n return;\n }\n\n let current: Record<string, unknown>;\n try {\n current = JSON.parse(await readFile(componentsJsonPath, \"utf8\")) as Record<string, unknown>;\n } catch {\n pushResultPath(input.result.skipped, componentsJsonPath);\n input.result.notes.push(\n \"components.json could not be parsed. Keep shadcn aliases pointed at src/components and src/lib/utils.\",\n );\n return;\n }\n\n const next = mergeComponentsJson(current, defaults);\n if (JSON.stringify(current) === JSON.stringify(next)) {\n pushResultPath(input.result.skipped, componentsJsonPath);\n return;\n }\n\n if (!input.dryRun) {\n await writeFile(componentsJsonPath, `${JSON.stringify(next, null, 2)}\\n`, \"utf8\");\n }\n pushResultPath(input.result.updated, componentsJsonPath);\n}\n\nasync function ensureShadcnGlobals(input: {\n root: string;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const globalsPath = path.join(input.root, \"src\", \"app\", \"globals.css\");\n input.result.ui?.files.push(globalsPath);\n\n if (!existsSync(globalsPath)) {\n const source = `@import \"tailwindcss\";\n\n${SHADCN_THEME_CSS}\n`;\n if (!input.dryRun) {\n await mkdir(path.dirname(globalsPath), { recursive: true });\n await writeFile(globalsPath, source, \"utf8\");\n }\n pushResultPath(input.result.created, globalsPath);\n return;\n }\n\n const source = await readFile(globalsPath, \"utf8\");\n const hasTailwindImport = source.includes('@import \"tailwindcss\"');\n const hasTheme = source.includes(\"--color-background\") || source.includes(\"--background:\");\n if (hasTailwindImport && hasTheme) {\n pushResultPath(input.result.skipped, globalsPath);\n return;\n }\n\n const nextSource = `${hasTailwindImport ? \"\" : '@import \"tailwindcss\";\\n\\n'}${source.trimEnd()}${\n hasTheme\n ? \"\\n\"\n : `\n\n${SHADCN_THEME_CSS}\n`\n }`;\n if (!input.dryRun) {\n await writeFile(globalsPath, nextSource, \"utf8\");\n }\n pushResultPath(input.result.updated, globalsPath);\n}\n\nasync function ensureTsconfigAlias(input: {\n root: string;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const tsconfigPath = path.join(input.root, \"tsconfig.json\");\n input.result.ui?.files.push(tsconfigPath);\n const defaults = {\n compilerOptions: {\n baseUrl: \".\",\n paths: {\n \"@/*\": [\"./src/*\"],\n },\n },\n };\n\n if (!existsSync(tsconfigPath)) {\n if (!input.dryRun) {\n await writeFile(tsconfigPath, `${JSON.stringify(defaults, null, 2)}\\n`, \"utf8\");\n }\n pushResultPath(input.result.created, tsconfigPath);\n return;\n }\n\n let tsconfig: Record<string, unknown>;\n try {\n tsconfig = JSON.parse(await readFile(tsconfigPath, \"utf8\")) as Record<string, unknown>;\n } catch {\n pushResultPath(input.result.skipped, tsconfigPath);\n input.result.notes.push(\n 'tsconfig.json could not be parsed. Add paths: { \"@/*\": [\"./src/*\"] } manually.',\n );\n return;\n }\n\n const compilerOptions = readObject(tsconfig.compilerOptions);\n const paths = readObject(compilerOptions.paths);\n const nextCompilerOptions = {\n ...compilerOptions,\n baseUrl: typeof compilerOptions.baseUrl === \"string\" ? compilerOptions.baseUrl : \".\",\n paths: {\n ...paths,\n \"@/*\": [\"./src/*\"],\n },\n };\n const nextTsconfig = {\n ...tsconfig,\n compilerOptions: nextCompilerOptions,\n };\n\n if (JSON.stringify(tsconfig) === JSON.stringify(nextTsconfig)) {\n pushResultPath(input.result.skipped, tsconfigPath);\n return;\n }\n\n if (!input.dryRun) {\n await writeFile(tsconfigPath, `${JSON.stringify(nextTsconfig, null, 2)}\\n`, \"utf8\");\n }\n pushResultPath(input.result.updated, tsconfigPath);\n}\n\nasync function updateUIPackageJson(input: {\n root: string;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const packageJsonPath = path.join(input.root, \"package.json\");\n input.result.ui?.files.push(packageJsonPath);\n if (!existsSync(packageJsonPath)) {\n pushResultPath(input.result.skipped, packageJsonPath);\n return;\n }\n\n const source = await readFile(packageJsonPath, \"utf8\");\n const manifest = JSON.parse(source) as PackageManifest;\n let changed = false;\n\n for (const [dependency, version] of Object.entries(UI_DEPENDENCIES)) {\n if (hasPackageDependency(manifest, dependency)) {\n continue;\n }\n\n manifest.dependencies = {\n ...manifest.dependencies,\n [dependency]: version,\n };\n changed = true;\n }\n\n if (!changed) {\n pushResultPath(input.result.skipped, packageJsonPath);\n return;\n }\n\n if (!input.dryRun) {\n await writeFile(packageJsonPath, `${JSON.stringify(manifest, null, 2)}\\n`, \"utf8\");\n }\n input.result.packageJson = packageJsonPath;\n pushResultPath(input.result.updated, packageJsonPath);\n}\n\nconst UI_DEPENDENCIES = {\n \"class-variance-authority\": \"^0.7.1\",\n clsx: \"^2.1.1\",\n \"tailwind-merge\": \"^3.3.1\",\n tailwindcss: \"^4.1.18\",\n} as const;\n\nconst SHADCN_THEME_CSS = `@custom-variant dark (&:is(.dark *));\n\n@theme inline {\n --color-background: var(--background);\n --color-foreground: var(--foreground);\n --color-card: var(--card);\n --color-card-foreground: var(--card-foreground);\n --color-popover: var(--popover);\n --color-popover-foreground: var(--popover-foreground);\n --color-primary: var(--primary);\n --color-primary-foreground: var(--primary-foreground);\n --color-secondary: var(--secondary);\n --color-secondary-foreground: var(--secondary-foreground);\n --color-muted: var(--muted);\n --color-muted-foreground: var(--muted-foreground);\n --color-accent: var(--accent);\n --color-accent-foreground: var(--accent-foreground);\n --color-destructive: var(--destructive);\n --color-border: var(--border);\n --color-input: var(--input);\n --color-ring: var(--ring);\n --radius-sm: calc(var(--radius) - 4px);\n --radius-md: calc(var(--radius) - 2px);\n --radius-lg: var(--radius);\n}\n\n:root {\n --radius: 0.5rem;\n --background: oklch(1 0 0);\n --foreground: oklch(0.145 0 0);\n --card: oklch(1 0 0);\n --card-foreground: oklch(0.145 0 0);\n --popover: oklch(1 0 0);\n --popover-foreground: oklch(0.145 0 0);\n --primary: oklch(0.205 0 0);\n --primary-foreground: oklch(0.985 0 0);\n --secondary: oklch(0.97 0 0);\n --secondary-foreground: oklch(0.205 0 0);\n --muted: oklch(0.97 0 0);\n --muted-foreground: oklch(0.556 0 0);\n --accent: oklch(0.97 0 0);\n --accent-foreground: oklch(0.205 0 0);\n --destructive: oklch(0.577 0.245 27.325);\n --border: oklch(0.922 0 0);\n --input: oklch(0.922 0 0);\n --ring: oklch(0.708 0 0);\n}\n\n.dark {\n --background: oklch(0.145 0 0);\n --foreground: oklch(0.985 0 0);\n --card: oklch(0.205 0 0);\n --card-foreground: oklch(0.985 0 0);\n --popover: oklch(0.205 0 0);\n --popover-foreground: oklch(0.985 0 0);\n --primary: oklch(0.922 0 0);\n --primary-foreground: oklch(0.205 0 0);\n --secondary: oklch(0.269 0 0);\n --secondary-foreground: oklch(0.985 0 0);\n --muted: oklch(0.269 0 0);\n --muted-foreground: oklch(0.708 0 0);\n --accent: oklch(0.269 0 0);\n --accent-foreground: oklch(0.985 0 0);\n --destructive: oklch(0.704 0.191 22.216);\n --border: oklch(1 0 0 / 10%);\n --input: oklch(1 0 0 / 15%);\n --ring: oklch(0.556 0 0);\n}\n\n@layer base {\n * {\n @apply border-border outline-ring/50;\n }\n\n body {\n @apply bg-background text-foreground;\n }\n}`;\n\nfunction createComponentsJson() {\n return {\n $schema: \"https://ui.shadcn.com/schema.json\",\n style: \"new-york\",\n rsc: true,\n tsx: true,\n tailwind: {\n config: \"\",\n css: \"src/app/globals.css\",\n baseColor: \"zinc\",\n cssVariables: true,\n },\n aliases: {\n components: \"@/components\",\n utils: \"@/lib/utils\",\n ui: \"@/components/ui\",\n lib: \"@/lib\",\n hooks: \"@/hooks\",\n },\n registries: {\n farm: {\n url: \"https://farmjs.dev/r/{name}.json\",\n },\n },\n };\n}\n\nfunction mergeComponentsJson(\n current: Record<string, unknown>,\n defaults: ReturnType<typeof createComponentsJson>,\n) {\n const aliases = readObject(current.aliases);\n const tailwind = readObject(current.tailwind);\n const registries = readObject(current.registries);\n\n return {\n ...current,\n $schema: typeof current.$schema === \"string\" ? current.$schema : defaults.$schema,\n style: typeof current.style === \"string\" ? current.style : defaults.style,\n rsc: typeof current.rsc === \"boolean\" ? current.rsc : defaults.rsc,\n tsx: typeof current.tsx === \"boolean\" ? current.tsx : defaults.tsx,\n tailwind: {\n ...defaults.tailwind,\n ...tailwind,\n },\n aliases: {\n ...defaults.aliases,\n ...aliases,\n },\n registries: {\n ...registries,\n farm: readObject(registries.farm).url ? registries.farm : defaults.registries.farm,\n },\n };\n}\n\nfunction shadcnUtilsTemplate() {\n return `import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n`;\n}\n\nfunction apiClientTemplate() {\n return `import { createIntegrations } from \"@farm.js/core/client\";\nimport type { AppIntegrations } from \"./integrations\";\n\nexport const { api, apiClient } = createIntegrations<AppIntegrations>();\n`;\n}\n\nfunction shadcnComponentTemplate(component: ShadcnComponentName) {\n switch (component) {\n case \"badge\":\n return `import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@/lib/utils\";\n\nconst badgeVariants = cva(\n \"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2\",\n {\n variants: {\n variant: {\n default: \"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80\",\n secondary: \"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n outline: \"text-foreground\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\nexport interface BadgeProps\n extends React.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof badgeVariants> {}\n\nexport function Badge({ className, variant, ...props }: BadgeProps) {\n return <div className={cn(badgeVariants({ variant }), className)} {...props} />;\n}\n\nexport { badgeVariants };\n`;\n case \"button\":\n return `import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@/lib/utils\";\n\nconst buttonVariants = cva(\n \"inline-flex h-9 items-center justify-center whitespace-nowrap rounded-md px-4 py-2 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground shadow hover:bg-primary/90\",\n secondary: \"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80\",\n outline: \"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n sm: \"h-8 rounded-md px-3 text-xs\",\n lg: \"h-10 rounded-md px-8\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {}\n\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, ...props }, ref) => {\n return (\n <button\n className={cn(buttonVariants({ variant, size, className }))}\n ref={ref}\n {...props}\n />\n );\n },\n);\nButton.displayName = \"Button\";\n\nexport { buttonVariants };\n`;\n case \"card\":\n return `import * as React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"rounded-lg border bg-card text-card-foreground shadow-sm\", className)}\n {...props}\n />\n ),\n);\nCard.displayName = \"Card\";\n\nexport const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex flex-col space-y-1.5 p-6\", className)} {...props} />\n ),\n);\nCardHeader.displayName = \"CardHeader\";\n\nexport const CardTitle = React.forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTMLHeadingElement>>(\n ({ className, ...props }, ref) => (\n <h3 ref={ref} className={cn(\"text-2xl font-semibold leading-none tracking-normal\", className)} {...props} />\n ),\n);\nCardTitle.displayName = \"CardTitle\";\n\nexport const CardDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(\n ({ className, ...props }, ref) => (\n <p ref={ref} className={cn(\"text-sm text-muted-foreground\", className)} {...props} />\n ),\n);\nCardDescription.displayName = \"CardDescription\";\n\nexport const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"p-6 pt-0\", className)} {...props} />\n ),\n);\nCardContent.displayName = \"CardContent\";\n\nexport const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex items-center p-6 pt-0\", className)} {...props} />\n ),\n);\nCardFooter.displayName = \"CardFooter\";\n`;\n case \"input\":\n return `import * as React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}\n\nexport const Input = React.forwardRef<HTMLInputElement, InputProps>(\n ({ className, type, ...props }, ref) => (\n <input\n type={type}\n className={cn(\n \"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n ref={ref}\n {...props}\n />\n ),\n);\nInput.displayName = \"Input\";\n`;\n case \"label\":\n return `import * as React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport const Label = React.forwardRef<HTMLLabelElement, React.LabelHTMLAttributes<HTMLLabelElement>>(\n ({ className, ...props }, ref) => (\n <label\n ref={ref}\n className={cn(\"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\", className)}\n {...props}\n />\n ),\n);\nLabel.displayName = \"Label\";\n`;\n }\n}\n\nfunction billingPricingTemplate(input: {\n key: string;\n provider: \"stripe\" | \"polar\" | \"autumn\";\n label: string;\n componentName: string;\n}) {\n return `\"use client\";\n\nimport * as React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Card,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from \"@/components/ui/card\";\nimport { apiClient } from \"@/lib/api\";\n\ntype BillingProduct = NonNullable<Awaited<ReturnType<typeof apiClient.${input.key}.products>>[\"data\"]>[number];\n\nexport function ${input.componentName}() {\n const [products, setProducts] = React.useState<BillingProduct[]>([]);\n const [loading, setLoading] = React.useState(true);\n const [checkingOut, setCheckingOut] = React.useState<string | null>(null);\n const [error, setError] = React.useState<string | null>(null);\n\n React.useEffect(() => {\n let active = true;\n\n async function loadProducts() {\n setLoading(true);\n setError(null);\n\n try {\n const response = await apiClient.${input.key}.products();\n if (response.error) {\n throw new Error(readErrorMessage(response.error, \"${input.label} request failed.\"));\n }\n\n if (active) {\n setProducts(Array.from(response.data ?? []));\n }\n } catch (cause) {\n if (active) {\n setError(cause instanceof Error ? cause.message : \"Could not load ${input.label} products.\");\n }\n } finally {\n if (active) {\n setLoading(false);\n }\n }\n }\n\n void loadProducts();\n\n return () => {\n active = false;\n };\n }, []);\n\n async function startCheckout(product: BillingProduct) {\n const productId = String(readProductField(product, \"id\") ?? \"\");\n if (!productId) {\n setError(\"This Stripe product is missing an id.\");\n return;\n }\n\n setCheckingOut(productId);\n setError(null);\n\n try {\n const response = await apiClient.${input.key}.checkout({\n body: {\n productId,\n successPath: \"/billing/success\",\n cancelPath: \"/integrations/${input.provider}\",\n },\n });\n if (response.error) {\n throw new Error(readErrorMessage(response.error, \"${input.label} checkout failed.\"));\n }\n\n const redirectTo = response.data?.redirectTo;\n if (!redirectTo) {\n throw new Error(\"${input.label} checkout did not return a redirect URL.\");\n }\n\n window.location.assign(redirectTo);\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : \"Could not start ${input.label} checkout.\");\n setCheckingOut(null);\n }\n }\n\n return (\n <main className=\"min-h-screen bg-background px-6 py-12 text-foreground\">\n <section className=\"mx-auto flex w-full max-w-5xl flex-col gap-8\">\n <div className=\"max-w-2xl space-y-3\">\n <Badge variant=\"secondary\">${input.label}</Badge>\n <h1 className=\"text-3xl font-semibold tracking-normal\">${input.label} billing</h1>\n <p className=\"text-sm leading-6 text-muted-foreground\">\n Plans, checkout, and customer billing actions in one place.\n </p>\n </div>\n\n {error ? (\n <div className=\"rounded-md border border-destructive/30 bg-destructive/10 px-4 py-3 text-sm text-destructive\">\n {error}\n </div>\n ) : null}\n\n {loading ? (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {Array.from({ length: 3 }).map((_, index) => (\n <Card key={index} className=\"min-h-[220px] animate-pulse\" />\n ))}\n </div>\n ) : products.length ? (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {products.map((product) => {\n const productId = String(readProductField(product, \"id\") ?? \"\");\n const fallbackName = productId || \"Product\";\n const name = String(readProductField(product, \"name\") ?? fallbackName);\n const description =\n readProductField(product, \"description\") ?? \"Connected to your Stripe catalog.\";\n\n return (\n <Card key={productId || name} className=\"flex min-h-[260px] flex-col\">\n <CardHeader>\n <CardTitle className=\"text-xl\">{name}</CardTitle>\n <CardDescription>{String(description)}</CardDescription>\n </CardHeader>\n <CardContent className=\"flex-1\">\n <div className=\"text-3xl font-semibold\">{formatProductPrice(product)}</div>\n </CardContent>\n <CardFooter>\n <Button\n className=\"w-full\"\n disabled={!productId || checkingOut === productId}\n onClick={() => void startCheckout(product)}\n >\n {checkingOut === productId ? \"Starting checkout...\" : \"Checkout\"}\n </Button>\n </CardFooter>\n </Card>\n );\n })}\n </div>\n ) : (\n <Card>\n <CardHeader>\n <CardTitle>No products yet</CardTitle>\n <CardDescription>\n Add products to the generated ${input.label} integration template or provider dashboard.\n </CardDescription>\n </CardHeader>\n </Card>\n )}\n </section>\n </main>\n );\n}\n\nfunction readProductField(product: BillingProduct, field: string) {\n return (product as Record<string, unknown>)[field];\n}\n\nfunction formatProductPrice(product: BillingProduct) {\n const amount = readProductField(product, \"amount\") ?? readProductField(product, \"unitAmount\");\n const currency = String(readProductField(product, \"currency\") ?? \"USD\").toUpperCase();\n const interval = readProductField(product, \"interval\");\n\n if (typeof amount === \"number\" && Number.isFinite(amount)) {\n const formatted = new Intl.NumberFormat(\"en\", {\n style: \"currency\",\n currency,\n }).format(amount / 100);\n\n return interval ? \\`\\${formatted}/\\${String(interval)}\\` : formatted;\n }\n\n return \"Custom\";\n}\n\nfunction readErrorMessage(error: unknown, fallback: string) {\n if (error && typeof error === \"object\" && \"message\" in error) {\n return String((error as { message?: unknown }).message);\n }\n\n return fallback;\n}\n`;\n}\n\nfunction aiChatTemplate() {\n return `\"use client\";\n\nimport * as React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Input } from \"@/components/ui/input\";\n\ntype ChatMessage = {\n role: \"user\" | \"assistant\";\n content: string;\n};\n\nexport function AIChat() {\n const [messages, setMessages] = React.useState<ChatMessage[]>([]);\n const [input, setInput] = React.useState(\"\");\n const [pending, setPending] = React.useState(false);\n const [error, setError] = React.useState<string | null>(null);\n\n async function sendMessage(event: React.FormEvent<HTMLFormElement>) {\n event.preventDefault();\n const nextInput = input.trim();\n if (!nextInput) {\n return;\n }\n\n const nextMessages: ChatMessage[] = [...messages, { role: \"user\", content: nextInput }];\n setMessages(nextMessages);\n setInput(\"\");\n setPending(true);\n setError(null);\n\n try {\n const response = await fetch(\"/api/chat\", {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n messages: nextMessages.map((message) => ({\n role: message.role,\n parts: [{ type: \"text\", text: message.content }],\n })),\n }),\n });\n\n const text = await response.text();\n if (!response.ok) {\n throw new Error(text || \"AI request failed.\");\n }\n\n setMessages([...nextMessages, { role: \"assistant\", content: text || \"Done.\" }]);\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : \"AI request failed.\");\n } finally {\n setPending(false);\n }\n }\n\n return (\n <main className=\"min-h-screen bg-background px-6 py-12 text-foreground\">\n <section className=\"mx-auto flex w-full max-w-3xl flex-col gap-6\">\n <div className=\"space-y-3\">\n <Badge variant=\"secondary\">AI</Badge>\n <h1 className=\"text-3xl font-semibold tracking-normal\">Chat</h1>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-xl\">Conversation</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"min-h-[320px] space-y-3 rounded-md border bg-muted/30 p-4\">\n {messages.length ? (\n messages.map((message, index) => (\n <div\n key={index}\n className={message.role === \"user\" ? \"ml-auto max-w-[85%] rounded-md bg-primary px-3 py-2 text-sm text-primary-foreground\" : \"max-w-[85%] rounded-md bg-background px-3 py-2 text-sm\"}\n >\n {message.content}\n </div>\n ))\n ) : (\n <p className=\"text-sm text-muted-foreground\">Start a conversation.</p>\n )}\n </div>\n\n {error ? <p className=\"text-sm text-destructive\">{error}</p> : null}\n\n <form className=\"flex gap-2\" onSubmit={sendMessage}>\n <Input\n value={input}\n onChange={(event) => setInput(event.target.value)}\n placeholder=\"Ask something...\"\n />\n <Button disabled={pending} type=\"submit\">\n {pending ? \"Sending...\" : \"Send\"}\n </Button>\n </form>\n </CardContent>\n </Card>\n </section>\n </main>\n );\n}\n`;\n}\n\nfunction supabaseAuthTemplate(key: string) {\n return `\"use client\";\n\nimport * as React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { apiClient } from \"@/lib/api\";\n\nexport function SupabaseAuthPanel() {\n const [email, setEmail] = React.useState(\"\");\n const [password, setPassword] = React.useState(\"\");\n const [mode, setMode] = React.useState<\"login\" | \"signup\">(\"login\");\n const [pending, setPending] = React.useState(false);\n const [status, setStatus] = React.useState<string | null>(null);\n\n async function submit(event: React.FormEvent<HTMLFormElement>) {\n event.preventDefault();\n setPending(true);\n setStatus(null);\n\n const response =\n mode === \"login\"\n ? await apiClient.${key}.login.post({ body: { email, password, returnTo: \"/dashboard\" } })\n : await apiClient.${key}.signup.post({ body: { email, password, returnTo: \"/dashboard\" } });\n\n if (response.error) {\n setStatus(response.error.message);\n setPending(false);\n return;\n }\n\n if (response.data?.redirectTo) {\n window.location.assign(response.data.redirectTo);\n return;\n }\n\n setStatus(response.data?.message ?? \"Check your email to continue.\");\n setPending(false);\n }\n\n async function loadSession() {\n const response = await apiClient.${key}.session.get();\n setStatus(response.error ? response.error.message : response.data?.authenticated ? \"Authenticated\" : \"No active session\");\n }\n\n async function logout() {\n const response = await apiClient.${key}.logout.post({ body: { returnTo: \"/\" } });\n if (response.data?.redirectTo) {\n window.location.assign(response.data.redirectTo);\n return;\n }\n setStatus(response.error?.message ?? \"Signed out\");\n }\n\n return (\n <main className=\"min-h-screen bg-background px-6 py-12 text-foreground\">\n <section className=\"mx-auto flex w-full max-w-xl flex-col gap-6\">\n <div className=\"space-y-3\">\n <Badge variant=\"secondary\">Supabase</Badge>\n <h1 className=\"text-3xl font-semibold tracking-normal\">Auth</h1>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-xl\">{mode === \"login\" ? \"Sign in\" : \"Create account\"}</CardTitle>\n <CardDescription>Email and password access for this app.</CardDescription>\n </CardHeader>\n <CardContent>\n <form className=\"space-y-4\" onSubmit={submit}>\n <div className=\"space-y-2\">\n <Label htmlFor=\"email\">Email</Label>\n <Input id=\"email\" value={email} onChange={(event) => setEmail(event.target.value)} type=\"email\" />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"password\">Password</Label>\n <Input id=\"password\" value={password} onChange={(event) => setPassword(event.target.value)} type=\"password\" />\n </div>\n {status ? <p className=\"text-sm text-muted-foreground\">{status}</p> : null}\n <div className=\"flex flex-wrap gap-2\">\n <Button disabled={pending} type=\"submit\">{pending ? \"Working...\" : mode === \"login\" ? \"Sign in\" : \"Sign up\"}</Button>\n <Button type=\"button\" variant=\"outline\" onClick={() => setMode(mode === \"login\" ? \"signup\" : \"login\")}>\n {mode === \"login\" ? \"Use sign up\" : \"Use sign in\"}\n </Button>\n <Button type=\"button\" variant=\"ghost\" onClick={() => void loadSession()}>Session</Button>\n <Button type=\"button\" variant=\"ghost\" onClick={() => void logout()}>Logout</Button>\n </div>\n </form>\n </CardContent>\n </Card>\n </section>\n </main>\n );\n}\n`;\n}\n\nfunction hostedAuthTemplate(input: {\n key: string;\n provider: string;\n componentName: string;\n statusCall: string;\n logoutCall: string;\n loginHref: string;\n signupHref: string;\n statusLabel: string;\n}) {\n return `\"use client\";\n\nimport * as React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { apiClient } from \"@/lib/api\";\n\nexport function ${input.componentName}() {\n const [status, setStatus] = React.useState<string>(\"Idle\");\n const [pending, setPending] = React.useState(false);\n\n async function refreshStatus() {\n setPending(true);\n const response = await apiClient.${input.key}.${input.statusCall}();\n if (response.error) {\n setStatus(response.error.message);\n } else {\n setStatus(response.data?.authenticated ? \"Authenticated\" : \"No active session\");\n }\n setPending(false);\n }\n\n async function logout() {\n setPending(true);\n const response = await apiClient.${input.key}.${input.logoutCall}();\n if (response.data?.redirectTo) {\n window.location.assign(response.data.redirectTo);\n return;\n }\n setStatus(response.error?.message ?? \"Signed out\");\n setPending(false);\n }\n\n return (\n <main className=\"min-h-screen bg-background px-6 py-12 text-foreground\">\n <section className=\"mx-auto flex w-full max-w-3xl flex-col gap-6\">\n <div className=\"space-y-3\">\n <Badge variant=\"secondary\">${input.provider}</Badge>\n <h1 className=\"text-3xl font-semibold tracking-normal\">Auth</h1>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-xl\">${input.provider} session</CardTitle>\n <CardDescription>Hosted auth, account session, and sign-out controls.</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <p className=\"rounded-md border bg-muted/30 px-3 py-2 text-sm\">{status}</p>\n <div className=\"flex flex-wrap gap-2\">\n <Button type=\"button\" onClick={() => window.location.assign(\"${input.loginHref}\")}>Sign in</Button>\n <Button type=\"button\" variant=\"outline\" onClick={() => window.location.assign(\"${input.signupHref}\")}>Sign up</Button>\n <Button type=\"button\" variant=\"ghost\" disabled={pending} onClick={() => void refreshStatus()}>Refresh</Button>\n <Button type=\"button\" variant=\"ghost\" disabled={pending} onClick={() => void logout()}>Logout</Button>\n </div>\n </CardContent>\n </Card>\n </section>\n </main>\n );\n}\n`;\n}\n\nfunction authRouteShellTemplate(input: {\n provider: string;\n componentName: string;\n signInHref: string;\n signUpHref: string;\n sessionHref: string;\n}) {\n return `\"use client\";\n\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from \"@/components/ui/card\";\n\nexport function ${input.componentName}() {\n return (\n <main className=\"min-h-screen bg-background px-6 py-12 text-foreground\">\n <section className=\"mx-auto flex w-full max-w-3xl flex-col gap-6\">\n <div className=\"space-y-3\">\n <Badge variant=\"secondary\">${input.provider}</Badge>\n <h1 className=\"text-3xl font-semibold tracking-normal\">Auth</h1>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-xl\">${input.provider} routes</CardTitle>\n <CardDescription>Account entry points and session route.</CardDescription>\n </CardHeader>\n <CardContent className=\"flex flex-wrap gap-2\">\n <Button type=\"button\" onClick={() => window.location.assign(\"${input.signInHref}\")}>Sign in</Button>\n <Button type=\"button\" variant=\"outline\" onClick={() => window.location.assign(\"${input.signUpHref}\")}>Sign up</Button>\n <Button type=\"button\" variant=\"ghost\" onClick={() => window.location.assign(\"${input.sessionHref}\")}>Session</Button>\n </CardContent>\n </Card>\n </section>\n </main>\n );\n}\n`;\n}\n\nfunction betterAuthClientTemplate() {\n return `import { createAuthClient } from \"better-auth/react\";\n\nexport const authClient = createAuthClient({\n baseURL: \"\",\n});\n`;\n}\n\nfunction betterAuthPanelTemplate() {\n return `\"use client\";\n\nimport * as React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { authClient } from \"@/lib/auth-client\";\n\ntype Mode = \"sign-in\" | \"sign-up\";\n\nexport function BetterAuthPanel() {\n const [mode, setMode] = React.useState<Mode>(\"sign-in\");\n const [pending, setPending] = React.useState(false);\n const [message, setMessage] = React.useState(\"Ready\");\n const [sessionEmail, setSessionEmail] = React.useState<string | null>(null);\n\n async function submit(event: React.FormEvent<HTMLFormElement>) {\n event.preventDefault();\n setPending(true);\n setMessage(mode === \"sign-in\" ? \"Signing in…\" : \"Creating account…\");\n\n const form = new FormData(event.currentTarget);\n const email = String(form.get(\"email\") || \"\");\n const password = String(form.get(\"password\") || \"\");\n const name = String(form.get(\"name\") || \"\");\n try {\n const response =\n mode === \"sign-in\"\n ? await authClient.signIn.email({ email, password })\n : await authClient.signUp.email({ email, password, name });\n\n if (response.error) {\n setMessage(response.error.message || \"Authentication failed.\");\n return;\n }\n\n setSessionEmail(email);\n setMessage(mode === \"sign-in\" ? \"Signed in.\" : \"Account created.\");\n } catch (cause) {\n setMessage(cause instanceof Error ? cause.message : \"Could not reach the auth server.\");\n } finally {\n setPending(false);\n }\n }\n\n async function refreshSession() {\n setPending(true);\n try {\n const response = await authClient.getSession();\n setSessionEmail(response.data?.user.email || null);\n setMessage(response.error?.message || (response.data ? \"Session active.\" : \"No active session.\"));\n } catch (cause) {\n setMessage(cause instanceof Error ? cause.message : \"Could not read the session.\");\n } finally {\n setPending(false);\n }\n }\n\n async function signOut() {\n setPending(true);\n try {\n const response = await authClient.signOut();\n if (response.error) {\n setMessage(response.error.message || \"Could not sign out.\");\n return;\n }\n setSessionEmail(null);\n setMessage(\"Signed out.\");\n } catch (cause) {\n setMessage(cause instanceof Error ? cause.message : \"Could not reach the auth server.\");\n } finally {\n setPending(false);\n }\n }\n\n return (\n <main className=\"min-h-screen bg-background px-5 py-12 text-foreground sm:px-8\">\n <section className=\"mx-auto grid w-full max-w-5xl gap-8 lg:grid-cols-[1fr_420px] lg:items-start\">\n <div className=\"space-y-5 py-4\">\n <Badge variant=\"secondary\">Better Auth × Farm.js</Badge>\n <div className=\"space-y-3\">\n <h1 className=\"max-w-xl text-4xl font-semibold tracking-tight sm:text-5xl\">\n Authentication that starts ready.\n </h1>\n <p className=\"max-w-xl text-base leading-7 text-muted-foreground\">\n Test account creation, email sign-in, session reads, and sign-out through Farm’s\n generated Better Auth integration.\n </p>\n </div>\n <div aria-live=\"polite\" className=\"border-l-2 border-primary pl-4 text-sm\">\n <p className=\"font-medium\">{message}</p>\n <p className=\"mt-1 text-muted-foreground\">\n {sessionEmail ? \\`Signed in as \\${sessionEmail}\\` : \"No authenticated user\"}\n </p>\n </div>\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>{mode === \"sign-in\" ? \"Welcome back\" : \"Create an account\"}</CardTitle>\n <CardDescription>\n {mode === \"sign-in\"\n ? \"Enter your credentials to start a secure session.\"\n : \"Use an email and password to create your local account.\"}\n </CardDescription>\n </CardHeader>\n <CardContent>\n <form className=\"space-y-4\" onSubmit={submit}>\n {mode === \"sign-up\" ? (\n <div className=\"space-y-2\">\n <Label htmlFor=\"name\">Name</Label>\n <Input autoComplete=\"name\" id=\"name\" name=\"name\" required />\n </div>\n ) : null}\n <div className=\"space-y-2\">\n <Label htmlFor=\"email\">Email</Label>\n <Input autoComplete=\"email\" id=\"email\" name=\"email\" required type=\"email\" />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"password\">Password</Label>\n <Input\n autoComplete={mode === \"sign-in\" ? \"current-password\" : \"new-password\"}\n id=\"password\"\n minLength={8}\n name=\"password\"\n required\n type=\"password\"\n />\n </div>\n <Button className=\"w-full\" disabled={pending} type=\"submit\">\n {pending ? \"Working…\" : mode === \"sign-in\" ? \"Sign in\" : \"Create account\"}\n </Button>\n </form>\n\n <div className=\"mt-4 grid gap-2 sm:grid-cols-2\">\n <Button\n disabled={pending}\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setMode(mode === \"sign-in\" ? \"sign-up\" : \"sign-in\");\n setMessage(\"Ready\");\n }}\n >\n {mode === \"sign-in\" ? \"Create account\" : \"Use sign in\"}\n </Button>\n <Button disabled={pending} type=\"button\" variant=\"outline\" onClick={() => void refreshSession()}>\n Check session\n </Button>\n </div>\n <Button\n className=\"mt-2 w-full\"\n disabled={pending || !sessionEmail}\n type=\"button\"\n variant=\"ghost\"\n onClick={() => void signOut()}\n >\n Sign out\n </Button>\n </CardContent>\n </Card>\n </section>\n </main>\n );\n}\n`;\n}\n\nfunction resendEmailTemplate(key: string) {\n return `\"use client\";\n\nimport * as React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { apiClient } from \"@/lib/api\";\n\nexport function ResendEmailConsole() {\n const [to, setTo] = React.useState(\"\");\n const [name, setName] = React.useState(\"Ada\");\n const [templateId, setTemplateId] = React.useState(\"welcome\");\n const [status, setStatus] = React.useState(\"Idle\");\n const [previewHtml, setPreviewHtml] = React.useState(\"\");\n\n async function loadTemplates() {\n const response = await apiClient.${key}.templates.get();\n setStatus(response.error ? response.error.message : \"Templates: \" + (response.data ?? []).map((item) => item.id).join(\", \"));\n }\n\n async function preview() {\n const response = await apiClient.${key}.preview.post({\n body: {\n templateId,\n data: { name },\n },\n });\n if (response.error) {\n setStatus(response.error.message);\n return;\n }\n setPreviewHtml(response.data?.html ?? \"\");\n setStatus(response.data?.subject ?? \"Preview loaded\");\n }\n\n async function send() {\n const response = await apiClient.${key}.send.post({\n body: {\n templateId,\n to,\n data: { name },\n },\n });\n setStatus(response.error ? response.error.message : \"Sent \" + (response.data?.id ?? \"email\"));\n }\n\n return (\n <main className=\"min-h-screen bg-background px-6 py-12 text-foreground\">\n <section className=\"mx-auto flex w-full max-w-3xl flex-col gap-6\">\n <div className=\"space-y-3\">\n <Badge variant=\"secondary\">Resend</Badge>\n <h1 className=\"text-3xl font-semibold tracking-normal\">Email console</h1>\n </div>\n <Card>\n <CardHeader>\n <CardTitle className=\"text-xl\">Send template</CardTitle>\n <CardDescription>Template previews and delivery controls.</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid gap-4 sm:grid-cols-3\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"templateId\">Template</Label>\n <Input id=\"templateId\" value={templateId} onChange={(event) => setTemplateId(event.target.value)} />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"to\">To</Label>\n <Input id=\"to\" value={to} onChange={(event) => setTo(event.target.value)} />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"name\">Name</Label>\n <Input id=\"name\" value={name} onChange={(event) => setName(event.target.value)} />\n </div>\n </div>\n <p className=\"rounded-md border bg-muted/30 px-3 py-2 text-sm\">{status}</p>\n {previewHtml ? <div className=\"max-h-64 overflow-auto rounded-md border p-3 text-sm\" dangerouslySetInnerHTML={{ __html: previewHtml }} /> : null}\n <div className=\"flex flex-wrap gap-2\">\n <Button type=\"button\" variant=\"outline\" onClick={() => void loadTemplates()}>Templates</Button>\n <Button type=\"button\" variant=\"outline\" onClick={() => void preview()}>Preview</Button>\n <Button type=\"button\" onClick={() => void send()}>Send</Button>\n </div>\n </CardContent>\n </Card>\n </section>\n </main>\n );\n}\n`;\n}\n\nfunction jobsConsoleTemplate(key: string, label: string, provider: \"inngest\" | \"trigger\") {\n const componentName = `${pascalCase(provider)}JobsConsole`;\n\n return `\"use client\";\n\nimport * as React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { apiClient } from \"@/lib/api\";\n\ntype JobTask = {\n key: string;\n description?: string | null;\n};\n\nexport function ${componentName}() {\n const [tasks, setTasks] = React.useState<JobTask[]>([]);\n const [taskKey, setTaskKey] = React.useState(\"\");\n const [runId, setRunId] = React.useState(\"\");\n const [status, setStatus] = React.useState(\"Idle\");\n\n async function loadTasks() {\n const response = await apiClient.${key}.tasks.list();\n if (response.error) {\n setStatus(response.error.message);\n return;\n }\n const nextTasks = Array.from(response.data ?? []);\n setTasks(nextTasks);\n setTaskKey(nextTasks[0]?.key ?? \"\");\n setStatus(nextTasks.length ? \"Tasks loaded\" : \"No tasks registered yet\");\n }\n\n async function triggerTask() {\n const task = (apiClient.${key} as Record<string, any>)[taskKey];\n if (!task?.trigger) {\n setStatus(\"Select a task first.\");\n return;\n }\n const response = await task.trigger({ body: { input: {} } });\n setStatus(response.error ? response.error.message : \"Triggered \" + (response.data?.runId ?? response.data?.id ?? taskKey));\n }\n\n async function checkStatus() {\n const task = (apiClient.${key} as Record<string, any>)[taskKey];\n if (!task?.status || !runId) {\n setStatus(\"Enter a task and run id.\");\n return;\n }\n const response = await task.status({ query: { runId } });\n setStatus(response.error ? response.error.message : JSON.stringify(response.data));\n }\n\n return (\n <main className=\"min-h-screen bg-background px-6 py-12 text-foreground\">\n <section className=\"mx-auto flex w-full max-w-4xl flex-col gap-6\">\n <div className=\"space-y-3\">\n <Badge variant=\"secondary\">${label}</Badge>\n <h1 className=\"text-3xl font-semibold tracking-normal\">Jobs console</h1>\n </div>\n <Card>\n <CardHeader>\n <CardTitle className=\"text-xl\">Tasks</CardTitle>\n <CardDescription>Task runs and status checks.</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"taskKey\">Task key</Label>\n <Input id=\"taskKey\" value={taskKey} onChange={(event) => setTaskKey(event.target.value)} />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"runId\">Run id</Label>\n <Input id=\"runId\" value={runId} onChange={(event) => setRunId(event.target.value)} />\n </div>\n </div>\n <p className=\"rounded-md border bg-muted/30 px-3 py-2 text-sm\">{status}</p>\n <div className=\"flex flex-wrap gap-2\">\n <Button type=\"button\" variant=\"outline\" onClick={() => void loadTasks()}>Load tasks</Button>\n <Button type=\"button\" onClick={() => void triggerTask()}>Trigger</Button>\n <Button type=\"button\" variant=\"ghost\" onClick={() => void checkStatus()}>Status</Button>\n </div>\n {tasks.length ? (\n <div className=\"grid gap-2\">\n {tasks.map((task) => (\n <button key={task.key} className=\"rounded-md border px-3 py-2 text-left text-sm\" onClick={() => setTaskKey(task.key)} type=\"button\">\n {task.key}\n </button>\n ))}\n </div>\n ) : null}\n </CardContent>\n </Card>\n </section>\n </main>\n );\n}\n`;\n}\n\nfunction unkeyApiKeysTemplate(key: string) {\n return `\"use client\";\n\nimport * as React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { apiClient } from \"@/lib/api\";\n\nexport function UnkeyApiKeysConsole() {\n const [name, setName] = React.useState(\"Development key\");\n const [prefix, setPrefix] = React.useState(\"farm\");\n const [apiKey, setApiKey] = React.useState(\"\");\n const [status, setStatus] = React.useState(\"Idle\");\n\n async function createKey() {\n const response = await apiClient.${key}.createKey.post({\n body: {\n name,\n prefix,\n },\n });\n if (response.error) {\n setStatus(response.error.message);\n return;\n }\n setApiKey(response.data?.key ?? \"\");\n setStatus(\"Created \" + (response.data?.keyId ?? \"key\"));\n }\n\n async function verifyKey() {\n const response = await apiClient.${key}.verifyKey.post({\n body: {\n key: apiKey,\n },\n });\n setStatus(response.error ? response.error.message : response.data?.valid ? \"Valid key\" : \"Invalid key\");\n }\n\n return (\n <main className=\"min-h-screen bg-background px-6 py-12 text-foreground\">\n <section className=\"mx-auto flex w-full max-w-3xl flex-col gap-6\">\n <div className=\"space-y-3\">\n <Badge variant=\"secondary\">Unkey</Badge>\n <h1 className=\"text-3xl font-semibold tracking-normal\">API keys</h1>\n </div>\n <Card>\n <CardHeader>\n <CardTitle className=\"text-xl\">Key console</CardTitle>\n <CardDescription>API key lifecycle controls.</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"name\">Name</Label>\n <Input id=\"name\" value={name} onChange={(event) => setName(event.target.value)} />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"prefix\">Prefix</Label>\n <Input id=\"prefix\" value={prefix} onChange={(event) => setPrefix(event.target.value)} />\n </div>\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"apiKey\">API key</Label>\n <Input id=\"apiKey\" value={apiKey} onChange={(event) => setApiKey(event.target.value)} />\n </div>\n <p className=\"rounded-md border bg-muted/30 px-3 py-2 text-sm\">{status}</p>\n <div className=\"flex flex-wrap gap-2\">\n <Button type=\"button\" onClick={() => void createKey()}>Create key</Button>\n <Button type=\"button\" variant=\"outline\" onClick={() => void verifyKey()}>Verify</Button>\n </div>\n </CardContent>\n </Card>\n </section>\n </main>\n );\n}\n`;\n}\n\nfunction pascalCase(input: string) {\n return input\n .split(/[^A-Za-z0-9]+/g)\n .filter(Boolean)\n .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)\n .join(\"\");\n}\n\nfunction kebabCase(input: string) {\n return input\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .replace(/[^A-Za-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .toLowerCase();\n}\n\nfunction hasPackageDependency(manifest: PackageManifest, dependency: string) {\n return (\n dependency in (manifest.dependencies || {}) ||\n dependency in (manifest.devDependencies || {}) ||\n dependency in (manifest.peerDependencies || {}) ||\n dependency in (manifest.optionalDependencies || {})\n );\n}\n\nfunction readObject(value: unknown): Record<string, unknown> {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n\nfunction pushResultPath(list: string[], filePath: string) {\n if (!list.includes(filePath)) {\n list.push(filePath);\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n aiChatUIFeature,\n auth0AuthUIFeature,\n authjsUIFeature,\n autumnBillingUIFeature,\n betterAuthUIFeature,\n clerkAuthUIFeature,\n installUIFeature,\n jobsUIFeature,\n polarBillingUIFeature,\n resendEmailUIFeature,\n stripeBillingUIFeature,\n supabaseAuthUIFeature,\n unkeyApiKeysUIFeature,\n workosAuthUIFeature,\n type AddFarmIntegrationUIResult,\n type UIFeatureDefinition,\n} from \"./ui-feature-registry\";\n\nexport type { AddFarmIntegrationUIResult } from \"./ui-feature-registry\";\n\ntype PackageManifest = {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n};\n\nexport interface AddFarmIntegrationOptions {\n root?: string;\n provider: string;\n key?: string;\n integrationsFile?: string;\n routeFile?: string;\n ui?: boolean;\n skipPackageJson?: boolean;\n skipConfig?: boolean;\n dryRun?: boolean;\n force?: boolean;\n}\n\nexport interface AddFarmIntegrationResult {\n provider: FarmIntegrationProvider;\n key: string;\n mode?: \"integration\" | \"route\";\n integrationFile: string;\n registryFile: string;\n routeFile?: string;\n routePath?: string;\n packageJson?: string;\n configFile?: string;\n created: string[];\n updated: string[];\n skipped: string[];\n env: string[];\n notes: string[];\n ui?: AddFarmIntegrationUIResult;\n}\n\nexport type FarmIntegrationProvider =\n | \"ai\"\n | \"auth0\"\n | \"authjs\"\n | \"autumn\"\n | \"better-auth\"\n | \"clerk\"\n | \"jobs-inngest\"\n | \"jobs-trigger\"\n | \"polar\"\n | \"resend\"\n | \"stripe\"\n | \"supabase\"\n | \"unkey\"\n | \"workos\";\n\ninterface IntegrationProviderDefinition {\n provider: FarmIntegrationProvider;\n aliases: readonly string[];\n defaultKey: string;\n fileName: string;\n exportName: string;\n description: string;\n env: readonly string[];\n dependencies?: Readonly<Record<string, string>>;\n devDependencies?: Readonly<Record<string, string>>;\n setupFiles?: readonly {\n path: string;\n merge?: \"lines\";\n source(): string;\n }[];\n notes?: readonly string[];\n ui?: UIFeatureDefinition;\n template(): string;\n}\n\nconst PROVIDERS: readonly IntegrationProviderDefinition[] = [\n {\n provider: \"ai\",\n aliases: [\"ai-sdk\", \"vercel-ai\", \"vercel-ai-sdk\", \"chat\"],\n defaultKey: \"chat\",\n fileName: \"chat\",\n exportName: \"POST\",\n description: \"Vercel AI SDK chat route\",\n env: [\"AI_GATEWAY_API_KEY\"],\n notes: [\n 'Use @ai-sdk/react useChat with api: \"/api/chat\" on the client.',\n \"Replace model with any AI SDK provider model or Vercel AI Gateway model id.\",\n \"No farm.config integration wiring is required for this route.\",\n ],\n ui: aiChatUIFeature(),\n template: () => `import { aiChatRoute } from \"@farm.js/integrations/ai\";\n\nexport const POST = aiChatRoute({\n model: \"openai/gpt-4o-mini\",\n system: \"You are a helpful assistant.\",\n});\n`,\n },\n {\n provider: \"stripe\",\n aliases: [\"billing-stripe\", \"payments\", \"stripe-billing\"],\n defaultKey: \"billing\",\n fileName: \"stripe\",\n exportName: \"stripeIntegration\",\n description: \"Stripe billing and checkout routes\",\n env: [\"STRIPE_SECRET_KEY\", \"STRIPE_WEBHOOK_SECRET\"],\n template: () => `import { stripe } from \"@farm.js/integrations/stripe\";\n\nexport const stripeIntegration = stripe({\n secretKey: process.env.STRIPE_SECRET_KEY,\n webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,\n products: [],\n log(event) {\n console.log(\"[stripe]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n ui: stripeBillingUIFeature(),\n },\n {\n provider: \"supabase\",\n aliases: [\"auth-supabase\", \"supabase-auth\"],\n defaultKey: \"auth\",\n fileName: \"supabase\",\n exportName: \"supabaseIntegration\",\n description: \"Supabase auth routes and middleware\",\n env: [\"SUPABASE_URL\", \"SUPABASE_ANON_KEY\", \"APP_BASE_URL\"],\n ui: supabaseAuthUIFeature(),\n template: () => `import { supabase } from \"@farm.js/integrations/supabase\";\n\nexport const supabaseIntegration = supabase({\n callbackUrl: \\`\\${process.env.APP_BASE_URL || \"http://localhost:3000\"}/auth/callback\\`,\n protectedRoutes: [\"/dashboard(.*)\"],\n pages: {\n signIn: \"/sign-in\",\n signUp: \"/sign-up\",\n },\n log(event) {\n console.log(\"[supabase]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"workos\",\n aliases: [\"auth-workos\", \"workos-auth\"],\n defaultKey: \"auth\",\n fileName: \"workos\",\n exportName: \"workosIntegration\",\n description: \"WorkOS auth routes and protected route middleware\",\n env: [\"WORKOS_CLIENT_ID\", \"WORKOS_API_KEY\", \"WORKOS_COOKIE_PASSWORD\"],\n ui: workosAuthUIFeature(),\n template: () => `import { workos } from \"@farm.js/integrations/workos\";\n\nexport const workosIntegration = workos({\n protectedRoutes: [\"/dashboard(.*)\"],\n log(event) {\n console.log(\"[workos]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"auth0\",\n aliases: [\"auth-auth0\", \"auth0-auth\"],\n defaultKey: \"auth\",\n fileName: \"auth0\",\n exportName: \"auth0Integration\",\n description: \"Auth0 login, callback, logout, and profile routes\",\n env: [\"AUTH0_DOMAIN\", \"AUTH0_CLIENT_ID\", \"AUTH0_CLIENT_SECRET\", \"AUTH0_SECRET\"],\n ui: auth0AuthUIFeature(),\n template: () => `import { auth0 } from \"@farm.js/integrations/auth0\";\n\nexport const auth0Integration = auth0({\n callbackUrl: \\`\\${process.env.APP_BASE_URL || \"http://localhost:3000\"}/auth/callback\\`,\n protectedRoutes: [\"/dashboard(.*)\"],\n log(event) {\n console.log(\"[auth0]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"clerk\",\n aliases: [\"auth-clerk\", \"clerk-auth\"],\n defaultKey: \"auth\",\n fileName: \"clerk\",\n exportName: \"clerkIntegration\",\n description: \"Clerk auth provider and protected route middleware\",\n env: [\"NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY\", \"CLERK_SECRET_KEY\"],\n ui: clerkAuthUIFeature(),\n template: () => `import { clerk } from \"@farm.js/integrations/clerk\";\n\nexport const clerkIntegration = clerk({\n signInUrl: \"/sign-in\",\n signUpUrl: \"/sign-up\",\n protectedRoutes: [\"/dashboard(.*)\"],\n log(event) {\n console.log(\"[clerk]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"resend\",\n aliases: [\"email\", \"resend-email\"],\n defaultKey: \"email\",\n fileName: \"resend\",\n exportName: \"resendIntegration\",\n description: \"Resend email send, preview, schedule, and webhook routes\",\n env: [\"RESEND_API_KEY\", \"RESEND_FROM_EMAIL\", \"RESEND_WEBHOOK_SECRET\"],\n ui: resendEmailUIFeature(),\n template: () => `import { createElement } from \"react\";\nimport { resend, template } from \"@farm.js/integrations/email\";\n\nfunction WelcomeEmail(props: { name: string }) {\n return createElement(\"div\", null, \\`Welcome \\${props.name}\\`);\n}\n\nWelcomeEmail.PreviewProps = {\n name: \"Ada\",\n};\n\nexport const emailTemplates = {\n welcome: template(WelcomeEmail, {\n subject: ({ name }) => \\`Welcome, \\${name}\\`,\n previewText: () => \"Welcome to the app\",\n }),\n} as const;\n\nexport const resendIntegration = resend({\n apiKey: process.env.RESEND_API_KEY,\n defaults: {\n from: process.env.RESEND_FROM_EMAIL,\n replyTo: process.env.RESEND_REPLY_TO_EMAIL ?? process.env.RESEND_FROM_EMAIL,\n },\n templates: emailTemplates,\n webhooks: process.env.RESEND_WEBHOOK_SECRET\n ? {\n secret: process.env.RESEND_WEBHOOK_SECRET,\n }\n : undefined,\n log(event) {\n console.log(\"[resend]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"jobs-inngest\",\n aliases: [\"inngest\", \"jobs\"],\n defaultKey: \"jobs\",\n fileName: \"jobs-inngest\",\n exportName: \"jobsIntegration\",\n description: \"Jobs integration backed by Inngest\",\n env: [\"INNGEST_APP_ID\", \"INNGEST_EVENT_KEY\", \"INNGEST_SIGNING_KEY\"],\n notes: [\"Add tasks to jobTasks before using the generated jobs API.\"],\n ui: jobsUIFeature(\"inngest\"),\n template: () => `import { defineTasks, inngest, jobs } from \"@farm.js/integrations/jobs\";\n\nexport const jobTasks = defineTasks({});\n\nexport const jobsIntegration = jobs({\n runtime: inngest({\n appId: process.env.INNGEST_APP_ID,\n eventKey: process.env.INNGEST_EVENT_KEY,\n signingKey: process.env.INNGEST_SIGNING_KEY,\n }),\n tasks: jobTasks,\n log(event) {\n console.log(\"[jobs:inngest]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"jobs-trigger\",\n aliases: [\"trigger\", \"trigger-dev\", \"jobs-triggerdev\"],\n defaultKey: \"jobs\",\n fileName: \"jobs-trigger\",\n exportName: \"jobsIntegration\",\n description: \"Jobs integration backed by Trigger.dev\",\n env: [\"TRIGGER_PROJECT_REF\", \"TRIGGER_SECRET_KEY\", \"TRIGGER_WEBHOOK_SECRET\"],\n notes: [\"Add tasks to jobTasks before using the generated jobs API.\"],\n ui: jobsUIFeature(\"trigger\"),\n template: () => `import { defineTasks, jobs, trigger } from \"@farm.js/integrations/jobs\";\n\nexport const jobTasks = defineTasks({});\n\nexport const jobsIntegration = jobs({\n runtime: trigger({\n projectRef: process.env.TRIGGER_PROJECT_REF,\n apiKey: process.env.TRIGGER_SECRET_KEY,\n webhookSecret: process.env.TRIGGER_WEBHOOK_SECRET,\n }),\n tasks: jobTasks,\n log(event) {\n console.log(\"[jobs:trigger]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"polar\",\n aliases: [\"polar-billing\", \"billing-polar\"],\n defaultKey: \"billing\",\n fileName: \"polar\",\n exportName: \"polarIntegration\",\n description: \"Polar billing and checkout routes\",\n env: [\"POLAR_ACCESS_TOKEN\", \"POLAR_WEBHOOK_SECRET\", \"APP_BASE_URL\"],\n notes: [\"Replace resolveBillingOwner with your app user or organization lookup.\"],\n ui: polarBillingUIFeature(),\n template: () => `import type { FarmIntegrationHandlerContext } from \"@farm.js/core\";\nimport { polar } from \"@farm.js/integrations/polar\";\n\nasync function resolveBillingOwner(_context: FarmIntegrationHandlerContext) {\n throw new Error(\"Configure Polar billing owner resolution for your app.\");\n}\n\nexport const polarIntegration = polar({\n accessToken: process.env.POLAR_ACCESS_TOKEN,\n server: (process.env.POLAR_SERVER as \"sandbox\" | \"production\" | undefined) ?? \"sandbox\",\n appBaseUrl: process.env.APP_BASE_URL,\n webhooks: process.env.POLAR_WEBHOOK_SECRET\n ? {\n secret: process.env.POLAR_WEBHOOK_SECRET,\n }\n : undefined,\n billing: {\n resolveOwner: resolveBillingOwner,\n plans: {},\n products: {},\n },\n log(event) {\n console.log(\"[polar]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"autumn\",\n aliases: [\"autumn-billing\", \"billing-autumn\"],\n defaultKey: \"billing\",\n fileName: \"autumn\",\n exportName: \"autumnIntegration\",\n description: \"Autumn billing and checkout routes\",\n env: [\"AUTUMN_SECRET_KEY\", \"AUTUMN_WEBHOOK_SECRET\", \"APP_BASE_URL\"],\n notes: [\"Replace resolveBillingOwner with your app user or organization lookup.\"],\n ui: autumnBillingUIFeature(),\n template: () => `import type { FarmIntegrationHandlerContext } from \"@farm.js/core\";\nimport { autumn } from \"@farm.js/integrations/autumn\";\n\nasync function resolveBillingOwner(_context: FarmIntegrationHandlerContext) {\n throw new Error(\"Configure Autumn billing owner resolution for your app.\");\n}\n\nexport const autumnIntegration = autumn({\n secretKey: process.env.AUTUMN_SECRET_KEY,\n appBaseUrl: process.env.APP_BASE_URL,\n webhooks: process.env.AUTUMN_WEBHOOK_SECRET\n ? {\n secret: process.env.AUTUMN_WEBHOOK_SECRET,\n }\n : undefined,\n billing: {\n resolveOwner: resolveBillingOwner,\n plans: {},\n products: {},\n },\n log(event) {\n console.log(\"[autumn]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"better-auth\",\n aliases: [\"betterauth\", \"auth-better-auth\"],\n defaultKey: \"auth\",\n fileName: \"better-auth\",\n exportName: \"betterAuthIntegration\",\n description: \"Better Auth route adapter\",\n env: [\"BETTER_AUTH_SECRET\", \"BETTER_AUTH_URL\", \"BETTER_AUTH_DATABASE_PATH\"],\n dependencies: {\n \"better-auth\": \"^1.5.5\",\n \"better-sqlite3\": \"^12.6.2\",\n },\n devDependencies: {\n \"@types/better-sqlite3\": \"^7.6.13\",\n },\n notes: [\n \"The generated SQLite database is intended for local development. Configure a persistent production database before deploying.\",\n \"Set BETTER_AUTH_SECRET to a high-entropy value of at least 32 characters.\",\n ],\n setupFiles: [\n {\n path: \"src/lib/auth.ts\",\n source: () => `import Database from \"better-sqlite3\";\nimport { betterAuth as createBetterAuth } from \"better-auth\";\nimport { getMigrations } from \"better-auth/db/migration\";\n\nconst baseURL = process.env.BETTER_AUTH_URL || \"http://localhost:3000\";\nexport const auth = createBetterAuth({\n database: new Database(process.env.BETTER_AUTH_DATABASE_PATH || \"better-auth.sqlite\"),\n secret: process.env.BETTER_AUTH_SECRET,\n baseURL,\n trustedOrigins: [baseURL],\n emailAndPassword: {\n enabled: true,\n },\n});\n\nconst migrations = await getMigrations(auth.options);\nawait migrations.runMigrations();\n`,\n },\n {\n path: \".env.example\",\n merge: \"lines\",\n source: () => `BETTER_AUTH_SECRET=replace-with-at-least-32-random-characters\nBETTER_AUTH_URL=http://localhost:3000\nBETTER_AUTH_DATABASE_PATH=better-auth.sqlite\n`,\n },\n {\n path: \".gitignore\",\n merge: \"lines\",\n source: () => `better-auth.sqlite\nbetter-auth.sqlite-shm\nbetter-auth.sqlite-wal\n`,\n },\n ],\n ui: betterAuthUIFeature(),\n template: () => `import { betterAuth } from \"@farm.js/integrations/better-auth\";\nimport { auth } from \"../auth.ts\";\n\nexport const betterAuthIntegration = betterAuth({\n instance: auth,\n log(event) {\n console.log(\"[better-auth]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"authjs\",\n aliases: [\"auth-js\", \"nextauth\", \"next-auth\"],\n defaultKey: \"auth\",\n fileName: \"authjs\",\n exportName: \"authjsIntegration\",\n description: \"Auth.js route adapter\",\n env: [],\n notes: [\"This template expects src/lib/auth.ts to export an Auth.js instance named auth.\"],\n ui: authjsUIFeature(),\n template: () => `import { authjs } from \"@farm.js/integrations/authjs\";\nimport { auth } from \"../auth.ts\";\n\nexport const authjsIntegration = authjs({\n instance: auth,\n log(event) {\n console.log(\"[authjs]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n {\n provider: \"unkey\",\n aliases: [\"api-keys\", \"apikeys\", \"keys\", \"unkey-api-keys\"],\n defaultKey: \"apiKeys\",\n fileName: \"unkey\",\n exportName: \"unkeyIntegration\",\n description: \"Unkey API key creation, verification, and route protection\",\n env: [\"UNKEY_ROOT_KEY\", \"UNKEY_API_ID\", \"UNKEY_BASE_URL\"],\n ui: unkeyApiKeysUIFeature(),\n template: () => `import { unkey } from \"@farm.js/integrations/unkey\";\n\nexport const unkeyIntegration = unkey({\n rootKey: process.env.UNKEY_ROOT_KEY,\n apiId: process.env.UNKEY_API_ID,\n baseUrl: process.env.UNKEY_BASE_URL,\n protectedRoutes: [\"/api/protected(.*)\"],\n log(event) {\n console.log(\"[unkey]\", event.phase, event.route?.path || \"none\");\n },\n});\n`,\n },\n] as const;\n\nexport function listFarmIntegrationProviders() {\n return PROVIDERS.map((provider) => ({\n name: provider.provider,\n aliases: [...provider.aliases],\n defaultKey: provider.defaultKey,\n description: provider.description,\n env: [...provider.env],\n ui: provider.ui\n ? {\n feature: provider.ui.name,\n description: provider.ui.description,\n components: [...provider.ui.components],\n }\n : undefined,\n }));\n}\n\nexport async function addFarmIntegration(\n options: AddFarmIntegrationOptions,\n): Promise<AddFarmIntegrationResult> {\n const root = path.resolve(options.root || process.cwd());\n const definition = resolveProvider(options.provider);\n\n if (definition.provider === \"ai\") {\n return addAIRouteIntegration({\n root,\n definition,\n routeFile: options.routeFile,\n ui: options.ui,\n skipPackageJson: options.skipPackageJson,\n dryRun: options.dryRun,\n force: options.force,\n });\n }\n\n const key = options.key || definition.defaultKey;\n assertValidIntegrationKey(key);\n\n const registryFile = path.resolve(\n root,\n options.integrationsFile || path.join(\"src\", \"lib\", \"integrations.ts\"),\n );\n const integrationFile = path.join(\n path.dirname(registryFile),\n \"integrations\",\n `${definition.fileName}.ts`,\n );\n const result: AddFarmIntegrationResult = {\n provider: definition.provider,\n key,\n mode: \"integration\",\n integrationFile,\n registryFile,\n created: [],\n updated: [],\n skipped: [],\n env: [...definition.env],\n notes: [...(definition.notes || [])],\n };\n\n await writeIntegrationComponent({\n path: integrationFile,\n definition,\n force: options.force,\n dryRun: options.dryRun,\n result,\n });\n await writeIntegrationSetupFiles({\n root,\n definition,\n force: options.force,\n dryRun: options.dryRun,\n result,\n });\n await writeIntegrationRegistry({\n path: registryFile,\n integrationFile,\n definition,\n key,\n dryRun: options.dryRun,\n result,\n });\n\n if (!options.skipPackageJson) {\n await updatePackageJson({\n root,\n definition,\n dryRun: options.dryRun,\n result,\n });\n }\n\n if (!options.skipConfig) {\n await updateFarmConfig({\n root,\n registryFile,\n dryRun: options.dryRun,\n result,\n });\n }\n\n if (options.ui) {\n await installUIFeature({\n root,\n definition,\n key,\n dryRun: options.dryRun,\n force: options.force,\n skipPackageJson: options.skipPackageJson,\n result,\n });\n }\n\n return result;\n}\n\nasync function addAIRouteIntegration(input: {\n root: string;\n definition: IntegrationProviderDefinition;\n routeFile?: string;\n ui?: boolean;\n skipPackageJson?: boolean;\n dryRun?: boolean;\n force?: boolean;\n}): Promise<AddFarmIntegrationResult> {\n const routeFile = path.resolve(\n input.root,\n input.routeFile || path.join(\"src\", \"app\", \"api\", \"chat\", \"route.ts\"),\n );\n const result: AddFarmIntegrationResult = {\n provider: \"ai\",\n key: input.definition.defaultKey,\n mode: \"route\",\n integrationFile: routeFile,\n registryFile: \"\",\n routeFile,\n routePath: \"/api/chat\",\n created: [],\n updated: [],\n skipped: [],\n env: [...input.definition.env],\n notes: [...(input.definition.notes || [])],\n };\n\n await writeIntegrationComponent({\n path: routeFile,\n definition: input.definition,\n force: input.force,\n dryRun: input.dryRun,\n result,\n });\n\n if (!input.skipPackageJson) {\n await updatePackageJson({\n root: input.root,\n definition: input.definition,\n dryRun: input.dryRun,\n result,\n });\n }\n\n if (input.ui) {\n await installUIFeature({\n root: input.root,\n definition: input.definition,\n key: input.definition.defaultKey,\n dryRun: input.dryRun,\n force: input.force,\n skipPackageJson: input.skipPackageJson,\n result,\n });\n }\n\n return result;\n}\n\nfunction resolveProvider(input: string) {\n const normalized = input.trim().toLowerCase();\n const match = PROVIDERS.find(\n (provider) => provider.provider === normalized || provider.aliases.includes(normalized),\n );\n\n if (!match) {\n const supported = PROVIDERS.map((provider) => provider.provider).join(\", \");\n throw new Error(`Unknown integration \"${input}\". Supported integrations: ${supported}.`);\n }\n\n return match;\n}\n\nfunction assertValidIntegrationKey(key: string) {\n if (!/^[A-Za-z_$][\\w$]*$/.test(key)) {\n throw new Error(`Integration key \"${key}\" must be a valid JavaScript object property name.`);\n }\n}\n\nasync function writeIntegrationComponent(input: {\n path: string;\n definition: IntegrationProviderDefinition;\n force?: boolean;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const exists = existsSync(input.path);\n if (exists && !input.force) {\n input.result.skipped.push(input.path);\n return;\n }\n\n if (!input.dryRun) {\n await mkdir(path.dirname(input.path), { recursive: true });\n await writeFile(input.path, input.definition.template(), \"utf8\");\n }\n\n if (exists) {\n input.result.updated.push(input.path);\n } else {\n input.result.created.push(input.path);\n }\n}\n\nasync function writeIntegrationRegistry(input: {\n path: string;\n integrationFile: string;\n definition: IntegrationProviderDefinition;\n key: string;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const importPath = toImportPath(path.relative(path.dirname(input.path), input.integrationFile));\n const importLine = `import { ${input.definition.exportName} } from \"${importPath}\";`;\n const propertyLine = ` ${input.key}: ${input.definition.exportName},`;\n\n let nextSource: string;\n const exists = existsSync(input.path);\n\n if (exists) {\n const source = await readFile(input.path, \"utf8\");\n nextSource = ensureRegistryEntry(source, {\n importLine,\n propertyLine,\n key: input.key,\n exportName: input.definition.exportName,\n });\n } else {\n nextSource = `${importLine}\n\nexport const appIntegrations = {\n${propertyLine}\n} as const;\n\nexport type AppIntegrations = typeof appIntegrations;\n`;\n }\n\n if (!input.dryRun) {\n await mkdir(path.dirname(input.path), { recursive: true });\n await writeFile(input.path, nextSource, \"utf8\");\n }\n\n input.result[exists ? \"updated\" : \"created\"].push(input.path);\n}\n\nfunction ensureRegistryEntry(\n source: string,\n input: {\n importLine: string;\n propertyLine: string;\n key: string;\n exportName: string;\n },\n) {\n const keyPattern = new RegExp(`(^|\\\\n)\\\\s*${escapeRegExp(input.key)}\\\\s*:`, \"m\");\n if (keyPattern.test(source)) {\n if (source.includes(`${input.key}: ${input.exportName}`)) {\n return source.includes(input.importLine) ? source : `${input.importLine}\\n${source}`;\n }\n\n throw new Error(\n `Integration key \"${input.key}\" already exists in the app integrations registry. Pass --key to use a different key.`,\n );\n }\n\n const sourceWithImport = source.includes(input.importLine)\n ? source\n : `${input.importLine}\\n${source}`;\n const appIntegrationsPattern =\n /export\\s+const\\s+appIntegrations\\s*=\\s*\\{([\\s\\S]*?)\\}\\s*as\\s+const;/m;\n const match = sourceWithImport.match(appIntegrationsPattern);\n\n if (!match) {\n return `${sourceWithImport.trimEnd()}\n\nexport const appIntegrations = {\n${input.propertyLine}\n} as const;\n\nexport type AppIntegrations = typeof appIntegrations;\n`;\n }\n\n const body = match[1] || \"\";\n const nextBody = body.trim().length\n ? `${body.trimEnd()}\\n${input.propertyLine}\\n`\n : `\\n${input.propertyLine}\\n`;\n\n return sourceWithImport.replace(appIntegrationsPattern, () => {\n return `export const appIntegrations = {${nextBody}} as const;`;\n });\n}\n\nasync function writeIntegrationSetupFiles(input: {\n root: string;\n definition: IntegrationProviderDefinition;\n force?: boolean;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n for (const file of input.definition.setupFiles || []) {\n const absolutePath = path.join(input.root, file.path);\n const exists = existsSync(absolutePath);\n if (exists && !input.force) {\n if (file.merge === \"lines\") {\n const source = await readFile(absolutePath, \"utf8\");\n const additions = file\n .source()\n .split(/\\r?\\n/)\n .filter((line) => line && !source.split(/\\r?\\n/).includes(line));\n if (!additions.length) {\n input.result.skipped.push(absolutePath);\n continue;\n }\n\n if (!input.dryRun) {\n await writeFile(absolutePath, `${source.trimEnd()}\\n${additions.join(\"\\n\")}\\n`, \"utf8\");\n }\n input.result.updated.push(absolutePath);\n continue;\n }\n\n input.result.skipped.push(absolutePath);\n continue;\n }\n\n if (!input.dryRun) {\n await mkdir(path.dirname(absolutePath), { recursive: true });\n await writeFile(absolutePath, file.source(), \"utf8\");\n }\n\n input.result[exists ? \"updated\" : \"created\"].push(absolutePath);\n }\n}\n\nasync function updatePackageJson(input: {\n root: string;\n definition: IntegrationProviderDefinition;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const packageJsonPath = path.join(input.root, \"package.json\");\n if (!existsSync(packageJsonPath)) {\n input.result.skipped.push(packageJsonPath);\n return;\n }\n\n const source = await readFile(packageJsonPath, \"utf8\");\n const manifest = JSON.parse(source) as PackageManifest;\n\n const dependencies = missingDependencies(manifest, input.definition.dependencies);\n const devDependencies = missingDependencies(manifest, input.definition.devDependencies);\n manifest.dependencies = {\n ...manifest.dependencies,\n ...(hasPackageDependency(manifest, \"@farm.js/integrations\")\n ? {}\n : { \"@farm.js/integrations\": getFarmIntegrationsVersion(manifest) }),\n ...dependencies,\n };\n if (Object.keys(devDependencies).length) {\n manifest.devDependencies = {\n ...manifest.devDependencies,\n ...devDependencies,\n };\n }\n\n const nextSource = `${JSON.stringify(manifest, null, 2)}\\n`;\n if (source === nextSource) {\n input.result.packageJson = packageJsonPath;\n input.result.skipped.push(packageJsonPath);\n return;\n }\n\n if (!input.dryRun) {\n await writeFile(packageJsonPath, nextSource, \"utf8\");\n }\n\n input.result.packageJson = packageJsonPath;\n input.result.updated.push(packageJsonPath);\n}\n\nfunction missingDependencies(\n manifest: PackageManifest,\n dependencies: Readonly<Record<string, string>> | undefined,\n) {\n return Object.fromEntries(\n Object.entries(dependencies || {}).filter(([name]) => !hasPackageDependency(manifest, name)),\n );\n}\n\nasync function updateFarmConfig(input: {\n root: string;\n registryFile: string;\n dryRun?: boolean;\n result: AddFarmIntegrationResult;\n}) {\n const configFile = findFarmConfig(input.root);\n\n if (!configFile) {\n const newConfigFile = path.join(input.root, \"farm.config.ts\");\n const importPath = toImportPath(path.relative(input.root, input.registryFile));\n const source = `import { defineConfig } from \"@farm.js/core\";\nimport { appIntegrations } from \"${importPath}\";\n\nexport default defineConfig({\n integrations: appIntegrations,\n});\n`;\n\n if (!input.dryRun) {\n await writeFile(newConfigFile, source, \"utf8\");\n }\n\n input.result.configFile = newConfigFile;\n input.result.created.push(newConfigFile);\n return;\n }\n\n input.result.configFile = configFile;\n const source = await readFile(configFile, \"utf8\");\n if (/\\bintegrations\\s*:/.test(source)) {\n input.result.skipped.push(configFile);\n input.result.notes.push(\n `farm.config already has an integrations field. Confirm it includes appIntegrations from ${path.relative(input.root, input.registryFile)}.`,\n );\n return;\n }\n\n const importPath = toImportPath(path.relative(path.dirname(configFile), input.registryFile));\n const importLine = `import { appIntegrations } from \"${importPath}\";`;\n const sourceWithImport = source.includes(importLine) ? source : `${importLine}\\n${source}`;\n const nextSource = insertIntegrationsConfig(sourceWithImport);\n\n if (nextSource === sourceWithImport) {\n input.result.skipped.push(configFile);\n input.result.notes.push(\n `Could not safely update ${path.relative(input.root, configFile)}. Add integrations: appIntegrations manually.`,\n );\n return;\n }\n\n if (!input.dryRun) {\n await writeFile(configFile, nextSource, \"utf8\");\n }\n\n input.result.updated.push(configFile);\n}\n\nfunction insertIntegrationsConfig(source: string) {\n const defineConfigCall = /\\bdefine(?:Farm)?Config\\s*\\(\\s*\\{/;\n if (defineConfigCall.test(source)) {\n return source.replace(defineConfigCall, (match) => {\n return `${match}\\n integrations: appIntegrations,`;\n });\n }\n\n if (/export\\s+default\\s+\\{/.test(source)) {\n return source.replace(/export\\s+default\\s+\\{/, (match) => {\n return `${match}\\n integrations: appIntegrations,`;\n });\n }\n\n return source;\n}\n\nfunction findFarmConfig(root: string) {\n const candidates = [\n \"farm.config.ts\",\n \"farm.config.mts\",\n \"farm.config.js\",\n \"farm.config.mjs\",\n \"config.ts\",\n \"config.mts\",\n \"config.js\",\n \"config.mjs\",\n ];\n for (const candidate of candidates) {\n const absolutePath = path.join(root, candidate);\n if (existsSync(absolutePath)) {\n return absolutePath;\n }\n }\n\n return null;\n}\n\nfunction hasPackageDependency(manifest: PackageManifest, dependency: string) {\n return (\n dependency in (manifest.dependencies || {}) ||\n dependency in (manifest.devDependencies || {}) ||\n dependency in (manifest.peerDependencies || {}) ||\n dependency in (manifest.optionalDependencies || {})\n );\n}\n\nfunction getFarmIntegrationsVersion(manifest: PackageManifest) {\n const farmCoreVersion =\n manifest.dependencies?.[\"@farm.js/core\"] ??\n manifest.devDependencies?.[\"@farm.js/core\"] ??\n manifest.peerDependencies?.[\"@farm.js/core\"] ??\n manifest.optionalDependencies?.[\"@farm.js/core\"];\n\n return farmCoreVersion?.startsWith(\"workspace:\") ? \"workspace:*\" : \"latest\";\n}\n\nfunction toImportPath(relativePath: string) {\n const normalized = relativePath.split(path.sep).join(\"/\");\n const withDot = normalized.startsWith(\".\") ? normalized : `./${normalized}`;\n return withDot.replace(/\\.tsx?$/, \".ts\");\n}\n\nfunction escapeRegExp(input: string) {\n return input.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n"],"mappings":"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"}
|