openship 0.1.0 → 0.1.1

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 (531) hide show
  1. package/.env.example +19 -3
  2. package/CONTRIBUTING.md +69 -19
  3. package/LICENSE +661 -0
  4. package/README.md +304 -108
  5. package/apps/api/Dockerfile +6 -8
  6. package/apps/api/package.json +25 -21
  7. package/apps/api/src/app.ts +46 -3
  8. package/apps/api/src/config/env.ts +81 -7
  9. package/apps/api/src/lib/auth-mode.ts +42 -0
  10. package/apps/api/src/lib/auth.ts +105 -0
  11. package/apps/api/src/lib/cache.ts +128 -0
  12. package/apps/api/src/lib/cloud-auth-proxy.ts +310 -0
  13. package/apps/api/src/lib/cloud-client.ts +103 -0
  14. package/apps/api/src/lib/compose-parser.ts +138 -0
  15. package/apps/api/src/lib/controller-helpers.ts +90 -0
  16. package/apps/api/src/lib/email-templates.ts +94 -0
  17. package/apps/api/src/lib/encryption.ts +102 -0
  18. package/apps/api/src/lib/local-user.ts +65 -0
  19. package/apps/api/src/lib/mail.ts +48 -0
  20. package/apps/api/src/lib/notifications.ts +195 -0
  21. package/apps/api/src/lib/openship-cloud.ts +101 -0
  22. package/apps/api/src/lib/resources.ts +96 -0
  23. package/apps/api/src/lib/screenshots.ts +189 -0
  24. package/apps/api/src/lib/ssh-manager.ts +369 -0
  25. package/apps/api/src/lib/ssl-scheduler.ts +109 -0
  26. package/apps/api/src/lib/stack-detector.ts +708 -0
  27. package/apps/api/src/lib/system-debug.ts +10 -0
  28. package/apps/api/src/middleware/auth.ts +49 -13
  29. package/apps/api/src/middleware/error-handler.ts +23 -3
  30. package/apps/api/src/middleware/index.ts +2 -0
  31. package/apps/api/src/middleware/internal-auth.ts +40 -0
  32. package/apps/api/src/middleware/local-only.ts +20 -0
  33. package/apps/api/src/middleware/rate-limiter.ts +9 -0
  34. package/apps/api/src/modules/analytics/analytics.controller.ts +111 -0
  35. package/apps/api/src/modules/analytics/analytics.routes.ts +29 -0
  36. package/apps/api/src/modules/analytics/analytics.schema.ts +37 -0
  37. package/apps/api/src/modules/analytics/analytics.service.ts +264 -0
  38. package/apps/api/src/modules/auth/auth.routes.ts +233 -6
  39. package/apps/api/src/modules/billing/billing.routes.ts +8 -0
  40. package/apps/api/src/modules/cloud/cloud.controller.ts +225 -0
  41. package/apps/api/src/modules/cloud/cloud.routes.ts +40 -0
  42. package/apps/api/src/modules/deployments/build.service.ts +791 -0
  43. package/apps/api/src/modules/deployments/deployment-lifecycle.ts +138 -0
  44. package/apps/api/src/modules/deployments/deployment.controller.ts +324 -16
  45. package/apps/api/src/modules/deployments/deployment.routes.ts +33 -7
  46. package/apps/api/src/modules/deployments/deployment.schema.ts +37 -5
  47. package/apps/api/src/modules/deployments/deployment.service.ts +178 -11
  48. package/apps/api/src/modules/deployments/preflight.ts +280 -0
  49. package/apps/api/src/modules/deployments/prepare.service.ts +252 -0
  50. package/apps/api/src/modules/deployments/session-manager.ts +283 -0
  51. package/apps/api/src/modules/deployments/ssl.service.ts +73 -0
  52. package/apps/api/src/modules/domains/domain.controller.ts +59 -7
  53. package/apps/api/src/modules/domains/domain.routes.ts +20 -5
  54. package/apps/api/src/modules/domains/domain.schema.ts +35 -0
  55. package/apps/api/src/modules/domains/domain.service.ts +375 -9
  56. package/apps/api/src/modules/github/github.auth.ts +397 -0
  57. package/apps/api/src/modules/github/github.controller.ts +387 -0
  58. package/apps/api/src/modules/github/github.local-auth.ts +251 -0
  59. package/apps/api/src/modules/github/github.routes.ts +50 -0
  60. package/apps/api/src/modules/github/github.schema.ts +52 -0
  61. package/apps/api/src/modules/github/github.service.ts +592 -0
  62. package/apps/api/src/modules/github/github.types.ts +158 -0
  63. package/apps/api/src/modules/github/github.webhook.ts +186 -0
  64. package/apps/api/src/modules/github/index.ts +16 -0
  65. package/apps/api/src/modules/health/health.routes.ts +35 -0
  66. package/apps/api/src/modules/projects/project.controller.ts +481 -12
  67. package/apps/api/src/modules/projects/project.routes.ts +63 -6
  68. package/apps/api/src/modules/projects/project.schema.ts +104 -6
  69. package/apps/api/src/modules/projects/project.service.ts +502 -11
  70. package/apps/api/src/modules/settings/settings.controller.ts +55 -0
  71. package/apps/api/src/modules/settings/settings.routes.ts +25 -0
  72. package/apps/api/src/modules/settings/settings.service.ts +49 -0
  73. package/apps/api/src/modules/system/filesystem.controller.ts +66 -0
  74. package/apps/api/src/modules/system/index.ts +1 -0
  75. package/apps/api/src/modules/system/server-check.controller.ts +475 -0
  76. package/apps/api/src/modules/system/setup-session.ts +255 -0
  77. package/apps/api/src/modules/system/setup.controller.ts +128 -0
  78. package/apps/api/src/modules/system/system.routes.ts +42 -0
  79. package/apps/api/src/modules/webhooks/webhook.controller.ts +57 -15
  80. package/apps/api/src/modules/webhooks/webhook.routes.ts +11 -8
  81. package/apps/api/src/modules/webhooks/webhook.service.ts +46 -5
  82. package/apps/api/src/modules/webhooks/webhook.types.ts +35 -0
  83. package/apps/api/tsconfig.json +3 -1
  84. package/apps/cli/package.json +8 -10
  85. package/apps/cli/tsconfig.json +2 -1
  86. package/apps/dashboard/Dockerfile +4 -6
  87. package/apps/dashboard/components.json +20 -0
  88. package/apps/dashboard/next-env.d.ts +6 -0
  89. package/apps/dashboard/next.config.mjs +11 -1
  90. package/apps/dashboard/package.json +25 -13
  91. package/apps/dashboard/postcss.config.mjs +5 -0
  92. package/apps/dashboard/public/android-chrome-192x192.png +0 -0
  93. package/apps/dashboard/public/android-chrome-512x512.png +0 -0
  94. package/apps/dashboard/public/apple-touch-icon.png +0 -0
  95. package/apps/dashboard/public/favicon-16x16.png +0 -0
  96. package/apps/dashboard/public/favicon-32x32.png +0 -0
  97. package/apps/dashboard/public/favicon.ico +0 -0
  98. package/apps/dashboard/public/site.webmanifest +19 -0
  99. package/apps/dashboard/src/app/(auth)/forgot-password/page.tsx +114 -0
  100. package/apps/dashboard/src/app/(auth)/layout.tsx +18 -3
  101. package/apps/dashboard/src/app/(auth)/login/page.tsx +215 -6
  102. package/apps/dashboard/src/app/(auth)/providers.tsx +34 -0
  103. package/apps/dashboard/src/app/(auth)/register/page.tsx +171 -5
  104. package/apps/dashboard/src/app/(auth)/reset-password/page.tsx +172 -0
  105. package/apps/dashboard/src/app/(auth)/verify-email/page.tsx +190 -0
  106. package/apps/dashboard/src/app/(dashboard)/(deployment)/build/[id]/page.tsx +162 -0
  107. package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/BuildSummary.tsx +166 -0
  108. package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/DnsConfiguration.tsx +119 -0
  109. package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/DomainSettings.tsx +291 -0
  110. package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/Header.tsx +71 -0
  111. package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/Sidebar.tsx +270 -0
  112. package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/SkeletonLoader.tsx +87 -0
  113. package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/page.tsx +169 -0
  114. package/apps/dashboard/src/app/(dashboard)/(deployment)/layout.tsx +7 -0
  115. package/apps/dashboard/src/app/(dashboard)/billing/page.tsx +1 -8
  116. package/apps/dashboard/src/app/(dashboard)/deployments/components/CommitDetailsModal.tsx +240 -0
  117. package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentCard.tsx +121 -0
  118. package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentHeader.tsx +89 -0
  119. package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentMenu.tsx +182 -0
  120. package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentsContent.tsx +324 -0
  121. package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentsFilters.tsx +99 -0
  122. package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentsList.tsx +31 -0
  123. package/apps/dashboard/src/app/(dashboard)/deployments/components/EmptyState.tsx +101 -0
  124. package/apps/dashboard/src/app/(dashboard)/deployments/components/LoadingSkeleton.tsx +57 -0
  125. package/apps/dashboard/src/app/(dashboard)/deployments/components/ProjectFilter.tsx +109 -0
  126. package/apps/dashboard/src/app/(dashboard)/deployments/components/index.ts +9 -0
  127. package/apps/dashboard/src/app/(dashboard)/deployments/page.tsx +9 -3
  128. package/apps/dashboard/src/app/(dashboard)/deployments/types.ts +44 -0
  129. package/apps/dashboard/src/app/(dashboard)/deployments/utils.ts +176 -0
  130. package/apps/dashboard/src/app/(dashboard)/domains/page.tsx +1 -6
  131. package/apps/dashboard/src/app/(dashboard)/integrations/page.tsx +321 -0
  132. package/apps/dashboard/src/app/(dashboard)/layout.tsx +22 -32
  133. package/apps/dashboard/src/app/(dashboard)/library/components/ConnectPrompt.tsx +187 -0
  134. package/apps/dashboard/src/app/(dashboard)/library/components/LibrarySidebar.tsx +147 -0
  135. package/apps/dashboard/src/app/(dashboard)/library/components/LoadingSkeleton.tsx +39 -0
  136. package/apps/dashboard/src/app/(dashboard)/library/components/LocalProjects.tsx +548 -0
  137. package/apps/dashboard/src/app/(dashboard)/library/components/RepositoryList.tsx +292 -0
  138. package/apps/dashboard/src/app/(dashboard)/library/components/TemplateGrid.tsx +36 -0
  139. package/apps/dashboard/src/app/(dashboard)/library/components/UrlImport.tsx +74 -0
  140. package/apps/dashboard/src/app/(dashboard)/library/page.tsx +121 -0
  141. package/apps/dashboard/src/app/(dashboard)/library/types.ts +26 -0
  142. package/apps/dashboard/src/app/(dashboard)/monitoring/page.tsx +1 -6
  143. package/apps/dashboard/src/app/(dashboard)/page.tsx +485 -0
  144. package/apps/dashboard/src/app/(dashboard)/projects/[id]/[[...slug]]/layout.tsx +22 -0
  145. package/apps/dashboard/src/app/(dashboard)/projects/[id]/[[...slug]]/page.tsx +286 -0
  146. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/AdvancedSettings.tsx +235 -0
  147. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/BuildSettings.tsx +174 -0
  148. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/DeleteConfirmationDialog.tsx +45 -0
  149. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/DeletionModal.tsx +95 -0
  150. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/Deployments.tsx +11 -0
  151. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/DomainSettings.tsx +523 -0
  152. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/EnvironmentSettings.tsx +246 -0
  153. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/GeneralSettings.tsx +93 -0
  154. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/GitInfo.tsx +261 -0
  155. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/GitSettings.tsx +391 -0
  156. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/LogsSettings.tsx +133 -0
  157. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/ProjectNotFound.tsx +95 -0
  158. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/ProjectsBottomNavigation.tsx +62 -0
  159. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/ResourceSettings.tsx +333 -0
  160. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/SettingSection.tsx +66 -0
  161. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/SettingsNavigation.tsx +27 -0
  162. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/SleepModeSettings.tsx +134 -0
  163. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/ProductionUrl.tsx +25 -0
  164. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/ProjectIdentity.tsx +159 -0
  165. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/ProjectInfo.tsx +58 -0
  166. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/SkeletonLoader.tsx +170 -0
  167. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/StatsCards.tsx +33 -0
  168. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/TopPaths.tsx +56 -0
  169. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/TrafficChart.tsx +157 -0
  170. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/index.ts +14 -0
  171. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/logs/LogsActions.tsx +52 -0
  172. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/logs/ServerLogs.tsx +249 -0
  173. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/logs/TerminalLogs.tsx +682 -0
  174. package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/logs/logs.css +127 -0
  175. package/apps/dashboard/src/app/(dashboard)/projects/components/DeploymentCard.tsx +73 -0
  176. package/apps/dashboard/src/app/(dashboard)/projects/components/ProjectCard.tsx +330 -0
  177. package/apps/dashboard/src/app/(dashboard)/projects/page.tsx +326 -4
  178. package/apps/dashboard/src/app/(dashboard)/providers.tsx +23 -0
  179. package/apps/dashboard/src/app/(dashboard)/servers/[serverId]/_components/components-tab.tsx +329 -0
  180. package/apps/dashboard/src/app/(dashboard)/servers/[serverId]/_components/overview-tab.tsx +229 -0
  181. package/apps/dashboard/src/app/(dashboard)/servers/[serverId]/_components/terminal-tab.tsx +38 -0
  182. package/apps/dashboard/src/app/(dashboard)/servers/[serverId]/page.tsx +437 -0
  183. package/apps/dashboard/src/app/(dashboard)/servers/new/_components/checking-state.tsx +15 -0
  184. package/apps/dashboard/src/app/(dashboard)/servers/new/_components/choose-mode.tsx +54 -0
  185. package/apps/dashboard/src/app/(dashboard)/servers/new/_components/component-row.tsx +65 -0
  186. package/apps/dashboard/src/app/(dashboard)/servers/new/_components/error-banner.tsx +13 -0
  187. package/apps/dashboard/src/app/(dashboard)/servers/new/_components/installing-panel.tsx +227 -0
  188. package/apps/dashboard/src/app/(dashboard)/servers/new/_components/results-panel.tsx +90 -0
  189. package/apps/dashboard/src/app/(dashboard)/servers/new/_components/setup-header.tsx +56 -0
  190. package/apps/dashboard/src/app/(dashboard)/servers/new/_components/types.ts +13 -0
  191. package/apps/dashboard/src/app/(dashboard)/servers/new/page.tsx +666 -0
  192. package/apps/dashboard/src/app/(dashboard)/servers/page.tsx +283 -0
  193. package/apps/dashboard/src/app/(dashboard)/settings/_components/BuildPreferences.tsx +110 -0
  194. package/apps/dashboard/src/app/(dashboard)/settings/_components/CloudConnection.tsx +147 -0
  195. package/apps/dashboard/src/app/(dashboard)/settings/_components/InstanceInfo.tsx +54 -0
  196. package/apps/dashboard/src/app/(dashboard)/settings/_components/ServerConnection.tsx +407 -0
  197. package/apps/dashboard/src/app/(dashboard)/settings/_components/SettingsSection.tsx +32 -0
  198. package/apps/dashboard/src/app/(dashboard)/settings/page.tsx +62 -3
  199. package/apps/dashboard/src/app/auth/callback/close/page.tsx +23 -0
  200. package/apps/dashboard/src/app/auth/callback/install/page.tsx +40 -0
  201. package/apps/dashboard/src/app/authorize/page.tsx +137 -0
  202. package/apps/dashboard/src/app/globals.css +57 -3
  203. package/apps/dashboard/src/app/layout.tsx +43 -3
  204. package/apps/dashboard/src/components/auth-shell.tsx +66 -0
  205. package/apps/dashboard/src/components/deployments/types.ts +44 -0
  206. package/apps/dashboard/src/components/global-deployments/index.ts +17 -0
  207. package/apps/dashboard/src/components/i18n-provider.tsx +100 -0
  208. package/apps/dashboard/src/components/import-project/BuildSettings.tsx +376 -0
  209. package/apps/dashboard/src/components/import-project/BuildSkeleton.tsx +161 -0
  210. package/apps/dashboard/src/components/import-project/BuildTerminal.tsx +358 -0
  211. package/apps/dashboard/src/components/import-project/ComposeServices.tsx +455 -0
  212. package/apps/dashboard/src/components/import-project/DeploymentProcessing.tsx +510 -0
  213. package/apps/dashboard/src/components/import-project/DockerSettings.tsx +64 -0
  214. package/apps/dashboard/src/components/import-project/EnvironmentVariables.tsx +481 -0
  215. package/apps/dashboard/src/components/import-project/Frameworks.tsx +90 -0
  216. package/apps/dashboard/src/components/import-project/ProjectSettings.tsx +160 -0
  217. package/apps/dashboard/src/components/import-project/types.ts +82 -0
  218. package/apps/dashboard/src/components/integrations/GithubPermissionModal.tsx +173 -0
  219. package/apps/dashboard/src/components/language-switcher.tsx +36 -0
  220. package/apps/dashboard/src/components/logo.tsx +13 -0
  221. package/apps/dashboard/src/components/network-error-handler.tsx +27 -0
  222. package/apps/dashboard/src/components/oauth-buttons.tsx +81 -0
  223. package/apps/dashboard/src/components/overview/ActivityChart.tsx +247 -0
  224. package/apps/dashboard/src/components/overview/ApiRequestsCard.tsx +111 -0
  225. package/apps/dashboard/src/components/overview/CreditsCard.tsx +137 -0
  226. package/apps/dashboard/src/components/overview/DeploymentsChart.tsx +195 -0
  227. package/apps/dashboard/src/components/overview/EmptyState.tsx +126 -0
  228. package/apps/dashboard/src/components/overview/LoadingSkeleton.tsx +92 -0
  229. package/apps/dashboard/src/components/overview/OverviewHeader.tsx +74 -0
  230. package/apps/dashboard/src/components/overview/OverviewHeroChart.tsx +344 -0
  231. package/apps/dashboard/src/components/overview/ProjectsCard.tsx +134 -0
  232. package/apps/dashboard/src/components/overview/QuickLinks.tsx +119 -0
  233. package/apps/dashboard/src/components/overview/SandboxesCard.tsx +150 -0
  234. package/apps/dashboard/src/components/overview/StatsGrid.tsx +166 -0
  235. package/apps/dashboard/src/components/overview/TokenUsageChart.tsx +206 -0
  236. package/apps/dashboard/src/components/overview/UsageStats.tsx +79 -0
  237. package/apps/dashboard/src/components/overview/index.ts +30 -0
  238. package/apps/dashboard/src/components/overview/types.ts +116 -0
  239. package/apps/dashboard/src/components/page-header.tsx +25 -0
  240. package/apps/dashboard/src/components/project-settings/ServerSideSwitch.jsx +60 -0
  241. package/apps/dashboard/src/components/shared/AlertBox.tsx +39 -0
  242. package/apps/dashboard/src/components/shared/CTASection.tsx +45 -0
  243. package/apps/dashboard/src/components/shared/ErrorState.tsx +176 -0
  244. package/apps/dashboard/src/components/shared/FeatureCard.tsx +20 -0
  245. package/apps/dashboard/src/components/shared/MDXComponents.tsx +24 -0
  246. package/apps/dashboard/src/components/shared/MachineSettingsModal.tsx +286 -0
  247. package/apps/dashboard/src/components/shared/Modal.tsx +39 -0
  248. package/apps/dashboard/src/components/shared/OTPInput.tsx +122 -0
  249. package/apps/dashboard/src/components/shared/PageHero.tsx +21 -0
  250. package/apps/dashboard/src/components/shared/PlatformFeatureCard.tsx +27 -0
  251. package/apps/dashboard/src/components/shared/StatCard.tsx +14 -0
  252. package/apps/dashboard/src/components/shared/ValueCard.tsx +20 -0
  253. package/apps/dashboard/src/components/shared/index.ts +8 -0
  254. package/apps/dashboard/src/components/sidebar.tsx +282 -0
  255. package/apps/dashboard/src/components/theme-provider.tsx +96 -0
  256. package/apps/dashboard/src/components/toast.tsx +106 -0
  257. package/apps/dashboard/src/components/ui/CustomCursor.tsx +107 -0
  258. package/apps/dashboard/src/components/ui/CustomSelect.tsx +126 -0
  259. package/apps/dashboard/src/components/ui/DropdownMenu.tsx +174 -0
  260. package/apps/dashboard/src/components/ui/FileIcon.jsx +59 -0
  261. package/apps/dashboard/src/components/ui/IconPickerModal.tsx +273 -0
  262. package/apps/dashboard/src/components/ui/InfoBanner.jsx +39 -0
  263. package/apps/dashboard/src/components/ui/Logo.tsx +14 -0
  264. package/apps/dashboard/src/components/ui/Modal.tsx +117 -0
  265. package/apps/dashboard/src/components/ui/PageContainer.tsx +12 -0
  266. package/apps/dashboard/src/components/ui/SectionContainer.jsx +7 -0
  267. package/apps/dashboard/src/components/ui/SlidingToggle.tsx +128 -0
  268. package/apps/dashboard/src/components/ui/Toast.tsx +29 -0
  269. package/apps/dashboard/src/components/ui/button.tsx +58 -0
  270. package/apps/dashboard/src/components/ui/card.tsx +60 -0
  271. package/apps/dashboard/src/components/ui/input.tsx +20 -0
  272. package/apps/dashboard/src/components/ui/label.tsx +19 -0
  273. package/apps/dashboard/src/components/ui/select.tsx +10 -0
  274. package/apps/dashboard/src/components/ui/textarea.tsx +9 -0
  275. package/apps/dashboard/src/constants/lang-colors.ts +25 -0
  276. package/apps/dashboard/src/constants/mock.ts +38 -0
  277. package/apps/dashboard/src/context/AuthContext.tsx +91 -0
  278. package/apps/dashboard/src/context/CloudContext.tsx +275 -0
  279. package/apps/dashboard/src/context/DeploymentContext.tsx +71 -0
  280. package/apps/dashboard/src/context/GitHubContext.tsx +288 -0
  281. package/apps/dashboard/src/context/ModalContext.tsx +300 -0
  282. package/apps/dashboard/src/context/NetworkContext.tsx +32 -0
  283. package/apps/dashboard/src/context/ProjectSettingsContext.tsx +727 -0
  284. package/apps/dashboard/src/context/ToastContext.tsx +129 -0
  285. package/apps/dashboard/src/context/deployment/index.ts +3 -0
  286. package/apps/dashboard/src/context/deployment/types.ts +183 -0
  287. package/apps/dashboard/src/context/deployment/useDeploymentBuild.ts +547 -0
  288. package/apps/dashboard/src/context/deployment/useDeploymentConfig.ts +176 -0
  289. package/apps/dashboard/src/hooks/useBuildConnection.ts +334 -0
  290. package/apps/dashboard/src/hooks/useMonitorStream.ts +146 -0
  291. package/apps/dashboard/src/hooks/useProjectData.ts +110 -0
  292. package/apps/dashboard/src/hooks/useSSEConnection.ts +465 -0
  293. package/apps/dashboard/src/hooks/useSSEStream.ts +309 -0
  294. package/apps/dashboard/src/hooks/useSessions.ts +104 -0
  295. package/apps/dashboard/src/hooks/useSetupStream.ts +223 -0
  296. package/apps/dashboard/src/i18n/dictionaries/ar.json +218 -0
  297. package/apps/dashboard/src/i18n/dictionaries/en.json +218 -0
  298. package/apps/dashboard/src/i18n/index.ts +16 -0
  299. package/apps/dashboard/src/lib/api/ai.ts +22 -0
  300. package/apps/dashboard/src/lib/api/auth.ts +13 -0
  301. package/apps/dashboard/src/lib/api/client.ts +199 -0
  302. package/apps/dashboard/src/lib/api/cloud.ts +15 -0
  303. package/apps/dashboard/src/lib/api/deploy.ts +58 -0
  304. package/apps/dashboard/src/lib/api/domains.ts +13 -0
  305. package/apps/dashboard/src/lib/api/endpoints.ts +129 -0
  306. package/apps/dashboard/src/lib/api/github.ts +31 -0
  307. package/apps/dashboard/src/lib/api/icons.ts +12 -0
  308. package/apps/dashboard/src/lib/api/index.ts +41 -0
  309. package/apps/dashboard/src/lib/api/projects.ts +153 -0
  310. package/apps/dashboard/src/lib/api/sandbox.ts +14 -0
  311. package/apps/dashboard/src/lib/api/settings.ts +21 -0
  312. package/apps/dashboard/src/lib/api/system.ts +159 -0
  313. package/apps/dashboard/src/lib/auth-client.ts +54 -0
  314. package/apps/dashboard/src/lib/country.ts +25 -0
  315. package/apps/dashboard/src/lib/server/api.ts +140 -0
  316. package/apps/dashboard/src/lib/server/session.ts +103 -0
  317. package/apps/dashboard/src/lib/sseClient.ts +241 -0
  318. package/apps/dashboard/src/lib/sseMessageProcessors.ts +323 -0
  319. package/apps/dashboard/src/lib/utils.ts +6 -0
  320. package/apps/dashboard/src/proxy.ts +46 -0
  321. package/apps/dashboard/src/styles/Toast.module.css +92 -0
  322. package/apps/dashboard/src/styles/fonts.css +93 -0
  323. package/apps/dashboard/src/styles/theme.css +336 -0
  324. package/apps/dashboard/src/types/research.ts +42 -0
  325. package/apps/dashboard/src/utils/SSEParser.js +150 -0
  326. package/apps/dashboard/src/utils/authWindow.ts +143 -0
  327. package/apps/dashboard/src/utils/codeTheme.ts +127 -0
  328. package/apps/dashboard/src/utils/colors.json +2810 -0
  329. package/apps/dashboard/src/utils/date.ts +121 -0
  330. package/apps/dashboard/src/utils/deployment.ts +128 -0
  331. package/apps/dashboard/src/utils/deploymentPhaseDetector.ts +232 -0
  332. package/apps/dashboard/src/utils/extToLang.js +103 -0
  333. package/apps/dashboard/src/utils/github.ts +62 -0
  334. package/apps/dashboard/src/utils/icons.js +46 -0
  335. package/apps/dashboard/src/utils/repoSlug.ts +110 -0
  336. package/apps/dashboard/src/utils/research-api.ts +163 -0
  337. package/apps/dashboard/src/utils/suggestions.ts +84 -0
  338. package/apps/dashboard/src/utils/theme.js +1 -0
  339. package/apps/dashboard/src/utils/ui-helpers.tsx +30 -0
  340. package/apps/dashboard/src/utils/upload.js +12 -0
  341. package/apps/dashboard/tsconfig.json +27 -5
  342. package/apps/desktop/forge.config.json +36 -0
  343. package/apps/desktop/package.json +26 -0
  344. package/apps/desktop/scripts/dev.mjs +58 -0
  345. package/apps/desktop/src/main/index.ts +675 -0
  346. package/apps/desktop/src/main/types/desktop.d.ts +33 -0
  347. package/apps/desktop/src/preload/index.ts +88 -0
  348. package/apps/desktop/src/renderer/index.html +462 -0
  349. package/apps/desktop/src/renderer/onboarding.js +511 -0
  350. package/apps/desktop/src/renderer/styles.css +1139 -0
  351. package/apps/desktop/tsconfig.json +17 -0
  352. package/apps/web/.source/browser.ts +13 -0
  353. package/apps/web/.source/dynamic.ts +8 -0
  354. package/apps/web/.source/server.ts +22 -0
  355. package/apps/web/.source/source.config.mjs +20 -0
  356. package/apps/web/Dockerfile +4 -6
  357. package/apps/web/content/blog/how-ai-builds-work.mdx +55 -0
  358. package/apps/web/content/blog/introducing-openship.mdx +46 -0
  359. package/apps/web/content/blog/self-hosting-cost-breakdown.mdx +59 -0
  360. package/apps/web/content/docs/_meta.json +14 -0
  361. package/apps/web/content/docs/api.mdx +98 -0
  362. package/apps/web/content/docs/cli.mdx +80 -0
  363. package/apps/web/content/docs/first-deployment.mdx +56 -0
  364. package/apps/web/content/docs/index.mdx +27 -0
  365. package/apps/web/content/docs/installation.mdx +65 -0
  366. package/apps/web/content/docs/quickstart.mdx +45 -0
  367. package/apps/web/next-env.d.ts +6 -0
  368. package/apps/web/next.config.mjs +16 -2
  369. package/apps/web/package.json +19 -12
  370. package/apps/web/postcss.config.mjs +5 -0
  371. package/apps/web/public/android-chrome-192x192.png +0 -0
  372. package/apps/web/public/android-chrome-512x512.png +0 -0
  373. package/apps/web/public/apple-touch-icon.png +0 -0
  374. package/apps/web/public/favicon-16x16.png +0 -0
  375. package/apps/web/public/favicon-32x32.png +0 -0
  376. package/apps/web/public/favicon.ico +0 -0
  377. package/apps/web/public/site.webmanifest +1 -0
  378. package/apps/web/source.config.ts +17 -0
  379. package/apps/web/src/app/(marketing)/layout.tsx +7 -22
  380. package/apps/web/src/app/blog/[...slug]/page.tsx +247 -0
  381. package/apps/web/src/app/blog/blog.css +575 -0
  382. package/apps/web/src/app/blog/layout.tsx +50 -0
  383. package/apps/web/src/app/blog/page.tsx +235 -0
  384. package/apps/web/src/app/docs/[[...slug]]/page.tsx +67 -0
  385. package/apps/web/src/app/docs/layout.tsx +62 -0
  386. package/apps/web/src/app/docs/toc-theme.css +71 -0
  387. package/apps/web/src/app/download/page.tsx +396 -0
  388. package/apps/web/src/app/globals.css +20 -3
  389. package/apps/web/src/app/layout.tsx +57 -3
  390. package/apps/web/src/app/page.tsx +47 -6
  391. package/apps/web/src/app/robots.ts +15 -0
  392. package/apps/web/src/app/sitemap.ts +35 -0
  393. package/apps/web/src/components/blog/share-sidebar.tsx +81 -0
  394. package/apps/web/src/components/blog/writer-sidebar.tsx +81 -0
  395. package/apps/web/src/components/landing/ai-native.tsx +169 -0
  396. package/apps/web/src/components/landing/backups.tsx +139 -0
  397. package/apps/web/src/components/landing/cdn.tsx +109 -0
  398. package/apps/web/src/components/landing/coming-soon.tsx +180 -0
  399. package/apps/web/src/components/landing/dark-section.tsx +166 -0
  400. package/apps/web/src/components/landing/dashboard.tsx +407 -0
  401. package/apps/web/src/components/landing/developer-experience.tsx +224 -0
  402. package/apps/web/src/components/landing/dns-domains.tsx +146 -0
  403. package/apps/web/src/components/landing/download-button.tsx +151 -0
  404. package/apps/web/src/components/landing/features/ai-visual.tsx +48 -0
  405. package/apps/web/src/components/landing/features/cloud-visual.tsx +44 -0
  406. package/apps/web/src/components/landing/features/git-visual.tsx +61 -0
  407. package/apps/web/src/components/landing/features/index.tsx +642 -0
  408. package/apps/web/src/components/landing/features/infra-visual.tsx +69 -0
  409. package/apps/web/src/components/landing/features/rollback-visual.tsx +42 -0
  410. package/apps/web/src/components/landing/features/ssl-visual.tsx +41 -0
  411. package/apps/web/src/components/landing/features/stacks-visual.tsx +54 -0
  412. package/apps/web/src/components/landing/final-cta.tsx +116 -0
  413. package/apps/web/src/components/landing/footer.tsx +145 -0
  414. package/apps/web/src/components/landing/hero.tsx +110 -0
  415. package/apps/web/src/components/landing/how-it-works.tsx +210 -0
  416. package/apps/web/src/components/landing/index.ts +21 -0
  417. package/apps/web/src/components/landing/mail-server.tsx +122 -0
  418. package/apps/web/src/components/landing/navbar.tsx +199 -0
  419. package/apps/web/src/components/landing/no-lockin.tsx +185 -0
  420. package/apps/web/src/components/landing/open-source-cta.tsx +151 -0
  421. package/apps/web/src/components/landing/portability.tsx +190 -0
  422. package/apps/web/src/components/landing/pricing.tsx +263 -0
  423. package/apps/web/src/components/landing/scaling.tsx +209 -0
  424. package/apps/web/src/components/landing/why-openship.tsx +291 -0
  425. package/apps/web/src/hooks/use-gsap-scroll.ts +158 -0
  426. package/apps/web/src/hooks/use-platform.ts +86 -0
  427. package/apps/web/src/lib/source.ts +12 -0
  428. package/apps/web/src/styles/fonts.css +84 -0
  429. package/apps/web/src/styles/landing.css +951 -0
  430. package/apps/web/src/styles/theme.css +227 -0
  431. package/apps/web/tsconfig.json +8 -3
  432. package/bun.lock +3260 -0
  433. package/docker-compose.yml +3 -0
  434. package/docs/screenshots/.gitkeep +0 -0
  435. package/docs/screenshots/screen.png +0 -0
  436. package/openship.code-workspace +7 -0
  437. package/package.json +23 -9
  438. package/packages/adapters/docs/ARCHITECTURE.md +160 -0
  439. package/packages/adapters/docs/BUILD-PIPELINE.md +171 -0
  440. package/packages/adapters/docs/CLOUD.md +239 -0
  441. package/packages/adapters/docs/EXECUTOR.md +174 -0
  442. package/packages/adapters/docs/LOG-STREAMING.md +175 -0
  443. package/packages/adapters/docs/SYSTEM.md +191 -0
  444. package/packages/adapters/package.json +14 -9
  445. package/packages/adapters/src/index.ts +144 -4
  446. package/packages/adapters/src/infra/cloud.ts +42 -0
  447. package/packages/adapters/src/infra/index.ts +9 -0
  448. package/packages/adapters/src/infra/noop.ts +27 -0
  449. package/packages/adapters/src/infra/traefik.ts +297 -0
  450. package/packages/adapters/src/infra/types.ts +36 -0
  451. package/packages/adapters/src/platform.ts +255 -0
  452. package/packages/adapters/src/runtime/bare.ts +567 -0
  453. package/packages/adapters/src/runtime/build-pipeline.ts +237 -0
  454. package/packages/adapters/src/runtime/cloud.ts +791 -0
  455. package/packages/adapters/src/runtime/deploy-pipeline.ts +146 -0
  456. package/packages/adapters/src/runtime/docker.ts +443 -0
  457. package/packages/adapters/src/runtime/index.ts +69 -0
  458. package/packages/adapters/src/runtime/local-build.ts +112 -0
  459. package/packages/adapters/src/runtime/transfer.ts +82 -0
  460. package/packages/adapters/src/runtime/types.ts +138 -0
  461. package/packages/adapters/src/system/catalog.ts +188 -0
  462. package/packages/adapters/src/system/checks.ts +228 -0
  463. package/packages/adapters/src/system/components.ts +45 -0
  464. package/packages/adapters/src/system/debug.ts +18 -0
  465. package/packages/adapters/src/system/environment.ts +168 -0
  466. package/packages/adapters/src/system/errors.ts +34 -0
  467. package/packages/adapters/src/system/executor.ts +600 -0
  468. package/packages/adapters/src/system/index.ts +58 -0
  469. package/packages/adapters/src/system/installer.ts +310 -0
  470. package/packages/adapters/src/system/setup.ts +442 -0
  471. package/packages/adapters/src/system/state.ts +96 -0
  472. package/packages/adapters/src/system/types.ts +116 -0
  473. package/packages/adapters/src/toolchain/catalog.ts +439 -0
  474. package/packages/adapters/src/toolchain/checks.ts +181 -0
  475. package/packages/adapters/src/toolchain/index.ts +38 -0
  476. package/packages/adapters/src/toolchain/installer.ts +189 -0
  477. package/packages/adapters/src/toolchain/types.ts +84 -0
  478. package/packages/adapters/src/types.ts +277 -0
  479. package/packages/adapters/tsconfig.json +3 -1
  480. package/packages/core/package.json +9 -9
  481. package/packages/core/src/constants.ts +44 -1
  482. package/packages/core/src/index.ts +2 -0
  483. package/packages/core/src/stacks.ts +778 -0
  484. package/packages/core/src/system.ts +111 -0
  485. package/packages/core/src/types.ts +22 -1
  486. package/packages/core/src/utils.ts +8 -0
  487. package/packages/core/tsconfig.json +3 -1
  488. package/packages/db/drizzle/0000_init.sql +231 -0
  489. package/packages/db/drizzle/0001_add_server_name.sql +1 -0
  490. package/packages/db/drizzle/meta/_journal.json +20 -0
  491. package/packages/db/drizzle.config.ts +10 -0
  492. package/packages/db/package.json +26 -14
  493. package/packages/db/src/client.ts +119 -0
  494. package/packages/db/src/index.ts +57 -8
  495. package/packages/db/src/repos/account.repo.ts +92 -0
  496. package/packages/db/src/repos/deployment.repo.ts +168 -0
  497. package/packages/db/src/repos/domain.repo.ts +102 -0
  498. package/packages/db/src/repos/git-installation.repo.ts +95 -0
  499. package/packages/db/src/repos/index.ts +43 -0
  500. package/packages/db/src/repos/instance-settings.repo.ts +43 -0
  501. package/packages/db/src/repos/project.repo.ts +159 -0
  502. package/packages/db/src/repos/session.repo.ts +82 -0
  503. package/packages/db/src/repos/settings.repo.ts +51 -0
  504. package/packages/db/src/repos/user.repo.ts +94 -0
  505. package/packages/db/src/schema/auth.ts +56 -0
  506. package/packages/db/src/schema/deployment.ts +87 -0
  507. package/packages/db/src/schema/domain.ts +46 -0
  508. package/packages/db/src/schema/github.ts +24 -0
  509. package/packages/db/src/schema/index.ts +6 -0
  510. package/packages/db/src/schema/project.ts +117 -0
  511. package/packages/db/src/schema/settings.ts +103 -0
  512. package/packages/db/tsconfig.json +3 -1
  513. package/packages/ui/package.json +17 -17
  514. package/packages/ui/src/components/status-dot.tsx +1 -1
  515. package/packages/ui/tsconfig.json +7 -2
  516. package/pnpm-workspace.yaml +0 -1
  517. package/{tooling/tsconfig/base.json → tsconfig.base.json} +0 -1
  518. package/turbo.json +4 -0
  519. package/apps/api/src/modules/auth/auth.controller.ts +0 -26
  520. package/apps/api/src/modules/auth/auth.schema.ts +0 -12
  521. package/apps/api/src/modules/auth/auth.service.ts +0 -23
  522. package/apps/dashboard/src/app/page.tsx +0 -6
  523. package/apps/web/src/app/(marketing)/docs/page.tsx +0 -10
  524. package/packages/adapters/src/base-adapter.ts +0 -49
  525. package/packages/adapters/src/docker-adapter.ts +0 -43
  526. package/packages/adapters/src/oblien-adapter.ts +0 -46
  527. package/packages/adapters/src/registry.ts +0 -22
  528. package/packages/db/prisma/schema.prisma +0 -160
  529. package/tooling/tsconfig/nextjs.json +0 -10
  530. package/tooling/tsconfig/node.json +0 -10
  531. package/tooling/tsconfig/package.json +0 -7
@@ -1,4 +1,144 @@
1
- export { type DeploymentAdapter } from "./base-adapter";
2
- export { DockerAdapter } from "./docker-adapter";
3
- export { OblienAdapter } from "./oblien-adapter";
4
- export { getAdapter } from "./registry";
1
+ /**
2
+ * @repo/adapters platform abstraction layer.
3
+ *
4
+ * Three layers, one entry point:
5
+ * 1. Runtime → build/deploy/stop/start lifecycle (Docker, Bare, Cloud)
6
+ * 2. Infra → routing (Traefik) + SSL (ACME) — separate from runtime
7
+ * 3. System → prerequisite checks + setup validation (self-hosted only)
8
+ *
9
+ * The Platform ties them together:
10
+ * const { runtime, routing, ssl, system } = getPlatform();
11
+ */
12
+
13
+ // ─── Shared types ────────────────────────────────────────────────────────────
14
+ export type {
15
+ ResourceConfig,
16
+ ContainerStatus,
17
+ BuildStrategy,
18
+ BuildConfig,
19
+ DeployConfig,
20
+ BuildResult,
21
+ DeploymentResult,
22
+ BuildStep,
23
+ LogEntry,
24
+ LogCallback,
25
+ ContainerInfo,
26
+ ResourceUsage,
27
+ RouteConfig,
28
+ SslResult,
29
+ SshConfig,
30
+ CommandExecutor,
31
+ } from "./types";
32
+
33
+ export {
34
+ BUILD_STEPS,
35
+ } from "./types";
36
+
37
+ export {
38
+ DEFAULT_RESOURCE_CONFIG,
39
+ DEFAULT_BUILD_RESOURCE_CONFIG,
40
+ } from "./types";
41
+
42
+ // ─── Runtime layer ───────────────────────────────────────────────────────────
43
+ export type { RuntimeAdapter, RuntimeCapability } from "./runtime/types";
44
+ export { assertCapability } from "./runtime/types";
45
+ export { DockerRuntime, type DockerConnectionOptions } from "./runtime/docker";
46
+ export { BareRuntime, type BareRuntimeOptions } from "./runtime/bare";
47
+ export { CloudRuntime } from "./runtime/cloud";
48
+ export { BuildLogger } from "./runtime/build-pipeline";
49
+ export {
50
+ type DeployEnvironment,
51
+ type DeployRouting,
52
+ type DeployPipelineInput,
53
+ type DeployPipelineResult,
54
+ runDeployPipeline,
55
+ } from "./runtime/deploy-pipeline";
56
+ export {
57
+ type RuntimeMode,
58
+ type CreateRuntimeOptions,
59
+ createRuntime,
60
+ } from "./runtime/index";
61
+
62
+ // ─── Infrastructure layer ────────────────────────────────────────────────────
63
+ export type { RoutingProvider, SslProvider } from "./infra/types";
64
+ export { TraefikProvider, type TraefikProviderOptions } from "./infra/traefik";
65
+ export { CloudInfraProvider } from "./infra/cloud";
66
+ export { NoopInfraProvider } from "./infra/noop";
67
+
68
+ // ─── System layer ────────────────────────────────────────────────────────────
69
+ export type {
70
+ ComponentStatus,
71
+ Feature,
72
+ FeatureReadiness,
73
+ InstallerConfig,
74
+ InstallResult,
75
+ PrerequisiteRule,
76
+ RuntimeMode as SystemRuntimeMode,
77
+ SystemComponentDefinition,
78
+ SetupResult,
79
+ SystemCheckResult,
80
+ SystemLog,
81
+ SystemLogCallback,
82
+ } from "./system/types";
83
+
84
+ export type { SetupState, SetupStateStore, ComponentState } from "./system/state";
85
+ export { FileStateStore } from "./system/state";
86
+
87
+ export type {
88
+ EnvironmentProfile,
89
+ LinuxDistro,
90
+ SystemArch,
91
+ SystemOs,
92
+ SystemPackageManager,
93
+ SystemServiceManager,
94
+ } from "./system/environment";
95
+ export { resolveEnvironment } from "./system/environment";
96
+ export { systemCatalog } from "./system/catalog";
97
+ export { SYSTEM_COMPONENTS, getSystemComponentDefinition } from "./system/components";
98
+ export {
99
+ isRemoteConnectionError,
100
+ isRetryableRemoteConnectionError,
101
+ isSshAuthError,
102
+ } from "./system/errors";
103
+
104
+ export { LocalExecutor, SshExecutor, createExecutor } from "./system/executor";
105
+
106
+ export {
107
+ checkAll as checkAllComponents,
108
+ checkComponents,
109
+ checkDocker,
110
+ checkGit,
111
+ checkNode,
112
+ checkTraefik,
113
+ COMPONENT_CHECKS,
114
+ } from "./system/checks";
115
+ export {
116
+ COMPONENT_INSTALLERS,
117
+ installDocker,
118
+ installGit,
119
+ installNode,
120
+ installTraefik,
121
+ } from "./system/installer";
122
+ export { SystemManager, type SystemManagerOptions } from "./system/setup";
123
+
124
+ // ─── Toolchain layer ────────────────────────────────────────────────────────
125
+ export type {
126
+ ToolchainStatus,
127
+ ToolchainCheckResult,
128
+ ToolchainCheckEntry,
129
+ ToolchainInstallPlan,
130
+ ToolchainInstallResult,
131
+ } from "./toolchain";
132
+
133
+ export { toolchainCatalog } from "./toolchain";
134
+ export {
135
+ checkTool,
136
+ checkTools,
137
+ checkToolchain,
138
+ checkToolchainForStack,
139
+ } from "./toolchain";
140
+ export { installTool, installTools } from "./toolchain";
141
+
142
+ // ─── Platform (top-level entry point) ────────────────────────────────────────
143
+ export type { PlatformTarget, PlatformConfig, Platform } from "./platform";
144
+ export { createPlatform, initPlatform, getPlatform, resetPlatform } from "./platform";
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Cloud infrastructure provider — routing + SSL via Oblien API.
3
+ *
4
+ * All operations are API calls to the Oblien platform. No local reverse
5
+ * proxy or ACME configuration needed.
6
+ */
7
+
8
+ import { Oblien } from "oblien";
9
+ import type { RouteConfig, SslResult } from "../types";
10
+ import type { RoutingProvider, SslProvider } from "./types";
11
+
12
+ export class CloudInfraProvider implements RoutingProvider, SslProvider {
13
+ private readonly client: Oblien;
14
+
15
+ constructor(client: Oblien) {
16
+ this.client = client;
17
+ }
18
+
19
+ // ── Routing ──────────────────────────────────────────────────────────
20
+
21
+ async registerRoute(route: RouteConfig): Promise<void> {
22
+ // TODO: POST /routes to Oblien API
23
+ void route;
24
+ }
25
+
26
+ async removeRoute(domain: string): Promise<void> {
27
+ // TODO: DELETE /routes/:domain
28
+ void domain;
29
+ }
30
+
31
+ // ── SSL ──────────────────────────────────────────────────────────────
32
+
33
+ async provisionCert(domain: string): Promise<SslResult> {
34
+ // TODO: POST /ssl/provision — Oblien manages certs
35
+ return { domain, expiresAt: "", issuer: "oblien" };
36
+ }
37
+
38
+ async renewCert(domain: string): Promise<SslResult> {
39
+ // TODO: POST /ssl/renew
40
+ return { domain, expiresAt: "", issuer: "oblien" };
41
+ }
42
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Infrastructure layer barrel exports.
3
+ */
4
+
5
+ export type { RoutingProvider, SslProvider } from "./types";
6
+
7
+ export { TraefikProvider, type TraefikProviderOptions } from "./traefik";
8
+ export { CloudInfraProvider } from "./cloud";
9
+ export { NoopInfraProvider } from "./noop";
@@ -0,0 +1,27 @@
1
+ /**
2
+ * No-op infrastructure provider — for desktop and development.
3
+ *
4
+ * Desktop apps and local dev environments don't need reverse proxies
5
+ * or SSL certificates. This provider silently accepts all calls.
6
+ */
7
+
8
+ import type { RouteConfig, SslResult } from "../types";
9
+ import type { RoutingProvider, SslProvider } from "./types";
10
+
11
+ export class NoopInfraProvider implements RoutingProvider, SslProvider {
12
+ async registerRoute(_route: RouteConfig): Promise<void> {
13
+ // Desktop/dev — no reverse proxy
14
+ }
15
+
16
+ async removeRoute(_domain: string): Promise<void> {
17
+ // No-op
18
+ }
19
+
20
+ async provisionCert(domain: string): Promise<SslResult> {
21
+ return { domain, expiresAt: "", issuer: "none" };
22
+ }
23
+
24
+ async renewCert(domain: string): Promise<SslResult> {
25
+ return { domain, expiresAt: "", issuer: "none" };
26
+ }
27
+ }
@@ -0,0 +1,297 @@
1
+ /**
2
+ * Traefik infrastructure provider — routing + SSL for self-hosted deployments.
3
+ *
4
+ * Uses Traefik's dynamic file provider: writes YAML config files to a watched
5
+ * directory. Traefik detects changes automatically — no reload needed.
6
+ *
7
+ * SSL is handled by Traefik's built-in ACME resolver (Let's Encrypt). When a
8
+ * route is configured with `tls.certResolver`, Traefik auto-provisions and
9
+ * auto-renews certificates.
10
+ *
11
+ * This provider works with BOTH Docker and Bare runtimes — it's independent
12
+ * of how the application process is managed.
13
+ *
14
+ * Typical Traefik static config (traefik.yml):
15
+ * ```yaml
16
+ * providers:
17
+ * file:
18
+ * directory: /etc/traefik/dynamic
19
+ * watch: true
20
+ *
21
+ * certificatesResolvers:
22
+ * letsencrypt:
23
+ * acme:
24
+ * email: admin@example.com
25
+ * storage: /etc/traefik/acme.json
26
+ * httpChallenge:
27
+ * entryPoint: web
28
+ * ```
29
+ */
30
+
31
+ import {
32
+ writeFile as fsWriteFile,
33
+ rm as fsRm,
34
+ mkdir as fsMkdir,
35
+ readFile as fsReadFile,
36
+ } from "node:fs/promises";
37
+ import { dirname, join } from "node:path";
38
+
39
+ import type { CommandExecutor, RouteConfig, SslResult } from "../types";
40
+ import type { RoutingProvider, SslProvider } from "./types";
41
+
42
+ // ─── Config ──────────────────────────────────────────────────────────────────
43
+
44
+ export interface TraefikProviderOptions {
45
+ /**
46
+ * Directory where Traefik watches for dynamic config files.
47
+ * Default: /etc/traefik/dynamic
48
+ */
49
+ configDir?: string;
50
+ /**
51
+ * ACME certificate resolver name (must match Traefik static config).
52
+ * Default: "letsencrypt"
53
+ */
54
+ certResolver?: string;
55
+ /**
56
+ * Path to Traefik's ACME storage file (for reading cert info).
57
+ * Default: /etc/traefik/acme.json
58
+ */
59
+ acmeStoragePath?: string;
60
+ /**
61
+ * Command executor for file operations.
62
+ *
63
+ * When provided, all file reads/writes go through the executor
64
+ * (supporting remote servers via SSH). When omitted, uses node:fs
65
+ * directly (local server).
66
+ *
67
+ * This is what enables the dual-path: same TraefikProvider, same
68
+ * config format, works both locally and remotely.
69
+ */
70
+ executor?: CommandExecutor;
71
+ }
72
+
73
+ const DEFAULT_CONFIG_DIR = "/etc/traefik/dynamic";
74
+ const DEFAULT_CERT_RESOLVER = "letsencrypt";
75
+ const DEFAULT_ACME_STORAGE = "/etc/traefik/acme.json";
76
+
77
+ // ─── Implementation ──────────────────────────────────────────────────────────
78
+
79
+ /**
80
+ * Traefik-based routing and SSL provider.
81
+ *
82
+ * Implements both RoutingProvider and SslProvider since Traefik handles
83
+ * both concerns through its dynamic configuration.
84
+ */
85
+ export class TraefikProvider implements RoutingProvider, SslProvider {
86
+ private readonly configDir: string;
87
+ private readonly certResolver: string;
88
+ private readonly acmeStoragePath: string;
89
+ private readonly executor: CommandExecutor | null;
90
+
91
+ constructor(opts?: TraefikProviderOptions) {
92
+ this.configDir = opts?.configDir ?? DEFAULT_CONFIG_DIR;
93
+ this.certResolver = opts?.certResolver ?? DEFAULT_CERT_RESOLVER;
94
+ this.acmeStoragePath = opts?.acmeStoragePath ?? DEFAULT_ACME_STORAGE;
95
+ this.executor = opts?.executor ?? null;
96
+ }
97
+
98
+ // ── File operation helpers (dual-path: local or remote) ──────────────
99
+
100
+ private async _writeFile(path: string, content: string): Promise<void> {
101
+ if (this.executor) {
102
+ await this.executor.writeFile(path, content);
103
+ } else {
104
+ await fsMkdir(dirname(path), { recursive: true });
105
+ await fsWriteFile(path, content, "utf-8");
106
+ }
107
+ }
108
+
109
+ private async _readFile(path: string): Promise<string> {
110
+ if (this.executor) {
111
+ return this.executor.readFile(path);
112
+ }
113
+ return fsReadFile(path, "utf-8");
114
+ }
115
+
116
+ private async _rm(path: string): Promise<void> {
117
+ if (this.executor) {
118
+ await this.executor.rm(path);
119
+ } else {
120
+ try {
121
+ await fsRm(path);
122
+ } catch {
123
+ // Already gone
124
+ }
125
+ }
126
+ }
127
+
128
+ private async _mkdir(path: string): Promise<void> {
129
+ if (this.executor) {
130
+ await this.executor.mkdir(path);
131
+ } else {
132
+ await fsMkdir(path, { recursive: true });
133
+ }
134
+ }
135
+
136
+ // ── Routing ──────────────────────────────────────────────────────────
137
+
138
+ /**
139
+ * Register a route by writing a Traefik dynamic config file.
140
+ *
141
+ * Creates a YAML file in the watched directory. Traefik picks it up
142
+ * automatically within seconds.
143
+ */
144
+ async registerRoute(route: RouteConfig): Promise<void> {
145
+ await this._mkdir(this.configDir);
146
+
147
+ const slug = this.domainSlug(route.domain);
148
+ const configPath = join(this.configDir, `${slug}.yml`);
149
+
150
+ // Build Traefik dynamic configuration YAML
151
+ const tlsBlock = route.tls
152
+ ? `\n tls:\n certResolver: ${this.certResolver}`
153
+ : "";
154
+
155
+ const yaml = `# Auto-generated by Openship — do not edit manually
156
+ http:
157
+ routers:
158
+ ${slug}:
159
+ rule: "Host(\`${route.domain}\`)"
160
+ service: ${slug}
161
+ entryPoints:
162
+ - websecure${tlsBlock}
163
+ services:
164
+ ${slug}:
165
+ loadBalancer:
166
+ servers:
167
+ - url: "${route.targetUrl}"
168
+ `;
169
+
170
+ await this._writeFile(configPath, yaml);
171
+ }
172
+
173
+ /**
174
+ * Remove a route by deleting its config file.
175
+ * Traefik detects the removal and drops the route.
176
+ */
177
+ async removeRoute(domain: string): Promise<void> {
178
+ const slug = this.domainSlug(domain);
179
+ const configPath = join(this.configDir, `${slug}.yml`);
180
+ await this._rm(configPath);
181
+ }
182
+
183
+ // ── SSL ──────────────────────────────────────────────────────────────
184
+
185
+ /**
186
+ * Provision a TLS certificate for a domain.
187
+ *
188
+ * With Traefik + ACME, certificate provisioning is automatic when a route
189
+ * has `tls.certResolver` configured. This method ensures the route exists
190
+ * with TLS enabled and returns cert info from ACME storage.
191
+ */
192
+ async provisionCert(domain: string): Promise<SslResult> {
193
+ // The route should already have TLS enabled via registerRoute().
194
+ // Traefik handles ACME challenge + cert issuance automatically.
195
+ // We check the ACME storage for cert info.
196
+ const certInfo = await this.readCertInfo(domain);
197
+
198
+ if (certInfo) {
199
+ return certInfo;
200
+ }
201
+
202
+ // Cert not yet available — Traefik is still provisioning.
203
+ // Return a pending result; the caller can poll.
204
+ return {
205
+ domain,
206
+ expiresAt: "",
207
+ issuer: this.certResolver,
208
+ };
209
+ }
210
+
211
+ /**
212
+ * Renew a TLS certificate.
213
+ *
214
+ * Traefik auto-renews certificates 30 days before expiry. This method
215
+ * is effectively a check + trigger: it touches the route config to ensure
216
+ * Traefik re-evaluates the cert.
217
+ */
218
+ async renewCert(domain: string): Promise<SslResult> {
219
+ // Touch the config file to trigger Traefik re-evaluation
220
+ const slug = this.domainSlug(domain);
221
+ const configPath = join(this.configDir, `${slug}.yml`);
222
+
223
+ try {
224
+ const content = await this._readFile(configPath);
225
+ const updated = content.replace(
226
+ /^# Auto-generated by Openship.*/,
227
+ `# Auto-generated by Openship — renewed ${new Date().toISOString()}`,
228
+ );
229
+ await this._writeFile(configPath, updated);
230
+ } catch {
231
+ // Config file doesn't exist — nothing to renew
232
+ }
233
+
234
+ return this.provisionCert(domain);
235
+ }
236
+
237
+ // ── Helpers ──────────────────────────────────────────────────────────
238
+
239
+ /**
240
+ * Convert a domain to a safe slug for file names and Traefik identifiers.
241
+ * "my-app.example.com" → "my-app-example-com"
242
+ */
243
+ private domainSlug(domain: string): string {
244
+ return domain.replace(/[^a-zA-Z0-9-]/g, "-").replace(/-+/g, "-");
245
+ }
246
+
247
+ /**
248
+ * Read certificate info from Traefik's ACME storage file.
249
+ *
250
+ * The acme.json file contains all managed certificates. We look for
251
+ * the one matching the given domain.
252
+ */
253
+ private async readCertInfo(domain: string): Promise<SslResult | null> {
254
+ try {
255
+ const raw = await this._readFile(this.acmeStoragePath);
256
+ const storage = JSON.parse(raw);
257
+
258
+ // ACME storage structure: { [resolverName]: { Certificates: [...] } }
259
+ const resolver = storage[this.certResolver];
260
+ if (!resolver?.Certificates) return null;
261
+
262
+ for (const cert of resolver.Certificates) {
263
+ if (cert.domain?.main === domain || cert.domain?.sans?.includes(domain)) {
264
+ // Parse the certificate to get expiry
265
+ // Certificate is base64-encoded PEM
266
+ const certPem = Buffer.from(cert.certificate, "base64").toString("utf-8");
267
+ const expiresAt = await this.parseCertExpiry(certPem);
268
+
269
+ return {
270
+ domain,
271
+ expiresAt: expiresAt ?? "",
272
+ issuer: this.certResolver,
273
+ };
274
+ }
275
+ }
276
+
277
+ return null;
278
+ } catch {
279
+ return null;
280
+ }
281
+ }
282
+
283
+ /**
284
+ * Extract the expiry date from a PEM certificate.
285
+ * Uses a simple regex on the date field — avoids heavy crypto deps.
286
+ */
287
+ private async parseCertExpiry(pem: string): Promise<string | null> {
288
+ // For a proper implementation, use node:crypto X509Certificate
289
+ try {
290
+ const { X509Certificate } = await import("node:crypto");
291
+ const cert = new X509Certificate(pem);
292
+ return new Date(cert.validTo).toISOString();
293
+ } catch {
294
+ return null;
295
+ }
296
+ }
297
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Infrastructure provider interfaces — routing and SSL.
3
+ *
4
+ * Routing and SSL are separate from the runtime because:
5
+ * - Docker is a runtime, not a reverse proxy. Traefik/Caddy/Nginx handle routing.
6
+ * - SSL is managed by ACME resolvers (Traefik, certbot), not by Docker.
7
+ * - Cloud routing uses a completely different mechanism (API calls).
8
+ * - Desktop/dev doesn't need routing or SSL at all.
9
+ *
10
+ * Implementations:
11
+ * - TraefikProvider → Traefik file provider + ACME (self-hosted)
12
+ * - CloudInfra → Oblien API (cloud)
13
+ * - NoopInfra → No-op (desktop/dev)
14
+ */
15
+
16
+ import type { RouteConfig, SslResult } from "../types";
17
+
18
+ // ─── Routing ─────────────────────────────────────────────────────────────────
19
+
20
+ export interface RoutingProvider {
21
+ /** Register a reverse-proxy route (domain → container/process) */
22
+ registerRoute(route: RouteConfig): Promise<void>;
23
+
24
+ /** Remove a reverse-proxy route */
25
+ removeRoute(domain: string): Promise<void>;
26
+ }
27
+
28
+ // ─── SSL ─────────────────────────────────────────────────────────────────────
29
+
30
+ export interface SslProvider {
31
+ /** Provision a new TLS certificate for a domain */
32
+ provisionCert(domain: string): Promise<SslResult>;
33
+
34
+ /** Renew an existing TLS certificate */
35
+ renewCert(domain: string): Promise<SslResult>;
36
+ }