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,128 @@
1
+ import { settingsVersionSchema } from '#devpush/lib/settings-version'
2
+ import { z } from 'zod'
3
+
4
+ export const publicIdSchema = z.string().min(1).max(128)
5
+ export const publicTimestampSchema = z.iso.datetime()
6
+ export const publicPageInputSchema = z.strictObject({
7
+ limit: z.coerce.number().int().min(1).max(100).default(25),
8
+ cursor: z.string().min(1).max(2048).optional(),
9
+ })
10
+ export const publicProjectInputSchema = z.strictObject({
11
+ projectId: publicIdSchema,
12
+ })
13
+ export const publicDeploymentInputSchema = z.strictObject({
14
+ deploymentId: publicIdSchema,
15
+ })
16
+ export const publicServerInputSchema = z.strictObject({
17
+ serverId: publicIdSchema,
18
+ })
19
+ export const publicBackupInputSchema = z.strictObject({
20
+ backupRunId: publicIdSchema,
21
+ })
22
+ export const publicProjectSchema = z.strictObject({
23
+ id: publicIdSchema,
24
+ teamId: publicIdSchema,
25
+ name: z.string(),
26
+ slug: z.string(),
27
+ repository: z.string(),
28
+ repositoryId: z.number().int().nullable(),
29
+ defaultServerId: publicIdSchema.nullable(),
30
+ settingsVersion: settingsVersionSchema,
31
+ createdAt: publicTimestampSchema,
32
+ })
33
+ export const publicEnvironmentSchema = z.strictObject({
34
+ id: publicIdSchema,
35
+ projectId: publicIdSchema,
36
+ name: z.string(),
37
+ slug: z.string(),
38
+ branch: z.string(),
39
+ isProduction: z.boolean(),
40
+ position: z.number().int(),
41
+ color: z.string(),
42
+ serverId: publicIdSchema.nullable(),
43
+ createdAt: publicTimestampSchema,
44
+ })
45
+ export const publicDeploymentSchema = z.strictObject({
46
+ id: publicIdSchema,
47
+ projectId: publicIdSchema,
48
+ environmentId: publicIdSchema,
49
+ serverId: publicIdSchema,
50
+ status: z.enum(['queued', 'running', 'succeeded', 'failed', 'canceled']),
51
+ phase: z.string().nullable(),
52
+ trigger: z.enum(['user', 'webhook', 'api', 'rollback']),
53
+ repository: z.string(),
54
+ sha: z.string(),
55
+ branch: z.string(),
56
+ createdAt: publicTimestampSchema,
57
+ startedAt: publicTimestampSchema.nullable(),
58
+ finishedAt: publicTimestampSchema.nullable(),
59
+ })
60
+ export const publicServerSchema = z.strictObject({
61
+ settingsVersion: settingsVersionSchema,
62
+ id: publicIdSchema,
63
+ teamId: publicIdSchema,
64
+ name: z.string(),
65
+ status: z.enum([
66
+ 'pending',
67
+ 'connected',
68
+ 'disconnected',
69
+ 'disabled',
70
+ 'deleted',
71
+ ]),
72
+ publicAddress: z.string().nullable(),
73
+ agentVersion: z.string().nullable(),
74
+ lastSeenAt: publicTimestampSchema.nullable(),
75
+ createdAt: publicTimestampSchema,
76
+ })
77
+ export const publicBackupRunSchema = z.strictObject({
78
+ id: publicIdSchema,
79
+ projectId: publicIdSchema,
80
+ environmentId: publicIdSchema,
81
+ deploymentId: publicIdSchema.nullable(),
82
+ serverId: publicIdSchema.nullable(),
83
+ status: z.enum(['queued', 'running', 'succeeded', 'failed', 'canceled']),
84
+ createdAt: publicTimestampSchema,
85
+ startedAt: publicTimestampSchema.nullable(),
86
+ finishedAt: publicTimestampSchema.nullable(),
87
+ })
88
+ const publicLogSchema = z.strictObject({
89
+ position: z.number().int().nonnegative(),
90
+ content: z.string().max(64 * 1024),
91
+ createdAt: publicTimestampSchema,
92
+ truncated: z.boolean(),
93
+ })
94
+ export const publicLogPageSchema = z.strictObject({
95
+ items: z.array(publicLogSchema).max(100),
96
+ nextCursor: z.string().nullable(),
97
+ retentionMayHaveRemovedEarlierEntries: z.literal(true),
98
+ })
99
+ export function publicPageSchema<T extends z.ZodType>(item: T) {
100
+ return z.strictObject({
101
+ items: z.array(item).max(100),
102
+ nextCursor: z.string().nullable(),
103
+ })
104
+ }
105
+ export const publicDeploymentAcceptedSchema = z.strictObject({
106
+ deploymentId: publicIdSchema,
107
+ statusUrl: z.string(),
108
+ })
109
+ export const publicBackupAcceptedSchema = z.strictObject({
110
+ backupRunId: publicIdSchema,
111
+ agentJobId: publicIdSchema,
112
+ statusUrl: z.string(),
113
+ })
114
+ export const publicRestoreAcceptedSchema = z.strictObject({
115
+ agentJobId: publicIdSchema,
116
+ statusUrl: z.string(),
117
+ })
118
+ export const publicErrorResponseSchema = z.strictObject({
119
+ error: z.strictObject({
120
+ code: z.string(),
121
+ message: z.string(),
122
+ policy: z
123
+ .strictObject({ message: z.string(), recoveryUrl: z.string().optional() })
124
+ .optional(),
125
+ requestId: z.string(),
126
+ fieldErrors: z.record(z.string(), z.array(z.string())).optional(),
127
+ }),
128
+ })
@@ -0,0 +1,337 @@
1
+ export const publicErrorMessages = {
2
+ WORKSPACE_RESTRICTED:
3
+ 'This workspace does not currently allow this action. Review its settings to continue.',
4
+ WORKSPACE_LIMIT_REACHED:
5
+ 'This action exceeds the workspace allowance. Review its settings to continue.',
6
+ RESOURCE_BUSY: 'Another workspace change is in progress. Please try again.',
7
+ SETTINGS_CONFLICT:
8
+ 'Settings changed since you started editing. Reload to load the latest settings.',
9
+ GITHUB_ACCESS_REFRESH_FAILED:
10
+ 'Unable to refresh GitHub access. Try again or reconnect GitHub in Account settings.',
11
+ API_KEY_CREATION_UNAVAILABLE:
12
+ 'API key could not be created. Check the scope and your current access, or revoke an unused key if you already have 100 active keys.',
13
+ API_KEY_REVOKED: 'This API key has been revoked. Create a new key instead.',
14
+ API_KEY_EXPIRED: 'This API key has expired. Create a new key instead.',
15
+ MCP_CONNECTION_CREATION_UNAVAILABLE:
16
+ 'MCP connection could not be created. Check your current access, or revoke an unused connection if you already have 100 active connections.',
17
+ ACCOUNT_EMAIL_UNCHANGED: 'Enter a different email address.',
18
+ ACCOUNT_EMAIL_NOT_ALLOWED:
19
+ 'This email address is not allowed for your account.',
20
+ RATE_LIMITED: 'Too many attempts. Please wait a moment and try again.',
21
+ PROJECT_NAME_INVALID:
22
+ 'Project names can only contain letters, numbers, hyphens, underscores and dots. They cannot start or end with a dot, underscore or hyphen.',
23
+ PROJECT_ENVIRONMENT_IDENTIFIER_DUPLICATED:
24
+ 'Environment identifiers must be unique.',
25
+ PROJECT_GITHUB_ACCOUNT_REQUIRED:
26
+ 'Connect your GitHub account before selecting a repository.',
27
+ PROJECT_GITHUB_ACCOUNT_INSTALLATION_REQUIRED:
28
+ 'Install the GitHub App for this account to continue.',
29
+ PROJECT_SERVER_INVALID: 'Select a valid server.',
30
+ PROJECT_CREATION_GITHUB_REQUIRED: 'Connect GitHub before creating a project.',
31
+ PROJECT_REPOSITORY_INSTALLATION_REQUIRED:
32
+ 'Install the GitHub app for this repository to continue.',
33
+ PROJECT_CREATION_PUSH_ACCESS_REQUIRED:
34
+ 'You need push access to create a project from this repository.',
35
+ DEPLOYMENT_ENVIRONMENT_NOT_FOUND: 'Deployment environment not found.',
36
+ DEPLOYMENT_BRANCH_MISMATCH:
37
+ 'The selected branch does not match this environment.',
38
+ DEPLOYMENT_SERVER_REQUIRED: 'Assign a server before deploying.',
39
+ DEPLOYMENT_SERVER_OFFLINE:
40
+ 'Wait until the assigned server is connected before deploying.',
41
+ DEPLOYMENT_AGENT_UPDATE_REQUIRED:
42
+ 'Update the assigned server agent before deploying.',
43
+ DEPLOYMENT_GITHUB_INSTALLATION_REQUIRED:
44
+ 'Connect a GitHub App installation before deploying.',
45
+ DEPLOYMENT_COMMIT_UNAVAILABLE:
46
+ 'The selected commit is not available on this branch.',
47
+ DEPLOYMENT_NOT_FOUND: 'Deployment not found.',
48
+ DEPLOYMENT_ROLLBACK_UNSUCCESSFUL:
49
+ 'Only successful deployments can be rolled back to.',
50
+ DEPLOYMENT_CONFIG_INVALID: 'Deployment config is invalid.',
51
+ DEPLOYMENT_SERVER_NOT_FOUND: 'Deployment server not found.',
52
+ DEPLOYMENT_SERVER_CHANGED:
53
+ 'This environment uses a different server now. Create a new deployment instead.',
54
+ DEPLOYMENT_ROLLBACK_SERVER_OFFLINE:
55
+ 'Reconnect the deployment server before rolling back.',
56
+ DEPLOYMENT_ROLLBACK_AGENT_UPDATE_REQUIRED:
57
+ 'Update the deployment server agent before rolling back.',
58
+ DEPLOYMENT_ENVIRONMENT_INACTIVE:
59
+ 'Deployment environment is no longer active.',
60
+ DEPLOYMENT_REDEPLOY_ACTIVE:
61
+ 'Queued or running deployments cannot be redeployed.',
62
+ DEPLOYMENT_REDEPLOY_SERVER_OFFLINE:
63
+ 'Reconnect the deployment server before redeploying.',
64
+ DEPLOYMENT_REDEPLOY_AGENT_UPDATE_REQUIRED:
65
+ 'Update the deployment server agent before redeploying.',
66
+ PROJECT_REPOSITORY_MISSING: 'Project repository is not configured.',
67
+ DEPLOYMENT_SERVER_DELETED:
68
+ 'Assigned server was deleted. Choose another server.',
69
+ PROJECT_HOST_COMMANDS_FORBIDDEN:
70
+ 'Only team owners and admins can change host lifecycle commands.',
71
+ PROJECT_HOST_COMMAND_SOURCE_FORBIDDEN:
72
+ 'Only team owners and admins can change the source of host lifecycle commands.',
73
+ PROJECT_NAME_CONFLICT: 'Project names must be unique within a team.',
74
+ PROJECT_DELETE_FORBIDDEN: 'Only team owners and admins can delete projects.',
75
+ PROJECT_DELETE_CONFIRMATION: 'Type the project name to confirm deletion.',
76
+ PROJECT_ACCESS_CHANGED: 'Project not found or access changed.',
77
+ PROJECT_ROUTE_ENVIRONMENT_INVALID:
78
+ 'Select a valid environment for every scoped route.',
79
+ PROJECT_ROUTE_DUPLICATED:
80
+ 'Each route path can only be configured once per scope.',
81
+ PROJECT_DOMAIN_ENVIRONMENT_INVALID:
82
+ 'Select a valid environment for every domain.',
83
+ PROJECT_DOMAIN_DUPLICATED: 'Each domain can only be added once.',
84
+ PROJECT_GENERATED_ALIAS_PROTECTED:
85
+ 'A custom domain cannot replace a generated alias.',
86
+ PROJECT_DOMAIN_NOT_FOUND: 'Domain not found.',
87
+ PROJECT_REPOSITORY_INSTALLATION_REQUIRED_SELECTION:
88
+ 'Select a GitHub App installation for this repository.',
89
+ PROJECT_REPOSITORY_GITHUB_REQUIRED:
90
+ 'Connect GitHub before changing the repository.',
91
+ PROJECT_REPOSITORY_PUSH_ACCESS_REQUIRED:
92
+ 'You need push access to use this repository.',
93
+ PROJECT_COMPOSE_PATH_REQUIRED:
94
+ 'Set a Compose file path before changing repositories.',
95
+ PROJECT_PRODUCTION_ENVIRONMENT_REQUIRED:
96
+ 'Production environment is required.',
97
+ PROJECT_ACTIVE_ENVIRONMENT_REQUIRED:
98
+ 'Project requires an active environment.',
99
+ PROJECT_ENVIRONMENT_SERVER_INVALID:
100
+ 'Select a valid server for every environment.',
101
+ PROJECT_ENVIRONMENT_SERVER_DUPLICATED:
102
+ 'Each environment can only have one server assignment.',
103
+ PROJECT_DEFAULT_SERVER_INVALID: 'Select a valid default server.',
104
+ PROJECT_SERVER_ASSIGNMENT_INVALID: 'Select a valid environment and server.',
105
+ PROJECT_VARIABLE_DUPLICATED:
106
+ 'Environment variable keys must be unique per environment.',
107
+ PROJECT_VARIABLE_ENVIRONMENT_INVALID:
108
+ 'Select a valid environment for every variable.',
109
+ BACKUP_SCHEDULE_INVALID:
110
+ 'Backup schedules must use a five-field cron expression.',
111
+ PROJECT_NOT_FOUND: 'Project not found.',
112
+ PROJECT_SERVER_ADDRESS_INVALID:
113
+ 'The assigned server has no valid IP address for generating its nip.io URL.',
114
+ PROJECT_RUNTIME_CONFIG_INVALID: 'Project runtime configuration is invalid.',
115
+ BACKUP_NAME_REQUIRED: 'Backup name is required.',
116
+ BACKUP_POLICY_REQUIRED:
117
+ 'Choose a backup policy when the environment has multiple enabled policies.',
118
+ BACKUP_SETTINGS_CONFLICT:
119
+ 'Backup settings changed while you were editing, or your access changed. Reload before saving again.',
120
+ BACKUP_ENVIRONMENT_INVALID: 'Select a valid backup environment.',
121
+ BACKUP_POLICY_NOT_FOUND: 'Backup policy not found.',
122
+ BACKUP_ALREADY_ACTIVE:
123
+ 'A backup is already queued or running for this environment.',
124
+ BACKUP_MANAGEMENT_FORBIDDEN:
125
+ 'Only team owners and admins can configure backups or restore data.',
126
+ BACKUPS_DISABLED: 'Backups are not enabled for this installation.',
127
+ ACCOUNT_NOT_FOUND: 'User not found.',
128
+ TEAM_NOT_FOUND: 'Team not found',
129
+ TEAM_NAME_REQUIRED: 'Team name is required.',
130
+ TEAM_SLUG_RESERVED: 'This slug is reserved.',
131
+ TEAM_SLUG_CONFLICT: 'A team with this slug already exists.',
132
+ TEAM_INVITE_EMAIL_REQUIRED: 'Enter at least one email address.',
133
+ TEAM_INVITE_NOT_FOUND: 'Invite not found.',
134
+ TEAM_MEMBER_NOT_FOUND: 'Member not found.',
135
+ TEAM_OWNER_ROLE_FORBIDDEN: 'Only team owners can manage owner roles.',
136
+ TEAM_OWNER_REMOVAL_FORBIDDEN: 'Only team owners can remove owners.',
137
+ TEAM_LAST_OWNER: 'There must be at least one owner.',
138
+ TEAM_MEMBERSHIP_CHANGED: 'Team membership changed. Try again.',
139
+ TEAM_SETTINGS_CHANGED:
140
+ 'Team settings or your access changed. Reload and try again.',
141
+ TEAM_TRANSFER_MEMBER_REQUIRED:
142
+ 'Choose another member to transfer ownership to.',
143
+ TEAM_TRANSFER_FORBIDDEN: 'Only team owners can transfer ownership.',
144
+ TEAM_MEMBER_ALREADY_OWNER: 'Member is already an owner.',
145
+ TEAM_DELETE_CONFIRMATION: 'Type the team name to confirm deletion.',
146
+ TEAM_DEFAULT_DELETE_FORBIDDEN: 'You cannot delete a default team.',
147
+ TEAM_STATE_CHANGED: 'Team changed or became a default team. Try again.',
148
+ TEAM_INVITATION_INVALID: 'Invalid or expired invitation.',
149
+ TEAM_INVITATION_EMAIL_MISMATCH:
150
+ 'Sign in with the invited email address to accept.',
151
+ TEAM_INVITATION_EMAIL_UNVERIFIED:
152
+ 'Verify your email address before accepting this invite.',
153
+ TEAM_EMAIL_REQUIRED: 'Email is required.',
154
+ TEAM_MANAGEMENT_FORBIDDEN: 'You do not have permission to manage this team.',
155
+ TEAM_MANAGER_REQUIRED: 'Only team owners and admins can manage this team.',
156
+ TEAM_OWNER_REQUIRED: 'Only team owners can manage this team.',
157
+ TEAM_SLUG_INVALID:
158
+ 'Team slugs can only contain letters, numbers, hyphens, underscores and dots. They cannot start or end with a dot, underscore or hyphen.',
159
+ TEAM_ALREADY_MEMBER: 'This email address is already a member of this team.',
160
+ TEAM_INVITATION_ALREADY_SENT:
161
+ 'An invitation has already been sent to this email address.',
162
+ ACCOUNT_NAME_REQUIRED: 'Name is required.',
163
+ ACCOUNT_USERNAME_CONFLICT: 'Username is already taken.',
164
+ AUTH_ACCOUNT_NOT_FOUND: 'Account not found.',
165
+ ACCOUNT_LAST_SIGN_IN_METHOD:
166
+ 'Connect another sign-in method before disconnecting this account.',
167
+ ACCOUNT_DEFAULT_TEAM_LEAVE_FORBIDDEN: 'You cannot leave your default team.',
168
+ ACCOUNT_MEMBERSHIP_NOT_FOUND: 'Team membership not found.',
169
+ ACCOUNT_DELETE_CONFIRMATION: 'Type the account email to confirm deletion.',
170
+ ACCOUNT_STATE_CHANGED: 'Account or team ownership changed. Try again.',
171
+ ACCOUNT_USERNAME_REQUIRED: 'Username is required.',
172
+ ACCOUNT_USERNAME_TOO_LONG: 'Username must be 50 characters or fewer.',
173
+ ACCOUNT_USERNAME_INVALID:
174
+ 'Username must start and end with a letter or number and only use letters, numbers, dots, underscores hyphens.',
175
+ ACCOUNT_OWNERSHIP_TRANSFER_REQUIRED:
176
+ 'Transfer ownership of teams where you are the only owner before deleting your account.',
177
+ BACKUP_ENABLED_CONFIG_NOT_FOUND: 'Enabled backup configuration not found.',
178
+ BACKUP_SERVER_REQUIRED: 'Backup environment is not assigned to a server.',
179
+ BACKUP_MONGODB_AGENT_UPDATE_REQUIRED:
180
+ 'Update the server agent before running MongoDB backups.',
181
+ BACKUP_CREDENTIALS_MISSING: 'Remote backup credentials are not configured.',
182
+ BACKUP_RESTORE_ARTIFACT_REQUIRED:
183
+ 'Select at least one backup artifact to restore.',
184
+ BACKUP_RUN_NOT_FOUND: 'Backup run not found.',
185
+ BACKUP_NO_RECOVERABLE_ARTIFACTS: 'This backup has no recoverable artifacts.',
186
+ BACKUP_SERVER_CHANGED:
187
+ 'Backup run is not assigned to the current environment server.',
188
+ BACKUP_FAILED_REMOTE_RESTORE:
189
+ 'Only local artifacts from this failed backup can be restored.',
190
+ BACKUP_ARTIFACT_NOT_FOUND: 'One or more backup artifacts were not found.',
191
+ BACKUP_ARTIFACT_TYPE_MISMATCH:
192
+ 'Backup artifact type does not match the restore target.',
193
+ BACKUP_DESTINATION_UNAVAILABLE:
194
+ 'The original remote backup destination is unavailable.',
195
+ BACKUP_RESTORE_CREDENTIALS_MISSING:
196
+ 'Remote restore credentials are not configured.',
197
+ BACKUP_ENVIRONMENT_NOT_FOUND: 'Backup environment not found.',
198
+ BACKUP_DESTINATION_PREFIX_INVALID:
199
+ 'Backup destination prefixes cannot contain .. segments.',
200
+ BACKUP_DATABASE_ENGINE_UNSUPPORTED:
201
+ 'This backup has no supported database engine metadata. Restore it manually.',
202
+ BACKUP_STORAGE_NOT_FOUND: 'Backup storage not found.',
203
+ BACKUP_STORAGE_SECRET_REQUIRED: 'Enter a secret access key.',
204
+ BACKUP_STORAGE_LOCATION_IMMUTABLE:
205
+ 'Create another storage destination to change its bucket, region or endpoint.',
206
+ BACKUP_STORAGE_REQUIRED: 'Select a workspace backup storage destination.',
207
+ BACKUP_STORAGE_TEAM_MISMATCH:
208
+ 'Select a backup storage destination in this workspace.',
209
+ BACKUP_STORAGE_IN_USE:
210
+ 'Storage cannot be removed while a policy, active backup or retained remote backup references it.',
211
+ AVATAR_STORAGE_UNAVAILABLE:
212
+ 'Image uploads are not configured for this installation.',
213
+ AVATAR_TYPE_UNSUPPORTED: 'Upload a PNG, JPEG, or WebP image.',
214
+ AVATAR_TOO_LARGE: 'Avatars must be 2 MB or smaller.',
215
+ AVATAR_CONTENT_MISMATCH: 'The uploaded file does not match its image type.',
216
+
217
+ SERVER_NOT_FOUND: 'Server not found.',
218
+ SERVER_NAME_CONFLICT: 'Server names must be unique within a team.',
219
+ SERVER_DISABLE_CONFIRMATION: 'Type the server name to confirm disabling.',
220
+ SERVER_DELETE_CONFIRMATION: 'Type the server name to confirm deletion.',
221
+ SERVER_STATE_CHANGED: 'Server state or permissions changed. Try again.',
222
+ SERVER_ENABLE_DISABLED_ONLY: 'Only disabled servers can be enabled.',
223
+ SERVER_DISABLED_ENROLLMENT: 'Disabled servers cannot be enrolled.',
224
+ SERVER_DELETED_ENROLLMENT: 'Deleted servers cannot be enrolled.',
225
+ SERVER_CONNECTED_ENROLLMENT:
226
+ 'Connected servers cannot be re-enrolled. Disable the server first.',
227
+ SERVER_ACCESS_CHANGED: 'Server not found or access changed.',
228
+ SERVER_NAME_INVALID:
229
+ 'Server names can only contain letters, numbers, hyphens, underscores and dots. They cannot start or end with a dot, underscore or hyphen.',
230
+ INVALID_INPUT: 'Check the entered values and try again.',
231
+ UNAUTHORIZED: 'Sign in to continue.',
232
+ FORBIDDEN: 'You do not have permission to perform this action.',
233
+ INTERNAL_ERROR: 'Unable to complete this action. Please try again.',
234
+ } as const
235
+
236
+ export type PublicErrorCode = keyof typeof publicErrorMessages
237
+
238
+ function isSafeLocalUrl(value: unknown): value is string {
239
+ return (
240
+ typeof value === 'string' &&
241
+ value.startsWith('/') &&
242
+ !value.startsWith('//') &&
243
+ !Array.from(value).some(
244
+ (character) =>
245
+ character === '\\' ||
246
+ character.charCodeAt(0) < 32 ||
247
+ character.charCodeAt(0) === 127,
248
+ )
249
+ )
250
+ }
251
+
252
+ // Server-function boundaries expose plain objects with registered public codes.
253
+ // Deliberate plugin refusals may attach public text; ordinary exceptions never do.
254
+ export class PublicError extends Error {
255
+ readonly code: PublicErrorCode
256
+ readonly policy?: { message: string; recoveryUrl?: string }
257
+ readonly reloadUrl?: string
258
+ constructor(
259
+ code: PublicErrorCode,
260
+ reloadUrl?: string,
261
+ policy?: { message: string; recoveryUrl?: string },
262
+ ) {
263
+ super(publicErrorMessages[code])
264
+ this.name = 'PublicError'
265
+ this.code = code
266
+ if (
267
+ (code === 'WORKSPACE_RESTRICTED' || code === 'WORKSPACE_LIMIT_REACHED') &&
268
+ policy &&
269
+ typeof policy.message === 'string' &&
270
+ policy.message.length > 0 &&
271
+ policy.message.length <= 400
272
+ ) {
273
+ const recoveryUrl = policy.recoveryUrl
274
+ this.policy = {
275
+ message: policy.message,
276
+ ...(isSafeLocalUrl(recoveryUrl) ? { recoveryUrl } : {}),
277
+ }
278
+ this.message = policy.message
279
+ }
280
+ if (isSafeLocalUrl(reloadUrl)) this.reloadUrl = reloadUrl
281
+ }
282
+ }
283
+
284
+ export function getPublicErrorMessage(error: unknown, fallback: string) {
285
+ if (error && typeof error === 'object') {
286
+ const candidate = error as {
287
+ code?: unknown
288
+ name?: unknown
289
+ status?: unknown
290
+ statusCode?: unknown
291
+ message?: unknown
292
+ policy?: { message?: unknown }
293
+ }
294
+ if (candidate.status === 429 || candidate.statusCode === 429)
295
+ return 'Too many attempts. Please wait a moment and try again.'
296
+ if (
297
+ candidate.name === 'PublicError' &&
298
+ typeof candidate.code === 'string' &&
299
+ Object.hasOwn(publicErrorMessages, candidate.code)
300
+ ) {
301
+ if (
302
+ (candidate.code === 'WORKSPACE_RESTRICTED' ||
303
+ candidate.code === 'WORKSPACE_LIMIT_REACHED') &&
304
+ typeof candidate.policy?.message === 'string' &&
305
+ candidate.policy.message.length <= 400
306
+ )
307
+ return candidate.policy.message
308
+ return candidate.code === 'INTERNAL_ERROR'
309
+ ? fallback
310
+ : publicErrorMessages[candidate.code as PublicErrorCode]
311
+ }
312
+ if (
313
+ typeof candidate.message === 'string' &&
314
+ /^(failed to fetch|fetch failed|load failed|networkerror\b|network request failed)/i.test(
315
+ candidate.message,
316
+ )
317
+ )
318
+ return 'Unable to connect. Check your connection and try again.'
319
+ }
320
+ return fallback
321
+ }
322
+
323
+ export function getPolicyRecoveryUrl(error: unknown): string | undefined {
324
+ if (
325
+ !error ||
326
+ typeof error !== 'object' ||
327
+ !('code' in error) ||
328
+ !['WORKSPACE_RESTRICTED', 'WORKSPACE_LIMIT_REACHED'].includes(
329
+ String(error.code),
330
+ ) ||
331
+ !('policy' in error)
332
+ )
333
+ return
334
+ const url = (error.policy as { recoveryUrl?: unknown } | undefined)
335
+ ?.recoveryUrl
336
+ return isSafeLocalUrl(url) ? url : undefined
337
+ }
@@ -0,0 +1,13 @@
1
+ import { QueryClient } from '@tanstack/react-query'
2
+
3
+ export function createQueryClient() {
4
+ return new QueryClient({
5
+ defaultOptions: {
6
+ queries: {
7
+ retry: false,
8
+ staleTime: 30_000,
9
+ refetchOnWindowFocus: false,
10
+ },
11
+ },
12
+ })
13
+ }
@@ -0,0 +1,11 @@
1
+ import { queryOptions } from '@tanstack/react-query'
2
+
3
+ import { getRepositorySelectionContext } from '#devpush/server/projects/functions'
4
+
5
+ export function repositorySelectionQueryOptions(teamSlug: string) {
6
+ return queryOptions({
7
+ queryKey: ['repository-selection', teamSlug],
8
+ queryFn: () => getRepositorySelectionContext({ data: { teamSlug } }),
9
+ staleTime: 30_000,
10
+ })
11
+ }
@@ -0,0 +1,30 @@
1
+ import type { QueryClient } from '@tanstack/react-query'
2
+
3
+ const resourceFamilies = new Set([
4
+ 'team-context',
5
+ 'server-context',
6
+ 'server-metrics',
7
+ 'manual-deploy-options',
8
+ 'operation-logs',
9
+ 'repository-selection',
10
+ 'project-context',
11
+ 'project-logs',
12
+ 'deployment-context',
13
+ 'deployment-logs',
14
+ 'current-user-context',
15
+ ])
16
+
17
+ // Mutation responses and navigation must not reuse pre-write snapshots. Mark
18
+ // inactive entries too; the next route loader fetches invalidated data on demand.
19
+ export async function invalidateResourceQueries(
20
+ queryClient: QueryClient,
21
+ teamSlug?: string,
22
+ ) {
23
+ const filters = {
24
+ predicate: ({ queryKey }: { queryKey: readonly unknown[] }) =>
25
+ resourceFamilies.has(String(queryKey[0])) &&
26
+ (teamSlug === undefined || queryKey[1] === teamSlug),
27
+ }
28
+ await queryClient.cancelQueries(filters)
29
+ await queryClient.invalidateQueries({ ...filters, refetchType: 'none' })
30
+ }
@@ -0,0 +1,19 @@
1
+ export function buildRuntimeId({
2
+ environmentId,
3
+ projectId,
4
+ }: {
5
+ environmentId: string
6
+ projectId: string
7
+ }) {
8
+ return `dp_${shortRuntimeId(projectId)}_${shortRuntimeId(environmentId)}`
9
+ }
10
+
11
+ function shortRuntimeId(value: string) {
12
+ const normalized = value.toLowerCase().replace(/[^a-z0-9]/g, '')
13
+
14
+ if (normalized.length >= 10) {
15
+ return normalized.slice(0, 10)
16
+ }
17
+
18
+ return normalized.padEnd(10, '0')
19
+ }
@@ -0,0 +1,14 @@
1
+ export function stringSearchValidator<const TKey extends string>(
2
+ keys: ReadonlyArray<TKey>,
3
+ ) {
4
+ return (search: Record<string, unknown>): Partial<Record<TKey, string>> => {
5
+ const result: Partial<Record<TKey, string>> = {}
6
+
7
+ for (const key of keys) {
8
+ const value = search[key]
9
+ if (typeof value === 'string') result[key] = value
10
+ }
11
+
12
+ return result
13
+ }
14
+ }
@@ -0,0 +1,43 @@
1
+ import { workspacePollInterval } from './workspace-updates'
2
+ import { queryOptions } from '@tanstack/react-query'
3
+ import { redirect } from '@tanstack/react-router'
4
+
5
+ import {
6
+ getTeamServerContext,
7
+ getTeamServerMetricHistory,
8
+ } from '#devpush/server/servers/functions'
9
+
10
+ export function serverContextQueryOptions(params: {
11
+ serverId: string
12
+ teamSlug: string
13
+ }) {
14
+ return queryOptions({
15
+ queryKey: ['server-context', params.teamSlug, params.serverId],
16
+ refetchInterval: () => workspacePollInterval(params.teamSlug, 5_000),
17
+ refetchIntervalInBackground: false,
18
+ refetchOnWindowFocus: 'always',
19
+ queryFn: async () => {
20
+ const context = await getTeamServerContext({ data: params })
21
+ if (!context) throw redirect({ to: '/auth/login' })
22
+ return context
23
+ },
24
+ })
25
+ }
26
+
27
+ export function serverMetricHistoryQueryOptions(params: {
28
+ serverId: string
29
+ teamSlug: string
30
+ }) {
31
+ return queryOptions({
32
+ queryKey: ['server-metrics', params.teamSlug, params.serverId],
33
+ staleTime: 30_000,
34
+ refetchInterval: () => workspacePollInterval(params.teamSlug, 30_000),
35
+ refetchIntervalInBackground: false,
36
+ refetchOnWindowFocus: true,
37
+ queryFn: async () => {
38
+ const history = await getTeamServerMetricHistory({ data: params })
39
+ if (!history) throw redirect({ to: '/auth/login' })
40
+ return history
41
+ },
42
+ })
43
+ }
@@ -0,0 +1,11 @@
1
+ import { z } from 'zod'
2
+
3
+ export const serverNameSchema = z
4
+ .string()
5
+ .trim()
6
+ .min(2, 'Enter a server name with at least 2 characters.')
7
+ .max(100, 'Server names must be 100 characters or fewer.')
8
+ .regex(
9
+ /^[A-Za-z0-9][A-Za-z0-9._-]*[A-Za-z0-9]$/,
10
+ 'Use letters, numbers, dots, underscores, or hyphens. Start and end with a letter or number.',
11
+ )
@@ -0,0 +1,45 @@
1
+ import { toast } from 'sonner'
2
+
3
+ /** Keep the draft intact until the user explicitly chooses to reload. */
4
+ export function showSettingsConflict(error: unknown): boolean {
5
+ if (
6
+ !error ||
7
+ typeof error !== 'object' ||
8
+ !('code' in error) ||
9
+ error.code !== 'SETTINGS_CONFLICT'
10
+ )
11
+ return false
12
+ toast.error('Your changes weren’t saved.', {
13
+ id: 'settings-conflict',
14
+ description:
15
+ 'Settings have changed since you started editing. Reload to load the latest settings.',
16
+ duration: Infinity,
17
+ closeButton: false,
18
+ className: 'settings-conflict-toast',
19
+ cancel: {
20
+ label: 'Dismiss',
21
+ onClick: () => toast.dismiss('settings-conflict'),
22
+ },
23
+ action: {
24
+ label: 'Reload',
25
+ onClick: () => {
26
+ if (
27
+ window.confirm('Reload and discard all unsaved changes on this page?')
28
+ )
29
+ if (
30
+ 'reloadUrl' in error &&
31
+ typeof error.reloadUrl === 'string' &&
32
+ error.reloadUrl.startsWith('/') &&
33
+ !error.reloadUrl.startsWith('//') &&
34
+ !error.reloadUrl.includes('\\') &&
35
+ !error.reloadUrl.includes('\r') &&
36
+ !error.reloadUrl.includes('\n')
37
+ )
38
+ window.location.assign(error.reloadUrl)
39
+ else window.location.reload()
40
+ else showSettingsConflict(error)
41
+ },
42
+ },
43
+ })
44
+ return true
45
+ }
@@ -0,0 +1,7 @@
1
+ import { z } from 'zod'
2
+
3
+ export const settingsVersionSchema = z
4
+ .number()
5
+ .int()
6
+ .min(1)
7
+ .max(Number.MAX_SAFE_INTEGER)