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,565 @@
1
+ export const AGENT_INSTALL_SCRIPT = `#!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ if [ -t 1 ] && [ -z "\${NO_COLOR:-}" ]; then
5
+ BOLD='\\033[1m'
6
+ DIM='\\033[2m'
7
+ GREEN='\\033[32m'
8
+ YELLOW='\\033[33m'
9
+ RED='\\033[31m'
10
+ CYAN_1='\\033[38;5;51m'
11
+ CYAN_2='\\033[38;5;87m'
12
+ CYAN_3='\\033[38;5;123m'
13
+ CYAN_4='\\033[38;5;159m'
14
+ CYAN_5='\\033[38;5;195m'
15
+ CYAN_6='\\033[38;5;225m'
16
+ RESET='\\033[0m'
17
+ else
18
+ BOLD=''
19
+ DIM=''
20
+ GREEN=''
21
+ YELLOW=''
22
+ RED=''
23
+ CYAN_1=''
24
+ CYAN_2=''
25
+ CYAN_3=''
26
+ CYAN_4=''
27
+ CYAN_5=''
28
+ CYAN_6=''
29
+ RESET=''
30
+ fi
31
+
32
+ info() { printf " %b::%b %s\n" "\${BOLD}" "\${RESET}" "$1"; }
33
+ ok() { printf " %bOK%b %s\n" "\${GREEN}" "\${RESET}" "$1"; }
34
+ warn() { printf " %b!!%b %s\n" "\${YELLOW}" "\${RESET}" "$1" >&2; }
35
+ fail() {
36
+ printf "\n %bERROR%b %s\n" "\${RED}" "\${RESET}" "$1" >&2
37
+ if [ -n "\${INSTALL_LOG:-}" ]; then
38
+ printf " Log: %s\n" "\${INSTALL_LOG}" >&2
39
+ fi
40
+ exit 1
41
+ }
42
+
43
+ printf '\n'
44
+ printf '%b%s%b\n' "\${CYAN_1}" ' ██╗██████╗ ███████╗██╗ ██╗ ██╗██████╗ ██╗ ██╗███████╗██╗ ██╗' "\${RESET}"
45
+ printf '%b%s%b\n' "\${CYAN_2}" ' ██╔╝██╔══██╗██╔════╝██║ ██║ ██╔╝██╔══██╗██║ ██║██╔════╝██║ ██║' "\${RESET}"
46
+ printf '%b%s%b\n' "\${CYAN_3}" ' ██╔╝ ██║ ██║█████╗ ██║ ██║ ██╔╝ ██████╔╝██║ ██║███████╗███████║' "\${RESET}"
47
+ printf '%b%s%b\n' "\${CYAN_4}" ' ██╔╝ ██║ ██║██╔══╝ ╚██╗ ██╔╝██╔╝ ██╔═══╝ ██║ ██║╚════██║██╔══██║' "\${RESET}"
48
+ printf '%b%s%b\n' "\${CYAN_5}" '██╔╝ ██████╔╝███████╗ ╚████╔╝██╔╝ ██║ ╚██████╔╝███████║██║ ██║' "\${RESET}"
49
+ printf '%b%s%b\n' "\${CYAN_6}" '╚═╝ ╚═════╝ ╚══════╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝' "\${RESET}"
50
+ printf '\n'
51
+
52
+ ADDRESS="\${DEVPUSH_ROUTING_ADDRESS:-}"
53
+ ADDRESS_SET=false
54
+ if [ -n "\${ADDRESS}" ]; then ADDRESS_SET=true; fi
55
+ while [ "$#" -gt 0 ]; do
56
+ case "$1" in
57
+ --address)
58
+ [ "$#" -ge 2 ] || fail "--address requires an IP address or auto."
59
+ ADDRESS="$2"
60
+ ADDRESS_SET=true
61
+ shift 2
62
+ ;;
63
+ *) fail "Unknown option: $1. Use --address IP or --address auto." ;;
64
+ esac
65
+ done
66
+ if [ "\${ADDRESS}" = auto ]; then ADDRESS=""; fi
67
+ if [ -n "\${ADDRESS}" ] && [[ ! "\${ADDRESS}" =~ ^[0-9a-fA-F:.]+$ ]]; then
68
+ fail "--address requires an IPv4 or IPv6 address, without a port."
69
+ fi
70
+
71
+ if [ "$(id -u)" -ne 0 ]; then
72
+ fail "Run this installer with sudo."
73
+ fi
74
+
75
+ if [ -z "\${DEVPUSH_BASE_URL:-}" ]; then
76
+ fail "DEVPUSH_BASE_URL is required."
77
+ fi
78
+
79
+ if [ -z "\${DEVPUSH_AGENT_TOKEN:-}" ]; then
80
+ fail "DEVPUSH_AGENT_TOKEN is required."
81
+ fi
82
+
83
+ AGENT_USER="\${DEVPUSH_AGENT_USER:-devpush}"
84
+ INSTALL_ROOT="\${DEVPUSH_INSTALL_ROOT:-}"
85
+ BINARY_URL="\${DEVPUSH_AGENT_BINARY_URL:-}"
86
+ CHECKSUM_URL="\${DEVPUSH_AGENT_CHECKSUM_URL:-}"
87
+ AUTO_UPDATE="\${DEVPUSH_AGENT_AUTO_UPDATE:-false}"
88
+ DEFAULT_BINARY_URL=false
89
+
90
+ detect_os() {
91
+ case "$(uname -s)" in
92
+ Linux) printf "linux" ;;
93
+ *)
94
+ fail "Unsupported OS: $(uname -s). devpush agents currently require Linux."
95
+ ;;
96
+ esac
97
+ }
98
+
99
+ detect_arch() {
100
+ case "$(uname -m)" in
101
+ x86_64 | amd64) printf "amd64" ;;
102
+ aarch64 | arm64) printf "arm64" ;;
103
+ *)
104
+ fail "Unsupported CPU architecture: $(uname -m)"
105
+ ;;
106
+ esac
107
+ }
108
+
109
+ if [ -z "\${BINARY_URL}" ]; then
110
+ BINARY_OS="$(detect_os)"
111
+ BINARY_ARCH="$(detect_arch)"
112
+ BINARY_URL="\${DEVPUSH_BASE_URL%/}/api/install/agent/binary?os=\${BINARY_OS}&arch=\${BINARY_ARCH}"
113
+ CHECKSUM_URL="\${DEVPUSH_BASE_URL%/}/api/install/agent/checksum?os=\${BINARY_OS}&arch=\${BINARY_ARCH}"
114
+ DEFAULT_BINARY_URL=true
115
+ fi
116
+
117
+ BINARY_OS="\${BINARY_OS:-$(detect_os)}"
118
+ BINARY_ARCH="\${BINARY_ARCH:-$(detect_arch)}"
119
+
120
+ if [ -r /etc/os-release ]; then
121
+ . /etc/os-release
122
+ fi
123
+
124
+ DISTRO_ID="\${ID:-unknown}"
125
+ DISTRO_NAME="\${PRETTY_NAME:-\${NAME:-unknown Linux}}"
126
+ PACKAGE_MANAGER=none
127
+ if command -v apt-get >/dev/null 2>&1; then
128
+ PACKAGE_MANAGER=apt
129
+ elif command -v dnf >/dev/null 2>&1; then
130
+ PACKAGE_MANAGER=dnf
131
+ elif command -v yum >/dev/null 2>&1; then
132
+ PACKAGE_MANAGER=yum
133
+ fi
134
+
135
+ target_path() {
136
+ printf "%s%s" "\${INSTALL_ROOT}" "$1"
137
+ }
138
+
139
+ LOG_DIR="$(target_path /var/log/devpush-agent)"
140
+ INSTALL_LOG="\${LOG_DIR}/install-$(date -u +%Y%m%d-%H%M%S).log"
141
+ install -d -m 0700 "\${LOG_DIR}"
142
+ : >"\${INSTALL_LOG}"
143
+ chmod 0600 "\${INSTALL_LOG}"
144
+ ln -sfn "$(basename "\${INSTALL_LOG}")" "\${LOG_DIR}/latest.log"
145
+ exec > >(tee -a "\${INSTALL_LOG}") 2>&1
146
+
147
+ printf '%bInstallation summary%b\n\n' "\${BOLD}" "\${RESET}"
148
+ printf ' Host %s\n' "\${DISTRO_NAME}"
149
+ printf ' Architecture %s\n' "\${BINARY_ARCH}"
150
+ printf ' Control plane %s\n' "\${DEVPUSH_BASE_URL}"
151
+ printf ' Agent user %s\n' "\${AGENT_USER}"
152
+ printf ' Auto-update %s\n\n' "\${AUTO_UPDATE}"
153
+
154
+ install_agent_dir() {
155
+ local mode="$1"
156
+ local path="$2"
157
+
158
+ if [ -n "\${INSTALL_ROOT}" ]; then
159
+ install -d -m "\${mode}" "\${path}"
160
+ else
161
+ install -d -m "\${mode}" -o "\${AGENT_USER}" -g "\${AGENT_USER}" "\${path}"
162
+ fi
163
+ }
164
+
165
+ if ! command -v curl >/dev/null 2>&1; then
166
+ fail "curl is required to download and verify the agent."
167
+ fi
168
+
169
+ WORK_DIR="$(mktemp -d)"
170
+ STEP_LOG="\${WORK_DIR}/step.log"
171
+ CONFIG_DRAINED=false
172
+ cleanup_install() {
173
+ if [ "\${CONFIG_DRAINED}" = true ]; then
174
+ "$(target_path /usr/local/bin)/devpush-agent" maintenance resume >/dev/null 2>&1 || true
175
+ fi
176
+ rm -rf "\${WORK_DIR}"
177
+ }
178
+ trap cleanup_install EXIT
179
+
180
+ run_step() {
181
+ local message="$1"
182
+ shift
183
+ info "\${message}"
184
+ : >"\${STEP_LOG}"
185
+ if "$@" >"\${STEP_LOG}" 2>&1; then
186
+ cat "\${STEP_LOG}" >>"\${INSTALL_LOG}"
187
+ ok "\${message}"
188
+ return
189
+ fi
190
+
191
+ cat "\${STEP_LOG}" >>"\${INSTALL_LOG}"
192
+ tail -n 40 "\${STEP_LOG}" >&2 || true
193
+ fail "\${message} failed."
194
+ }
195
+
196
+ try_step() {
197
+ local message="$1"
198
+ shift
199
+ info "\${message}"
200
+ : >"\${STEP_LOG}"
201
+ if "$@" >"\${STEP_LOG}" 2>&1; then
202
+ cat "\${STEP_LOG}" >>"\${INSTALL_LOG}"
203
+ ok "\${message}"
204
+ return 0
205
+ fi
206
+ cat "\${STEP_LOG}" >>"\${INSTALL_LOG}"
207
+ return 1
208
+ }
209
+
210
+ install_packages() {
211
+ case "\${PACKAGE_MANAGER}" in
212
+ apt)
213
+ DEBIAN_FRONTEND=noninteractive apt-get update
214
+ DEBIAN_FRONTEND=noninteractive apt-get install -y "$@"
215
+ ;;
216
+ dnf) dnf install -y "$@" ;;
217
+ yum) yum install -y "$@" ;;
218
+ *) return 1 ;;
219
+ esac
220
+ }
221
+
222
+ install_docker() {
223
+ case "\${PACKAGE_MANAGER}" in
224
+ apt)
225
+ case "\${DISTRO_ID}" in
226
+ debian | ubuntu) ;;
227
+ *) return 1 ;;
228
+ esac
229
+ DEBIAN_FRONTEND=noninteractive apt-get update
230
+ DEBIAN_FRONTEND=noninteractive apt-get install -y ca-certificates curl
231
+ install -m 0755 -d /etc/apt/keyrings
232
+ curl -fsSL "https://download.docker.com/linux/\${DISTRO_ID}/gpg" -o /etc/apt/keyrings/docker.asc
233
+ chmod a+r /etc/apt/keyrings/docker.asc
234
+ . /etc/os-release
235
+ printf 'deb [arch=%s signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/%s %s stable\n' \
236
+ "$(dpkg --print-architecture)" "\${DISTRO_ID}" "\${VERSION_CODENAME}" \
237
+ >/etc/apt/sources.list.d/docker.list
238
+ DEBIAN_FRONTEND=noninteractive apt-get update
239
+ DEBIAN_FRONTEND=noninteractive apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
240
+ ;;
241
+ dnf)
242
+ local repo_family
243
+ case "\${DISTRO_ID}" in
244
+ fedora) repo_family=fedora ;;
245
+ centos | rhel | rocky | almalinux) repo_family=centos ;;
246
+ *) return 1 ;;
247
+ esac
248
+ dnf install -y dnf-plugins-core
249
+ dnf config-manager --add-repo "https://download.docker.com/linux/\${repo_family}/docker-ce.repo"
250
+ dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
251
+ ;;
252
+ yum)
253
+ local repo_family
254
+ case "\${DISTRO_ID}" in
255
+ centos | rhel) repo_family=centos ;;
256
+ *) return 1 ;;
257
+ esac
258
+ yum install -y yum-utils
259
+ yum-config-manager --add-repo "https://download.docker.com/linux/\${repo_family}/docker-ce.repo"
260
+ yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
261
+ ;;
262
+ *) return 1 ;;
263
+ esac
264
+ }
265
+
266
+ if ! command -v git >/dev/null 2>&1; then
267
+ if [ "\${PACKAGE_MANAGER}" = none ]; then
268
+ fail "Git is required. Install it and run this command again."
269
+ fi
270
+ run_step "Installing Git and CA certificates" install_packages git ca-certificates
271
+ else
272
+ ok "Git is available"
273
+ fi
274
+
275
+ if ! command -v docker >/dev/null 2>&1; then
276
+ run_step "Installing Docker Engine and Compose" install_docker
277
+ else
278
+ ok "Docker is available"
279
+ fi
280
+
281
+ if ! command -v systemctl >/dev/null 2>&1; then
282
+ fail "systemd is required to manage the devpush agent."
283
+ fi
284
+
285
+ run_step "Enabling Docker" systemctl enable --now docker
286
+
287
+ if ! docker compose version >/dev/null 2>&1; then
288
+ if [ "\${PACKAGE_MANAGER}" = none ]; then
289
+ fail "The Docker Compose plugin is required."
290
+ fi
291
+ run_step "Installing Docker Compose" install_packages docker-compose-plugin
292
+ fi
293
+
294
+ if ! docker compose version >/dev/null 2>&1; then
295
+ fail "The Docker Compose plugin is required. Install it and run this command again."
296
+ fi
297
+ ok "Docker Compose is available"
298
+
299
+ if ! command -v rclone >/dev/null 2>&1; then
300
+ if [ "\${PACKAGE_MANAGER}" != none ]; then
301
+ if ! try_step "Installing rclone for remote backups" install_packages rclone; then
302
+ warn "rclone could not be installed; remote backups will remain unavailable."
303
+ fi
304
+ fi
305
+ fi
306
+
307
+ if ! command -v rclone >/dev/null 2>&1; then
308
+ warn "rclone is unavailable; install it before enabling remote backups."
309
+ else
310
+ ok "rclone is available"
311
+ fi
312
+
313
+ if [ -z "\${INSTALL_ROOT}" ] && ! id -u "\${AGENT_USER}" >/dev/null 2>&1; then
314
+ useradd --system --create-home --home-dir /var/lib/devpush-agent --shell /usr/sbin/nologin "\${AGENT_USER}"
315
+ fi
316
+
317
+ if getent group docker >/dev/null 2>&1; then
318
+ if [ -z "\${INSTALL_ROOT}" ]; then
319
+ usermod -aG docker "\${AGENT_USER}"
320
+ fi
321
+ SUPPLEMENTARY_GROUPS="SupplementaryGroups=docker"
322
+ else
323
+ SUPPLEMENTARY_GROUPS=""
324
+ fi
325
+
326
+ ETC_DIR="$(target_path /etc/devpush)"
327
+ STATE_DIR="$(target_path /var/lib/devpush-agent)"
328
+ BIN_DIR="$(target_path /usr/local/bin)"
329
+ SYSTEMD_DIR="$(target_path /etc/systemd/system)"
330
+ LIB_DIR="$(target_path /usr/local/lib/devpush)"
331
+
332
+ install -d -m 0755 "\${ETC_DIR}"
333
+ install_agent_dir 0750 "\${STATE_DIR}"
334
+ install -d -m 0755 "\${BIN_DIR}"
335
+ install -d -m 0755 "\${SYSTEMD_DIR}"
336
+ install -d -m 0755 "\${LIB_DIR}"
337
+
338
+ binary_name="devpush-agent-\${BINARY_OS}-\${BINARY_ARCH}"
339
+ tmp_binary="\${WORK_DIR}/\${binary_name}"
340
+ run_step "Downloading devpush agent" curl -fsSL "\${BINARY_URL}" -o "\${tmp_binary}"
341
+
342
+ if [ -n "\${CHECKSUM_URL}" ]; then
343
+ if ! command -v sha256sum >/dev/null 2>&1; then
344
+ fail "sha256sum is required to verify the agent binary."
345
+ fi
346
+ run_step "Downloading agent checksum" curl -fsSL "\${CHECKSUM_URL}" -o "\${WORK_DIR}/checksum"
347
+ run_step "Verifying agent checksum" bash -c 'cd "$1" && sha256sum -c checksum' _ "\${WORK_DIR}"
348
+ elif [ "\${DEFAULT_BINARY_URL}" = true ]; then
349
+ fail "The control plane did not provide an agent checksum URL."
350
+ else
351
+ warn "A custom binary URL was supplied without DEVPUSH_AGENT_CHECKSUM_URL; its checksum was not verified."
352
+ fi
353
+
354
+ if [ "\${ADDRESS_SET}" = false ] && [ -f "\${ETC_DIR}/agent.env" ]; then
355
+ ADDRESS="$(sed -n 's/^DEVPUSH_ROUTING_ADDRESS="\\(.*\\)"$/\\1/p' "\${ETC_DIR}/agent.env")"
356
+ fi
357
+ if [ -z "\${DEVPUSH_TRAEFIK_EMAIL+x}" ] && [ -f "\${ETC_DIR}/agent.env" ]; then
358
+ DEVPUSH_TRAEFIK_EMAIL="$(sed -n 's/^DEVPUSH_TRAEFIK_EMAIL="\\(.*\\)"$/\\1/p' "\${ETC_DIR}/agent.env")"
359
+ fi
360
+ chmod 0755 "\${tmp_binary}"
361
+ run_step "Validating agent configuration" env DEVPUSH_ROUTING_ADDRESS="\${ADDRESS}" "\${tmp_binary}" --check-config --config /dev/null
362
+
363
+ if [ -f "\${ETC_DIR}/agent.env" ] && [ -x "\${BIN_DIR}/devpush-agent" ]; then
364
+ previous_base="$(sed -n 's/^DEVPUSH_BASE_URL="\\(.*\\)"$/\\1/p' "\${ETC_DIR}/agent.env")"
365
+ if [ "\${previous_base%/}" != "\${DEVPUSH_BASE_URL%/}" ]; then
366
+ fail "Use devpush-agent maintenance switch to change control planes safely."
367
+ fi
368
+ if systemctl is-active --quiet devpush-agent; then
369
+ # The existing process drains jobs before an atomic binary replacement.
370
+ run_step "Safely updating devpush agent" "\${BIN_DIR}/devpush-agent" maintenance update --binary "\${tmp_binary}"
371
+ run_step "Draining agent before configuration changes" "\${BIN_DIR}/devpush-agent" maintenance drain
372
+ CONFIG_DRAINED=true
373
+ elif ! cmp -s "\${tmp_binary}" "\${BIN_DIR}/devpush-agent"; then
374
+ install -m 0755 "\${tmp_binary}" "\${BIN_DIR}/devpush-agent.new"
375
+ mv "\${BIN_DIR}/devpush-agent.new" "\${BIN_DIR}/devpush-agent"
376
+ fi
377
+ previous_token="$(sed -n 's/^DEVPUSH_AGENT_TOKEN="\\(.*\\)"$/\\1/p' "\${ETC_DIR}/agent.env")"
378
+ if [ -n "\${previous_token}" ]; then DEVPUSH_AGENT_TOKEN="\${previous_token}"; fi
379
+ else
380
+ install -m 0755 "\${tmp_binary}" "\${BIN_DIR}/devpush-agent"
381
+ fi
382
+ AGENT_VERSION="$("\${BIN_DIR}/devpush-agent" version 2>/dev/null || printf unknown)"
383
+ ok "Installed \${AGENT_VERSION}"
384
+
385
+ cat >"\${ETC_DIR}/agent.env" <<EOF
386
+ DEVPUSH_BASE_URL="\${DEVPUSH_BASE_URL}"
387
+ DEVPUSH_AGENT_TOKEN="\${DEVPUSH_AGENT_TOKEN}"
388
+ DEVPUSH_STATE_DIR="\${STATE_DIR}"
389
+ DEVPUSH_ROUTING_ADDRESS="\${ADDRESS}"
390
+ EOF
391
+
392
+ if [ -n "\${DEVPUSH_TRAEFIK_EMAIL:-}" ]; then
393
+ printf 'DEVPUSH_TRAEFIK_EMAIL="%s"\\n' "\${DEVPUSH_TRAEFIK_EMAIL}" >>"\${ETC_DIR}/agent.env"
394
+ fi
395
+
396
+ if [ -z "\${INSTALL_ROOT}" ]; then
397
+ chown root:"\${AGENT_USER}" "\${ETC_DIR}/agent.env"
398
+ fi
399
+ chmod 0640 "\${ETC_DIR}/agent.env"
400
+
401
+ cat >"\${LIB_DIR}/update-agent" <<'EOF'
402
+ #!/usr/bin/env bash
403
+ set -euo pipefail
404
+
405
+ DEVPUSH_BASE_URL="$(sed -n 's/^DEVPUSH_BASE_URL="\\(.*\\)"$/\\1/p' /etc/devpush/agent.env)"
406
+ if [ -z "\${DEVPUSH_BASE_URL}" ]; then
407
+ echo "Agent control-plane URL is missing." >&2
408
+ exit 1
409
+ fi
410
+
411
+ case "$(uname -s)" in Linux) os=linux ;; *) echo "Unsupported OS." >&2; exit 1 ;; esac
412
+ case "$(uname -m)" in x86_64|amd64) arch=amd64 ;; aarch64|arm64) arch=arm64 ;; *) echo "Unsupported architecture." >&2; exit 1 ;; esac
413
+ base="\${DEVPUSH_BASE_URL%/}/api/install/agent"
414
+ tmp="$(mktemp -d)"
415
+ trap 'rm -rf "\${tmp}"' EXIT
416
+ echo "Downloading devpush agent..."
417
+ curl -fsSL "\${base}/binary?os=\${os}&arch=\${arch}" -o "\${tmp}/devpush-agent-linux-\${arch}"
418
+ curl -fsSL "\${base}/checksum?os=\${os}&arch=\${arch}" -o "\${tmp}/checksum"
419
+ echo "Verifying downloaded binary..."
420
+ (cd "\${tmp}" && sha256sum -c checksum)
421
+ if cmp -s "\${tmp}/devpush-agent-linux-\${arch}" /usr/local/bin/devpush-agent; then
422
+ echo "devpush agent is already current."
423
+ exit 0
424
+ fi
425
+ /usr/local/bin/devpush-agent maintenance update --binary "\${tmp}/devpush-agent-linux-\${arch}"
426
+ echo "devpush agent updated."
427
+ EOF
428
+ chmod 0755 "\${LIB_DIR}/update-agent"
429
+
430
+ cat >"\${SYSTEMD_DIR}/devpush-agent.service" <<EOF
431
+ [Unit]
432
+ Description=devpush agent
433
+ After=network-online.target docker.service
434
+ Wants=network-online.target docker.service
435
+
436
+ [Service]
437
+ User=\${AGENT_USER}
438
+ Group=\${AGENT_USER}
439
+ \${SUPPLEMENTARY_GROUPS}
440
+ EnvironmentFile=\${ETC_DIR}/agent.env
441
+ ExecStart=\${BIN_DIR}/devpush-agent
442
+ Restart=always
443
+ RestartSec=5
444
+
445
+ [Install]
446
+ WantedBy=multi-user.target
447
+ EOF
448
+
449
+ cat >"\${SYSTEMD_DIR}/devpush-agent-update.service" <<EOF
450
+ [Unit]
451
+ Description=Update devpush agent
452
+ After=network-online.target
453
+ Wants=network-online.target
454
+
455
+ [Service]
456
+ Type=oneshot
457
+ ExecStart=\${LIB_DIR}/update-agent
458
+ EOF
459
+
460
+ cat >"\${SYSTEMD_DIR}/devpush-agent-update.timer" <<EOF
461
+ [Unit]
462
+ Description=Check for devpush agent updates daily
463
+
464
+ [Timer]
465
+ OnCalendar=daily
466
+ RandomizedDelaySec=1h
467
+ Persistent=true
468
+
469
+ [Install]
470
+ WantedBy=timers.target
471
+ EOF
472
+
473
+ run_step "Registering the systemd service" systemctl daemon-reload
474
+ run_step "Enabling the devpush agent" systemctl enable devpush-agent
475
+ run_step "Starting the devpush agent" systemctl restart devpush-agent
476
+
477
+ if [ "\${AUTO_UPDATE}" = "true" ]; then
478
+ systemctl enable --now devpush-agent-update.timer
479
+ else
480
+ systemctl disable --now devpush-agent-update.timer >/dev/null 2>&1 || true
481
+ fi
482
+
483
+ if command -v ss >/dev/null 2>&1; then
484
+ for port in 80 443; do
485
+ if ss -H -ltn "sport = :\${port}" 2>/dev/null | grep -q .; then
486
+ warn "Port \${port} is already in use. Public deployments require ports 80 and 443 for managed Traefik."
487
+ fi
488
+ done
489
+ fi
490
+
491
+ if command -v ufw >/dev/null 2>&1 && ufw status 2>/dev/null | grep -q '^Status: active'; then
492
+ for port in 80 443; do
493
+ if ! ufw status 2>/dev/null | grep -Eq "^\${port}(/tcp)?[[:space:]]+ALLOW"; then
494
+ warn "UFW is active and does not show an allow rule for TCP port \${port}."
495
+ fi
496
+ done
497
+ elif command -v firewall-cmd >/dev/null 2>&1 && firewall-cmd --state >/dev/null 2>&1; then
498
+ for port in 80 443; do
499
+ if ! firewall-cmd --quiet --query-port="\${port}/tcp"; then
500
+ warn "firewalld is active and does not allow TCP port \${port} in its default zone."
501
+ fi
502
+ done
503
+ fi
504
+
505
+ printf '\n%b%s%b\n' "\${GREEN}" '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' "\${RESET}"
506
+ printf '%b devpush agent installation complete%b\n' "\${BOLD}\${GREEN}" "\${RESET}"
507
+ printf '%b%s%b\n\n' "\${GREEN}" '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' "\${RESET}"
508
+ printf ' Agent %s\n' "\${AGENT_VERSION}"
509
+ printf ' Service %s\n' "$(systemctl is-active devpush-agent 2>/dev/null || printf unknown)"
510
+ printf ' Config %s\n' "\${ETC_DIR}/agent.env"
511
+ printf ' State %s\n' "\${STATE_DIR}"
512
+ printf ' Auto-update %s\n' "\${AUTO_UPDATE}"
513
+ printf ' Install log %s\n' "\${INSTALL_LOG}"
514
+ printf '\n%bUseful commands%b\n\n' "\${BOLD}" "\${RESET}"
515
+ printf ' Status sudo systemctl status devpush-agent\n'
516
+ printf ' Logs sudo journalctl -u devpush-agent -f\n'
517
+ printf ' Restart sudo systemctl restart devpush-agent\n'
518
+ printf ' Stop sudo systemctl stop devpush-agent\n'
519
+ printf ' Update sudo %s/update-agent\n' "\${LIB_DIR}"
520
+ printf ' Rotate key sudo %s/devpush-agent credential rotate\n' "\${BIN_DIR}"
521
+ printf '\n%bNext steps%b\n\n' "\${BOLD}" "\${RESET}"
522
+ printf ' 1. Wait for this server to show as connected in devpush.\n'
523
+ printf ' 2. Allow inbound TCP ports 80 and 443 in the host and provider firewall.\n'
524
+ printf ' 3. Deploy a project; devpush will start managed Traefik when a public route is needed.\n\n'
525
+ printf '%b%s%b\n\n' "\${GREEN}" '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' "\${RESET}"
526
+ `
527
+
528
+ export function isAgentEnrollmentToken(token: string) {
529
+ return /^dps_[A-Za-z0-9_-]{43}$/.test(token)
530
+ }
531
+
532
+ export function buildTokenizedAgentInstallScript({
533
+ autoUpdate,
534
+ baseUrl,
535
+ token,
536
+ traefikEmail,
537
+ }: {
538
+ autoUpdate: boolean
539
+ baseUrl: string
540
+ token: string
541
+ traefikEmail?: string
542
+ }) {
543
+ if (!isAgentEnrollmentToken(token)) {
544
+ throw new Error('Invalid agent enrollment token.')
545
+ }
546
+ const lines = [
547
+ '#!/usr/bin/env bash',
548
+ `export DEVPUSH_BASE_URL=${shellQuote(baseUrl)}`,
549
+ `export DEVPUSH_AGENT_TOKEN=${shellQuote(token)}`,
550
+ `export DEVPUSH_AGENT_AUTO_UPDATE=${shellQuote(String(autoUpdate))}`,
551
+ ]
552
+
553
+ if (traefikEmail) {
554
+ lines.push(`export DEVPUSH_TRAEFIK_EMAIL=${shellQuote(traefikEmail)}`)
555
+ }
556
+
557
+ return `${lines.join('\n')}\n${AGENT_INSTALL_SCRIPT.replace(
558
+ /^#!\/usr\/bin\/env bash\n/,
559
+ '',
560
+ )}`
561
+ }
562
+
563
+ function shellQuote(value: string) {
564
+ return `'${value.replaceAll("'", "'\\''")}'`
565
+ }
@@ -0,0 +1,65 @@
1
+ import { createHash } from 'node:crypto'
2
+ import type {
3
+ AgentRelease,
4
+ AgentReleaseAsset,
5
+ } from '#devpush/lib/agent-release.mjs'
6
+
7
+ type ReleaseSource = {
8
+ release: AgentRelease
9
+ asset: AgentReleaseAsset
10
+ fetcher?: typeof fetch
11
+ }
12
+
13
+ function verify(body: Buffer, asset: AgentReleaseAsset) {
14
+ if (
15
+ body.length !== asset.size ||
16
+ createHash('sha256').update(body).digest('hex') !== asset.sha256
17
+ )
18
+ throw new Error(`Agent release integrity check failed: ${asset.filename}`)
19
+ return body
20
+ }
21
+
22
+ export async function readReleasedAgentBinary({
23
+ release,
24
+ asset,
25
+ fetcher = fetch,
26
+ }: ReleaseSource) {
27
+ const response = await fetcher(asset.url, {
28
+ signal: AbortSignal.timeout(30_000),
29
+ })
30
+ if (!response.ok || !response.body)
31
+ throw new Error(
32
+ `Pinned agent release ${release.version} is unavailable (${response.status}).`,
33
+ )
34
+ const reader = response.body.getReader()
35
+ const chunks: Uint8Array[] = []
36
+ let size = 0
37
+ try {
38
+ for (;;) {
39
+ const chunk = await reader.read()
40
+ if (chunk.done) break
41
+ size += chunk.value.byteLength
42
+ if (size > asset.size) {
43
+ await reader.cancel()
44
+ throw new Error('Agent release exceeds its pinned size.')
45
+ }
46
+ chunks.push(chunk.value)
47
+ }
48
+ } finally {
49
+ reader.releaseLock()
50
+ }
51
+ const body = verify(Buffer.concat(chunks), asset)
52
+ return body
53
+ }
54
+
55
+ export async function releasedAgentIsAvailable({
56
+ asset,
57
+ fetcher = fetch,
58
+ }: ReleaseSource) {
59
+ const response = await fetcher(asset.url, {
60
+ method: 'HEAD',
61
+ signal: AbortSignal.timeout(8000),
62
+ })
63
+ const size = response.headers.get('content-length')
64
+ return response.ok && (size === null || Number(size) === asset.size)
65
+ }