devpush 0.0.0-stage → 1.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (456) hide show
  1. package/README.md +6 -2
  2. package/agent-release.json +37 -0
  3. package/dist/package/LICENSE.md +21 -0
  4. package/dist/package/migrate.mjs +182 -0
  5. package/dist/package/plugins.mjs +125 -0
  6. package/dist/package/vite.mjs +439 -0
  7. package/package.json +170 -4
  8. package/public/apple-touch-icon.png +0 -0
  9. package/public/favicon.svg +1 -0
  10. package/public/logo-email.png +0 -0
  11. package/public/robots.txt +3 -0
  12. package/public/social.png +0 -0
  13. package/src/cloudflare-runtime.d.ts +78 -0
  14. package/src/components/about-dialog.tsx +70 -0
  15. package/src/components/copy-button.tsx +74 -0
  16. package/src/components/logo-mark.tsx +20 -0
  17. package/src/components/pending-collection.tsx +103 -0
  18. package/src/components/resource-avatar.tsx +65 -0
  19. package/src/components/route-error-state.tsx +95 -0
  20. package/src/components/section-navigation.tsx +39 -0
  21. package/src/components/settings-layout.tsx +111 -0
  22. package/src/components/storage-capabilities.tsx +11 -0
  23. package/src/components/table-pager.tsx +101 -0
  24. package/src/components/ui/alert-dialog.tsx +180 -0
  25. package/src/components/ui/alert.tsx +78 -0
  26. package/src/components/ui/avatar.tsx +58 -0
  27. package/src/components/ui/badge.tsx +49 -0
  28. package/src/components/ui/button-group.tsx +38 -0
  29. package/src/components/ui/button.tsx +67 -0
  30. package/src/components/ui/card.tsx +82 -0
  31. package/src/components/ui/chart.tsx +307 -0
  32. package/src/components/ui/checkbox.tsx +30 -0
  33. package/src/components/ui/combobox.tsx +256 -0
  34. package/src/components/ui/dialog.tsx +163 -0
  35. package/src/components/ui/dropdown-menu.tsx +110 -0
  36. package/src/components/ui/empty.tsx +65 -0
  37. package/src/components/ui/field.tsx +192 -0
  38. package/src/components/ui/input-group.tsx +118 -0
  39. package/src/components/ui/input-otp.tsx +70 -0
  40. package/src/components/ui/input.tsx +19 -0
  41. package/src/components/ui/label.tsx +24 -0
  42. package/src/components/ui/pagination.tsx +34 -0
  43. package/src/components/ui/popover.tsx +86 -0
  44. package/src/components/ui/select.tsx +145 -0
  45. package/src/components/ui/skeleton.tsx +19 -0
  46. package/src/components/ui/sonner.tsx +47 -0
  47. package/src/components/ui/switch.tsx +31 -0
  48. package/src/components/ui/table.tsx +81 -0
  49. package/src/components/ui/textarea.tsx +18 -0
  50. package/src/components/ui/tooltip.tsx +55 -0
  51. package/src/features/admin/admin-settings.tsx +1048 -0
  52. package/src/features/auth/current-user-context-query.ts +11 -0
  53. package/src/features/auth/login-form.tsx +442 -0
  54. package/src/features/auth/sign-out-menu-item.tsx +42 -0
  55. package/src/features/deployments/deployment-actions.tsx +336 -0
  56. package/src/features/deployments/deployment-alias-badge.tsx +35 -0
  57. package/src/features/deployments/deployment-detail.tsx +596 -0
  58. package/src/features/deployments/deployment-filters.ts +66 -0
  59. package/src/features/deployments/deployment-list.tsx +465 -0
  60. package/src/features/deployments/deployment-visit-links.tsx +104 -0
  61. package/src/features/deployments/deployments-page.tsx +376 -0
  62. package/src/features/logs/log-scroll-area.tsx +69 -0
  63. package/src/features/notifications/email-preferences.tsx +232 -0
  64. package/src/features/onboarding/profile-onboarding.tsx +162 -0
  65. package/src/features/plugins/contributions.tsx +118 -0
  66. package/src/features/projects/backup-job-logs.tsx +143 -0
  67. package/src/features/projects/backup-policy-delete-dialog.tsx +82 -0
  68. package/src/features/projects/backup-restore-actions.tsx +573 -0
  69. package/src/features/projects/backup-status-icon.tsx +33 -0
  70. package/src/features/projects/backup-target-list.tsx +222 -0
  71. package/src/features/projects/backup-timestamp.tsx +32 -0
  72. package/src/features/projects/backup-volume-picker.tsx +158 -0
  73. package/src/features/projects/compose-service-input.tsx +64 -0
  74. package/src/features/projects/deploy-readiness.ts +28 -0
  75. package/src/features/projects/environment-dot.tsx +91 -0
  76. package/src/features/projects/log-keyword-filter.tsx +48 -0
  77. package/src/features/projects/manual-deploy-dialog.tsx +563 -0
  78. package/src/features/projects/pending-section.ts +26 -0
  79. package/src/features/projects/project-backup-details-pending.tsx +305 -0
  80. package/src/features/projects/project-backup-details.tsx +936 -0
  81. package/src/features/projects/project-backup-policy.tsx +644 -0
  82. package/src/features/projects/project-backup-utils.ts +190 -0
  83. package/src/features/projects/project-backups-pending.tsx +136 -0
  84. package/src/features/projects/project-backups.tsx +876 -0
  85. package/src/features/projects/project-environment-settings.tsx +1128 -0
  86. package/src/features/projects/project-heading.tsx +68 -0
  87. package/src/features/projects/project-layout.tsx +188 -0
  88. package/src/features/projects/project-logs.tsx +461 -0
  89. package/src/features/projects/project-overview.tsx +280 -0
  90. package/src/features/projects/project-route-pending.tsx +1064 -0
  91. package/src/features/projects/project-routing-settings.tsx +663 -0
  92. package/src/features/projects/project-settings-section.tsx +64 -0
  93. package/src/features/projects/project-settings-utils.ts +101 -0
  94. package/src/features/projects/project-settings.tsx +1472 -0
  95. package/src/features/projects/repository-picker-dialog.tsx +404 -0
  96. package/src/features/repositories/new-project-dialog-launcher.tsx +44 -0
  97. package/src/features/repositories/new-project-dialog.tsx +1204 -0
  98. package/src/features/repositories/new-project-pending.tsx +28 -0
  99. package/src/features/repositories/repository-list-pending.tsx +59 -0
  100. package/src/features/servers/server-availability-alert.tsx +44 -0
  101. package/src/features/servers/server-availability.ts +29 -0
  102. package/src/features/servers/server-avatar.tsx +52 -0
  103. package/src/features/servers/server-detail-pending.tsx +315 -0
  104. package/src/features/servers/server-detail.tsx +855 -0
  105. package/src/features/servers/server-metric-chart-pending.tsx +38 -0
  106. package/src/features/servers/server-metric-chart.tsx +182 -0
  107. package/src/features/servers/server-metric-format.ts +50 -0
  108. package/src/features/servers/server-metrics-pending.tsx +75 -0
  109. package/src/features/servers/server-metrics.tsx +136 -0
  110. package/src/features/servers/team-servers.tsx +432 -0
  111. package/src/features/settings/settings-route-pending.tsx +406 -0
  112. package/src/features/teams/backup-storage-settings.tsx +483 -0
  113. package/src/features/teams/navigation.ts +51 -0
  114. package/src/features/teams/new-team-dialog.tsx +132 -0
  115. package/src/features/teams/pending-section.ts +19 -0
  116. package/src/features/teams/team-header.tsx +1286 -0
  117. package/src/features/teams/team-heading.tsx +57 -0
  118. package/src/features/teams/team-home.tsx +391 -0
  119. package/src/features/teams/team-invite.tsx +155 -0
  120. package/src/features/teams/team-route-pending.tsx +505 -0
  121. package/src/features/teams/team-settings.tsx +1555 -0
  122. package/src/features/teams/use-workspace-updates.ts +126 -0
  123. package/src/features/users/api-keys-settings.tsx +544 -0
  124. package/src/features/users/api-scope-selection.tsx +269 -0
  125. package/src/features/users/connected-apps-settings.tsx +449 -0
  126. package/src/features/users/mcp-consent.tsx +220 -0
  127. package/src/features/users/profile-picture.tsx +171 -0
  128. package/src/features/users/user-settings.tsx +1064 -0
  129. package/src/lib/account-settings-schema.ts +78 -0
  130. package/src/lib/action-feedback.ts +81 -0
  131. package/src/lib/admin-search-schema.ts +8 -0
  132. package/src/lib/agent-release.d.mts +21 -0
  133. package/src/lib/agent-release.mjs +90 -0
  134. package/src/lib/allowlist-schema.ts +79 -0
  135. package/src/lib/api-key-schema.ts +176 -0
  136. package/src/lib/auth/client.ts +20 -0
  137. package/src/lib/avatar-schema.ts +11 -0
  138. package/src/lib/backup-cron.ts +118 -0
  139. package/src/lib/backup-database.ts +41 -0
  140. package/src/lib/backup-feature.ts +2 -0
  141. package/src/lib/backup-paths.ts +7 -0
  142. package/src/lib/backup-policy-schema.ts +85 -0
  143. package/src/lib/backup-resource-schema.ts +12 -0
  144. package/src/lib/backup-restore-schema.ts +15 -0
  145. package/src/lib/backup-storage-schema.ts +55 -0
  146. package/src/lib/deferred-module.ts +38 -0
  147. package/src/lib/deployment-logs-query.ts +63 -0
  148. package/src/lib/display-name.ts +7 -0
  149. package/src/lib/error-message.ts +119 -0
  150. package/src/lib/form-errors.ts +10 -0
  151. package/src/lib/internal-redirect.ts +25 -0
  152. package/src/lib/manual-deploy-options-query.ts +21 -0
  153. package/src/lib/notification-preferences.ts +43 -0
  154. package/src/lib/onboarding.ts +11 -0
  155. package/src/lib/operation-logs-query.ts +51 -0
  156. package/src/lib/page-head.ts +14 -0
  157. package/src/lib/project-context-query.ts +257 -0
  158. package/src/lib/project-creation-schema.ts +64 -0
  159. package/src/lib/project-env-schema.ts +23 -0
  160. package/src/lib/project-environments-schema.ts +56 -0
  161. package/src/lib/project-routing-schema.ts +94 -0
  162. package/src/lib/project-runtime-config.ts +131 -0
  163. package/src/lib/project-settings-schema.ts +75 -0
  164. package/src/lib/public-api-schema.ts +128 -0
  165. package/src/lib/public-error.ts +337 -0
  166. package/src/lib/query.ts +13 -0
  167. package/src/lib/repository-selection-query.ts +11 -0
  168. package/src/lib/resource-cache.ts +30 -0
  169. package/src/lib/runtime-id.ts +19 -0
  170. package/src/lib/search.ts +14 -0
  171. package/src/lib/server-context-query.ts +43 -0
  172. package/src/lib/server-name-schema.ts +11 -0
  173. package/src/lib/settings-conflict.ts +45 -0
  174. package/src/lib/settings-version.ts +7 -0
  175. package/src/lib/team-context-query.ts +126 -0
  176. package/src/lib/team-context-schema.ts +8 -0
  177. package/src/lib/team-forms-schema.ts +45 -0
  178. package/src/lib/team-role.ts +13 -0
  179. package/src/lib/team-settings-schema.ts +48 -0
  180. package/src/lib/urls.ts +3 -0
  181. package/src/lib/use-avatar-input.ts +61 -0
  182. package/src/lib/use-refresh-error.ts +18 -0
  183. package/src/lib/use-settings-version.ts +23 -0
  184. package/src/lib/utils.ts +6 -0
  185. package/src/lib/validation.ts +5 -0
  186. package/src/lib/workspace-updates.ts +53 -0
  187. package/src/package/config.ts +10 -0
  188. package/src/package/env.mjs +54 -0
  189. package/src/package/migrate-api.d.ts +5 -0
  190. package/src/package/migrate.ts +56 -0
  191. package/src/package/plugins.ts +141 -0
  192. package/src/package/sqlite.mjs +2 -0
  193. package/src/package/vite-api.d.ts +5 -0
  194. package/src/package/vite.ts +324 -0
  195. package/src/package/watch-guard.cjs +26 -0
  196. package/src/plugins/client.ts +57 -0
  197. package/src/plugins/contract.ts +188 -0
  198. package/src/plugins/default.server.ts +4 -0
  199. package/src/plugins/default.ui.ts +4 -0
  200. package/src/plugins/operations.ts +45 -0
  201. package/src/plugins/server.ts +197 -0
  202. package/src/plugins/version.ts +1 -0
  203. package/src/routeTree.gen.ts +1275 -0
  204. package/src/router.tsx +46 -0
  205. package/src/routes/$teamSlug.index.tsx +53 -0
  206. package/src/routes/$teamSlug.new-project.tsx +13 -0
  207. package/src/routes/$teamSlug.projects.$projectName.backups.$backupId.tsx +40 -0
  208. package/src/routes/$teamSlug.projects.$projectName.backups.tsx +82 -0
  209. package/src/routes/$teamSlug.projects.$projectName.deployments.$deploymentId.tsx +52 -0
  210. package/src/routes/$teamSlug.projects.$projectName.deployments.tsx +86 -0
  211. package/src/routes/$teamSlug.projects.$projectName.logs.tsx +55 -0
  212. package/src/routes/$teamSlug.projects.$projectName.settings.tsx +51 -0
  213. package/src/routes/$teamSlug.projects.$projectName.tsx +106 -0
  214. package/src/routes/$teamSlug.projects.tsx +40 -0
  215. package/src/routes/$teamSlug.servers.$serverId.tsx +31 -0
  216. package/src/routes/$teamSlug.servers.index.tsx +59 -0
  217. package/src/routes/$teamSlug.servers.tsx +7 -0
  218. package/src/routes/$teamSlug.settings.tsx +56 -0
  219. package/src/routes/$teamSlug.tsx +86 -0
  220. package/src/routes/[.]well-known.oauth-authorization-server.api.auth.ts +13 -0
  221. package/src/routes/[.]well-known.oauth-protected-resource.mcp.ts +6 -0
  222. package/src/routes/__root.tsx +155 -0
  223. package/src/routes/admin.tsx +55 -0
  224. package/src/routes/api/agents/certificates.ts +21 -0
  225. package/src/routes/api/agents/credentials/rotate.ts +22 -0
  226. package/src/routes/api/agents/heartbeat.ts +42 -0
  227. package/src/routes/api/agents/job-logs.ts +22 -0
  228. package/src/routes/api/agents/jobs/complete.ts +22 -0
  229. package/src/routes/api/agents/jobs/next.ts +29 -0
  230. package/src/routes/api/agents/jobs/progress.ts +32 -0
  231. package/src/routes/api/agents/jobs/status.ts +22 -0
  232. package/src/routes/api/agents/register.ts +45 -0
  233. package/src/routes/api/agents/runtime-logs.ts +22 -0
  234. package/src/routes/api/agents/switch.ts +25 -0
  235. package/src/routes/api/auth/$.ts +38 -0
  236. package/src/routes/api/cron/backups.ts +33 -0
  237. package/src/routes/api/cron/maintenance.ts +30 -0
  238. package/src/routes/api/github/install.callback.ts +51 -0
  239. package/src/routes/api/github/install.ts +41 -0
  240. package/src/routes/api/github/webhook.ts +11 -0
  241. package/src/routes/api/health.ts +19 -0
  242. package/src/routes/api/install/agent.$token.ts +50 -0
  243. package/src/routes/api/install/agent.binary.ts +83 -0
  244. package/src/routes/api/install/agent.checksum.ts +45 -0
  245. package/src/routes/api/install/agent.ts +26 -0
  246. package/src/routes/api/plugins/$.ts +11 -0
  247. package/src/routes/api/v1/$.ts +15 -0
  248. package/src/routes/api/workspaces/updates.ts +8 -0
  249. package/src/routes/auth.login.tsx +50 -0
  250. package/src/routes/deployments.$deploymentId.unavailable.tsx +21 -0
  251. package/src/routes/index.tsx +23 -0
  252. package/src/routes/invites.$token.tsx +35 -0
  253. package/src/routes/mcp.ts +13 -0
  254. package/src/routes/oauth.consent.tsx +54 -0
  255. package/src/routes/onboarding.tsx +37 -0
  256. package/src/routes/onboarding.workspace.tsx +44 -0
  257. package/src/routes/settings.tsx +30 -0
  258. package/src/routes/uploads/avatars/$fileName.ts +44 -0
  259. package/src/server/admin/access.ts +67 -0
  260. package/src/server/admin/functions.ts +122 -0
  261. package/src/server/admin/service.ts +260 -0
  262. package/src/server/agents/backup-state.ts +210 -0
  263. package/src/server/agents/certificates.ts +96 -0
  264. package/src/server/agents/claims.ts +116 -0
  265. package/src/server/agents/cleanup.ts +52 -0
  266. package/src/server/agents/compatibility.ts +116 -0
  267. package/src/server/agents/completion.ts +83 -0
  268. package/src/server/agents/container-cleanup-state.ts +51 -0
  269. package/src/server/agents/deployment-state.ts +111 -0
  270. package/src/server/agents/job-payloads.ts +159 -0
  271. package/src/server/agents/jobs.ts +1293 -0
  272. package/src/server/agents/protocol.ts +400 -0
  273. package/src/server/agents/reconciliation.ts +43 -0
  274. package/src/server/agents/runtime-logs.ts +337 -0
  275. package/src/server/agents/runtime-state.ts +125 -0
  276. package/src/server/api/admission.ts +12 -0
  277. package/src/server/api/authorization.ts +115 -0
  278. package/src/server/api/credentials.ts +569 -0
  279. package/src/server/api/cursors.ts +72 -0
  280. package/src/server/api/errors.ts +24 -0
  281. package/src/server/api/functions.ts +60 -0
  282. package/src/server/api/handler.ts +274 -0
  283. package/src/server/api/mutation-operations.ts +913 -0
  284. package/src/server/api/operation-context.ts +139 -0
  285. package/src/server/api/operation-contract.ts +1099 -0
  286. package/src/server/api/operations.ts +64 -0
  287. package/src/server/api/read-operations.ts +891 -0
  288. package/src/server/api/retention.ts +33 -0
  289. package/src/server/auth/access.ts +109 -0
  290. package/src/server/auth/auth-methods.ts +28 -0
  291. package/src/server/auth/better-auth.ts +518 -0
  292. package/src/server/auth/context.ts +28 -0
  293. package/src/server/auth/email-change.ts +47 -0
  294. package/src/server/auth/email-delivery.ts +51 -0
  295. package/src/server/auth/provider-identity.ts +19 -0
  296. package/src/server/auth/provider-tokens.ts +27 -0
  297. package/src/server/auth/session.server.ts +19 -0
  298. package/src/server/backups/database-commands.ts +40 -0
  299. package/src/server/backups/destination.ts +12 -0
  300. package/src/server/backups/feature.ts +6 -0
  301. package/src/server/backups/policy-validation.ts +51 -0
  302. package/src/server/backups/queue-state.ts +137 -0
  303. package/src/server/backups/service.ts +918 -0
  304. package/src/server/backups/storage-functions.ts +42 -0
  305. package/src/server/backups/storage-state.ts +67 -0
  306. package/src/server/backups/storage.ts +237 -0
  307. package/src/server/config.ts +274 -0
  308. package/src/server/db/atomic.ts +16 -0
  309. package/src/server/db/d1-connection.ts +83 -0
  310. package/src/server/db/errors.ts +17 -0
  311. package/src/server/db/index.cloudflare.ts +15 -0
  312. package/src/server/db/index.ts +35 -0
  313. package/src/server/db/libsql-connection.ts +72 -0
  314. package/src/server/db/log-schema.ts +102 -0
  315. package/src/server/db/migrate-libsql.ts +29 -0
  316. package/src/server/db/migrate-sqlite.ts +47 -0
  317. package/src/server/db/migration-history.ts +12 -0
  318. package/src/server/db/migrations-logs/0000_initial.sql +48 -0
  319. package/src/server/db/migrations-logs/0001_runtime_log_order.sql +2 -0
  320. package/src/server/db/migrations-logs/meta/0000_snapshot.json +327 -0
  321. package/src/server/db/migrations-logs/meta/0001_snapshot.json +329 -0
  322. package/src/server/db/migrations-logs/meta/_journal.json +20 -0
  323. package/src/server/db/migrations-sqlite/0000_initial.sql +894 -0
  324. package/src/server/db/migrations-sqlite/0001_agent_indexes.sql +5 -0
  325. package/src/server/db/migrations-sqlite/meta/0000_snapshot.json +5816 -0
  326. package/src/server/db/migrations-sqlite/meta/0001_snapshot.json +5841 -0
  327. package/src/server/db/migrations-sqlite/meta/_journal.json +20 -0
  328. package/src/server/db/oauth-schema.ts +216 -0
  329. package/src/server/db/remote-config.ts +47 -0
  330. package/src/server/db/schema.ts +1218 -0
  331. package/src/server/db/sqlite-connection.ts +94 -0
  332. package/src/server/db/sqlite-files.ts +27 -0
  333. package/src/server/db/sqlite-params.ts +19 -0
  334. package/src/server/db/worker-connection.ts +47 -0
  335. package/src/server/deleted-resources.ts +133 -0
  336. package/src/server/deletion-recovery.ts +272 -0
  337. package/src/server/email/layout.tsx +85 -0
  338. package/src/server/email/notification-template.tsx +62 -0
  339. package/src/server/email/otp-template.tsx +48 -0
  340. package/src/server/email/service.ts +251 -0
  341. package/src/server/email/team-invite-template.tsx +59 -0
  342. package/src/server/email/theme.ts +10 -0
  343. package/src/server/github/http.ts +14 -0
  344. package/src/server/github/install-state.ts +48 -0
  345. package/src/server/github/service.ts +831 -0
  346. package/src/server/github/webhook-handler.ts +198 -0
  347. package/src/server/github/webhooks.ts +205 -0
  348. package/src/server/http/auth.ts +11 -0
  349. package/src/server/http/error-diagnostics.ts +66 -0
  350. package/src/server/http/plugin-request.ts +15 -0
  351. package/src/server/http/proxy-request.ts +53 -0
  352. package/src/server/http/public-errors.ts +48 -0
  353. package/src/server/http/rate-limit.ts +59 -0
  354. package/src/server/http/request-body.ts +54 -0
  355. package/src/server/http/request-ip.ts +54 -0
  356. package/src/server/http/security-headers.ts +36 -0
  357. package/src/server/install/agent-binary.ts +230 -0
  358. package/src/server/install/agent-script.ts +565 -0
  359. package/src/server/install/release-binary.ts +65 -0
  360. package/src/server/logs/budget.ts +72 -0
  361. package/src/server/logs/cleanup.ts +64 -0
  362. package/src/server/logs/deployments.ts +98 -0
  363. package/src/server/logs/operations.ts +145 -0
  364. package/src/server/logs/retention.ts +39 -0
  365. package/src/server/maintenance.ts +61 -0
  366. package/src/server/mcp/connections.ts +358 -0
  367. package/src/server/mcp/functions.ts +63 -0
  368. package/src/server/mcp/handler.ts +295 -0
  369. package/src/server/mcp/oauth-discovery.cloudflare.ts +6 -0
  370. package/src/server/mcp/oauth-discovery.ts +8 -0
  371. package/src/server/mcp/oauth-provider.ts +220 -0
  372. package/src/server/mcp/urls.ts +20 -0
  373. package/src/server/notifications/functions.ts +51 -0
  374. package/src/server/notifications/observe.ts +303 -0
  375. package/src/server/notifications/outbox.ts +335 -0
  376. package/src/server/notifications/preferences.ts +131 -0
  377. package/src/server/notifications/query.ts +16 -0
  378. package/src/server/plugins/scope.ts +17 -0
  379. package/src/server/plugins/server-context.ts +157 -0
  380. package/src/server/plugins/services.server.ts +10 -0
  381. package/src/server/plugins/workspace-access.ts +74 -0
  382. package/src/server/projects/backup-policy-state.ts +68 -0
  383. package/src/server/projects/backups.ts +219 -0
  384. package/src/server/projects/compose-metadata.ts +174 -0
  385. package/src/server/projects/configuration-state.ts +90 -0
  386. package/src/server/projects/context.ts +909 -0
  387. package/src/server/projects/creation-state.ts +46 -0
  388. package/src/server/projects/deletion-state.ts +69 -0
  389. package/src/server/projects/deployment-config.ts +139 -0
  390. package/src/server/projects/deployment-logs.ts +97 -0
  391. package/src/server/projects/deployments.ts +1123 -0
  392. package/src/server/projects/domain-state.ts +71 -0
  393. package/src/server/projects/environment-branches.ts +75 -0
  394. package/src/server/projects/environment-state.ts +158 -0
  395. package/src/server/projects/environments.ts +424 -0
  396. package/src/server/projects/functions.ts +748 -0
  397. package/src/server/projects/generated-hostname.ts +77 -0
  398. package/src/server/projects/hostnames.ts +244 -0
  399. package/src/server/projects/mappers.ts +457 -0
  400. package/src/server/projects/names.ts +41 -0
  401. package/src/server/projects/project-env-vars.ts +28 -0
  402. package/src/server/projects/queue-state.ts +118 -0
  403. package/src/server/projects/repository.ts +368 -0
  404. package/src/server/projects/route-state.ts +37 -0
  405. package/src/server/projects/runtime-logs.ts +97 -0
  406. package/src/server/projects/settings-context.ts +58 -0
  407. package/src/server/projects/settings.ts +738 -0
  408. package/src/server/projects/types.ts +355 -0
  409. package/src/server/realtime/agent-events.ts +32 -0
  410. package/src/server/realtime/node-broadcaster.ts +71 -0
  411. package/src/server/realtime/node-handler.ts +55 -0
  412. package/src/server/realtime/service.ts +125 -0
  413. package/src/server/realtime/workspace-object.cloudflare.ts +62 -0
  414. package/src/server/realtime/workspace-object.ts +3 -0
  415. package/src/server/resources/color.ts +13 -0
  416. package/src/server/runtime/background.ts +21 -0
  417. package/src/server/runtime/node-asset-cache-plugin.ts +12 -0
  418. package/src/server/runtime/node-scheduler-plugin.ts +17 -0
  419. package/src/server/runtime/node-scheduler.ts +51 -0
  420. package/src/server/runtime/platform-env.cloudflare.ts +17 -0
  421. package/src/server/runtime/platform-env.ts +19 -0
  422. package/src/server/runtime/scheduled-task-error.ts +9 -0
  423. package/src/server/scheduled-tasks.ts +28 -0
  424. package/src/server/secrets/crypto.ts +56 -0
  425. package/src/server/servers/functions.ts +233 -0
  426. package/src/server/servers/lifecycle.ts +122 -0
  427. package/src/server/servers/metric-history-schema.ts +24 -0
  428. package/src/server/servers/metric-history.ts +55 -0
  429. package/src/server/servers/monitoring.ts +592 -0
  430. package/src/server/servers/service.ts +1211 -0
  431. package/src/server/servers/status.ts +32 -0
  432. package/src/server/servers/switch.ts +96 -0
  433. package/src/server/settings-version.ts +43 -0
  434. package/src/server/storage/capabilities.ts +6 -0
  435. package/src/server/storage/local-object-store.cloudflare.ts +7 -0
  436. package/src/server/storage/local-object-store.ts +50 -0
  437. package/src/server/storage/object-store.ts +160 -0
  438. package/src/server/teams/creation.ts +51 -0
  439. package/src/server/teams/delete-policy.ts +13 -0
  440. package/src/server/teams/deletion-state.ts +80 -0
  441. package/src/server/teams/functions.ts +324 -0
  442. package/src/server/teams/invitations.ts +38 -0
  443. package/src/server/teams/membership.ts +86 -0
  444. package/src/server/teams/queries.ts +261 -0
  445. package/src/server/teams/service.ts +1127 -0
  446. package/src/server/teams/types.ts +101 -0
  447. package/src/server/uploads/avatar.ts +133 -0
  448. package/src/server/users/deletion-state.ts +93 -0
  449. package/src/server/users/functions.ts +160 -0
  450. package/src/server/users/onboarding.ts +17 -0
  451. package/src/server/users/service.ts +644 -0
  452. package/src/server.ts +55 -0
  453. package/src/styles/shadcn.css +653 -0
  454. package/src/styles/theme.css +76 -0
  455. package/src/styles.css +177 -0
  456. package/wrangler.template.jsonc +37 -0
@@ -0,0 +1,47 @@
1
+ import type { BetterAuthPlugin } from 'better-auth'
2
+ import {
3
+ APIError,
4
+ createAuthMiddleware,
5
+ getSessionFromCtx,
6
+ } from 'better-auth/api'
7
+ import { PublicError } from '#devpush/lib/public-error'
8
+ import { isEmailAllowlisted } from './access'
9
+
10
+ export async function assertAllowedEmailChange(email: string) {
11
+ if (!(await isEmailAllowlisted(email)))
12
+ throw new PublicError('ACCOUNT_EMAIL_NOT_ALLOWED')
13
+ }
14
+
15
+ export async function assertAllowedAuthEmailChange(email: string) {
16
+ try {
17
+ await assertAllowedEmailChange(email)
18
+ } catch (error) {
19
+ if (error instanceof PublicError)
20
+ throw new APIError('FORBIDDEN', {
21
+ code: error.code,
22
+ message: error.message,
23
+ })
24
+ throw error
25
+ }
26
+ }
27
+
28
+ export function requireAllowedEmailChanges(): BetterAuthPlugin {
29
+ return {
30
+ id: 'devpush-allowed-email-changes',
31
+ hooks: {
32
+ before: [
33
+ {
34
+ matcher: (ctx) => ctx.path === '/change-email',
35
+ handler: createAuthMiddleware(async (ctx) => {
36
+ // Avoid exposing policy to anonymous callers and honor live revocation.
37
+ if (!(await getSessionFromCtx(ctx, { disableCookieCache: true })))
38
+ throw new APIError('UNAUTHORIZED')
39
+ const email: unknown = ctx.body?.newEmail
40
+ if (typeof email === 'string')
41
+ await assertAllowedAuthEmailChange(email)
42
+ }),
43
+ },
44
+ ],
45
+ },
46
+ }
47
+ }
@@ -0,0 +1,51 @@
1
+ import type { BetterAuthPlugin } from 'better-auth'
2
+ import { APIError, createAuthMiddleware } from 'better-auth/api'
3
+
4
+ export function requireAuthEmailDelivery(): BetterAuthPlugin {
5
+ return {
6
+ id: 'require-auth-email-delivery',
7
+ hooks: {
8
+ before: [
9
+ {
10
+ matcher: (ctx) =>
11
+ [
12
+ '/email-otp/send-verification-otp',
13
+ '/change-email',
14
+ '/send-verification-email',
15
+ '/verify-email',
16
+ ].includes(ctx.path ?? ''),
17
+ handler: createAuthMiddleware(async (ctx) => ({
18
+ context: {
19
+ context: {
20
+ // Better Auth's default helper logs and swallows send failures.
21
+ // Override only this request: success must mean sending succeeded.
22
+ runInBackgroundOrAwait: async (
23
+ task: Promise<unknown> | void,
24
+ ) => {
25
+ try {
26
+ await task
27
+ } catch (error) {
28
+ ctx.context.logger.error(
29
+ 'Failed to send authentication email',
30
+ error,
31
+ )
32
+ throw new APIError('SERVICE_UNAVAILABLE', {
33
+ code:
34
+ ctx.path === '/email-otp/send-verification-otp'
35
+ ? 'OTP_SEND_FAILED'
36
+ : 'EMAIL_SEND_FAILED',
37
+ message:
38
+ ctx.path === '/email-otp/send-verification-otp'
39
+ ? 'Unable to send your sign-in code. Please try again in a moment.'
40
+ : 'Unable to send the verification email. Please try again in a moment.',
41
+ })
42
+ }
43
+ },
44
+ },
45
+ },
46
+ })),
47
+ },
48
+ ],
49
+ },
50
+ }
51
+ }
@@ -0,0 +1,19 @@
1
+ import { sql } from 'drizzle-orm'
2
+ import type { AtomicStore } from '#devpush/server/db/atomic'
3
+
4
+ export async function replacePendingIdentity(
5
+ store: AtomicStore,
6
+ input: {
7
+ identifier: string
8
+ value: string
9
+ expiresAt: Date
10
+ },
11
+ ) {
12
+ await store.batch([
13
+ store.run(
14
+ sql`delete from verification where identifier = ${input.identifier}`,
15
+ ),
16
+ store.run(sql`insert into verification (id, identifier, value, expires_at)
17
+ values (${crypto.randomUUID()}, ${input.identifier}, ${input.value}, ${input.expiresAt.getTime()})`),
18
+ ])
19
+ }
@@ -0,0 +1,27 @@
1
+ import { symmetricDecrypt, symmetricEncrypt } from 'better-auth/crypto'
2
+ import { config } from '#devpush/server/config'
3
+
4
+ // Better Auth's single-secret encryption format. Use the same key/codec as
5
+ // encryptOAuthTokens so refresh and reconnect never switch storage formats.
6
+ // Bare hex includes a 24-byte nonce and 16-byte authentication tag. Shorter
7
+ // hex strings cannot be encrypted envelopes.
8
+ function isEncrypted(value: string) {
9
+ return (
10
+ value.startsWith('$ba$') ||
11
+ (value.length >= 80 && value.length % 2 === 0 && /^[0-9a-f]+$/i.test(value))
12
+ )
13
+ }
14
+
15
+ export async function readProviderToken(value: string) {
16
+ return isEncrypted(value)
17
+ ? symmetricDecrypt({ key: config.BETTER_AUTH_SECRET, data: value })
18
+ : value
19
+ }
20
+
21
+ export async function storeProviderToken(value: string) {
22
+ if (isEncrypted(value)) {
23
+ await readProviderToken(value)
24
+ return value
25
+ }
26
+ return symmetricEncrypt({ key: config.BETTER_AUTH_SECRET, data: value })
27
+ }
@@ -0,0 +1,19 @@
1
+ import { getRequest } from '@tanstack/react-start/server'
2
+
3
+ import { auth } from '#devpush/server/auth/better-auth'
4
+
5
+ export async function getAuthSession() {
6
+ const request = getRequest()
7
+
8
+ return auth.api.getSession({
9
+ headers: request.headers,
10
+ })
11
+ }
12
+
13
+ export async function requireAuthSession(message = 'Unauthorized') {
14
+ const session = await getAuthSession()
15
+
16
+ if (!session) throw new Error(message)
17
+
18
+ return session
19
+ }
@@ -0,0 +1,40 @@
1
+ import { backupDatabaseSchema } from '#devpush/lib/backup-database'
2
+ import type { BackupDatabase } from '#devpush/lib/backup-database'
3
+
4
+ function quote(value: string) {
5
+ return "'" + value.replaceAll("'", "'\\''") + "'"
6
+ }
7
+ export function buildDatabaseBackupCommand(value: BackupDatabase) {
8
+ const target = backupDatabaseSchema.parse(value)
9
+ const name = quote(target.database)
10
+ switch (target.engine) {
11
+ case 'postgres': {
12
+ const flags =
13
+ 'pg_dump --clean --if-exists --no-owner --no-acl -U "${POSTGRES_USER:-postgres}"'
14
+ const dump = target.database
15
+ ? `${flags} --dbname=${name}`
16
+ : `databases="$(psql -v ON_ERROR_STOP=1 -U "\${POSTGRES_USER:-postgres}" --dbname=postgres -Atc "SELECT datname FROM pg_database WHERE NOT datistemplate ORDER BY datname")" || exit $?; printf '%s\\n' "$databases" | while IFS= read -r database; do ${flags} --create --dbname="$database" || exit $?; done`
17
+ return `export PGPASSWORD="\${POSTGRES_PASSWORD:-}"; ${dump}`
18
+ }
19
+ case 'mysql':
20
+ return `export MYSQL_PWD="\${MYSQL_ROOT_PASSWORD:?MYSQL_ROOT_PASSWORD is required}"; mysqldump -u root --single-transaction --quick --no-tablespaces ${target.database ? `--databases -- ${name}` : '--all-databases'}`
21
+ case 'mariadb':
22
+ return `export MYSQL_PWD="\${MARIADB_ROOT_PASSWORD:-\${MYSQL_ROOT_PASSWORD:?A root password is required}}"; mariadb-dump -u root --single-transaction --quick ${target.database ? `--databases -- ${name}` : '--all-databases'}`
23
+ case 'mongo':
24
+ return `mongodump --username="\${MONGO_INITDB_ROOT_USERNAME:?MongoDB username is required}" --password="\${MONGO_INITDB_ROOT_PASSWORD:?MongoDB password is required}" --authenticationDatabase=admin --archive${target.database ? ` --db=${name}` : ''}`
25
+ }
26
+ }
27
+ export function buildDatabaseRestoreCommand(value: BackupDatabase) {
28
+ const target = backupDatabaseSchema.parse(value)
29
+ const name = quote(target.database)
30
+ switch (target.engine) {
31
+ case 'postgres':
32
+ return `export PGPASSWORD="\${POSTGRES_PASSWORD:-}"; psql -v ON_ERROR_STOP=1 -U "\${POSTGRES_USER:-postgres}" --dbname=${target.database ? name : 'template1'}`
33
+ case 'mysql':
34
+ return 'export MYSQL_PWD="${MYSQL_ROOT_PASSWORD:?MYSQL_ROOT_PASSWORD is required}"; mysql -u root'
35
+ case 'mariadb':
36
+ return 'export MYSQL_PWD="${MARIADB_ROOT_PASSWORD:-${MYSQL_ROOT_PASSWORD:?A root password is required}}"; mariadb -u root'
37
+ case 'mongo':
38
+ return 'mongorestore --username="${MONGO_INITDB_ROOT_USERNAME:?MongoDB username is required}" --password="${MONGO_INITDB_ROOT_PASSWORD:?MongoDB password is required}" --authenticationDatabase=admin --archive --drop'
39
+ }
40
+ }
@@ -0,0 +1,12 @@
1
+ import type { BackupDestination } from './service'
2
+
3
+ // Runs and queued jobs keep location/ownership, never credential copies.
4
+ export function backupDestinationSnapshot(destination: BackupDestination) {
5
+ return {
6
+ storageId: destination.storageId,
7
+ bucket: destination.bucket,
8
+ region: destination.region,
9
+ endpoint: destination.endpoint,
10
+ prefix: destination.prefix,
11
+ }
12
+ }
@@ -0,0 +1,6 @@
1
+ import { config } from '#devpush/server/config'
2
+ import { PublicError } from '#devpush/lib/public-error'
3
+
4
+ export function requireBackupsEnabled() {
5
+ if (!config.DEVPUSH_BACKUPS_ENABLED) throw new PublicError('BACKUPS_DISABLED')
6
+ }
@@ -0,0 +1,51 @@
1
+ import { and, eq } from 'drizzle-orm'
2
+ import { z } from 'zod'
3
+ import {
4
+ backupConfigSchema,
5
+ normalizeBackupVolumes,
6
+ } from '#devpush/lib/backup-policy-schema'
7
+ import { getDefaultBackupPrefix } from '#devpush/lib/backup-paths'
8
+ import { PublicError } from '#devpush/lib/public-error'
9
+ import { db } from '#devpush/server/db'
10
+ import { environments } from '#devpush/server/db/schema'
11
+ import { resolveBackupDestination } from './storage'
12
+
13
+ const policySchema = backupConfigSchema.extend({ id: z.string().trim().min(1) })
14
+
15
+ export async function prepareBackupPolicy({
16
+ teamId,
17
+ projectId,
18
+ policy,
19
+ }: {
20
+ teamId: string
21
+ projectId: string
22
+ policy: unknown
23
+ }) {
24
+ const parsed = policySchema.parse(policy)
25
+ const [environment] = await db
26
+ .select({ id: environments.id })
27
+ .from(environments)
28
+ .where(
29
+ and(
30
+ eq(environments.id, parsed.environmentId),
31
+ eq(environments.projectId, projectId),
32
+ eq(environments.status, 'active'),
33
+ ),
34
+ )
35
+ .limit(1)
36
+ if (!environment) throw new PublicError('BACKUP_ENVIRONMENT_INVALID')
37
+ const normalized = {
38
+ ...parsed,
39
+ volumes: normalizeBackupVolumes(parsed.volumes),
40
+ destination: {
41
+ ...parsed.destination,
42
+ prefix:
43
+ parsed.destination.prefix ??
44
+ getDefaultBackupPrefix(projectId, parsed.environmentId, parsed.id),
45
+ },
46
+ }
47
+ if (normalized.destination.storageId || normalized.retention.remote.enabled) {
48
+ await resolveBackupDestination(teamId, normalized.destination)
49
+ }
50
+ return normalized
51
+ }
@@ -0,0 +1,137 @@
1
+ import { backupDestinationSnapshot } from './destination'
2
+ import { sql } from 'drizzle-orm'
3
+ import type { SQL } from 'drizzle-orm'
4
+ import type { AtomicStore } from '#devpush/server/db/atomic'
5
+ import {
6
+ agentJobs,
7
+ backupConfigs,
8
+ backupRuns,
9
+ environments,
10
+ projects,
11
+ servers,
12
+ } from '#devpush/server/db/schema'
13
+ import type { BackupDestination, BackupJobPayload } from './service'
14
+ import type { ApiMutationAdmission } from '#devpush/server/api/admission'
15
+
16
+ export const backupCleanupRetryDelayMs = 60 * 60 * 1000
17
+
18
+ // Release reservations before the associated jobs are canceled, in the same
19
+ // deletion batch. Match project/server ownership as well as payload run IDs.
20
+ export function releaseBackupCleanupRuns(input: {
21
+ jobIds: SQL
22
+ guard: SQL
23
+ message: string
24
+ now: Date
25
+ }) {
26
+ return sql`update backup_runs set cleanup_queued_at = null, cleanup_error_message = ${input.message}, updated_at = ${input.now.getTime()}
27
+ where ${input.guard} and exists(select 1 from agent_jobs as cleanup,
28
+ json_each(case when json_valid(cleanup.payload) then cleanup.payload else '{}' end, '$.backupRunIds') as target
29
+ where cleanup.id in (${input.jobIds}) and cleanup.type = 'backup_cleanup' and cleanup.status in ('queued','running')
30
+ and cleanup.server_id = backup_runs.server_id and cleanup.project_id = backup_runs.project_id and target.value = backup_runs.id)`
31
+ }
32
+
33
+ export async function enqueueBackupCleanup(
34
+ store: AtomicStore,
35
+ input: {
36
+ jobId: string
37
+ projectId: string
38
+ serverId: string
39
+ backupRunIds: string[]
40
+ now: Date
41
+ destination: BackupDestination
42
+ artifacts: Array<{
43
+ backupRunId: string
44
+ storage: 'local' | 'remote'
45
+ objectKey: string
46
+ }>
47
+ },
48
+ ) {
49
+ const now = input.now.getTime()
50
+ // An ID collision must fail even when eligibility would otherwise skip the
51
+ // insert; the following statement must never find an older job with this ID.
52
+ const eligible = sql`select id from ${backupRuns}
53
+ where id in (select value from json_each(${JSON.stringify(input.backupRunIds)}))
54
+ and server_id = ${input.serverId} and project_id = ${input.projectId}
55
+ and exists(select 1 from servers where id = ${input.serverId} and status <> 'deleted')
56
+ and exists(select 1 from projects where id = ${input.projectId} and status = 'active')
57
+ and (cleanup_error_message is null or updated_at <= ${now - backupCleanupRetryDelayMs})
58
+ and (status = 'succeeded' or (status = 'failed' and json_extract(manifest, '$.localRecoveryAvailable') = 1)) and cleanup_queued_at is null`
59
+ const keys = (
60
+ storage: 'local' | 'remote',
61
+ ) => sql`select distinct json_extract(artifact.value, '$.objectKey') as object_key
62
+ from json_each(${JSON.stringify(input.artifacts)}) as artifact
63
+ where json_extract(artifact.value, '$.backupRunId') in (select id from eligible)
64
+ and json_extract(artifact.value, '$.storage') = ${storage} order by object_key`
65
+ const [, marked] = await store.batch([
66
+ store.run(sql`with eligible as materialized (${eligible}), local_keys as (${keys('local')}), remote_keys as (${keys('remote')})
67
+ insert into ${agentJobs} (id, type, status, server_id, project_id, payload, max_attempts, available_at, created_at, updated_at)
68
+ select ${input.jobId}, 'backup_cleanup', 'queued', ${input.serverId}, ${input.projectId},
69
+ json_patch(json_object('schemaVersion', 1, 'backupRunIds', json((select json_group_array(id) from eligible)),
70
+ 'localObjectKeys', json((select json_group_array(object_key) from local_keys)),
71
+ 'remoteObjectKeys', json((select json_group_array(object_key) from remote_keys)), 'reason', 'Backup retention expired.'),
72
+ case when exists(select 1 from remote_keys) then json_object('destination', json(${JSON.stringify(backupDestinationSnapshot(input.destination))})) else '{}' end),
73
+ 5, ${now}, ${now}, ${now} where exists(select 1 from eligible)
74
+ or exists(select 1 from ${agentJobs} where id = ${input.jobId})`),
75
+ store.all(sql`update ${backupRuns} set cleanup_queued_at = ${now}, cleanup_error_message = null, updated_at = ${now}
76
+ where id in (select runtime.value from ${agentJobs} as job, json_each(job.payload, '$.backupRunIds') as runtime where job.id = ${input.jobId})
77
+ returning id`),
78
+ ])
79
+ return marked.map((row) => {
80
+ const id = Array.isArray(row)
81
+ ? row[0]
82
+ : typeof row === 'object' && row !== null && 'id' in row
83
+ ? row.id
84
+ : undefined
85
+ if (typeof id !== 'string')
86
+ throw new Error('Invalid backup cleanup queue result.')
87
+ return id
88
+ })
89
+ }
90
+
91
+ export async function enqueueBackup(
92
+ store: AtomicStore,
93
+ input: {
94
+ backupRunId: string
95
+ agentJobId: string
96
+ configId: string
97
+ projectId: string
98
+ environmentId: string
99
+ deploymentId: string | null
100
+ serverId: string
101
+ runtimeId: string
102
+ scheduleKey: string | null
103
+ manifest: unknown
104
+ payload: BackupJobPayload
105
+ now: Date
106
+ admission?: ApiMutationAdmission
107
+ },
108
+ ) {
109
+ const now = input.now.getTime()
110
+ // Force a primary-key error for a reused ID instead of letting a skipped
111
+ // insert attach the new job to an older backup run.
112
+ const [created] = await store.batch([
113
+ store.all(sql`insert into ${backupRuns}
114
+ (id, project_id, environment_id, deployment_id, server_id, runtime_id, config_id, schedule_key, status, manifest, destination, created_at, updated_at)
115
+ select ${input.backupRunId}, ${input.projectId}, ${input.environmentId}, ${input.deploymentId},
116
+ ${input.serverId}, ${input.runtimeId}, ${input.configId}, ${input.scheduleKey}, 'queued',
117
+ ${input.manifest == null ? null : JSON.stringify(input.manifest)}, ${input.payload.retention.remote.enabled ? JSON.stringify(backupDestinationSnapshot(input.payload.destination)) : null}, ${now}, ${now}
118
+ where exists(select 1 from ${backupRuns} where id = ${input.backupRunId}) or (
119
+ not exists(select 1 from ${backupRuns} where environment_id = ${input.environmentId} and status in ('queued', 'running'))
120
+ ${input.scheduleKey === null ? sql`` : sql`and not exists(select 1 from ${backupRuns} where environment_id = ${input.environmentId} and schedule_key = ${input.scheduleKey})`}
121
+ and exists(select 1 from ${backupConfigs} as config
122
+ join ${environments} as env on env.id = config.environment_id
123
+ join ${projects} as project on project.id = env.project_id
124
+ join ${servers} as server on server.id = coalesce(env.server_id, project.default_server_id)
125
+ where config.id = ${input.configId} and config.enabled = 1 and env.id = ${input.environmentId}
126
+ and project.id = ${input.projectId} and env.status = 'active' and project.status = 'active'
127
+ and server.id = ${input.serverId} and server.status in ('connected', 'disconnected'))
128
+ and ${input.admission?.guard ?? sql`1`}) returning id`),
129
+ store.run(sql`insert into ${agentJobs}
130
+ (id, type, status, server_id, project_id, payload, max_attempts, available_at, created_at, updated_at)
131
+ select ${input.agentJobId}, 'backup', 'queued', server_id, project_id,
132
+ ${JSON.stringify({ ...input.payload, destination: backupDestinationSnapshot(input.payload.destination) })}, 5, ${now}, ${now}, ${now}
133
+ from ${backupRuns} where id = ${input.backupRunId}`),
134
+ ...(input.admission?.statements ?? []),
135
+ ])
136
+ return created.length === 1
137
+ }