devpush 0.0.0-stage → 1.0.0-beta.4

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 +22 -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 +168 -3
  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,101 @@
1
+ import type { AgentUpdate } from '#devpush/server/agents/compatibility'
2
+ import type { TeamRole } from '#devpush/lib/team-role'
3
+ import type { getResourceColor } from '#devpush/server/resources/color'
4
+ import type { ServerMonitoringSummary } from '#devpush/server/servers/monitoring'
5
+ import type { ServerStatus } from '#devpush/server/servers/status'
6
+
7
+ export type TeamSummary = {
8
+ settingsVersion: number
9
+ id: string
10
+ slug: string
11
+ name: string
12
+ image: string | null
13
+ color: ReturnType<typeof getResourceColor>
14
+ role: TeamRole
15
+ }
16
+
17
+ export type ProjectSummary = {
18
+ id: string
19
+ name: string
20
+ avatarUrl: string | null
21
+ githubRepo: string
22
+ defaultHost: string | null
23
+ defaultRouteHttps: boolean
24
+ color: ReturnType<typeof getResourceColor>
25
+ }
26
+
27
+ export type ServerSummary = {
28
+ id: string
29
+ name: string
30
+ publicIpv4?: string | null
31
+ publicIpv6?: string | null
32
+ publicAddress: string | null
33
+ status: ServerStatus
34
+ agentVersion: string | null
35
+ agentUpdate: AgentUpdate
36
+ lastSeenAt: string | null
37
+ monitoring: ServerMonitoringSummary
38
+ }
39
+
40
+ export type TeamMemberSummary = {
41
+ id: string
42
+ role: TeamRole
43
+ user: {
44
+ id: string
45
+ name: string
46
+ username: string
47
+ email: string
48
+ image: string | null
49
+ }
50
+ }
51
+
52
+ export type TeamInviteSummary = {
53
+ id: string
54
+ email: string
55
+ role: Exclude<TeamRole, 'owner'>
56
+ expiresAt: string
57
+ createdAt: string
58
+ inviter: {
59
+ id: string
60
+ name: string
61
+ email: string
62
+ image: string | null
63
+ } | null
64
+ }
65
+
66
+ export type UserTeamInviteSummary = {
67
+ id: string
68
+ role: Exclude<TeamRole, 'owner'>
69
+ expiresAt: string
70
+ createdAt: string
71
+ team: {
72
+ id: string
73
+ slug: string
74
+ name: string
75
+ image: string | null
76
+ color: ReturnType<typeof getResourceColor>
77
+ }
78
+ inviter: {
79
+ id: string
80
+ name: string
81
+ email: string
82
+ image: string | null
83
+ } | null
84
+ }
85
+
86
+ export type UserContext = {
87
+ user: {
88
+ profileConfirmedAt?: number | null
89
+ settingsVersion: number
90
+ id: string
91
+ name: string
92
+ username: string
93
+ email: string
94
+ image: string | null
95
+ defaultTeamId: string | null
96
+ isInstallationAdmin: boolean
97
+ }
98
+ teams: Array<TeamSummary>
99
+ defaultTeam: TeamSummary
100
+ invites: Array<UserTeamInviteSummary>
101
+ }
@@ -0,0 +1,133 @@
1
+ import { PublicError } from '#devpush/lib/public-error'
2
+ import {
3
+ getObjectStore,
4
+ isObjectStorageConfigured,
5
+ } from '#devpush/server/storage/object-store'
6
+
7
+ export type AvatarOwner = {
8
+ filePrefix: 'user' | 'team' | 'project'
9
+ resourceId: string
10
+ }
11
+
12
+ export async function resolveAvatarUpdate({
13
+ currentAvatarPath,
14
+ avatarDataUrl,
15
+ deleteAvatar,
16
+ filePrefix,
17
+ resourceId,
18
+ }: {
19
+ currentAvatarPath: string | null
20
+ avatarDataUrl?: string | null
21
+ deleteAvatar: boolean
22
+ filePrefix: AvatarOwner['filePrefix']
23
+ resourceId: string
24
+ }) {
25
+ if (!avatarDataUrl && !deleteAvatar) {
26
+ return currentAvatarPath
27
+ }
28
+
29
+ if (deleteAvatar || !avatarDataUrl) {
30
+ return null
31
+ }
32
+
33
+ if (!isObjectStorageConfigured()) {
34
+ throw new PublicError('AVATAR_STORAGE_UNAVAILABLE')
35
+ }
36
+ const parsed = parseAvatarDataUrl(avatarDataUrl)
37
+ if (!/^[A-Za-z0-9_-]+$/.test(resourceId))
38
+ throw new Error('Invalid avatar owner.')
39
+ const version = crypto.randomUUID().replaceAll('-', '')
40
+ const fileName = `${filePrefix}_${resourceId}~${version}.${parsed.extension}`
41
+ const publicPath = `/uploads/avatars/${fileName}`
42
+
43
+ await getObjectStore().put(
44
+ `avatars/${fileName}`,
45
+ parsed.buffer,
46
+ parsed.mimeType,
47
+ )
48
+
49
+ return publicPath
50
+ }
51
+
52
+ function parseAvatarDataUrl(dataUrl: string) {
53
+ const match =
54
+ /^data:(image\/(?:png|jpeg|webp));base64,([A-Za-z0-9+/=]+)$/.exec(dataUrl)
55
+
56
+ if (!match || match[1] === undefined || match[2] === undefined) {
57
+ throw new PublicError('AVATAR_TYPE_UNSUPPORTED')
58
+ }
59
+
60
+ const mimeType = match[1]
61
+ const buffer = Buffer.from(match[2], 'base64')
62
+
63
+ if (buffer.byteLength > 2 * 1024 * 1024) {
64
+ throw new PublicError('AVATAR_TOO_LARGE')
65
+ }
66
+
67
+ if (!matchesImageSignature(buffer, mimeType)) {
68
+ throw new PublicError('AVATAR_CONTENT_MISMATCH')
69
+ }
70
+
71
+ return {
72
+ buffer,
73
+ mimeType,
74
+ extension:
75
+ mimeType === 'image/jpeg'
76
+ ? 'jpg'
77
+ : mimeType === 'image/png'
78
+ ? 'png'
79
+ : 'webp',
80
+ }
81
+ }
82
+
83
+ function matchesImageSignature(buffer: Buffer, mimeType: string) {
84
+ if (mimeType === 'image/png') {
85
+ return buffer
86
+ .subarray(0, 8)
87
+ .equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))
88
+ }
89
+
90
+ if (mimeType === 'image/jpeg') {
91
+ return (
92
+ buffer.length >= 3 &&
93
+ buffer[0] === 0xff &&
94
+ buffer[1] === 0xd8 &&
95
+ buffer[2] === 0xff
96
+ )
97
+ }
98
+
99
+ return (
100
+ buffer.length >= 12 &&
101
+ buffer.subarray(0, 4).toString('ascii') === 'RIFF' &&
102
+ buffer.subarray(8, 12).toString('ascii') === 'WEBP'
103
+ )
104
+ }
105
+
106
+ export async function removeOwnedAvatar(
107
+ publicPath: string | null | undefined,
108
+ owner: AvatarOwner,
109
+ options: { strict?: boolean } = {},
110
+ ) {
111
+ if (!publicPath) {
112
+ return
113
+ }
114
+
115
+ if (!publicPath.startsWith('/uploads/avatars/')) {
116
+ return
117
+ }
118
+ const prefix = `/uploads/avatars/${owner.filePrefix}_${owner.resourceId}`
119
+ if (
120
+ !/^[A-Za-z0-9_-]+$/.test(owner.resourceId) ||
121
+ !publicPath.startsWith(prefix)
122
+ )
123
+ return
124
+ const suffix = publicPath.slice(prefix.length)
125
+ if (!/^(?:~[a-f0-9]{32})?\.(?:png|jpe?g|webp)$/.test(suffix)) return
126
+
127
+ try {
128
+ await getObjectStore().delete(publicPath.slice('/uploads/'.length))
129
+ } catch (error) {
130
+ if (options.strict) throw error
131
+ // Missing old avatar files should not block saving settings.
132
+ }
133
+ }
@@ -0,0 +1,93 @@
1
+ import { sql } from 'drizzle-orm'
2
+ import type { AtomicStore } from '#devpush/server/db/atomic'
3
+ import { teamDeletionStatements } from '#devpush/server/teams/deletion-state'
4
+ import { installationAdminPredicate } from '#devpush/server/admin/access'
5
+
6
+ export type UserCleanupJobPayload = {
7
+ schemaVersion: 1
8
+ userId: string
9
+ email: string
10
+ avatarPath: string | null
11
+ soleMemberOwnedTeamIds: string[]
12
+ }
13
+
14
+ export async function deleteUserState(
15
+ store: AtomicStore,
16
+ input: {
17
+ userId: string
18
+ email: string
19
+ now: Date
20
+ adminActorUserId?: string
21
+ },
22
+ ) {
23
+ const now = input.now.getTime()
24
+ const jobId = crypto.randomUUID()
25
+ const guard = sql`u.id = ${input.userId} and u.email = ${input.email}
26
+ and ${
27
+ input.adminActorUserId
28
+ ? sql`u.status in ('active', 'banned') and u.id <> ${input.adminActorUserId} and ${installationAdminPredicate(input.adminActorUserId)}`
29
+ : sql`u.status = 'active'`
30
+ }
31
+ and not exists(select 1 from team_members owner join teams t on t.id = owner.team_id
32
+ where owner.user_id = ${input.userId} and owner.role = 'owner' and t.status = 'active'
33
+ and exists(select 1 from team_members other where other.team_id = t.id and other.user_id <> ${input.userId})
34
+ and not exists(select 1 from team_members other_owner join user other_user on other_user.id = other_owner.user_id
35
+ where other_owner.team_id = t.id and other_user.status = 'active'
36
+ and other_owner.user_id <> ${input.userId} and other_owner.role = 'owner'))`
37
+ const queued = sql`exists(select 1 from user_cleanup_jobs where id = ${jobId} and user_id = ${input.userId})`
38
+ const [created] = await store.batch([
39
+ store.all(sql`insert into user_cleanup_jobs (id, user_id, status, payload, available_at, created_at, updated_at)
40
+ select ${jobId}, u.id, 'queued', json_object('schemaVersion', 1, 'userId', u.id, 'email', u.email,
41
+ 'avatarPath', u.image, 'soleMemberOwnedTeamIds', json((select json_group_array(id) from
42
+ (select t.id from teams t join team_members sole on sole.team_id = t.id
43
+ where t.status = 'active' and sole.user_id = ${input.userId} and sole.role = 'owner'
44
+ and not exists(select 1 from team_members other where other.team_id = t.id and other.user_id <> ${input.userId}) order by t.id)))),
45
+ ${now}, ${now}, ${now} from user u where ${guard} returning id`),
46
+ store.run(sql`delete from team_invites where team_id in (
47
+ select value from user_cleanup_jobs as cleanup, json_each(cleanup.payload, '$.soleMemberOwnedTeamIds')
48
+ where cleanup.id = ${jobId}) and ${queued}`),
49
+ store.run(
50
+ sql`delete from session where user_id = ${input.userId} and ${queued}`,
51
+ ),
52
+ store.run(
53
+ sql`delete from account where user_id = ${input.userId} and ${queued}`,
54
+ ),
55
+ store.run(sql`update user set status = 'deleted', default_team_id = null, updated_at = ${now}
56
+ where id = ${input.userId} and ${queued}`),
57
+ ])
58
+ return created.length === 1
59
+ }
60
+
61
+ export async function cleanupDeletedUserState(
62
+ store: AtomicStore,
63
+ input: {
64
+ payload: UserCleanupJobPayload
65
+ now: Date
66
+ claim: { id: string; attempt: number }
67
+ },
68
+ ) {
69
+ const p = input.payload
70
+ const guard = sql`exists(select 1 from user where id = ${p.userId} and status = 'deleted') and exists(select 1 from user_cleanup_jobs where id = ${input.claim.id} and user_id = ${p.userId} and status = 'running' and attempt = ${input.claim.attempt} and claimed_at = ${input.now.getTime()})`
71
+ const statements = teamDeletionStatements({
72
+ teamIds: sql`select id from teams where status = 'active'
73
+ and id in (select value from json_each(${JSON.stringify(p.soleMemberOwnedTeamIds)}))
74
+ and exists(select 1 from team_members sole where sole.team_id = teams.id and sole.user_id = ${p.userId} and sole.role = 'owner')
75
+ and not exists(select 1 from team_members other where other.team_id = teams.id and other.user_id <> ${p.userId})`,
76
+ guard,
77
+ reason: 'Team deleted because the owning user was deleted.',
78
+ message: 'Canceled because the owning user was deleted.',
79
+ now: input.now,
80
+ clearDefaults: true,
81
+ })
82
+ const [found] = await store.batch([
83
+ store.all(sql`select id from user where id = ${p.userId} and ${guard}`),
84
+ ...statements.map((query) => store.run(query)),
85
+ store.run(
86
+ sql`delete from team_invites where (inviter_id = ${p.userId} or lower(email) = ${p.email.toLowerCase()}) and ${guard}`,
87
+ ),
88
+ store.run(
89
+ sql`delete from team_members where user_id = ${p.userId} and ${guard}`,
90
+ ),
91
+ ])
92
+ if (found.length !== 1) throw new Error('Deleted user not found.')
93
+ }
@@ -0,0 +1,160 @@
1
+ import { getAuthMethods } from '#devpush/server/auth/auth-methods'
2
+ import {
3
+ getAuthSession,
4
+ requireAuthSession,
5
+ } from '#devpush/server/auth/session.server'
6
+ import { getUserContext } from '#devpush/server/teams/service'
7
+ import {
8
+ listAuthAccounts,
9
+ listUserTeams,
10
+ assertActiveUser,
11
+ disconnectAuthAccount,
12
+ deleteUserAccount,
13
+ leaveTeam,
14
+ updateUserGeneral,
15
+ } from '#devpush/server/users/service'
16
+ import { and, eq, sql } from 'drizzle-orm'
17
+ import { db } from '#devpush/server/db'
18
+ import { user } from '#devpush/server/db/schema'
19
+ import { PublicError } from '#devpush/lib/public-error'
20
+ import { assertAllowedEmailChange } from '#devpush/server/auth/email-change'
21
+ import { publicErrorsMiddleware } from '#devpush/server/http/public-errors'
22
+ import { getRequest } from '@tanstack/react-start/server'
23
+ import { createServerFn } from '@tanstack/react-start'
24
+ import { z } from 'zod'
25
+
26
+ import { auth } from '#devpush/server/auth/better-auth'
27
+ import {
28
+ accountSettingsSchema,
29
+ accountEmailSchema,
30
+ accountValidationErrors,
31
+ accountServiceErrors,
32
+ } from '#devpush/lib/account-settings-schema'
33
+
34
+ export const updateUserGeneralAction = createServerFn({ method: 'POST' })
35
+ .middleware([publicErrorsMiddleware])
36
+ .validator((data: z.input<typeof accountSettingsSchema>) => data)
37
+ .handler(async ({ data }) => {
38
+ const session = await requireAuthSession()
39
+ const parsed = accountSettingsSchema.safeParse(data)
40
+ if (!parsed.success)
41
+ return { fieldErrors: accountValidationErrors(parsed.error.issues) }
42
+ try {
43
+ const profile = await updateUserGeneral({
44
+ userId: session.user.id,
45
+ ...parsed.data,
46
+ })
47
+ return { user: profile, fieldErrors: null }
48
+ } catch (error) {
49
+ const fieldErrors = accountServiceErrors(error)
50
+ if (fieldErrors) return { fieldErrors }
51
+ throw error
52
+ }
53
+ })
54
+
55
+ export const requestEmailChangeAction = createServerFn({ method: 'POST' })
56
+ .middleware([publicErrorsMiddleware])
57
+ .validator((data: unknown) => accountEmailSchema.parse(data))
58
+ .handler(async ({ data }) => {
59
+ const session = await requireAuthSession()
60
+
61
+ if (data.newEmail === session.user.email.toLowerCase())
62
+ throw new PublicError('ACCOUNT_EMAIL_UNCHANGED')
63
+
64
+ const request = getRequest()
65
+
66
+ await assertActiveUser(session.user.id)
67
+ await assertAllowedEmailChange(data.newEmail)
68
+
69
+ const changed = await db
70
+ .update(user)
71
+ .set({ settingsVersion: sql`${user.settingsVersion} + 1` })
72
+ .where(
73
+ and(
74
+ eq(user.id, session.user.id),
75
+ eq(user.status, 'active'),
76
+ eq(user.settingsVersion, data.settingsVersion),
77
+ eq(user.email, session.user.email),
78
+ ),
79
+ )
80
+ .returning({ settingsVersion: user.settingsVersion })
81
+ if (!changed.length) throw new PublicError('SETTINGS_CONFLICT')
82
+ await auth.api.changeEmail({
83
+ body: {
84
+ newEmail: data.newEmail,
85
+ callbackURL: '/settings#email',
86
+ },
87
+ headers: request.headers,
88
+ })
89
+ return changed[0]!
90
+ })
91
+
92
+ export const disconnectAuthAccountAction = createServerFn({ method: 'POST' })
93
+ .middleware([publicErrorsMiddleware])
94
+ .validator((data: unknown) =>
95
+ z
96
+ .object({
97
+ providerId: z.string().min(1),
98
+ accountId: z.string().min(1).optional().nullable(),
99
+ })
100
+ .parse(data),
101
+ )
102
+ .handler(async ({ data }) => {
103
+ const session = await requireAuthSession()
104
+
105
+ return disconnectAuthAccount({
106
+ userId: session.user.id,
107
+ ...data,
108
+ })
109
+ })
110
+
111
+ export const leaveTeamAction = createServerFn({ method: 'POST' })
112
+ .middleware([publicErrorsMiddleware])
113
+ .validator((data: unknown) =>
114
+ z.object({ teamId: z.string().min(1) }).parse(data),
115
+ )
116
+ .handler(async ({ data }) => {
117
+ const session = await requireAuthSession()
118
+
119
+ return leaveTeam({
120
+ userId: session.user.id,
121
+ teamId: data.teamId,
122
+ })
123
+ })
124
+
125
+ export const deleteUserAccountAction = createServerFn({ method: 'POST' })
126
+ .middleware([publicErrorsMiddleware])
127
+ .validator((data: unknown) =>
128
+ z.object({ confirmationName: z.string().trim().min(1) }).parse(data),
129
+ )
130
+ .handler(async ({ data }) => {
131
+ const session = await requireAuthSession()
132
+
133
+ return deleteUserAccount({
134
+ userId: session.user.id,
135
+ confirmationName: data.confirmationName,
136
+ })
137
+ })
138
+
139
+ export const getUserSettingsContext = createServerFn({ method: 'GET' })
140
+ .middleware([publicErrorsMiddleware])
141
+ .handler(async () => {
142
+ const session = await getAuthSession()
143
+
144
+ if (!session) {
145
+ return null
146
+ }
147
+
148
+ const [context, accounts, teams] = await Promise.all([
149
+ getUserContext(session.user.id),
150
+ listAuthAccounts(session.user.id, { validateUser: false }),
151
+ listUserTeams(session.user.id),
152
+ ])
153
+
154
+ return {
155
+ ...context,
156
+ accounts,
157
+ authMethods: getAuthMethods(),
158
+ teams,
159
+ }
160
+ })
@@ -0,0 +1,17 @@
1
+ import { createServerFn } from '@tanstack/react-start'
2
+ import { requireAuthSession } from '#devpush/server/auth/session.server'
3
+ import { publicErrorsMiddleware } from '#devpush/server/http/public-errors'
4
+ import { accountSettingsSchema } from '#devpush/lib/account-settings-schema'
5
+ import { updateUserGeneral } from './service'
6
+
7
+ export const confirmProfile = createServerFn({ method: 'POST' })
8
+ .middleware([publicErrorsMiddleware])
9
+ .validator((input: unknown) => accountSettingsSchema.parse(input))
10
+ .handler(async ({ data }) => {
11
+ const session = await requireAuthSession()
12
+ return updateUserGeneral({
13
+ ...data,
14
+ userId: session.user.id,
15
+ confirmProfile: true,
16
+ })
17
+ })