vibecarbon 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (495) hide show
  1. package/LICENSE +663 -0
  2. package/README.md +188 -0
  3. package/carbon/.claude/hooks/task-completed-gate.sh +19 -0
  4. package/carbon/.claude/hooks/teammate-idle-gate.sh +29 -0
  5. package/carbon/.claude/settings.json +29 -0
  6. package/carbon/.cursor/rules/vibecarbon.mdc +6 -0
  7. package/carbon/.dockerignore +57 -0
  8. package/carbon/.env.example +219 -0
  9. package/carbon/.github/copilot-instructions.md +3 -0
  10. package/carbon/.github/workflows/deploy.yml +346 -0
  11. package/carbon/.github/workflows/vibecarbon-build.yml +81 -0
  12. package/carbon/.windsurfrules +74 -0
  13. package/carbon/AGENTS.md +422 -0
  14. package/carbon/CLAUDE.md +3 -0
  15. package/carbon/DEVELOPMENT.md +187 -0
  16. package/carbon/Dockerfile +98 -0
  17. package/carbon/LICENSE +21 -0
  18. package/carbon/PRODUCTION.md +364 -0
  19. package/carbon/README.md +193 -0
  20. package/carbon/TESTING.md +138 -0
  21. package/carbon/backup/Dockerfile +75 -0
  22. package/carbon/backup/backup.sh +95 -0
  23. package/carbon/backup/compose-backup.sh +140 -0
  24. package/carbon/biome.json +83 -0
  25. package/carbon/cloud-init/docker-ce-setup.yaml +55 -0
  26. package/carbon/cloud-init/k3s/master-init.sh +215 -0
  27. package/carbon/cloud-init/k3s/supabase-init.sh +167 -0
  28. package/carbon/cloud-init/k3s/worker-init.sh +147 -0
  29. package/carbon/components.json +24 -0
  30. package/carbon/content/blog/authentication-guide.mdx +34 -0
  31. package/carbon/content/blog/getting-started.mdx +41 -0
  32. package/carbon/content/changelog/v0-1-0.mdx +40 -0
  33. package/carbon/content/docs/analytics.mdx +90 -0
  34. package/carbon/content/docs/authentication.mdx +231 -0
  35. package/carbon/content/docs/background-jobs.mdx +116 -0
  36. package/carbon/content/docs/cli.mdx +630 -0
  37. package/carbon/content/docs/database.mdx +236 -0
  38. package/carbon/content/docs/deployment.mdx +227 -0
  39. package/carbon/content/docs/development.mdx +238 -0
  40. package/carbon/content/docs/environments.mdx +84 -0
  41. package/carbon/content/docs/getting-started.mdx +112 -0
  42. package/carbon/content/docs/legal/privacy-policy.mdx +89 -0
  43. package/carbon/content/docs/legal/terms-of-service.mdx +99 -0
  44. package/carbon/content/docs/optional-services.mdx +160 -0
  45. package/carbon/db/Dockerfile +23 -0
  46. package/carbon/docker-compose.dev-init.yml +5 -0
  47. package/carbon/docker-compose.metabase.override.yml +14 -0
  48. package/carbon/docker-compose.metabase.prod.yml +28 -0
  49. package/carbon/docker-compose.metabase.yml +84 -0
  50. package/carbon/docker-compose.n8n.override.yml +14 -0
  51. package/carbon/docker-compose.n8n.prod.yml +31 -0
  52. package/carbon/docker-compose.n8n.yml +97 -0
  53. package/carbon/docker-compose.observability.override.yml +18 -0
  54. package/carbon/docker-compose.observability.prod.yml +28 -0
  55. package/carbon/docker-compose.observability.yml +125 -0
  56. package/carbon/docker-compose.override.yml +28 -0
  57. package/carbon/docker-compose.prod.yml +294 -0
  58. package/carbon/docker-compose.yml +508 -0
  59. package/carbon/docker-entrypoint.sh +12 -0
  60. package/carbon/ha/activate-standby.sh +52 -0
  61. package/carbon/ha/primary-init.sql +36 -0
  62. package/carbon/ha/standby-init.sh +74 -0
  63. package/carbon/k8s/LICENSE +99 -0
  64. package/carbon/k8s/README.md +272 -0
  65. package/carbon/k8s/base/app/deployment.yaml +130 -0
  66. package/carbon/k8s/base/app/hpa.yaml +44 -0
  67. package/carbon/k8s/base/app/kustomization.yaml +10 -0
  68. package/carbon/k8s/base/app/network-policy.yaml +124 -0
  69. package/carbon/k8s/base/app/pdb.yaml +14 -0
  70. package/carbon/k8s/base/app/rbac.yaml +36 -0
  71. package/carbon/k8s/base/app/service.yaml +16 -0
  72. package/carbon/k8s/base/backup/cronjob.yaml +120 -0
  73. package/carbon/k8s/base/backup/kustomization.yaml +7 -0
  74. package/carbon/k8s/base/backup/network-policy.yaml +31 -0
  75. package/carbon/k8s/base/backup/rbac.yaml +7 -0
  76. package/carbon/k8s/base/cluster-autoscaler/deployment.yaml +103 -0
  77. package/carbon/k8s/base/cluster-autoscaler/kustomization.yaml +17 -0
  78. package/carbon/k8s/base/cluster-autoscaler/rbac.yaml +109 -0
  79. package/carbon/k8s/base/config/configmap.yaml +48 -0
  80. package/carbon/k8s/base/config/kustomization.yaml +8 -0
  81. package/carbon/k8s/base/hetzner-ccm/kustomization.yaml +9 -0
  82. package/carbon/k8s/base/hetzner-csi/kustomization.yaml +9 -0
  83. package/carbon/k8s/base/kustomization.yaml +43 -0
  84. package/carbon/k8s/base/namespace.yaml +7 -0
  85. package/carbon/k8s/base/network-policies.yaml +95 -0
  86. package/carbon/k8s/base/registry/kustomization.yaml +5 -0
  87. package/carbon/k8s/base/registry/local-registry.yaml +193 -0
  88. package/carbon/k8s/base/traefik/certificate.yaml +21 -0
  89. package/carbon/k8s/base/traefik/configmap.yaml +13 -0
  90. package/carbon/k8s/base/traefik/deployment.yaml +165 -0
  91. package/carbon/k8s/base/traefik/ingressroute.yaml +141 -0
  92. package/carbon/k8s/base/traefik/kustomization.yaml +11 -0
  93. package/carbon/k8s/base/traefik/middleware.yaml +109 -0
  94. package/carbon/k8s/base/traefik/network-policy.yaml +92 -0
  95. package/carbon/k8s/base/traefik/service.yaml +38 -0
  96. package/carbon/k8s/flux/README.md +49 -0
  97. package/carbon/k8s/flux/clusters/primary/vibecarbon.yaml +128 -0
  98. package/carbon/k8s/flux/clusters/standby/vibecarbon.yaml +83 -0
  99. package/carbon/k8s/gitops/cert-manager-webhook-hetzner/helm-release.yaml +38 -0
  100. package/carbon/k8s/gitops/cert-manager-webhook-hetzner/helm-repository.yaml +16 -0
  101. package/carbon/k8s/gitops/cert-manager-webhook-hetzner/kustomization.yaml +10 -0
  102. package/carbon/k8s/gitops/supabase/helm-release.yaml +66 -0
  103. package/carbon/k8s/gitops/supabase/helm-repository.yaml +18 -0
  104. package/carbon/k8s/gitops/supabase/kustomization.yaml +33 -0
  105. package/carbon/k8s/infra/cert-manager-resources/cluster-issuers-cloudflare.yaml +51 -0
  106. package/carbon/k8s/infra/cert-manager-resources/cluster-issuers-hetzner.yaml +59 -0
  107. package/carbon/k8s/infra/cert-manager-resources/cluster-issuers-manual.yaml +43 -0
  108. package/carbon/k8s/infra/cert-manager-resources/kustomization.yaml +15 -0
  109. package/carbon/k8s/infra/kustomization.yaml +21 -0
  110. package/carbon/k8s/infra/traefik-crds/kustomization.yaml +10 -0
  111. package/carbon/k8s/overlays/local/configmap.yaml +23 -0
  112. package/carbon/k8s/overlays/local/ingressroute-studio.yaml +104 -0
  113. package/carbon/k8s/overlays/local/kustomization.yaml +215 -0
  114. package/carbon/k8s/overlays/local/namespace.yaml +8 -0
  115. package/carbon/k8s/overlays/local/secrets.yaml +32 -0
  116. package/carbon/k8s/overlays/production/kustomization.yaml +34 -0
  117. package/carbon/k8s/test-local.sh +318 -0
  118. package/carbon/k8s/values/supabase.values.yaml +133 -0
  119. package/carbon/package.json +154 -0
  120. package/carbon/runtime.Dockerfile +17 -0
  121. package/carbon/scripts/_dev-jwt.mjs +45 -0
  122. package/carbon/scripts/check-rls.ts +53 -0
  123. package/carbon/scripts/dev-init.js +191 -0
  124. package/carbon/scripts/dev.js +191 -0
  125. package/carbon/scripts/docker-down.js +63 -0
  126. package/carbon/scripts/docker-logs.js +59 -0
  127. package/carbon/scripts/docker-up.js +222 -0
  128. package/carbon/scripts/generate-dev-configs.sh +131 -0
  129. package/carbon/scripts/generate-rss.ts +116 -0
  130. package/carbon/scripts/generate-sitemap.ts +102 -0
  131. package/carbon/scripts/k8s-apply.js +71 -0
  132. package/carbon/scripts/k8s-delete.js +75 -0
  133. package/carbon/scripts/lib/manifest.js +176 -0
  134. package/carbon/scripts/secret-scan.mjs +278 -0
  135. package/carbon/scripts/validate-dev-configs.sh +101 -0
  136. package/carbon/src/client/App.tsx +202 -0
  137. package/carbon/src/client/assets/hyperformant-dark.svg +29 -0
  138. package/carbon/src/client/assets/hyperformant-light.svg +29 -0
  139. package/carbon/src/client/assets/logos/aider.svg +1 -0
  140. package/carbon/src/client/assets/logos/antigravity.svg +1 -0
  141. package/carbon/src/client/assets/logos/bolt.svg +1 -0
  142. package/carbon/src/client/assets/logos/claude-code.svg +1 -0
  143. package/carbon/src/client/assets/logos/copilot.svg +1 -0
  144. package/carbon/src/client/assets/logos/cursor.svg +1 -0
  145. package/carbon/src/client/assets/logos/gemini-cli.svg +1 -0
  146. package/carbon/src/client/assets/logos/lovable.svg +1 -0
  147. package/carbon/src/client/assets/logos/openai-codex.svg +1 -0
  148. package/carbon/src/client/assets/logos/v0.svg +1 -0
  149. package/carbon/src/client/assets/logos/windsurf.svg +1 -0
  150. package/carbon/src/client/assets/vibecarbon-icon.svg +19 -0
  151. package/carbon/src/client/assets/vibecarbon-logo-dark.svg +29 -0
  152. package/carbon/src/client/assets/vibecarbon-logo-light.svg +29 -0
  153. package/carbon/src/client/components/AIIntegrationSection.tsx +120 -0
  154. package/carbon/src/client/components/AppSidebar.tsx +760 -0
  155. package/carbon/src/client/components/ArchitectureSection.tsx +46 -0
  156. package/carbon/src/client/components/CTAFooter.tsx +59 -0
  157. package/carbon/src/client/components/ComparisonSection.tsx +132 -0
  158. package/carbon/src/client/components/ContentPanel.tsx +66 -0
  159. package/carbon/src/client/components/ContentSkeleton.tsx +21 -0
  160. package/carbon/src/client/components/ErrorBoundary.tsx +46 -0
  161. package/carbon/src/client/components/FAQSection.tsx +76 -0
  162. package/carbon/src/client/components/FileUpload.tsx +210 -0
  163. package/carbon/src/client/components/HeaderActions.tsx +17 -0
  164. package/carbon/src/client/components/Hero.tsx +608 -0
  165. package/carbon/src/client/components/ImpersonationBanner.tsx +31 -0
  166. package/carbon/src/client/components/LanguageSwitcher.tsx +67 -0
  167. package/carbon/src/client/components/Logo.tsx +87 -0
  168. package/carbon/src/client/components/LogoStrip.tsx +76 -0
  169. package/carbon/src/client/components/MetricsStrip.tsx +48 -0
  170. package/carbon/src/client/components/Nav.tsx +195 -0
  171. package/carbon/src/client/components/NewsletterSignup.tsx +147 -0
  172. package/carbon/src/client/components/NotificationDrawer.tsx +171 -0
  173. package/carbon/src/client/components/PageHeader.tsx +24 -0
  174. package/carbon/src/client/components/PlanGate.tsx +36 -0
  175. package/carbon/src/client/components/PricingSection.tsx +371 -0
  176. package/carbon/src/client/components/SEO.tsx +34 -0
  177. package/carbon/src/client/components/SmoothScroll.tsx +45 -0
  178. package/carbon/src/client/components/TechStackSection.tsx +165 -0
  179. package/carbon/src/client/components/WorkflowSection.tsx +604 -0
  180. package/carbon/src/client/components/admin/DockerLogs.tsx +276 -0
  181. package/carbon/src/client/components/admin/PerformanceMetrics.tsx +230 -0
  182. package/carbon/src/client/components/admin/ServiceCard.tsx +45 -0
  183. package/carbon/src/client/components/admin/ServicesStatus.tsx +296 -0
  184. package/carbon/src/client/components/architecture/ArchitectureDiagram.tsx +413 -0
  185. package/carbon/src/client/components/auth/AuthProvider.tsx +466 -0
  186. package/carbon/src/client/components/effects/FilmGrainOverlay.tsx +35 -0
  187. package/carbon/src/client/components/effects/FresnelEdge.tsx +49 -0
  188. package/carbon/src/client/components/effects/GlowTracker.tsx +46 -0
  189. package/carbon/src/client/components/effects/SparkBurst.tsx +145 -0
  190. package/carbon/src/client/components/effects/VGlowEffect.tsx +83 -0
  191. package/carbon/src/client/components/effects/index.ts +2 -0
  192. package/carbon/src/client/components/layouts/SidebarLayout.tsx +20 -0
  193. package/carbon/src/client/components/scroll/ScrollSection.tsx +76 -0
  194. package/carbon/src/client/components/scroll/ScrollytellingProvider.tsx +81 -0
  195. package/carbon/src/client/components/scroll/index.ts +2 -0
  196. package/carbon/src/client/components/ui/accordion.tsx +71 -0
  197. package/carbon/src/client/components/ui/alert-dialog.tsx +162 -0
  198. package/carbon/src/client/components/ui/alert.tsx +73 -0
  199. package/carbon/src/client/components/ui/aspect-ratio.tsx +22 -0
  200. package/carbon/src/client/components/ui/avatar.tsx +91 -0
  201. package/carbon/src/client/components/ui/badge.tsx +50 -0
  202. package/carbon/src/client/components/ui/breadcrumb.tsx +100 -0
  203. package/carbon/src/client/components/ui/button-group.tsx +78 -0
  204. package/carbon/src/client/components/ui/button.tsx +120 -0
  205. package/carbon/src/client/components/ui/calendar.tsx +182 -0
  206. package/carbon/src/client/components/ui/card.tsx +85 -0
  207. package/carbon/src/client/components/ui/carousel.tsx +227 -0
  208. package/carbon/src/client/components/ui/chart.tsx +357 -0
  209. package/carbon/src/client/components/ui/checkbox.tsx +27 -0
  210. package/carbon/src/client/components/ui/collapsible.tsx +15 -0
  211. package/carbon/src/client/components/ui/command.tsx +178 -0
  212. package/carbon/src/client/components/ui/context-menu.tsx +233 -0
  213. package/carbon/src/client/components/ui/dialog.tsx +132 -0
  214. package/carbon/src/client/components/ui/drawer.tsx +118 -0
  215. package/carbon/src/client/components/ui/dropdown-menu.tsx +242 -0
  216. package/carbon/src/client/components/ui/empty.tsx +94 -0
  217. package/carbon/src/client/components/ui/field.tsx +226 -0
  218. package/carbon/src/client/components/ui/hover-card.tsx +44 -0
  219. package/carbon/src/client/components/ui/input-group.tsx +146 -0
  220. package/carbon/src/client/components/ui/input-otp.tsx +83 -0
  221. package/carbon/src/client/components/ui/input.tsx +20 -0
  222. package/carbon/src/client/components/ui/item.tsx +188 -0
  223. package/carbon/src/client/components/ui/kbd.tsx +26 -0
  224. package/carbon/src/client/components/ui/label.tsx +21 -0
  225. package/carbon/src/client/components/ui/menubar.tsx +250 -0
  226. package/carbon/src/client/components/ui/navigation-menu.tsx +155 -0
  227. package/carbon/src/client/components/ui/pagination.tsx +102 -0
  228. package/carbon/src/client/components/ui/popover.tsx +75 -0
  229. package/carbon/src/client/components/ui/progress.tsx +66 -0
  230. package/carbon/src/client/components/ui/radio-group.tsx +36 -0
  231. package/carbon/src/client/components/ui/resizable.tsx +46 -0
  232. package/carbon/src/client/components/ui/scroll-area.tsx +48 -0
  233. package/carbon/src/client/components/ui/select.tsx +186 -0
  234. package/carbon/src/client/components/ui/separator.tsx +21 -0
  235. package/carbon/src/client/components/ui/sheet.tsx +124 -0
  236. package/carbon/src/client/components/ui/sidebar.tsx +702 -0
  237. package/carbon/src/client/components/ui/skeleton.tsx +13 -0
  238. package/carbon/src/client/components/ui/slider.tsx +57 -0
  239. package/carbon/src/client/components/ui/sonner.tsx +45 -0
  240. package/carbon/src/client/components/ui/spinner.tsx +15 -0
  241. package/carbon/src/client/components/ui/switch.tsx +30 -0
  242. package/carbon/src/client/components/ui/table.tsx +89 -0
  243. package/carbon/src/client/components/ui/tabs.tsx +73 -0
  244. package/carbon/src/client/components/ui/textarea.tsx +18 -0
  245. package/carbon/src/client/components/ui/toggle-group.tsx +87 -0
  246. package/carbon/src/client/components/ui/toggle.tsx +44 -0
  247. package/carbon/src/client/components/ui/tooltip.tsx +56 -0
  248. package/carbon/src/client/hooks/api/index.ts +14 -0
  249. package/carbon/src/client/hooks/api/useAuthSettings.ts +80 -0
  250. package/carbon/src/client/hooks/api/useSubscription.ts +87 -0
  251. package/carbon/src/client/hooks/use-mobile.ts +21 -0
  252. package/carbon/src/client/hooks/useMousePosition.ts +91 -0
  253. package/carbon/src/client/hooks/useNotifications.tsx +124 -0
  254. package/carbon/src/client/hooks/useOrganizationMembers.ts +127 -0
  255. package/carbon/src/client/hooks/useOrganizations.tsx +230 -0
  256. package/carbon/src/client/hooks/usePackageManager.ts +69 -0
  257. package/carbon/src/client/hooks/useReducedMotion.ts +20 -0
  258. package/carbon/src/client/hooks/useRunningServices.ts +114 -0
  259. package/carbon/src/client/hooks/useScrollProgress.ts +56 -0
  260. package/carbon/src/client/index.css +467 -0
  261. package/carbon/src/client/index.html +56 -0
  262. package/carbon/src/client/lib/admin-services.ts +151 -0
  263. package/carbon/src/client/lib/api.ts +32 -0
  264. package/carbon/src/client/lib/blog.ts +35 -0
  265. package/carbon/src/client/lib/changelog.ts +33 -0
  266. package/carbon/src/client/lib/docs-search.ts +101 -0
  267. package/carbon/src/client/lib/docs.ts +37 -0
  268. package/carbon/src/client/lib/i18n.ts +32 -0
  269. package/carbon/src/client/lib/supabase.ts +72 -0
  270. package/carbon/src/client/lib/tailwind-colors.ts +357 -0
  271. package/carbon/src/client/lib/theme.ts +117 -0
  272. package/carbon/src/client/lib/utils.ts +22 -0
  273. package/carbon/src/client/locales/de.json +529 -0
  274. package/carbon/src/client/locales/en.json +461 -0
  275. package/carbon/src/client/locales/es.json +529 -0
  276. package/carbon/src/client/locales/fr.json +529 -0
  277. package/carbon/src/client/locales/pt.json +529 -0
  278. package/carbon/src/client/main.tsx +56 -0
  279. package/carbon/src/client/mdx.d.ts +13 -0
  280. package/carbon/src/client/pages/ApiDocs.tsx +76 -0
  281. package/carbon/src/client/pages/AuthCallback.tsx +34 -0
  282. package/carbon/src/client/pages/Blog.tsx +167 -0
  283. package/carbon/src/client/pages/Changelog.tsx +171 -0
  284. package/carbon/src/client/pages/Charts.tsx +388 -0
  285. package/carbon/src/client/pages/Checkout.tsx +227 -0
  286. package/carbon/src/client/pages/Contact.tsx +174 -0
  287. package/carbon/src/client/pages/Dashboard.tsx +368 -0
  288. package/carbon/src/client/pages/Docs.tsx +372 -0
  289. package/carbon/src/client/pages/ForgotPassword.tsx +111 -0
  290. package/carbon/src/client/pages/Home.tsx +187 -0
  291. package/carbon/src/client/pages/Legal.tsx +100 -0
  292. package/carbon/src/client/pages/Login.tsx +408 -0
  293. package/carbon/src/client/pages/MFAVerify.tsx +156 -0
  294. package/carbon/src/client/pages/NotFound.tsx +21 -0
  295. package/carbon/src/client/pages/Onboarding.tsx +246 -0
  296. package/carbon/src/client/pages/ResetPassword.tsx +200 -0
  297. package/carbon/src/client/pages/UIComponents.tsx +390 -0
  298. package/carbon/src/client/pages/admin/ContactSubmissions.tsx +220 -0
  299. package/carbon/src/client/pages/admin/Dashboard.tsx +24 -0
  300. package/carbon/src/client/pages/admin/Infrastructure.tsx +257 -0
  301. package/carbon/src/client/pages/admin/Jobs.tsx +225 -0
  302. package/carbon/src/client/pages/admin/Logs.tsx +18 -0
  303. package/carbon/src/client/pages/admin/Newsletter.tsx +300 -0
  304. package/carbon/src/client/pages/admin/Notifications.tsx +603 -0
  305. package/carbon/src/client/pages/admin/Organizations.tsx +306 -0
  306. package/carbon/src/client/pages/admin/Settings.tsx +314 -0
  307. package/carbon/src/client/pages/admin/Theme.tsx +465 -0
  308. package/carbon/src/client/pages/admin/Users.tsx +365 -0
  309. package/carbon/src/client/pages/api-docs.css +156 -0
  310. package/carbon/src/client/pages/organizations/Details.tsx +200 -0
  311. package/carbon/src/client/pages/organizations/Members.tsx +402 -0
  312. package/carbon/src/client/pages/settings/Billing.tsx +473 -0
  313. package/carbon/src/client/pages/settings/Profile.tsx +160 -0
  314. package/carbon/src/client/pages/settings/Security.tsx +341 -0
  315. package/carbon/src/client/public/favicon.svg +19 -0
  316. package/carbon/src/client/public/robots.txt +8 -0
  317. package/carbon/src/server/billing/index.ts +104 -0
  318. package/carbon/src/server/billing/provider.ts +81 -0
  319. package/carbon/src/server/billing/providers/paddle.ts +314 -0
  320. package/carbon/src/server/billing/providers/polar.ts +325 -0
  321. package/carbon/src/server/billing/providers/stripe.ts +233 -0
  322. package/carbon/src/server/emails/templates.ts +116 -0
  323. package/carbon/src/server/index.ts +554 -0
  324. package/carbon/src/server/lib/auth.ts +6 -0
  325. package/carbon/src/server/lib/email.ts +64 -0
  326. package/carbon/src/server/lib/env.ts +112 -0
  327. package/carbon/src/server/lib/errors.ts +21 -0
  328. package/carbon/src/server/lib/logger.ts +17 -0
  329. package/carbon/src/server/lib/rate-limiter.ts +288 -0
  330. package/carbon/src/server/lib/request.ts +34 -0
  331. package/carbon/src/server/lib/stripe.ts +42 -0
  332. package/carbon/src/server/lib/supabase.ts +65 -0
  333. package/carbon/src/server/middleware/requirePlan.ts +80 -0
  334. package/carbon/src/server/routes/_internal/services-status.ts +958 -0
  335. package/carbon/src/server/routes/_internal/verify-role.ts +185 -0
  336. package/carbon/src/server/routes/health.ts +48 -0
  337. package/carbon/src/server/routes/v1/admin/contact.ts +128 -0
  338. package/carbon/src/server/routes/v1/admin/jobs.ts +171 -0
  339. package/carbon/src/server/routes/v1/admin/newsletter.ts +237 -0
  340. package/carbon/src/server/routes/v1/auth.ts +390 -0
  341. package/carbon/src/server/routes/v1/billing.ts +718 -0
  342. package/carbon/src/server/routes/v1/contact.ts +93 -0
  343. package/carbon/src/server/routes/v1/index.ts +1333 -0
  344. package/carbon/src/server/routes/v1/newsletter.ts +181 -0
  345. package/carbon/src/server/routes/v1/performance.ts +157 -0
  346. package/carbon/src/server/routes/v1/stats.ts +170 -0
  347. package/carbon/src/server/routes/v1/theme.ts +106 -0
  348. package/carbon/src/server/routes/webhooks/billing.ts +376 -0
  349. package/carbon/src/server/routes/webhooks/stripe.ts +276 -0
  350. package/carbon/src/server/types.ts +11 -0
  351. package/carbon/src/shared/pricing.ts +155 -0
  352. package/carbon/src/shared/types.ts +338 -0
  353. package/carbon/supabase/migrations/00001_init.sql +717 -0
  354. package/carbon/supabase/migrations/00002_theme_settings.sql +13 -0
  355. package/carbon/supabase/migrations/00003_pg_cron.sql +121 -0
  356. package/carbon/supabase/migrations/00004_contact_newsletter.sql +81 -0
  357. package/carbon/supabase/migrations/00005_localization_languages.sql +22 -0
  358. package/carbon/supabase/seed.sql +16 -0
  359. package/carbon/tests/_helpers/app.ts +45 -0
  360. package/carbon/tests/_helpers/env.ts +37 -0
  361. package/carbon/tests/_helpers/factories.ts +69 -0
  362. package/carbon/tests/_helpers/jwt.ts +23 -0
  363. package/carbon/tests/_helpers/setup-integration.ts +20 -0
  364. package/carbon/tests/_helpers/setup-rtl.ts +12 -0
  365. package/carbon/tests/component/ErrorBoundary.test.tsx +53 -0
  366. package/carbon/tests/component/use-auth-settings.test.tsx +119 -0
  367. package/carbon/tests/integration/server/routes/contact.test.ts +162 -0
  368. package/carbon/tests/integration/server/routes/health.test.ts +61 -0
  369. package/carbon/tests/structural/i18n-parity.test.ts +42 -0
  370. package/carbon/tests/unit/client/utils.test.ts +49 -0
  371. package/carbon/tests/unit/shared/pricing.test.ts +93 -0
  372. package/carbon/tsconfig.json +27 -0
  373. package/carbon/tsconfig.server.json +27 -0
  374. package/carbon/tsconfig.test.json +9 -0
  375. package/carbon/vite.config.ts +110 -0
  376. package/carbon/vitest.config.ts +74 -0
  377. package/carbon/volumes/db/jwt.sql +57 -0
  378. package/carbon/volumes/db/metabase-init.sh +29 -0
  379. package/carbon/volumes/db/n8n-init.sh +25 -0
  380. package/carbon/volumes/db/realtime.sql +33 -0
  381. package/carbon/volumes/db/roles.sql +93 -0
  382. package/carbon/volumes/db/set-passwords.sh +12 -0
  383. package/carbon/volumes/db/super-admin.dev.sql +113 -0
  384. package/carbon/volumes/db/super-admin.generated.sql +113 -0
  385. package/carbon/volumes/db/super-admin.sql +114 -0
  386. package/carbon/volumes/grafana/dashboards/logs.json +179 -0
  387. package/carbon/volumes/grafana/dashboards/overview.json +523 -0
  388. package/carbon/volumes/grafana/dashboards/postgresql.json +337 -0
  389. package/carbon/volumes/grafana/dashboards.dev/logs.json +179 -0
  390. package/carbon/volumes/grafana/dashboards.dev/overview.json +156 -0
  391. package/carbon/volumes/grafana/dashboards.dev/postgresql.json +337 -0
  392. package/carbon/volumes/grafana/provisioning/dashboards/dashboards.dev.yml +16 -0
  393. package/carbon/volumes/grafana/provisioning/dashboards/dashboards.yml +16 -0
  394. package/carbon/volumes/grafana/provisioning/datasources/datasources.yml +43 -0
  395. package/carbon/volumes/kong/docker-entrypoint.sh +9 -0
  396. package/carbon/volumes/kong/kong.yml +208 -0
  397. package/carbon/volumes/loki/loki-config.yml +58 -0
  398. package/carbon/volumes/n8n/hooks.js +131 -0
  399. package/carbon/volumes/n8n/scripts/setup.sh +66 -0
  400. package/carbon/volumes/prometheus/prometheus.yml +43 -0
  401. package/carbon/volumes/promtail/promtail-config.yml +64 -0
  402. package/carbon/volumes/traefik/middlewares.dev.yml +83 -0
  403. package/carbon/volumes/traefik/middlewares.yml +95 -0
  404. package/carbon/volumes/traefik/vite-dev.yml +20 -0
  405. package/package.json +95 -0
  406. package/src/access.js +354 -0
  407. package/src/activate.js +187 -0
  408. package/src/add.js +718 -0
  409. package/src/backup.js +786 -0
  410. package/src/cli.js +350 -0
  411. package/src/configure.js +967 -0
  412. package/src/console.js +155 -0
  413. package/src/create.js +1499 -0
  414. package/src/deploy.js +311 -0
  415. package/src/destroy.js +2033 -0
  416. package/src/diagnose.js +735 -0
  417. package/src/down.js +80 -0
  418. package/src/failover.js +1032 -0
  419. package/src/lib/backup-s3.js +179 -0
  420. package/src/lib/build.js +33 -0
  421. package/src/lib/checksum.js +28 -0
  422. package/src/lib/ci-setup.js +666 -0
  423. package/src/lib/cli/help.js +129 -0
  424. package/src/lib/cli/parse-flags.js +160 -0
  425. package/src/lib/cli/select-action.js +65 -0
  426. package/src/lib/cli/select-environment.js +108 -0
  427. package/src/lib/cli/tty-guard.js +75 -0
  428. package/src/lib/cloudflare.js +447 -0
  429. package/src/lib/colors.js +52 -0
  430. package/src/lib/command.js +361 -0
  431. package/src/lib/config.js +359 -0
  432. package/src/lib/cost.js +103 -0
  433. package/src/lib/deploy/bundle.js +231 -0
  434. package/src/lib/deploy/compose/acme-verify.js +121 -0
  435. package/src/lib/deploy/compose/build-args.js +78 -0
  436. package/src/lib/deploy/compose/ha.js +1874 -0
  437. package/src/lib/deploy/compose/index.js +1294 -0
  438. package/src/lib/deploy/compose/reconcile.js +74 -0
  439. package/src/lib/deploy/github.js +382 -0
  440. package/src/lib/deploy/image.js +191 -0
  441. package/src/lib/deploy/index.js +119 -0
  442. package/src/lib/deploy/k8s/LICENSE +99 -0
  443. package/src/lib/deploy/k8s/gitops-deploy.js +298 -0
  444. package/src/lib/deploy/k8s/ha/index.js +1000 -0
  445. package/src/lib/deploy/k8s/index.js +62 -0
  446. package/src/lib/deploy/k8s/k3s.js +2515 -0
  447. package/src/lib/deploy/orchestrator.js +1401 -0
  448. package/src/lib/deploy/prompts.js +545 -0
  449. package/src/lib/deploy/remote-build.js +130 -0
  450. package/src/lib/deploy/state.js +120 -0
  451. package/src/lib/deploy/utils.js +328 -0
  452. package/src/lib/deploy-logger.js +93 -0
  453. package/src/lib/dns-propagation.js +48 -0
  454. package/src/lib/environment.js +58 -0
  455. package/src/lib/fetch-retry.js +103 -0
  456. package/src/lib/github-environments.js +335 -0
  457. package/src/lib/hetzner-dns.js +377 -0
  458. package/src/lib/hetzner-guided-setup.js +275 -0
  459. package/src/lib/host-keys.js +37 -0
  460. package/src/lib/iac/cloud-init.js +52 -0
  461. package/src/lib/iac/index.js +325 -0
  462. package/src/lib/iac/programs/hetzner-compose.js +130 -0
  463. package/src/lib/iac/programs/hetzner-k8s.js +320 -0
  464. package/src/lib/kubectl.js +81 -0
  465. package/src/lib/licensing/index.js +259 -0
  466. package/src/lib/licensing/tiers.js +181 -0
  467. package/src/lib/licensing/validator.js +171 -0
  468. package/src/lib/merge-package-json.js +90 -0
  469. package/src/lib/operator-ip.js +381 -0
  470. package/src/lib/package-manager.js +111 -0
  471. package/src/lib/perf.js +71 -0
  472. package/src/lib/project-guard.js +39 -0
  473. package/src/lib/project.js +334 -0
  474. package/src/lib/providers/base.js +276 -0
  475. package/src/lib/providers/hetzner-s3.js +656 -0
  476. package/src/lib/providers/hetzner.js +755 -0
  477. package/src/lib/providers/index.js +164 -0
  478. package/src/lib/s3.js +510 -0
  479. package/src/lib/secret-scan.js +583 -0
  480. package/src/lib/secrets.js +63 -0
  481. package/src/lib/server-types.js +195 -0
  482. package/src/lib/shell.js +91 -0
  483. package/src/lib/ssh.js +241 -0
  484. package/src/lib/tracker.js +242 -0
  485. package/src/lib/upgrade-policy.js +170 -0
  486. package/src/lib/validators.js +105 -0
  487. package/src/lib/version.js +5 -0
  488. package/src/remove.js +292 -0
  489. package/src/reset.js +97 -0
  490. package/src/restore.js +871 -0
  491. package/src/scale.js +1734 -0
  492. package/src/shell.js +222 -0
  493. package/src/status.js +981 -0
  494. package/src/up.js +264 -0
  495. package/src/upgrade.js +721 -0
@@ -0,0 +1,181 @@
1
+ /**
2
+ * License tier definitions for Vibecarbon
3
+ *
4
+ * Graphite tier: Free local development (no license key needed)
5
+ * Diamond tier: Full automation for indie hackers & startups
6
+ * Fullerene tier: Commercial license for agencies & enterprise
7
+ */
8
+
9
+ export const TIERS = {
10
+ graphite: {
11
+ name: 'Graphite',
12
+ displayName: 'Vibecarbon Graphite',
13
+ features: ['local-dev', 'all-addons'],
14
+ providers: [],
15
+ maxServers: 0,
16
+ license: 'MIT',
17
+ deployFlags: [],
18
+ // Pricing
19
+ price: 0,
20
+ originalPrice: 0,
21
+ discountPercent: 0,
22
+ hostingCost: '$0',
23
+ // Marketing
24
+ marketingFeatures: [
25
+ 'Create projects',
26
+ 'Local development',
27
+ 'Full Vibecarbon stack',
28
+ 'All add-ons (observability, n8n, metabase, redis, CI/CD)',
29
+ 'Community support',
30
+ ],
31
+ },
32
+ diamond: {
33
+ name: 'Diamond',
34
+ displayName: 'Vibecarbon Diamond',
35
+ features: [
36
+ 'docker-compose',
37
+ 'kubernetes',
38
+ 'autoscaling',
39
+ 'single-vps',
40
+ 'ha',
41
+ 'multi-region',
42
+ 'failover',
43
+ 'advanced-monitoring',
44
+ 'all-addons',
45
+ ],
46
+ providers: ['hetzner'],
47
+ maxServers: Infinity,
48
+ license: 'AGPL-Exception',
49
+ deployFlags: ['--ha', '--k8s'],
50
+ // Pricing
51
+ price: 149,
52
+ originalPrice: 299,
53
+ discountPercent: 50,
54
+ hostingCost: '~$5-100/mo',
55
+ badge: 'Lifetime Access',
56
+ // Marketing
57
+ marketingFeatures: [
58
+ 'All deployment modes (Compose, Compose HA, Kubernetes)',
59
+ 'Single VPS, HA, or multi-VPS Kubernetes clusters',
60
+ 'Full Vibecarbon stack',
61
+ 'All add-ons (observability, n8n, metabase, redis, CI/CD)',
62
+ 'PostgreSQL streaming replication (HA)',
63
+ 'Advanced monitoring & alerting',
64
+ 'Unlimited servers & projects',
65
+ 'Community support',
66
+ 'Full automation for indie hackers & startups',
67
+ ],
68
+ },
69
+ fullerene: {
70
+ name: 'Fullerene',
71
+ displayName: 'Vibecarbon Fullerene',
72
+ features: [
73
+ 'docker-compose',
74
+ 'kubernetes',
75
+ 'autoscaling',
76
+ 'single-vps',
77
+ 'ha',
78
+ 'multi-region',
79
+ 'failover',
80
+ 'advanced-monitoring',
81
+ 'all-addons',
82
+ 'commercial-use',
83
+ ],
84
+ providers: ['hetzner'],
85
+ maxServers: Infinity,
86
+ license: 'AGPL-Exception',
87
+ deployFlags: ['--ha', '--k8s'],
88
+ // Pricing
89
+ price: 499,
90
+ originalPrice: 999,
91
+ discountPercent: 50,
92
+ hostingCost: '~$5-100/mo',
93
+ badge: 'Lifetime Access',
94
+ // Marketing
95
+ marketingFeatures: [
96
+ 'Commercial use rights (AGPL exception)',
97
+ 'Deploy for clients & organizations',
98
+ 'All deployment modes (Compose, Compose HA, Kubernetes)',
99
+ 'Full Vibecarbon stack',
100
+ 'All add-ons (observability, n8n, metabase, redis, CI/CD)',
101
+ 'Advanced monitoring & alerting',
102
+ 'Unlimited servers & projects',
103
+ 'Email support',
104
+ 'Commercial license for agencies & enterprise',
105
+ ],
106
+ },
107
+ };
108
+
109
+ /**
110
+ * Get tier by name
111
+ * @param {string} tierName - The tier name (graphite, diamond, fullerene)
112
+ * @returns {object|null} The tier configuration or null if not found
113
+ */
114
+ export function getTier(tierName) {
115
+ return TIERS[tierName] || null;
116
+ }
117
+
118
+ /**
119
+ * Check if a tier has access to a specific feature
120
+ * @param {string} tierName - The tier name
121
+ * @param {string} feature - The feature to check
122
+ * @returns {boolean} Whether the tier has access to the feature
123
+ */
124
+ export function hasFeature(tierName, feature) {
125
+ const tier = getTier(tierName);
126
+ return tier ? tier.features.includes(feature) : false;
127
+ }
128
+
129
+ /**
130
+ * Check if a tier allows a specific deployment flag
131
+ * @param {string} tierName - The tier name
132
+ * @param {string} flag - The deployment flag (e.g., '--k8s', '--ha', '--compose')
133
+ * @returns {boolean} Whether the tier allows the flag
134
+ */
135
+ export function allowsFlag(tierName, _flag) {
136
+ // Graphite tier cannot deploy at all
137
+ if (tierName === 'graphite') {
138
+ return false;
139
+ }
140
+
141
+ // Diamond and Fullerene allow all deployment flags
142
+ if (tierName === 'diamond' || tierName === 'fullerene') {
143
+ return true;
144
+ }
145
+
146
+ return false;
147
+ }
148
+
149
+ /**
150
+ * Get the required tier for a deployment flag
151
+ * @param {string} flag - The deployment flag
152
+ * @returns {string} The minimum required tier
153
+ */
154
+ export function getRequiredTier(flag) {
155
+ // All deployment flags now require only a Diamond (or higher) license
156
+ void flag;
157
+ return 'diamond';
158
+ }
159
+
160
+ /**
161
+ * Get all tier names
162
+ * @returns {string[]} Array of tier names
163
+ */
164
+ export function getTierNames() {
165
+ return Object.keys(TIERS);
166
+ }
167
+
168
+ /**
169
+ * Compare two tiers and return which one is higher
170
+ * @param {string} tierA - First tier name
171
+ * @param {string} tierB - Second tier name
172
+ * @returns {number} -1 if A < B, 0 if equal, 1 if A > B
173
+ */
174
+ export function compareTiers(tierA, tierB) {
175
+ const order = { graphite: 0, diamond: 1, fullerene: 2 };
176
+ const a = order[tierA] ?? -1;
177
+ const b = order[tierB] ?? -1;
178
+ if (a < b) return -1;
179
+ if (a > b) return 1;
180
+ return 0;
181
+ }
@@ -0,0 +1,171 @@
1
+ /**
2
+ * License key validator for Vibecarbon
3
+ *
4
+ * Key format:
5
+ * vc-<tier>-<customer_id>-<signature>
6
+ *
7
+ * Example: vc-d-a7f2b9c1-x8kd9mwp2v4n...
8
+ *
9
+ * - vc: prefix
10
+ * - tier: single character — d (Diamond) or f (Fullerene)
11
+ * - customer_id: 8-character hex identifier
12
+ * - signature: Ed25519 signature encoded as lowercase hex
13
+ *
14
+ * All licenses are lifetime (no expiration).
15
+ */
16
+
17
+ import { createPublicKey, verify } from 'node:crypto';
18
+
19
+ // Licensing is now enabled
20
+ const LICENSING_DISABLED = false;
21
+
22
+ // Ed25519 public key for license verification (embedded for offline validation)
23
+ const PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
24
+ MCowBQYDK2VwAyEAUrn80IKtISxTCpGjc5rf2ZZhhhu+SktK4L2GEWrjT6Q=
25
+ -----END PUBLIC KEY-----`;
26
+
27
+ // For development/testing - accept any key with valid format
28
+ const DEV_MODE = process.env.VIBECARBON_DEV_LICENSE === 'true';
29
+
30
+ // Tier character mapping
31
+ const TIER_MAP = { d: 'diamond', f: 'fullerene' };
32
+
33
+ /**
34
+ * Parse a license key: vc-<tier>-<customer_id>-<signature>
35
+ * @param {string} key - The license key string
36
+ * @returns {object} Parsed key components or error
37
+ */
38
+ export function parseLicenseKey(key) {
39
+ if (!key || typeof key !== 'string') {
40
+ return { valid: false, error: 'License key is required' };
41
+ }
42
+
43
+ const trimmedKey = key.trim().toLowerCase();
44
+ const parts = trimmedKey.split('-');
45
+
46
+ // Must have at least 4 parts: vc, tier, customer_id, signature
47
+ if (parts.length < 4) {
48
+ return { valid: false, error: 'Invalid license key format' };
49
+ }
50
+
51
+ const [prefix, tierChar, customerId, ...signatureParts] = parts;
52
+ const signature = signatureParts.join('-');
53
+
54
+ // Validate prefix
55
+ if (prefix !== 'vc') {
56
+ return { valid: false, error: 'Invalid license key prefix' };
57
+ }
58
+
59
+ // Validate tier character
60
+ const tier = TIER_MAP[tierChar];
61
+ if (!tier) {
62
+ return { valid: false, error: 'Invalid license tier' };
63
+ }
64
+
65
+ // Validate customer ID (8 hex characters)
66
+ if (!/^[a-f0-9]{8}$/.test(customerId)) {
67
+ return { valid: false, error: 'Invalid customer ID format' };
68
+ }
69
+
70
+ // Validate signature exists and has minimum length
71
+ if (!signature || signature.length < 10) {
72
+ return { valid: false, error: 'Invalid signature' };
73
+ }
74
+
75
+ return {
76
+ valid: true,
77
+ tier,
78
+ tierChar,
79
+ customerId,
80
+ isLifetime: true,
81
+ signature,
82
+ originalKey: key.trim(),
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Verify the cryptographic signature of a license key
88
+ * @param {object} parsedKey - Parsed license key from parseLicenseKey()
89
+ * @returns {object} Verification result
90
+ */
91
+ export function verifySignature(parsedKey) {
92
+ if (!parsedKey.valid) {
93
+ return { valid: false, error: parsedKey.error };
94
+ }
95
+
96
+ // In development mode, skip signature verification
97
+ if (DEV_MODE) {
98
+ return { valid: true, verified: false, devMode: true };
99
+ }
100
+
101
+ try {
102
+ const publicKey = createPublicKey(PUBLIC_KEY_PEM);
103
+
104
+ // Signed message: <tierChar>-<customerId>
105
+ const message = `${parsedKey.tierChar}-${parsedKey.customerId}`;
106
+ const signatureBuffer = Buffer.from(parsedKey.signature, 'hex');
107
+
108
+ const isValid = verify(null, Buffer.from(message), publicKey, signatureBuffer);
109
+
110
+ if (!isValid) {
111
+ return { valid: false, error: 'Invalid license signature' };
112
+ }
113
+
114
+ return { valid: true, verified: true };
115
+ } catch (error) {
116
+ return { valid: false, error: `Signature verification failed: ${error.message}` };
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Validate a complete license key
122
+ * @param {string} key - The license key string
123
+ * @returns {object} Complete validation result
124
+ */
125
+ export function validateLicenseKey(key) {
126
+ // When licensing is disabled, bypass all validation
127
+ if (LICENSING_DISABLED) {
128
+ return {
129
+ valid: true,
130
+ tier: 'fullerene',
131
+ customerId: 'UNLICENSED',
132
+ isLifetime: true,
133
+ verified: false,
134
+ devMode: false,
135
+ licensingDisabled: true,
136
+ };
137
+ }
138
+
139
+ // Parse the key
140
+ const parsed = parseLicenseKey(key);
141
+ if (!parsed.valid) {
142
+ return parsed;
143
+ }
144
+
145
+ // Verify signature
146
+ const signatureResult = verifySignature(parsed);
147
+ if (!signatureResult.valid) {
148
+ return signatureResult;
149
+ }
150
+
151
+ return {
152
+ valid: true,
153
+ tier: parsed.tier,
154
+ customerId: parsed.customerId,
155
+ isLifetime: true,
156
+ verified: signatureResult.verified,
157
+ devMode: signatureResult.devMode || false,
158
+ };
159
+ }
160
+
161
+ /**
162
+ * Generate a development license key (for testing only)
163
+ * @param {string} tier - 'diamond' or 'fullerene'
164
+ * @returns {string} A development license key
165
+ */
166
+ export function generateDevLicenseKey(tier = 'fullerene') {
167
+ const tierChar = tier === 'diamond' ? 'd' : 'f';
168
+ const customerId = 'de000001'; // 8 hex chars
169
+ const signature = 'de0e0000000000000000';
170
+ return `vc-${tierChar}-${customerId}-${signature}`;
171
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Smart package.json merge for upgrades
3
+ *
4
+ * Merges the template package.json into the user's existing one:
5
+ * - Updates versions of shared dependencies (template wins)
6
+ * - Adds new template dependencies the user doesn't have
7
+ * - Preserves all user-added dependencies not in the template
8
+ * - Merges pnpm/npm config sections (overrides, etc.)
9
+ * - Updates scripts from template, preserves user-added scripts
10
+ * - Preserves other top-level fields the user may have added
11
+ */
12
+
13
+ /**
14
+ * Deep-merge two plain objects. Source values win for shared keys.
15
+ * Arrays are replaced, not concatenated.
16
+ *
17
+ * @param {Record<string, unknown>} target
18
+ * @param {Record<string, unknown>} source
19
+ * @returns {Record<string, unknown>}
20
+ */
21
+ function deepMerge(target, source) {
22
+ const result = { ...target };
23
+ for (const key of Object.keys(source)) {
24
+ if (
25
+ source[key] &&
26
+ typeof source[key] === 'object' &&
27
+ !Array.isArray(source[key]) &&
28
+ target[key] &&
29
+ typeof target[key] === 'object' &&
30
+ !Array.isArray(target[key])
31
+ ) {
32
+ result[key] = deepMerge(target[key], source[key]);
33
+ } else {
34
+ result[key] = source[key];
35
+ }
36
+ }
37
+ return result;
38
+ }
39
+
40
+ /**
41
+ * Merge dependency maps: update shared deps to template versions, add new ones, keep user extras.
42
+ *
43
+ * @param {Record<string, string>} [userDeps]
44
+ * @param {Record<string, string>} [templateDeps]
45
+ * @returns {Record<string, string>}
46
+ */
47
+ function mergeDeps(userDeps, templateDeps) {
48
+ if (!templateDeps) return userDeps || {};
49
+ if (!userDeps) return { ...templateDeps };
50
+
51
+ const merged = { ...userDeps };
52
+
53
+ for (const [pkg, version] of Object.entries(templateDeps)) {
54
+ // Update existing or add new — template version wins
55
+ merged[pkg] = version;
56
+ }
57
+
58
+ return merged;
59
+ }
60
+
61
+ /**
62
+ * Merge the user's package.json with the template's package.json.
63
+ *
64
+ * @param {object} userPkg - The user's current package.json (parsed)
65
+ * @param {object} templatePkg - The template's package.json (parsed)
66
+ * @returns {object} - The merged package.json
67
+ */
68
+ export function mergePackageJson(userPkg, templatePkg) {
69
+ // Start from the user's package.json to preserve all their fields
70
+ const merged = { ...userPkg };
71
+
72
+ // Update dependencies (template versions win, user extras preserved)
73
+ merged.dependencies = mergeDeps(userPkg.dependencies, templatePkg.dependencies);
74
+ merged.devDependencies = mergeDeps(userPkg.devDependencies, templatePkg.devDependencies);
75
+
76
+ // Merge scripts: template scripts win, user-added scripts preserved
77
+ merged.scripts = { ...userPkg.scripts, ...templatePkg.scripts };
78
+
79
+ // Merge pnpm config section (overrides, onlyBuiltDependencies, etc.)
80
+ if (templatePkg.pnpm) {
81
+ merged.pnpm = deepMerge(userPkg.pnpm || {}, templatePkg.pnpm);
82
+ }
83
+
84
+ // Update these standard fields from template
85
+ merged.type = templatePkg.type;
86
+ merged.version = templatePkg.version;
87
+ merged.private = templatePkg.private;
88
+
89
+ return merged;
90
+ }