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.
- package/.env.example +19 -3
- package/CONTRIBUTING.md +69 -19
- package/LICENSE +661 -0
- package/README.md +304 -108
- package/apps/api/Dockerfile +6 -8
- package/apps/api/package.json +25 -21
- package/apps/api/src/app.ts +46 -3
- package/apps/api/src/config/env.ts +81 -7
- package/apps/api/src/lib/auth-mode.ts +42 -0
- package/apps/api/src/lib/auth.ts +105 -0
- package/apps/api/src/lib/cache.ts +128 -0
- package/apps/api/src/lib/cloud-auth-proxy.ts +310 -0
- package/apps/api/src/lib/cloud-client.ts +103 -0
- package/apps/api/src/lib/compose-parser.ts +138 -0
- package/apps/api/src/lib/controller-helpers.ts +90 -0
- package/apps/api/src/lib/email-templates.ts +94 -0
- package/apps/api/src/lib/encryption.ts +102 -0
- package/apps/api/src/lib/local-user.ts +65 -0
- package/apps/api/src/lib/mail.ts +48 -0
- package/apps/api/src/lib/notifications.ts +195 -0
- package/apps/api/src/lib/openship-cloud.ts +101 -0
- package/apps/api/src/lib/resources.ts +96 -0
- package/apps/api/src/lib/screenshots.ts +189 -0
- package/apps/api/src/lib/ssh-manager.ts +369 -0
- package/apps/api/src/lib/ssl-scheduler.ts +109 -0
- package/apps/api/src/lib/stack-detector.ts +708 -0
- package/apps/api/src/lib/system-debug.ts +10 -0
- package/apps/api/src/middleware/auth.ts +49 -13
- package/apps/api/src/middleware/error-handler.ts +23 -3
- package/apps/api/src/middleware/index.ts +2 -0
- package/apps/api/src/middleware/internal-auth.ts +40 -0
- package/apps/api/src/middleware/local-only.ts +20 -0
- package/apps/api/src/middleware/rate-limiter.ts +9 -0
- package/apps/api/src/modules/analytics/analytics.controller.ts +111 -0
- package/apps/api/src/modules/analytics/analytics.routes.ts +29 -0
- package/apps/api/src/modules/analytics/analytics.schema.ts +37 -0
- package/apps/api/src/modules/analytics/analytics.service.ts +264 -0
- package/apps/api/src/modules/auth/auth.routes.ts +233 -6
- package/apps/api/src/modules/billing/billing.routes.ts +8 -0
- package/apps/api/src/modules/cloud/cloud.controller.ts +225 -0
- package/apps/api/src/modules/cloud/cloud.routes.ts +40 -0
- package/apps/api/src/modules/deployments/build.service.ts +791 -0
- package/apps/api/src/modules/deployments/deployment-lifecycle.ts +138 -0
- package/apps/api/src/modules/deployments/deployment.controller.ts +324 -16
- package/apps/api/src/modules/deployments/deployment.routes.ts +33 -7
- package/apps/api/src/modules/deployments/deployment.schema.ts +37 -5
- package/apps/api/src/modules/deployments/deployment.service.ts +178 -11
- package/apps/api/src/modules/deployments/preflight.ts +280 -0
- package/apps/api/src/modules/deployments/prepare.service.ts +252 -0
- package/apps/api/src/modules/deployments/session-manager.ts +283 -0
- package/apps/api/src/modules/deployments/ssl.service.ts +73 -0
- package/apps/api/src/modules/domains/domain.controller.ts +59 -7
- package/apps/api/src/modules/domains/domain.routes.ts +20 -5
- package/apps/api/src/modules/domains/domain.schema.ts +35 -0
- package/apps/api/src/modules/domains/domain.service.ts +375 -9
- package/apps/api/src/modules/github/github.auth.ts +397 -0
- package/apps/api/src/modules/github/github.controller.ts +387 -0
- package/apps/api/src/modules/github/github.local-auth.ts +251 -0
- package/apps/api/src/modules/github/github.routes.ts +50 -0
- package/apps/api/src/modules/github/github.schema.ts +52 -0
- package/apps/api/src/modules/github/github.service.ts +592 -0
- package/apps/api/src/modules/github/github.types.ts +158 -0
- package/apps/api/src/modules/github/github.webhook.ts +186 -0
- package/apps/api/src/modules/github/index.ts +16 -0
- package/apps/api/src/modules/health/health.routes.ts +35 -0
- package/apps/api/src/modules/projects/project.controller.ts +481 -12
- package/apps/api/src/modules/projects/project.routes.ts +63 -6
- package/apps/api/src/modules/projects/project.schema.ts +104 -6
- package/apps/api/src/modules/projects/project.service.ts +502 -11
- package/apps/api/src/modules/settings/settings.controller.ts +55 -0
- package/apps/api/src/modules/settings/settings.routes.ts +25 -0
- package/apps/api/src/modules/settings/settings.service.ts +49 -0
- package/apps/api/src/modules/system/filesystem.controller.ts +66 -0
- package/apps/api/src/modules/system/index.ts +1 -0
- package/apps/api/src/modules/system/server-check.controller.ts +475 -0
- package/apps/api/src/modules/system/setup-session.ts +255 -0
- package/apps/api/src/modules/system/setup.controller.ts +128 -0
- package/apps/api/src/modules/system/system.routes.ts +42 -0
- package/apps/api/src/modules/webhooks/webhook.controller.ts +57 -15
- package/apps/api/src/modules/webhooks/webhook.routes.ts +11 -8
- package/apps/api/src/modules/webhooks/webhook.service.ts +46 -5
- package/apps/api/src/modules/webhooks/webhook.types.ts +35 -0
- package/apps/api/tsconfig.json +3 -1
- package/apps/cli/package.json +8 -10
- package/apps/cli/tsconfig.json +2 -1
- package/apps/dashboard/Dockerfile +4 -6
- package/apps/dashboard/components.json +20 -0
- package/apps/dashboard/next-env.d.ts +6 -0
- package/apps/dashboard/next.config.mjs +11 -1
- package/apps/dashboard/package.json +25 -13
- package/apps/dashboard/postcss.config.mjs +5 -0
- package/apps/dashboard/public/android-chrome-192x192.png +0 -0
- package/apps/dashboard/public/android-chrome-512x512.png +0 -0
- package/apps/dashboard/public/apple-touch-icon.png +0 -0
- package/apps/dashboard/public/favicon-16x16.png +0 -0
- package/apps/dashboard/public/favicon-32x32.png +0 -0
- package/apps/dashboard/public/favicon.ico +0 -0
- package/apps/dashboard/public/site.webmanifest +19 -0
- package/apps/dashboard/src/app/(auth)/forgot-password/page.tsx +114 -0
- package/apps/dashboard/src/app/(auth)/layout.tsx +18 -3
- package/apps/dashboard/src/app/(auth)/login/page.tsx +215 -6
- package/apps/dashboard/src/app/(auth)/providers.tsx +34 -0
- package/apps/dashboard/src/app/(auth)/register/page.tsx +171 -5
- package/apps/dashboard/src/app/(auth)/reset-password/page.tsx +172 -0
- package/apps/dashboard/src/app/(auth)/verify-email/page.tsx +190 -0
- package/apps/dashboard/src/app/(dashboard)/(deployment)/build/[id]/page.tsx +162 -0
- package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/BuildSummary.tsx +166 -0
- package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/DnsConfiguration.tsx +119 -0
- package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/DomainSettings.tsx +291 -0
- package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/Header.tsx +71 -0
- package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/Sidebar.tsx +270 -0
- package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/components/SkeletonLoader.tsx +87 -0
- package/apps/dashboard/src/app/(dashboard)/(deployment)/deploy/[slug]/page.tsx +169 -0
- package/apps/dashboard/src/app/(dashboard)/(deployment)/layout.tsx +7 -0
- package/apps/dashboard/src/app/(dashboard)/billing/page.tsx +1 -8
- package/apps/dashboard/src/app/(dashboard)/deployments/components/CommitDetailsModal.tsx +240 -0
- package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentCard.tsx +121 -0
- package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentHeader.tsx +89 -0
- package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentMenu.tsx +182 -0
- package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentsContent.tsx +324 -0
- package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentsFilters.tsx +99 -0
- package/apps/dashboard/src/app/(dashboard)/deployments/components/DeploymentsList.tsx +31 -0
- package/apps/dashboard/src/app/(dashboard)/deployments/components/EmptyState.tsx +101 -0
- package/apps/dashboard/src/app/(dashboard)/deployments/components/LoadingSkeleton.tsx +57 -0
- package/apps/dashboard/src/app/(dashboard)/deployments/components/ProjectFilter.tsx +109 -0
- package/apps/dashboard/src/app/(dashboard)/deployments/components/index.ts +9 -0
- package/apps/dashboard/src/app/(dashboard)/deployments/page.tsx +9 -3
- package/apps/dashboard/src/app/(dashboard)/deployments/types.ts +44 -0
- package/apps/dashboard/src/app/(dashboard)/deployments/utils.ts +176 -0
- package/apps/dashboard/src/app/(dashboard)/domains/page.tsx +1 -6
- package/apps/dashboard/src/app/(dashboard)/integrations/page.tsx +321 -0
- package/apps/dashboard/src/app/(dashboard)/layout.tsx +22 -32
- package/apps/dashboard/src/app/(dashboard)/library/components/ConnectPrompt.tsx +187 -0
- package/apps/dashboard/src/app/(dashboard)/library/components/LibrarySidebar.tsx +147 -0
- package/apps/dashboard/src/app/(dashboard)/library/components/LoadingSkeleton.tsx +39 -0
- package/apps/dashboard/src/app/(dashboard)/library/components/LocalProjects.tsx +548 -0
- package/apps/dashboard/src/app/(dashboard)/library/components/RepositoryList.tsx +292 -0
- package/apps/dashboard/src/app/(dashboard)/library/components/TemplateGrid.tsx +36 -0
- package/apps/dashboard/src/app/(dashboard)/library/components/UrlImport.tsx +74 -0
- package/apps/dashboard/src/app/(dashboard)/library/page.tsx +121 -0
- package/apps/dashboard/src/app/(dashboard)/library/types.ts +26 -0
- package/apps/dashboard/src/app/(dashboard)/monitoring/page.tsx +1 -6
- package/apps/dashboard/src/app/(dashboard)/page.tsx +485 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/[[...slug]]/layout.tsx +22 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/[[...slug]]/page.tsx +286 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/AdvancedSettings.tsx +235 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/BuildSettings.tsx +174 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/DeleteConfirmationDialog.tsx +45 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/DeletionModal.tsx +95 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/Deployments.tsx +11 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/DomainSettings.tsx +523 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/EnvironmentSettings.tsx +246 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/GeneralSettings.tsx +93 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/GitInfo.tsx +261 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/GitSettings.tsx +391 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/LogsSettings.tsx +133 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/ProjectNotFound.tsx +95 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/ProjectsBottomNavigation.tsx +62 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/ResourceSettings.tsx +333 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/SettingSection.tsx +66 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/SettingsNavigation.tsx +27 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/SleepModeSettings.tsx +134 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/ProductionUrl.tsx +25 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/ProjectIdentity.tsx +159 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/ProjectInfo.tsx +58 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/SkeletonLoader.tsx +170 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/StatsCards.tsx +33 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/TopPaths.tsx +56 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/TrafficChart.tsx +157 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/general/index.ts +14 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/logs/LogsActions.tsx +52 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/logs/ServerLogs.tsx +249 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/logs/TerminalLogs.tsx +682 -0
- package/apps/dashboard/src/app/(dashboard)/projects/[id]/components/logs/logs.css +127 -0
- package/apps/dashboard/src/app/(dashboard)/projects/components/DeploymentCard.tsx +73 -0
- package/apps/dashboard/src/app/(dashboard)/projects/components/ProjectCard.tsx +330 -0
- package/apps/dashboard/src/app/(dashboard)/projects/page.tsx +326 -4
- package/apps/dashboard/src/app/(dashboard)/providers.tsx +23 -0
- package/apps/dashboard/src/app/(dashboard)/servers/[serverId]/_components/components-tab.tsx +329 -0
- package/apps/dashboard/src/app/(dashboard)/servers/[serverId]/_components/overview-tab.tsx +229 -0
- package/apps/dashboard/src/app/(dashboard)/servers/[serverId]/_components/terminal-tab.tsx +38 -0
- package/apps/dashboard/src/app/(dashboard)/servers/[serverId]/page.tsx +437 -0
- package/apps/dashboard/src/app/(dashboard)/servers/new/_components/checking-state.tsx +15 -0
- package/apps/dashboard/src/app/(dashboard)/servers/new/_components/choose-mode.tsx +54 -0
- package/apps/dashboard/src/app/(dashboard)/servers/new/_components/component-row.tsx +65 -0
- package/apps/dashboard/src/app/(dashboard)/servers/new/_components/error-banner.tsx +13 -0
- package/apps/dashboard/src/app/(dashboard)/servers/new/_components/installing-panel.tsx +227 -0
- package/apps/dashboard/src/app/(dashboard)/servers/new/_components/results-panel.tsx +90 -0
- package/apps/dashboard/src/app/(dashboard)/servers/new/_components/setup-header.tsx +56 -0
- package/apps/dashboard/src/app/(dashboard)/servers/new/_components/types.ts +13 -0
- package/apps/dashboard/src/app/(dashboard)/servers/new/page.tsx +666 -0
- package/apps/dashboard/src/app/(dashboard)/servers/page.tsx +283 -0
- package/apps/dashboard/src/app/(dashboard)/settings/_components/BuildPreferences.tsx +110 -0
- package/apps/dashboard/src/app/(dashboard)/settings/_components/CloudConnection.tsx +147 -0
- package/apps/dashboard/src/app/(dashboard)/settings/_components/InstanceInfo.tsx +54 -0
- package/apps/dashboard/src/app/(dashboard)/settings/_components/ServerConnection.tsx +407 -0
- package/apps/dashboard/src/app/(dashboard)/settings/_components/SettingsSection.tsx +32 -0
- package/apps/dashboard/src/app/(dashboard)/settings/page.tsx +62 -3
- package/apps/dashboard/src/app/auth/callback/close/page.tsx +23 -0
- package/apps/dashboard/src/app/auth/callback/install/page.tsx +40 -0
- package/apps/dashboard/src/app/authorize/page.tsx +137 -0
- package/apps/dashboard/src/app/globals.css +57 -3
- package/apps/dashboard/src/app/layout.tsx +43 -3
- package/apps/dashboard/src/components/auth-shell.tsx +66 -0
- package/apps/dashboard/src/components/deployments/types.ts +44 -0
- package/apps/dashboard/src/components/global-deployments/index.ts +17 -0
- package/apps/dashboard/src/components/i18n-provider.tsx +100 -0
- package/apps/dashboard/src/components/import-project/BuildSettings.tsx +376 -0
- package/apps/dashboard/src/components/import-project/BuildSkeleton.tsx +161 -0
- package/apps/dashboard/src/components/import-project/BuildTerminal.tsx +358 -0
- package/apps/dashboard/src/components/import-project/ComposeServices.tsx +455 -0
- package/apps/dashboard/src/components/import-project/DeploymentProcessing.tsx +510 -0
- package/apps/dashboard/src/components/import-project/DockerSettings.tsx +64 -0
- package/apps/dashboard/src/components/import-project/EnvironmentVariables.tsx +481 -0
- package/apps/dashboard/src/components/import-project/Frameworks.tsx +90 -0
- package/apps/dashboard/src/components/import-project/ProjectSettings.tsx +160 -0
- package/apps/dashboard/src/components/import-project/types.ts +82 -0
- package/apps/dashboard/src/components/integrations/GithubPermissionModal.tsx +173 -0
- package/apps/dashboard/src/components/language-switcher.tsx +36 -0
- package/apps/dashboard/src/components/logo.tsx +13 -0
- package/apps/dashboard/src/components/network-error-handler.tsx +27 -0
- package/apps/dashboard/src/components/oauth-buttons.tsx +81 -0
- package/apps/dashboard/src/components/overview/ActivityChart.tsx +247 -0
- package/apps/dashboard/src/components/overview/ApiRequestsCard.tsx +111 -0
- package/apps/dashboard/src/components/overview/CreditsCard.tsx +137 -0
- package/apps/dashboard/src/components/overview/DeploymentsChart.tsx +195 -0
- package/apps/dashboard/src/components/overview/EmptyState.tsx +126 -0
- package/apps/dashboard/src/components/overview/LoadingSkeleton.tsx +92 -0
- package/apps/dashboard/src/components/overview/OverviewHeader.tsx +74 -0
- package/apps/dashboard/src/components/overview/OverviewHeroChart.tsx +344 -0
- package/apps/dashboard/src/components/overview/ProjectsCard.tsx +134 -0
- package/apps/dashboard/src/components/overview/QuickLinks.tsx +119 -0
- package/apps/dashboard/src/components/overview/SandboxesCard.tsx +150 -0
- package/apps/dashboard/src/components/overview/StatsGrid.tsx +166 -0
- package/apps/dashboard/src/components/overview/TokenUsageChart.tsx +206 -0
- package/apps/dashboard/src/components/overview/UsageStats.tsx +79 -0
- package/apps/dashboard/src/components/overview/index.ts +30 -0
- package/apps/dashboard/src/components/overview/types.ts +116 -0
- package/apps/dashboard/src/components/page-header.tsx +25 -0
- package/apps/dashboard/src/components/project-settings/ServerSideSwitch.jsx +60 -0
- package/apps/dashboard/src/components/shared/AlertBox.tsx +39 -0
- package/apps/dashboard/src/components/shared/CTASection.tsx +45 -0
- package/apps/dashboard/src/components/shared/ErrorState.tsx +176 -0
- package/apps/dashboard/src/components/shared/FeatureCard.tsx +20 -0
- package/apps/dashboard/src/components/shared/MDXComponents.tsx +24 -0
- package/apps/dashboard/src/components/shared/MachineSettingsModal.tsx +286 -0
- package/apps/dashboard/src/components/shared/Modal.tsx +39 -0
- package/apps/dashboard/src/components/shared/OTPInput.tsx +122 -0
- package/apps/dashboard/src/components/shared/PageHero.tsx +21 -0
- package/apps/dashboard/src/components/shared/PlatformFeatureCard.tsx +27 -0
- package/apps/dashboard/src/components/shared/StatCard.tsx +14 -0
- package/apps/dashboard/src/components/shared/ValueCard.tsx +20 -0
- package/apps/dashboard/src/components/shared/index.ts +8 -0
- package/apps/dashboard/src/components/sidebar.tsx +282 -0
- package/apps/dashboard/src/components/theme-provider.tsx +96 -0
- package/apps/dashboard/src/components/toast.tsx +106 -0
- package/apps/dashboard/src/components/ui/CustomCursor.tsx +107 -0
- package/apps/dashboard/src/components/ui/CustomSelect.tsx +126 -0
- package/apps/dashboard/src/components/ui/DropdownMenu.tsx +174 -0
- package/apps/dashboard/src/components/ui/FileIcon.jsx +59 -0
- package/apps/dashboard/src/components/ui/IconPickerModal.tsx +273 -0
- package/apps/dashboard/src/components/ui/InfoBanner.jsx +39 -0
- package/apps/dashboard/src/components/ui/Logo.tsx +14 -0
- package/apps/dashboard/src/components/ui/Modal.tsx +117 -0
- package/apps/dashboard/src/components/ui/PageContainer.tsx +12 -0
- package/apps/dashboard/src/components/ui/SectionContainer.jsx +7 -0
- package/apps/dashboard/src/components/ui/SlidingToggle.tsx +128 -0
- package/apps/dashboard/src/components/ui/Toast.tsx +29 -0
- package/apps/dashboard/src/components/ui/button.tsx +58 -0
- package/apps/dashboard/src/components/ui/card.tsx +60 -0
- package/apps/dashboard/src/components/ui/input.tsx +20 -0
- package/apps/dashboard/src/components/ui/label.tsx +19 -0
- package/apps/dashboard/src/components/ui/select.tsx +10 -0
- package/apps/dashboard/src/components/ui/textarea.tsx +9 -0
- package/apps/dashboard/src/constants/lang-colors.ts +25 -0
- package/apps/dashboard/src/constants/mock.ts +38 -0
- package/apps/dashboard/src/context/AuthContext.tsx +91 -0
- package/apps/dashboard/src/context/CloudContext.tsx +275 -0
- package/apps/dashboard/src/context/DeploymentContext.tsx +71 -0
- package/apps/dashboard/src/context/GitHubContext.tsx +288 -0
- package/apps/dashboard/src/context/ModalContext.tsx +300 -0
- package/apps/dashboard/src/context/NetworkContext.tsx +32 -0
- package/apps/dashboard/src/context/ProjectSettingsContext.tsx +727 -0
- package/apps/dashboard/src/context/ToastContext.tsx +129 -0
- package/apps/dashboard/src/context/deployment/index.ts +3 -0
- package/apps/dashboard/src/context/deployment/types.ts +183 -0
- package/apps/dashboard/src/context/deployment/useDeploymentBuild.ts +547 -0
- package/apps/dashboard/src/context/deployment/useDeploymentConfig.ts +176 -0
- package/apps/dashboard/src/hooks/useBuildConnection.ts +334 -0
- package/apps/dashboard/src/hooks/useMonitorStream.ts +146 -0
- package/apps/dashboard/src/hooks/useProjectData.ts +110 -0
- package/apps/dashboard/src/hooks/useSSEConnection.ts +465 -0
- package/apps/dashboard/src/hooks/useSSEStream.ts +309 -0
- package/apps/dashboard/src/hooks/useSessions.ts +104 -0
- package/apps/dashboard/src/hooks/useSetupStream.ts +223 -0
- package/apps/dashboard/src/i18n/dictionaries/ar.json +218 -0
- package/apps/dashboard/src/i18n/dictionaries/en.json +218 -0
- package/apps/dashboard/src/i18n/index.ts +16 -0
- package/apps/dashboard/src/lib/api/ai.ts +22 -0
- package/apps/dashboard/src/lib/api/auth.ts +13 -0
- package/apps/dashboard/src/lib/api/client.ts +199 -0
- package/apps/dashboard/src/lib/api/cloud.ts +15 -0
- package/apps/dashboard/src/lib/api/deploy.ts +58 -0
- package/apps/dashboard/src/lib/api/domains.ts +13 -0
- package/apps/dashboard/src/lib/api/endpoints.ts +129 -0
- package/apps/dashboard/src/lib/api/github.ts +31 -0
- package/apps/dashboard/src/lib/api/icons.ts +12 -0
- package/apps/dashboard/src/lib/api/index.ts +41 -0
- package/apps/dashboard/src/lib/api/projects.ts +153 -0
- package/apps/dashboard/src/lib/api/sandbox.ts +14 -0
- package/apps/dashboard/src/lib/api/settings.ts +21 -0
- package/apps/dashboard/src/lib/api/system.ts +159 -0
- package/apps/dashboard/src/lib/auth-client.ts +54 -0
- package/apps/dashboard/src/lib/country.ts +25 -0
- package/apps/dashboard/src/lib/server/api.ts +140 -0
- package/apps/dashboard/src/lib/server/session.ts +103 -0
- package/apps/dashboard/src/lib/sseClient.ts +241 -0
- package/apps/dashboard/src/lib/sseMessageProcessors.ts +323 -0
- package/apps/dashboard/src/lib/utils.ts +6 -0
- package/apps/dashboard/src/proxy.ts +46 -0
- package/apps/dashboard/src/styles/Toast.module.css +92 -0
- package/apps/dashboard/src/styles/fonts.css +93 -0
- package/apps/dashboard/src/styles/theme.css +336 -0
- package/apps/dashboard/src/types/research.ts +42 -0
- package/apps/dashboard/src/utils/SSEParser.js +150 -0
- package/apps/dashboard/src/utils/authWindow.ts +143 -0
- package/apps/dashboard/src/utils/codeTheme.ts +127 -0
- package/apps/dashboard/src/utils/colors.json +2810 -0
- package/apps/dashboard/src/utils/date.ts +121 -0
- package/apps/dashboard/src/utils/deployment.ts +128 -0
- package/apps/dashboard/src/utils/deploymentPhaseDetector.ts +232 -0
- package/apps/dashboard/src/utils/extToLang.js +103 -0
- package/apps/dashboard/src/utils/github.ts +62 -0
- package/apps/dashboard/src/utils/icons.js +46 -0
- package/apps/dashboard/src/utils/repoSlug.ts +110 -0
- package/apps/dashboard/src/utils/research-api.ts +163 -0
- package/apps/dashboard/src/utils/suggestions.ts +84 -0
- package/apps/dashboard/src/utils/theme.js +1 -0
- package/apps/dashboard/src/utils/ui-helpers.tsx +30 -0
- package/apps/dashboard/src/utils/upload.js +12 -0
- package/apps/dashboard/tsconfig.json +27 -5
- package/apps/desktop/forge.config.json +36 -0
- package/apps/desktop/package.json +26 -0
- package/apps/desktop/scripts/dev.mjs +58 -0
- package/apps/desktop/src/main/index.ts +675 -0
- package/apps/desktop/src/main/types/desktop.d.ts +33 -0
- package/apps/desktop/src/preload/index.ts +88 -0
- package/apps/desktop/src/renderer/index.html +462 -0
- package/apps/desktop/src/renderer/onboarding.js +511 -0
- package/apps/desktop/src/renderer/styles.css +1139 -0
- package/apps/desktop/tsconfig.json +17 -0
- package/apps/web/.source/browser.ts +13 -0
- package/apps/web/.source/dynamic.ts +8 -0
- package/apps/web/.source/server.ts +22 -0
- package/apps/web/.source/source.config.mjs +20 -0
- package/apps/web/Dockerfile +4 -6
- package/apps/web/content/blog/how-ai-builds-work.mdx +55 -0
- package/apps/web/content/blog/introducing-openship.mdx +46 -0
- package/apps/web/content/blog/self-hosting-cost-breakdown.mdx +59 -0
- package/apps/web/content/docs/_meta.json +14 -0
- package/apps/web/content/docs/api.mdx +98 -0
- package/apps/web/content/docs/cli.mdx +80 -0
- package/apps/web/content/docs/first-deployment.mdx +56 -0
- package/apps/web/content/docs/index.mdx +27 -0
- package/apps/web/content/docs/installation.mdx +65 -0
- package/apps/web/content/docs/quickstart.mdx +45 -0
- package/apps/web/next-env.d.ts +6 -0
- package/apps/web/next.config.mjs +16 -2
- package/apps/web/package.json +19 -12
- package/apps/web/postcss.config.mjs +5 -0
- package/apps/web/public/android-chrome-192x192.png +0 -0
- package/apps/web/public/android-chrome-512x512.png +0 -0
- package/apps/web/public/apple-touch-icon.png +0 -0
- package/apps/web/public/favicon-16x16.png +0 -0
- package/apps/web/public/favicon-32x32.png +0 -0
- package/apps/web/public/favicon.ico +0 -0
- package/apps/web/public/site.webmanifest +1 -0
- package/apps/web/source.config.ts +17 -0
- package/apps/web/src/app/(marketing)/layout.tsx +7 -22
- package/apps/web/src/app/blog/[...slug]/page.tsx +247 -0
- package/apps/web/src/app/blog/blog.css +575 -0
- package/apps/web/src/app/blog/layout.tsx +50 -0
- package/apps/web/src/app/blog/page.tsx +235 -0
- package/apps/web/src/app/docs/[[...slug]]/page.tsx +67 -0
- package/apps/web/src/app/docs/layout.tsx +62 -0
- package/apps/web/src/app/docs/toc-theme.css +71 -0
- package/apps/web/src/app/download/page.tsx +396 -0
- package/apps/web/src/app/globals.css +20 -3
- package/apps/web/src/app/layout.tsx +57 -3
- package/apps/web/src/app/page.tsx +47 -6
- package/apps/web/src/app/robots.ts +15 -0
- package/apps/web/src/app/sitemap.ts +35 -0
- package/apps/web/src/components/blog/share-sidebar.tsx +81 -0
- package/apps/web/src/components/blog/writer-sidebar.tsx +81 -0
- package/apps/web/src/components/landing/ai-native.tsx +169 -0
- package/apps/web/src/components/landing/backups.tsx +139 -0
- package/apps/web/src/components/landing/cdn.tsx +109 -0
- package/apps/web/src/components/landing/coming-soon.tsx +180 -0
- package/apps/web/src/components/landing/dark-section.tsx +166 -0
- package/apps/web/src/components/landing/dashboard.tsx +407 -0
- package/apps/web/src/components/landing/developer-experience.tsx +224 -0
- package/apps/web/src/components/landing/dns-domains.tsx +146 -0
- package/apps/web/src/components/landing/download-button.tsx +151 -0
- package/apps/web/src/components/landing/features/ai-visual.tsx +48 -0
- package/apps/web/src/components/landing/features/cloud-visual.tsx +44 -0
- package/apps/web/src/components/landing/features/git-visual.tsx +61 -0
- package/apps/web/src/components/landing/features/index.tsx +642 -0
- package/apps/web/src/components/landing/features/infra-visual.tsx +69 -0
- package/apps/web/src/components/landing/features/rollback-visual.tsx +42 -0
- package/apps/web/src/components/landing/features/ssl-visual.tsx +41 -0
- package/apps/web/src/components/landing/features/stacks-visual.tsx +54 -0
- package/apps/web/src/components/landing/final-cta.tsx +116 -0
- package/apps/web/src/components/landing/footer.tsx +145 -0
- package/apps/web/src/components/landing/hero.tsx +110 -0
- package/apps/web/src/components/landing/how-it-works.tsx +210 -0
- package/apps/web/src/components/landing/index.ts +21 -0
- package/apps/web/src/components/landing/mail-server.tsx +122 -0
- package/apps/web/src/components/landing/navbar.tsx +199 -0
- package/apps/web/src/components/landing/no-lockin.tsx +185 -0
- package/apps/web/src/components/landing/open-source-cta.tsx +151 -0
- package/apps/web/src/components/landing/portability.tsx +190 -0
- package/apps/web/src/components/landing/pricing.tsx +263 -0
- package/apps/web/src/components/landing/scaling.tsx +209 -0
- package/apps/web/src/components/landing/why-openship.tsx +291 -0
- package/apps/web/src/hooks/use-gsap-scroll.ts +158 -0
- package/apps/web/src/hooks/use-platform.ts +86 -0
- package/apps/web/src/lib/source.ts +12 -0
- package/apps/web/src/styles/fonts.css +84 -0
- package/apps/web/src/styles/landing.css +951 -0
- package/apps/web/src/styles/theme.css +227 -0
- package/apps/web/tsconfig.json +8 -3
- package/bun.lock +3260 -0
- package/docker-compose.yml +3 -0
- package/docs/screenshots/.gitkeep +0 -0
- package/docs/screenshots/screen.png +0 -0
- package/openship.code-workspace +7 -0
- package/package.json +23 -9
- package/packages/adapters/docs/ARCHITECTURE.md +160 -0
- package/packages/adapters/docs/BUILD-PIPELINE.md +171 -0
- package/packages/adapters/docs/CLOUD.md +239 -0
- package/packages/adapters/docs/EXECUTOR.md +174 -0
- package/packages/adapters/docs/LOG-STREAMING.md +175 -0
- package/packages/adapters/docs/SYSTEM.md +191 -0
- package/packages/adapters/package.json +14 -9
- package/packages/adapters/src/index.ts +144 -4
- package/packages/adapters/src/infra/cloud.ts +42 -0
- package/packages/adapters/src/infra/index.ts +9 -0
- package/packages/adapters/src/infra/noop.ts +27 -0
- package/packages/adapters/src/infra/traefik.ts +297 -0
- package/packages/adapters/src/infra/types.ts +36 -0
- package/packages/adapters/src/platform.ts +255 -0
- package/packages/adapters/src/runtime/bare.ts +567 -0
- package/packages/adapters/src/runtime/build-pipeline.ts +237 -0
- package/packages/adapters/src/runtime/cloud.ts +791 -0
- package/packages/adapters/src/runtime/deploy-pipeline.ts +146 -0
- package/packages/adapters/src/runtime/docker.ts +443 -0
- package/packages/adapters/src/runtime/index.ts +69 -0
- package/packages/adapters/src/runtime/local-build.ts +112 -0
- package/packages/adapters/src/runtime/transfer.ts +82 -0
- package/packages/adapters/src/runtime/types.ts +138 -0
- package/packages/adapters/src/system/catalog.ts +188 -0
- package/packages/adapters/src/system/checks.ts +228 -0
- package/packages/adapters/src/system/components.ts +45 -0
- package/packages/adapters/src/system/debug.ts +18 -0
- package/packages/adapters/src/system/environment.ts +168 -0
- package/packages/adapters/src/system/errors.ts +34 -0
- package/packages/adapters/src/system/executor.ts +600 -0
- package/packages/adapters/src/system/index.ts +58 -0
- package/packages/adapters/src/system/installer.ts +310 -0
- package/packages/adapters/src/system/setup.ts +442 -0
- package/packages/adapters/src/system/state.ts +96 -0
- package/packages/adapters/src/system/types.ts +116 -0
- package/packages/adapters/src/toolchain/catalog.ts +439 -0
- package/packages/adapters/src/toolchain/checks.ts +181 -0
- package/packages/adapters/src/toolchain/index.ts +38 -0
- package/packages/adapters/src/toolchain/installer.ts +189 -0
- package/packages/adapters/src/toolchain/types.ts +84 -0
- package/packages/adapters/src/types.ts +277 -0
- package/packages/adapters/tsconfig.json +3 -1
- package/packages/core/package.json +9 -9
- package/packages/core/src/constants.ts +44 -1
- package/packages/core/src/index.ts +2 -0
- package/packages/core/src/stacks.ts +778 -0
- package/packages/core/src/system.ts +111 -0
- package/packages/core/src/types.ts +22 -1
- package/packages/core/src/utils.ts +8 -0
- package/packages/core/tsconfig.json +3 -1
- package/packages/db/drizzle/0000_init.sql +231 -0
- package/packages/db/drizzle/0001_add_server_name.sql +1 -0
- package/packages/db/drizzle/meta/_journal.json +20 -0
- package/packages/db/drizzle.config.ts +10 -0
- package/packages/db/package.json +26 -14
- package/packages/db/src/client.ts +119 -0
- package/packages/db/src/index.ts +57 -8
- package/packages/db/src/repos/account.repo.ts +92 -0
- package/packages/db/src/repos/deployment.repo.ts +168 -0
- package/packages/db/src/repos/domain.repo.ts +102 -0
- package/packages/db/src/repos/git-installation.repo.ts +95 -0
- package/packages/db/src/repos/index.ts +43 -0
- package/packages/db/src/repos/instance-settings.repo.ts +43 -0
- package/packages/db/src/repos/project.repo.ts +159 -0
- package/packages/db/src/repos/session.repo.ts +82 -0
- package/packages/db/src/repos/settings.repo.ts +51 -0
- package/packages/db/src/repos/user.repo.ts +94 -0
- package/packages/db/src/schema/auth.ts +56 -0
- package/packages/db/src/schema/deployment.ts +87 -0
- package/packages/db/src/schema/domain.ts +46 -0
- package/packages/db/src/schema/github.ts +24 -0
- package/packages/db/src/schema/index.ts +6 -0
- package/packages/db/src/schema/project.ts +117 -0
- package/packages/db/src/schema/settings.ts +103 -0
- package/packages/db/tsconfig.json +3 -1
- package/packages/ui/package.json +17 -17
- package/packages/ui/src/components/status-dot.tsx +1 -1
- package/packages/ui/tsconfig.json +7 -2
- package/pnpm-workspace.yaml +0 -1
- package/{tooling/tsconfig/base.json → tsconfig.base.json} +0 -1
- package/turbo.json +4 -0
- package/apps/api/src/modules/auth/auth.controller.ts +0 -26
- package/apps/api/src/modules/auth/auth.schema.ts +0 -12
- package/apps/api/src/modules/auth/auth.service.ts +0 -23
- package/apps/dashboard/src/app/page.tsx +0 -6
- package/apps/web/src/app/(marketing)/docs/page.tsx +0 -10
- package/packages/adapters/src/base-adapter.ts +0 -49
- package/packages/adapters/src/docker-adapter.ts +0 -43
- package/packages/adapters/src/oblien-adapter.ts +0 -46
- package/packages/adapters/src/registry.ts +0 -22
- package/packages/db/prisma/schema.prisma +0 -160
- package/tooling/tsconfig/nextjs.json +0 -10
- package/tooling/tsconfig/node.json +0 -10
- package/tooling/tsconfig/package.json +0 -7
package/docker-compose.yml
CHANGED
|
@@ -50,9 +50,12 @@ services:
|
|
|
50
50
|
NODE_ENV: production
|
|
51
51
|
PORT: 4000
|
|
52
52
|
CLOUD_MODE: "false"
|
|
53
|
+
DEPLOY_MODE: docker
|
|
53
54
|
DATABASE_URL: postgresql://openship:openship@postgres:5432/openship
|
|
54
55
|
REDIS_URL: redis://redis:6379
|
|
55
56
|
JWT_SECRET: change-me-in-production
|
|
57
|
+
BETTER_AUTH_SECRET: change-me-in-production # used for session signing
|
|
58
|
+
TRUSTED_ORIGINS: http://localhost:3001,http://localhost:3000
|
|
56
59
|
depends_on:
|
|
57
60
|
- postgres
|
|
58
61
|
- redis
|
|
File without changes
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,31 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openship",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Open-source, self-hostable deployment platform",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "https://github.com/oblien/openship.git"
|
|
9
9
|
},
|
|
10
|
+
"workspaces": [
|
|
11
|
+
"apps/*",
|
|
12
|
+
"packages/*"
|
|
13
|
+
],
|
|
10
14
|
"scripts": {
|
|
11
15
|
"build": "turbo run build",
|
|
12
16
|
"dev": "turbo run dev",
|
|
17
|
+
"dev:api": "turbo run dev --filter=@repo/api...",
|
|
18
|
+
"dev:saas": "turbo run dev:saas --filter=@repo/api --filter=@repo/dashboard --concurrency=10",
|
|
19
|
+
"dev:dashboard": "turbo run dev --filter=@repo/dashboard",
|
|
20
|
+
"dev:desktop": "turbo run dev --filter=@repo/desktop",
|
|
21
|
+
"dev:web": "turbo run dev --filter=@repo/web",
|
|
22
|
+
"dev:all": "turbo run dev",
|
|
13
23
|
"lint": "turbo run lint",
|
|
14
24
|
"test": "turbo run test",
|
|
15
25
|
"format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"",
|
|
16
|
-
"db:generate": "turbo run db:generate --filter
|
|
17
|
-
"db:push": "turbo run db:push --filter
|
|
18
|
-
"db:migrate": "turbo run db:migrate --filter
|
|
26
|
+
"db:generate": "turbo run db:generate --filter=@repo/db",
|
|
27
|
+
"db:push": "turbo run db:push --filter=@repo/db",
|
|
28
|
+
"db:migrate": "turbo run db:migrate --filter=@repo/db",
|
|
19
29
|
"clean": "turbo run clean && rm -rf node_modules"
|
|
20
30
|
},
|
|
21
31
|
"devDependencies": {
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"typescript": "^5.4.0"
|
|
32
|
+
"prettier": "^3.8.1",
|
|
33
|
+
"turbo": "^2.8.14",
|
|
34
|
+
"typescript": "^5.9.3"
|
|
26
35
|
},
|
|
27
|
-
"packageManager": "
|
|
36
|
+
"packageManager": "bun@1.3.10",
|
|
28
37
|
"engines": {
|
|
29
38
|
"node": ">=20.0.0"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@octokit/auth-oauth-device": "^8.0.3",
|
|
42
|
+
"api": "^6.1.3",
|
|
43
|
+
"oblien": "^2.1.7"
|
|
30
44
|
}
|
|
31
45
|
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Platform Architecture
|
|
2
|
+
|
|
3
|
+
> `@repo/adapters` — the abstraction layer between Openship's API and the underlying infrastructure.
|
|
4
|
+
|
|
5
|
+
## Three Deployment Targets
|
|
6
|
+
|
|
7
|
+
The same codebase runs in three completely different environments. The `createPlatform()` factory resolves the correct combination at startup based on config.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌────────────────┬──────────────────────┬──────────────────────────┬─────────────────────┐
|
|
11
|
+
│ │ cloud (Oblien) │ selfhosted │ desktop │
|
|
12
|
+
├────────────────┼──────────────────────┼──────────────────────────┼─────────────────────┤
|
|
13
|
+
│ Runtime │ CloudRuntime │ DockerRuntime or │ BareRuntime │
|
|
14
|
+
│ │ (pure API calls) │ BareRuntime │ (local executor) │
|
|
15
|
+
├────────────────┼──────────────────────┼──────────────────────────┼─────────────────────┤
|
|
16
|
+
│ Routing │ CloudInfraProvider │ TraefikProvider │ NoopInfraProvider │
|
|
17
|
+
│ │ (pure API calls) │ (writes YAML via exec) │ (silent no-op) │
|
|
18
|
+
├────────────────┼──────────────────────┼──────────────────────────┼─────────────────────┤
|
|
19
|
+
│ SSL │ CloudInfraProvider │ TraefikProvider (ACME) │ NoopInfraProvider │
|
|
20
|
+
│ │ (pure API calls) │ (file ops via exec) │ (no-op) │
|
|
21
|
+
├────────────────┼──────────────────────┼──────────────────────────┼─────────────────────┤
|
|
22
|
+
│ System │ null │ SystemManager │ null │
|
|
23
|
+
│ │ (no RCE at all) │ (checks + installers) │ (no setup needed) │
|
|
24
|
+
├────────────────┼──────────────────────┼──────────────────────────┼─────────────────────┤
|
|
25
|
+
│ Executor │ null │ LocalExecutor or │ null │
|
|
26
|
+
│ │ (nothing executes) │ SshExecutor (shared) │ (BareRuntime owns) │
|
|
27
|
+
├────────────────┼──────────────────────┼──────────────────────────┼─────────────────────┤
|
|
28
|
+
│ ssh2 loaded? │ NO │ Only if SSH config set │ NO │
|
|
29
|
+
└────────────────┴──────────────────────┴──────────────────────────┴─────────────────────┘
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Three Layers
|
|
33
|
+
|
|
34
|
+
Each layer has a single responsibility. They are composed by the Platform, never used directly.
|
|
35
|
+
|
|
36
|
+
### 1. Runtime — build/deploy/stop lifecycle
|
|
37
|
+
|
|
38
|
+
| Class | Transport | Use Case |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| `DockerRuntime` | dockerode (socket / SSH / TLS) | Self-hosted with Docker |
|
|
41
|
+
| `BareRuntime` | `CommandExecutor` (local or SSH) | Self-hosted bare metal, desktop |
|
|
42
|
+
| `CloudRuntime` | HTTP API calls (Oblien SDK) | Oblien cloud |
|
|
43
|
+
|
|
44
|
+
- Docker has its **own** SSH transport via dockerode — separate from the shared executor
|
|
45
|
+
- Bare uses the **shared** executor for everything (git, npm, nohup, kill, PID files)
|
|
46
|
+
- Cloud makes **zero** local calls — pure API stubs
|
|
47
|
+
|
|
48
|
+
### 2. Infra — routing + SSL
|
|
49
|
+
|
|
50
|
+
| Class | Transport | Use Case |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| `TraefikProvider` | `CommandExecutor` (dual-path) | Self-hosted |
|
|
53
|
+
| `CloudInfraProvider` | HTTP API calls (Oblien SDK) | Oblien cloud |
|
|
54
|
+
| `NoopInfraProvider` | Nothing | Desktop / dev |
|
|
55
|
+
|
|
56
|
+
- Traefik writes YAML config files to a watched directory via the executor
|
|
57
|
+
- SSL is Traefik's built-in ACME resolver — cert info read via the executor
|
|
58
|
+
- The executor enables Traefik config to be written on the local machine OR a remote server via SSH
|
|
59
|
+
|
|
60
|
+
### 3. System — prerequisite checks + server setup
|
|
61
|
+
|
|
62
|
+
| Class | Transport | Use Case |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| `SystemManager` | `CommandExecutor` | Self-hosted only |
|
|
65
|
+
| _null_ | — | Cloud and Desktop (no setup needed) |
|
|
66
|
+
|
|
67
|
+
- Checks: docker, traefik, git, node, bun — all via executor
|
|
68
|
+
- Installers: automated install scripts with real-time log streaming
|
|
69
|
+
- State: cached in `SetupStateStore` (file or DB), 24h auto-reverification
|
|
70
|
+
- Feature gating: `requireFeature("deploy")` reads cached state (free on hot paths)
|
|
71
|
+
|
|
72
|
+
## File Map
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
src/
|
|
76
|
+
├── types.ts # Shared types: configs, CommandExecutor, SshConfig
|
|
77
|
+
├── platform.ts # Factory + singleton (createPlatform, getPlatform)
|
|
78
|
+
├── index.ts # Barrel exports
|
|
79
|
+
│
|
|
80
|
+
├── runtime/
|
|
81
|
+
│ ├── types.ts # RuntimeAdapter interface, RuntimeCapability
|
|
82
|
+
│ ├── docker.ts # DockerRuntime (dockerode)
|
|
83
|
+
│ ├── bare.ts # BareRuntime (executor-based)
|
|
84
|
+
│ ├── cloud.ts # CloudRuntime (API stubs)
|
|
85
|
+
│ └── index.ts # Factory + re-exports
|
|
86
|
+
│
|
|
87
|
+
├── infra/
|
|
88
|
+
│ ├── types.ts # RoutingProvider, SslProvider interfaces
|
|
89
|
+
│ ├── traefik.ts # Traefik file provider (dual-path via executor)
|
|
90
|
+
│ ├── cloud.ts # Cloud infra (API stubs)
|
|
91
|
+
│ └── noop.ts # No-op (desktop/dev)
|
|
92
|
+
│
|
|
93
|
+
└── system/
|
|
94
|
+
├── types.ts # SystemLog, ComponentStatus, InstallerConfig, etc.
|
|
95
|
+
├── executor.ts # LocalExecutor, SshExecutor, createExecutor()
|
|
96
|
+
├── state.ts # SetupStateStore interface, FileStateStore
|
|
97
|
+
├── checks.ts # Component health checks (all via executor)
|
|
98
|
+
├── installer.ts # Component installers (all via executor)
|
|
99
|
+
├── setup.ts # SystemManager orchestrator
|
|
100
|
+
└── index.ts # Barrel exports
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## How It's Wired
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
107
|
+
│ API (apps/api) │
|
|
108
|
+
│ │
|
|
109
|
+
│ app.ts: bootstrapPlatform() │
|
|
110
|
+
│ │ │
|
|
111
|
+
│ ▼ │
|
|
112
|
+
│ controller-helpers.ts: resolveConfig() → initPlatform() │
|
|
113
|
+
│ platform() → getPlatform() │
|
|
114
|
+
│ │
|
|
115
|
+
│ service code: const { runtime, routing, ssl } = platform() │
|
|
116
|
+
│ await runtime.build(config, onLog) │
|
|
117
|
+
│ await routing.registerRoute({ domain, ... }) │
|
|
118
|
+
│ await ssl.provisionCert(domain) │
|
|
119
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
120
|
+
│
|
|
121
|
+
▼
|
|
122
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
123
|
+
│ @repo/adapters │
|
|
124
|
+
│ │
|
|
125
|
+
│ createPlatform(config) ─┬─ "cloud" → CloudRuntime │
|
|
126
|
+
│ │ + CloudInfraProvider │
|
|
127
|
+
│ │ + system: null │
|
|
128
|
+
│ │ + executor: null │
|
|
129
|
+
│ │ │
|
|
130
|
+
│ ├─ "selfhosted" → Docker/BareRuntime │
|
|
131
|
+
│ │ + TraefikProvider │
|
|
132
|
+
│ │ + SystemManager │
|
|
133
|
+
│ │ + executor ─┐ │
|
|
134
|
+
│ │ │ │
|
|
135
|
+
│ │ ┌───────────────────────┘ │
|
|
136
|
+
│ │ │ shared across: │
|
|
137
|
+
│ │ │ • BareRuntime (if bare mode) │
|
|
138
|
+
│ │ │ • TraefikProvider │
|
|
139
|
+
│ │ │ • SystemManager │
|
|
140
|
+
│ │ │ • checks.ts + installer.ts │
|
|
141
|
+
│ │ │
|
|
142
|
+
│ └─ "desktop" → BareRuntime (own) │
|
|
143
|
+
│ + NoopInfraProvider │
|
|
144
|
+
│ + system: null │
|
|
145
|
+
│ + executor: null │
|
|
146
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Environment Variables
|
|
150
|
+
|
|
151
|
+
| Variable | Values | Effect |
|
|
152
|
+
|---|---|---|
|
|
153
|
+
| `CLOUD_MODE` | `true` / `false` | Force cloud target (overrides DEPLOY_MODE) |
|
|
154
|
+
| `DEPLOY_MODE` | `docker` / `bare` / `cloud` / `desktop` | Select runtime + target |
|
|
155
|
+
|
|
156
|
+
Resolution priority in `resolveConfig()`:
|
|
157
|
+
1. `CLOUD_MODE=true` or `DEPLOY_MODE=cloud` → `target: "cloud"`
|
|
158
|
+
2. `DEPLOY_MODE=desktop` → `target: "desktop"`
|
|
159
|
+
3. Everything else → `target: "selfhosted"` + `runtime: DEPLOY_MODE`
|
|
160
|
+
4. Default (nothing set) → `target: "selfhosted"`, `runtime: "docker"`
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Build Pipeline & Process Management
|
|
2
|
+
|
|
3
|
+
> How builds run, how processes are tracked, and how cleanup works across all runtimes.
|
|
4
|
+
|
|
5
|
+
## Build Flow
|
|
6
|
+
|
|
7
|
+
All three runtimes implement `build()` but with completely different transports:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
build.service.ts
|
|
11
|
+
│
|
|
12
|
+
│ Creates BuildLogger (single source of truth for all log emission)
|
|
13
|
+
│ Creates logCallback → pushes to logs[] + SSE broadcast
|
|
14
|
+
│
|
|
15
|
+
▼
|
|
16
|
+
runtime.build(config, logger)
|
|
17
|
+
│
|
|
18
|
+
├─ CloudRuntime → Oblien API: workspace.build() + execAndStream()
|
|
19
|
+
├─ BareRuntime → executor.streamExec() through runBuildPipeline()
|
|
20
|
+
└─ DockerRuntime → (stub — Docker builds via Dockerfile)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## BuildLogger — Single Source of Truth
|
|
24
|
+
|
|
25
|
+
Every log emission goes through `BuildLogger`. No adapter creates `LogEntry` objects with step metadata directly.
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
class BuildLogger {
|
|
29
|
+
log(message: string, level?) // Plain log line
|
|
30
|
+
step(step, status, message) // Step lifecycle event (stepper UI)
|
|
31
|
+
runStep(step, label, fn) // Run a step: emit running → execute → completed/failed
|
|
32
|
+
get callback(): LogCallback // Pass to exec functions for raw output streaming
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Who calls what
|
|
37
|
+
|
|
38
|
+
| Caller | Method | Purpose |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| `runBuildPipeline()` | `logger.runStep("clone", ...)` | Step events for clone/install/build |
|
|
41
|
+
| `runBuildPipeline()` | `logger.log(...)` | Pipeline status messages |
|
|
42
|
+
| `build.service.ts` | `logger.step("deploy", ...)` | Deploy phase step events |
|
|
43
|
+
| `build.service.ts` | `logger.log(...)` | Deploy status messages |
|
|
44
|
+
| `executor.streamExec()` | `logger.callback` (raw `LogCallback`) | stdout/stderr lines from shell commands |
|
|
45
|
+
| `cloud.ts execAndStream()` | raw `LogCallback` | Oblien exec output chunks |
|
|
46
|
+
|
|
47
|
+
## Shared Build Pipeline
|
|
48
|
+
|
|
49
|
+
`runBuildPipeline()` is used by `BareRuntime` and would be used by `DockerRuntime` when it supports builds. `CloudRuntime` has its own build flow via the Oblien API.
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
runBuildPipeline(env, config, logger)
|
|
53
|
+
│
|
|
54
|
+
├─ Step: clone
|
|
55
|
+
│ env.exec(`git clone --branch ${branch} --depth 1 ${repo} .`, logger.callback)
|
|
56
|
+
│
|
|
57
|
+
├─ Step: install
|
|
58
|
+
│ env.exec(`npm install` / `yarn` / `pnpm install`, logger.callback)
|
|
59
|
+
│
|
|
60
|
+
├─ Step: build (if buildCommand configured)
|
|
61
|
+
│ env.exec(buildCommand, logger.callback)
|
|
62
|
+
│
|
|
63
|
+
└─ Returns { status: "deploying" | "failed", durationMs }
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The `BuildEnvironment` abstraction decouples the pipeline from the executor:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
interface BuildEnvironment {
|
|
70
|
+
projectDir: string;
|
|
71
|
+
exec(command: string, onLog: LogCallback): Promise<void>;
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
BareRuntime wires it to `this.executor.streamExec()`. A future Docker build could wire it to `docker exec`.
|
|
76
|
+
|
|
77
|
+
## Process Management (Bare Runtime)
|
|
78
|
+
|
|
79
|
+
### Deploy — setsid for proper process groups
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
deploy(config)
|
|
83
|
+
│
|
|
84
|
+
│ setsid nohup npm start >> logfile 2>&1 &
|
|
85
|
+
│ echo $!
|
|
86
|
+
│ │
|
|
87
|
+
│ └─ PID captured → written to .pids/{deploymentId}.pid
|
|
88
|
+
│
|
|
89
|
+
└─ setsid makes npm the process group leader
|
|
90
|
+
so all child processes belong to the same PGID
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Stop — kill the entire tree
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
stop(containerId)
|
|
97
|
+
│
|
|
98
|
+
│ 1. Read PID from .pids/{containerId}.pid
|
|
99
|
+
│ 2. kill -- -${pid} ← SIGTERM the entire process group
|
|
100
|
+
│ (fallback: kill ${pid} if group kill not supported)
|
|
101
|
+
│ 3. Wait up to 10s for graceful shutdown
|
|
102
|
+
│ 4. kill -9 -- -${pid} ← SIGKILL the group if still alive
|
|
103
|
+
│
|
|
104
|
+
└─ This ensures child processes (e.g., node spawned by npm)
|
|
105
|
+
are cleaned up too — no orphans
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### PID Tracking
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
${workDir}/
|
|
112
|
+
.pids/
|
|
113
|
+
{deploymentId}.pid ← contains the PID as plain text
|
|
114
|
+
.logs/
|
|
115
|
+
{deploymentId}.log ← stdout + stderr from the process
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
All PID operations go through the executor:
|
|
119
|
+
- `readPid()` → `executor.readFile(pidFile)`
|
|
120
|
+
- `writePid()` → `executor.writeFile(pidFile, pid)`
|
|
121
|
+
- `isAlive()` → `executor.exec("kill -0 ${pid}")`
|
|
122
|
+
|
|
123
|
+
This means PID management works identically on local and remote (SSH) servers.
|
|
124
|
+
|
|
125
|
+
### Build Cancellation
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
cancelBuild(sessionId)
|
|
129
|
+
│
|
|
130
|
+
│ Read PID from .pids/build-{sessionId}.pid
|
|
131
|
+
│ kill -- -${pid} ← kill entire build process group
|
|
132
|
+
│
|
|
133
|
+
└─ Kills git clone, npm install, or whatever is running
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Resource Configuration
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
interface ResourceConfig {
|
|
140
|
+
cpuCores: number; // Fractional cores (e.g., 0.5, 1, 2)
|
|
141
|
+
memoryMb: number; // Memory in megabytes
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Defaults
|
|
145
|
+
DEFAULT_RESOURCE_CONFIG = { cpuCores: 0.5, memoryMb: 512 } // runtime
|
|
146
|
+
DEFAULT_BUILD_RESOURCE_CONFIG = { cpuCores: 2, memoryMb: 4096 } // build
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
- Cloud: `cpuCores` passed directly to Oblien SDK (fractional, e.g., 0.5)
|
|
150
|
+
- Docker: used for container resource limits
|
|
151
|
+
- Bare: informational only (OS manages resources)
|
|
152
|
+
|
|
153
|
+
## Error Handling
|
|
154
|
+
|
|
155
|
+
Build failures cascade cleanly:
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
Pipeline step fails (e.g., npm install exits non-zero)
|
|
159
|
+
│
|
|
160
|
+
├─ executor.streamExec returns { code: non-zero }
|
|
161
|
+
├─ BuildEnvironment.exec throws Error
|
|
162
|
+
├─ runBuildPipeline catches → logger.step(step, "failed", message)
|
|
163
|
+
├─ Returns { status: "failed" }
|
|
164
|
+
│
|
|
165
|
+
▼
|
|
166
|
+
build.service.ts
|
|
167
|
+
├─ Updates deployment status to "failed"
|
|
168
|
+
├─ Persists logs to DB via finishBuildSession()
|
|
169
|
+
├─ Broadcasts failure via SSE
|
|
170
|
+
└─ Sends failure notification email
|
|
171
|
+
```
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# Cloud Architecture
|
|
2
|
+
|
|
3
|
+
> How Openship connects to Oblien cloud infrastructure — same pipeline, two auth paths.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Openship runs in two modes. Both use the **exact same** `CloudRuntime` and build/deploy pipeline. The only difference is how the Oblien SDK client gets authenticated:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────────────────────────────────────────────────────────────┐
|
|
11
|
+
│ CloudRuntime(client) │
|
|
12
|
+
│ │
|
|
13
|
+
│ build() → provisionBuildWorkspace → runBuildPipeline → deploy() │
|
|
14
|
+
│ stop() / start() / restart() / destroy() │
|
|
15
|
+
│ logs / metrics / domain management │
|
|
16
|
+
│ │
|
|
17
|
+
│ Doesn't know or care HOW the Oblien client was authenticated. │
|
|
18
|
+
└────────────────────────────┬────────────────────────────────────────────┘
|
|
19
|
+
│
|
|
20
|
+
┌──────────────┴──────────────┐
|
|
21
|
+
│ │
|
|
22
|
+
┌──────────▼──────────┐ ┌───────────▼───────────┐
|
|
23
|
+
│ SaaS (CLOUD_MODE) │ │ Local (!CLOUD_MODE) │
|
|
24
|
+
│ │ │ │
|
|
25
|
+
│ Master credentials │ │ Namespace token │
|
|
26
|
+
│ clientId + secret │ │ from stored session │
|
|
27
|
+
│ │ │ │
|
|
28
|
+
│ new Oblien({ │ │ new Oblien({ │
|
|
29
|
+
│ clientId, │ │ token │
|
|
30
|
+
│ clientSecret │ │ }) │
|
|
31
|
+
│ }) │ │ │
|
|
32
|
+
│ │ │ Scoped to user's │
|
|
33
|
+
│ Full platform │ │ namespace (os-{uid}) │
|
|
34
|
+
│ access │ │ 30min TTL │
|
|
35
|
+
└─────────────────────┘ └────────────────────────┘
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Mode 1: SaaS (`CLOUD_MODE=true`)
|
|
39
|
+
|
|
40
|
+
When Openship runs as the hosted SaaS platform (api.openship.io):
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
Server startup
|
|
44
|
+
→ initPlatform({ target: "cloud", cloudClientId, cloudClientSecret })
|
|
45
|
+
→ new Oblien({ clientId, clientSecret }) ← master creds from env
|
|
46
|
+
→ CloudRuntime(client) ← singleton, stays for process lifetime
|
|
47
|
+
→ build.service.ts uses platform().runtime directly
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The SaaS also exposes a token endpoint for local instances:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
POST /api/cloud/token (requires auth)
|
|
54
|
+
→ ensureNamespace(userId) ← creates os-{userId} namespace if needed
|
|
55
|
+
→ client.tokens.create({ scope: "namespace", namespace, ttl: 1800 })
|
|
56
|
+
→ { token, namespace, expiresAt }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Key files
|
|
60
|
+
|
|
61
|
+
| File | Purpose |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `apps/api/src/lib/openship-cloud.ts` | `ensureNamespace()` + `issueNamespaceToken()` |
|
|
64
|
+
| `apps/api/src/modules/cloud/cloud.controller.ts` | `getToken()` handler |
|
|
65
|
+
| `apps/api/src/modules/cloud/cloud.routes.ts` | `cloudSaasRoutes` → `POST /token` |
|
|
66
|
+
|
|
67
|
+
## Mode 2: Local (`CLOUD_MODE=false`)
|
|
68
|
+
|
|
69
|
+
When Openship runs locally (desktop app, self-hosted, CLI):
|
|
70
|
+
|
|
71
|
+
### Step 1: User connects their Openship Cloud account
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
Dashboard Settings page
|
|
75
|
+
→ user enters email + password
|
|
76
|
+
→ POST /api/cloud/connect
|
|
77
|
+
→ Local API proxies login to api.openship.io/api/auth/sign-in/email
|
|
78
|
+
→ Receives session token
|
|
79
|
+
→ Encrypts + stores in user_settings.cloud_session_token
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Step 2: Deploy to cloud
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
build.service.ts → executeBuildAndDeploy()
|
|
86
|
+
→ detects !CLOUD_MODE && target === "cloud"
|
|
87
|
+
→ getCloudToken(userId)
|
|
88
|
+
→ reads encrypted session from DB
|
|
89
|
+
→ POST api.openship.io/api/cloud/token (with Bearer session)
|
|
90
|
+
→ receives namespace-scoped Oblien token (cached in memory, 30min TTL)
|
|
91
|
+
→ createPlatform({ target: "cloud", cloudToken: result.token })
|
|
92
|
+
→ new Oblien({ token }) ← namespace-scoped
|
|
93
|
+
→ CloudRuntime(client) ← per-deploy instance
|
|
94
|
+
→ same build() → same deploy() → same everything
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Key files
|
|
98
|
+
|
|
99
|
+
| File | Purpose |
|
|
100
|
+
|---|---|
|
|
101
|
+
| `apps/api/src/lib/cloud-client.ts` | `connectCloud()`, `disconnectCloud()`, `isCloudConnected()`, `getCloudToken()` |
|
|
102
|
+
| `apps/api/src/modules/cloud/cloud.controller.ts` | `connect()`, `disconnect()`, `status()` handlers |
|
|
103
|
+
| `apps/api/src/modules/cloud/cloud.routes.ts` | `cloudLocalRoutes` → `POST /connect`, `POST /disconnect`, `GET /status` |
|
|
104
|
+
| `apps/dashboard/src/app/(dashboard)/settings/page.tsx` | Cloud connection UI |
|
|
105
|
+
| `apps/dashboard/src/lib/api/cloud.ts` | `cloudApi` client-side helpers |
|
|
106
|
+
|
|
107
|
+
## Auth Flow Diagram
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
LOCAL MODE — full round trip:
|
|
111
|
+
|
|
112
|
+
┌──────────────┐ POST /api/cloud/connect
|
|
113
|
+
│ Dashboard │ ──────────────────────────────▶ ┌──────────────┐
|
|
114
|
+
│ Settings │ { email, password } │ Local API │
|
|
115
|
+
│ │ │ │
|
|
116
|
+
│ │ { connected: true } │ cloud │
|
|
117
|
+
│ │ ◀────────────────────────────────│ controller │
|
|
118
|
+
└──────────────┘ └──────┬───────┘
|
|
119
|
+
│
|
|
120
|
+
POST /api/auth/sign-in │
|
|
121
|
+
{ email, password } │
|
|
122
|
+
▼
|
|
123
|
+
┌──────────────┐
|
|
124
|
+
│ Openship │
|
|
125
|
+
│ Cloud SaaS │
|
|
126
|
+
│ │
|
|
127
|
+
│ Returns │
|
|
128
|
+
│ session token│
|
|
129
|
+
└──────────────┘
|
|
130
|
+
│
|
|
131
|
+
encrypt(token) │
|
|
132
|
+
store in DB │
|
|
133
|
+
▼
|
|
134
|
+
┌──────────────┐
|
|
135
|
+
│ user_settings│
|
|
136
|
+
│ cloud_session│
|
|
137
|
+
│ _token (enc) │
|
|
138
|
+
└──────────────┘
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
DEPLOY TIME:
|
|
142
|
+
|
|
143
|
+
┌──────────────┐ ┌──────────────┐
|
|
144
|
+
│ build.service│ ── getCloudToken(userId) ──────▶ │ cloud-client │
|
|
145
|
+
│ │ │ │
|
|
146
|
+
│ │ │ 1. read DB │
|
|
147
|
+
│ │ │ 2. decrypt │
|
|
148
|
+
│ │ { token, namespace } │ 3. POST /api │
|
|
149
|
+
│ │ ◀────────────────────────────────│ /cloud │
|
|
150
|
+
└──────┬───────┘ │ /token │
|
|
151
|
+
│ └──────┬───────┘
|
|
152
|
+
│ createPlatform({ │
|
|
153
|
+
│ target: "cloud", ▼
|
|
154
|
+
│ cloudToken: token ┌──────────────────────────┐
|
|
155
|
+
│ }) │ Openship Cloud SaaS │
|
|
156
|
+
│ │ │
|
|
157
|
+
▼ │ ensureNamespace(userId) │
|
|
158
|
+
┌──────────────┐ │ issueNamespaceToken() │
|
|
159
|
+
│ CloudRuntime │ │ │
|
|
160
|
+
│ │ │ Returns Oblien namespace │
|
|
161
|
+
│ new Oblien({ │ │ token (30min TTL) │
|
|
162
|
+
│ token │ └──────────────────────────┘
|
|
163
|
+
│ }) │
|
|
164
|
+
│ │
|
|
165
|
+
│ build() │──────▶ Oblien API (workspaces, runtime, deploy...)
|
|
166
|
+
│ deploy() │
|
|
167
|
+
└──────────────┘
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Namespace Model
|
|
171
|
+
|
|
172
|
+
Each user gets an isolated Oblien namespace:
|
|
173
|
+
|
|
174
|
+
- **Slug**: `os-{userId}`
|
|
175
|
+
- **Creation**: Idempotent — 409 on duplicate is caught, existing namespace fetched
|
|
176
|
+
- **Cached**: In-memory `Map<userId, slug>` on SaaS server
|
|
177
|
+
|
|
178
|
+
The namespace token gives full access to everything in that namespace:
|
|
179
|
+
- Create/manage workspaces
|
|
180
|
+
- Build & deploy
|
|
181
|
+
- Domain management
|
|
182
|
+
- Logs & metrics
|
|
183
|
+
|
|
184
|
+
## Security
|
|
185
|
+
|
|
186
|
+
| Concern | Approach |
|
|
187
|
+
|---|---|
|
|
188
|
+
| Cloud session at rest | AES-256 encrypted via `encrypt()`/`decrypt()` in `encryption.ts` |
|
|
189
|
+
| Session in transit | HTTPS only (api.openship.io) |
|
|
190
|
+
| Expired sessions | Auto-cleared on 401 from SaaS API |
|
|
191
|
+
| Namespace tokens | 30min TTL, 5min refresh buffer, in-memory cache only |
|
|
192
|
+
| Token scope | Namespace-scoped — user can only access their own resources |
|
|
193
|
+
| No browser cookies | Session lives server-side in DB, never exposed to dashboard |
|
|
194
|
+
|
|
195
|
+
## API Endpoints
|
|
196
|
+
|
|
197
|
+
### SaaS routes (`CLOUD_MODE=true`, mounted at `/api/cloud`)
|
|
198
|
+
|
|
199
|
+
| Method | Path | Handler | Purpose |
|
|
200
|
+
|---|---|---|---|
|
|
201
|
+
| POST | `/token` | `getToken` | Mint namespace-scoped Oblien token |
|
|
202
|
+
|
|
203
|
+
### Local routes (`CLOUD_MODE=false`, mounted at `/api/cloud`)
|
|
204
|
+
|
|
205
|
+
| Method | Path | Handler | Purpose |
|
|
206
|
+
|---|---|---|---|
|
|
207
|
+
| POST | `/connect` | `connect` | Proxy login → store encrypted session |
|
|
208
|
+
| POST | `/disconnect` | `disconnect` | Clear stored session |
|
|
209
|
+
| GET | `/status` | `status` | Check connection state |
|
|
210
|
+
|
|
211
|
+
### Dashboard API (`apps/dashboard/src/lib/api/cloud.ts`)
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
cloudApi.connect(email, password) // POST /api/cloud/connect
|
|
215
|
+
cloudApi.disconnect() // POST /api/cloud/disconnect
|
|
216
|
+
cloudApi.status() // GET /api/cloud/status
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Route Mounting (`app.ts`)
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
if (env.CLOUD_MODE) {
|
|
223
|
+
// SaaS: mint tokens for local instances
|
|
224
|
+
app.route("/api/cloud", cloudSaasRoutes);
|
|
225
|
+
} else {
|
|
226
|
+
// Local: manage connection to Openship Cloud
|
|
227
|
+
app.route("/api/cloud", cloudLocalRoutes);
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Dynamic imports ensure zero code bleed between modes.
|
|
232
|
+
|
|
233
|
+
## Database
|
|
234
|
+
|
|
235
|
+
| Table | Column | Type | Purpose |
|
|
236
|
+
|---|---|---|---|
|
|
237
|
+
| `user_settings` | `cloud_session_token` | `text` (nullable) | Encrypted Openship Cloud session |
|
|
238
|
+
|
|
239
|
+
Migration: `packages/db/drizzle/0004_add_cloud_session_token.sql`
|