@stacksjs/ts-cloud 0.7.55 → 0.7.57

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 (467) hide show
  1. package/dist/alerts/alerts.test.d.ts +1 -0
  2. package/dist/alerts/delivery.d.ts +45 -0
  3. package/dist/alerts/evaluator.d.ts +12 -0
  4. package/dist/alerts/health.d.ts +34 -0
  5. package/dist/alerts/index.d.ts +6 -0
  6. package/dist/alerts/model.d.ts +170 -0
  7. package/dist/alerts/store.d.ts +90 -0
  8. package/dist/alerts/telemetry.d.ts +3 -0
  9. package/dist/api/client.d.ts +197 -0
  10. package/dist/api/handler.d.ts +18 -0
  11. package/dist/api/handler.test.d.ts +1 -0
  12. package/dist/api/index.d.ts +6 -0
  13. package/dist/api/openapi.d.ts +2 -0
  14. package/dist/api/service.d.ts +28 -0
  15. package/dist/api/types.d.ts +119 -0
  16. package/dist/auth/encryption.d.ts +3 -0
  17. package/dist/auth/index.d.ts +8 -0
  18. package/dist/auth/mailer.d.ts +9 -0
  19. package/dist/auth/oidc.d.ts +36 -0
  20. package/dist/auth/oidc.test.d.ts +1 -0
  21. package/dist/auth/store.d.ts +121 -0
  22. package/dist/auth/store.test.d.ts +1 -0
  23. package/dist/auth/totp.d.ts +11 -0
  24. package/dist/auth/totp.test.d.ts +1 -0
  25. package/dist/auth/types.d.ts +138 -0
  26. package/dist/automation/index.d.ts +2 -0
  27. package/dist/automation/store.d.ts +46 -0
  28. package/dist/automation/store.test.d.ts +1 -0
  29. package/dist/automation/types.d.ts +66 -0
  30. package/dist/aws/acm.d.ts +0 -4
  31. package/dist/aws/application-autoscaling.d.ts +0 -5
  32. package/dist/aws/backup.d.ts +42 -0
  33. package/dist/aws/bedrock.d.ts +0 -5
  34. package/dist/aws/client.d.ts +3 -6
  35. package/dist/aws/cloudformation.d.ts +0 -4
  36. package/dist/aws/cloudfront-media.test.d.ts +1 -0
  37. package/dist/aws/cloudfront-origin.test.d.ts +1 -0
  38. package/dist/aws/cloudfront.d.ts +87 -3
  39. package/dist/aws/cloudwatch-logs.d.ts +2 -4
  40. package/dist/aws/cloudwatch.d.ts +1 -1
  41. package/dist/aws/comprehend.d.ts +0 -5
  42. package/dist/aws/connect.d.ts +0 -4
  43. package/dist/aws/cost-explorer-cache.d.ts +1 -15
  44. package/dist/aws/cost-explorer.d.ts +18 -9
  45. package/dist/aws/cost-explorer.test.d.ts +1 -0
  46. package/dist/aws/dynamodb.d.ts +0 -4
  47. package/dist/aws/ec2.d.ts +0 -4
  48. package/dist/aws/ecr.d.ts +0 -4
  49. package/dist/aws/ecs.d.ts +17 -7
  50. package/dist/aws/efs.d.ts +0 -4
  51. package/dist/aws/elasticache.d.ts +0 -4
  52. package/dist/aws/elbv2.d.ts +0 -7
  53. package/dist/aws/email.d.ts +0 -10
  54. package/dist/aws/eventbridge.d.ts +0 -4
  55. package/dist/aws/iam.d.ts +1 -5
  56. package/dist/aws/imap-server.d.ts +0 -7
  57. package/dist/aws/index.d.ts +4 -3
  58. package/dist/aws/index.js +31 -31
  59. package/dist/aws/kendra.d.ts +0 -5
  60. package/dist/aws/lambda.d.ts +3 -5
  61. package/dist/aws/opensearch.d.ts +0 -4
  62. package/dist/aws/personalize.d.ts +0 -5
  63. package/dist/aws/polly.d.ts +0 -5
  64. package/dist/aws/rds.d.ts +59 -4
  65. package/dist/aws/rekognition.d.ts +0 -5
  66. package/dist/aws/route53-domains.d.ts +0 -4
  67. package/dist/aws/route53.d.ts +0 -4
  68. package/dist/aws/s3.d.ts +10 -6
  69. package/dist/aws/scheduler.d.ts +0 -4
  70. package/dist/aws/secrets-manager.d.ts +0 -4
  71. package/dist/aws/setup-sms.d.ts +0 -14
  72. package/dist/aws/sms.d.ts +0 -10
  73. package/dist/aws/smtp-server.d.ts +0 -11
  74. package/dist/aws/sns.d.ts +0 -4
  75. package/dist/aws/sqs.d.ts +0 -4
  76. package/dist/aws/ssm.d.ts +0 -4
  77. package/dist/aws/sts.d.ts +0 -4
  78. package/dist/aws/support.d.ts +0 -4
  79. package/dist/aws/textract.d.ts +0 -5
  80. package/dist/aws/transcribe.d.ts +0 -4
  81. package/dist/aws/translate.d.ts +0 -5
  82. package/dist/aws/voice.d.ts +0 -11
  83. package/dist/aws/xray.d.ts +1 -0
  84. package/dist/backups/aws-database-source.d.ts +19 -0
  85. package/dist/backups/aws-database-source.test.d.ts +1 -0
  86. package/dist/backups/aws-infrastructure-source.d.ts +43 -0
  87. package/dist/backups/aws-infrastructure-source.test.d.ts +1 -0
  88. package/dist/backups/control-plane-source.d.ts +16 -0
  89. package/dist/backups/control-plane-source.test.d.ts +1 -0
  90. package/dist/backups/docker-volume-source.d.ts +31 -0
  91. package/dist/backups/docker-volume-source.test.d.ts +1 -0
  92. package/dist/backups/filesystem-source.d.ts +34 -0
  93. package/dist/backups/filesystem-source.test.d.ts +1 -0
  94. package/dist/backups/index.d.ts +10 -0
  95. package/dist/backups/logical-database-source.d.ts +16 -0
  96. package/dist/backups/logical-database-source.test.d.ts +1 -0
  97. package/dist/backups/model.d.ts +121 -0
  98. package/dist/backups/s3-destination.d.ts +85 -0
  99. package/dist/backups/s3-destination.test.d.ts +1 -0
  100. package/dist/backups/service.d.ts +80 -0
  101. package/dist/backups/service.test.d.ts +1 -0
  102. package/dist/backups/store.d.ts +30 -0
  103. package/dist/backups/store.test.d.ts +1 -0
  104. package/dist/bin/cli.js +3360 -1802
  105. package/dist/{chunk-tjjgajbh.js → chunk-01d86gt1.js} +301 -9
  106. package/dist/{chunk-73vcqg6z.js → chunk-0z43x8re.js} +7 -7
  107. package/dist/{chunk-tnztxpcb.js → chunk-32e7ya18.js} +61 -49
  108. package/dist/{chunk-qpj3edwz.js → chunk-4cjrg98a.js} +3 -7
  109. package/dist/{chunk-hsk6fe6x.js → chunk-50jpda9q.js} +2 -2
  110. package/dist/{chunk-93hjhs78.js → chunk-703nkybg.js} +1 -1
  111. package/dist/{chunk-d5vqwj8s.js → chunk-9m6b4m74.js} +755 -720
  112. package/dist/chunk-e05phx5f.js +10 -0
  113. package/dist/{chunk-f29w04w5.js → chunk-exbcsab2.js} +10 -4
  114. package/dist/{chunk-eq08r166.js → chunk-f55nkpvb.js} +2 -2
  115. package/dist/{chunk-3bfv1z4v.js → chunk-fv1bj3yt.js} +63 -56
  116. package/dist/chunk-fw3q88wk.js +48641 -0
  117. package/dist/{chunk-3knnr7wh.js → chunk-he9a874b.js} +170 -2
  118. package/dist/{chunk-zn0nxxa8.js → chunk-hpv68b4a.js} +1070 -1070
  119. package/dist/chunk-k114qwg9.js +12 -0
  120. package/dist/{chunk-r16e02bc.js → chunk-vdk53yyq.js} +3900 -4101
  121. package/dist/{chunk-jp2a8yad.js → chunk-vvkd46k1.js} +15 -13
  122. package/dist/{chunk-vd87cpvn.js → chunk-wj3s95p9.js} +62 -46
  123. package/dist/{chunk-mj1tmhte.js → chunk-x9s0cqfx.js} +1 -1
  124. package/dist/{chunk-3rsfns7x.js → chunk-ybcz6sxc.js} +2048 -387
  125. package/dist/{chunk-arsh1g5h.js → chunk-zqtpg06c.js} +14 -11
  126. package/dist/compose/index.d.ts +6 -0
  127. package/dist/compose/parser.d.ts +13 -0
  128. package/dist/compose/parser.test.d.ts +1 -0
  129. package/dist/compose/runtime.d.ts +10 -0
  130. package/dist/compose/service.d.ts +18 -0
  131. package/dist/compose/store.d.ts +59 -0
  132. package/dist/compose/store.test.d.ts +1 -0
  133. package/dist/compose/templates.d.ts +17 -0
  134. package/dist/compose/types.d.ts +164 -0
  135. package/dist/configuration/backends.d.ts +66 -0
  136. package/dist/configuration/backends.test.d.ts +1 -0
  137. package/dist/configuration/dotenv.d.ts +14 -0
  138. package/dist/configuration/dotenv.test.d.ts +1 -0
  139. package/dist/configuration/index.d.ts +6 -0
  140. package/dist/configuration/migrate.d.ts +10 -0
  141. package/dist/configuration/migrate.test.d.ts +1 -0
  142. package/dist/configuration/model.d.ts +50 -0
  143. package/dist/configuration/service.d.ts +144 -0
  144. package/dist/configuration/service.test.d.ts +1 -0
  145. package/dist/configuration/store.d.ts +33 -0
  146. package/dist/configuration/store.test.d.ts +1 -0
  147. package/dist/control-plane/authorization.d.ts +24 -0
  148. package/dist/control-plane/authorization.test.d.ts +1 -0
  149. package/dist/control-plane/index.d.ts +8 -0
  150. package/dist/control-plane/migrations.d.ts +7 -0
  151. package/dist/control-plane/search.d.ts +25 -0
  152. package/dist/control-plane/store.d.ts +117 -0
  153. package/dist/control-plane/store.test.d.ts +1 -0
  154. package/dist/control-plane/types.d.ts +381 -0
  155. package/dist/cost/reporting.d.ts +24 -0
  156. package/dist/cost/reporting.test.d.ts +1 -0
  157. package/dist/cost/resource-inventory.d.ts +32 -0
  158. package/dist/cost/resource-inventory.test.d.ts +1 -0
  159. package/dist/cost/resource-optimization.d.ts +59 -0
  160. package/dist/cost/resource-optimization.test.d.ts +1 -0
  161. package/dist/data-services/adapters.d.ts +39 -0
  162. package/dist/data-services/aws-transports.d.ts +29 -0
  163. package/dist/data-services/aws-transports.test.d.ts +1 -0
  164. package/dist/data-services/capabilities.d.ts +2 -0
  165. package/dist/data-services/data-services.test.d.ts +1 -0
  166. package/dist/data-services/docker-transport.d.ts +55 -0
  167. package/dist/data-services/docker-transport.test.d.ts +1 -0
  168. package/dist/data-services/index.d.ts +8 -0
  169. package/dist/data-services/model.d.ts +79 -0
  170. package/dist/data-services/secrets.d.ts +13 -0
  171. package/dist/data-services/secrets.test.d.ts +1 -0
  172. package/dist/data-services/service.d.ts +51 -0
  173. package/dist/data-services/store.d.ts +17 -0
  174. package/dist/deploy/container-image.d.ts +28 -0
  175. package/dist/deploy/container-image.test.d.ts +1 -0
  176. package/dist/deploy/dashboard-audit.test.d.ts +1 -0
  177. package/dist/deploy/dashboard-auth.d.ts +4 -23
  178. package/dist/deploy/dashboard-backups.integration.test.d.ts +1 -0
  179. package/dist/deploy/dashboard-configuration.integration.test.d.ts +1 -0
  180. package/dist/deploy/dashboard-control-plane.d.ts +37 -0
  181. package/dist/deploy/dashboard-control-plane.test.d.ts +1 -0
  182. package/dist/deploy/dashboard-data-services.integration.test.d.ts +1 -0
  183. package/dist/deploy/dashboard-environment-scope.test.d.ts +1 -0
  184. package/dist/deploy/dashboard-guard.d.ts +12 -0
  185. package/dist/deploy/dashboard-guard.test.d.ts +1 -0
  186. package/dist/deploy/dashboard-identities.d.ts +15 -0
  187. package/dist/deploy/dashboard-identities.test.d.ts +1 -0
  188. package/dist/deploy/dashboard-jobs.integration.test.d.ts +1 -0
  189. package/dist/deploy/dashboard-login-page.d.ts +5 -5
  190. package/dist/deploy/dashboard-login-page.test.d.ts +1 -0
  191. package/dist/deploy/dashboard-oidc.integration.test.d.ts +1 -0
  192. package/dist/deploy/dashboard-onboarding.integration.test.d.ts +1 -0
  193. package/dist/deploy/dashboard-policy.d.ts +4 -2
  194. package/dist/deploy/dashboard-queue-worker.integration.test.d.ts +1 -0
  195. package/dist/deploy/dashboard-release.integration.test.d.ts +1 -0
  196. package/dist/deploy/dashboard-route-manifest.d.ts +14 -0
  197. package/dist/deploy/dashboard-route-manifest.test.d.ts +1 -0
  198. package/dist/deploy/dashboard-security.integration.test.d.ts +1 -0
  199. package/dist/deploy/dashboard-session.d.ts +3 -14
  200. package/dist/deploy/dashboard-source.integration.test.d.ts +1 -0
  201. package/dist/deploy/dashboard-users.d.ts +3 -0
  202. package/dist/deploy/fullstack-container.d.ts +87 -0
  203. package/dist/deploy/fullstack-container.test.d.ts +1 -0
  204. package/dist/deploy/index.d.ts +7 -2
  205. package/dist/deploy/index.js +65 -25
  206. package/dist/deploy/local-dashboard-server.d.ts +30 -0
  207. package/dist/deploy/quick-deploy.d.ts +1 -1
  208. package/dist/deploy/serverless-operations.d.ts +1 -0
  209. package/dist/deploy/site-target.d.ts +16 -0
  210. package/dist/deploy/static-api-origin.d.ts +107 -0
  211. package/dist/deploy/static-api-origin.test.d.ts +1 -0
  212. package/dist/deploy/static-site-helper.d.ts +0 -16
  213. package/dist/deploy/telemetry-access.d.ts +5 -0
  214. package/dist/deploy/telemetry-access.test.d.ts +1 -0
  215. package/dist/deploy/telemetry-collection.d.ts +44 -0
  216. package/dist/deploy/telemetry-collection.test.d.ts +1 -0
  217. package/dist/dns/index.js +3 -3
  218. package/dist/dns/route53-adapter.d.ts +1 -1
  219. package/dist/drivers/hetzner/cloud-init.d.ts +1 -1
  220. package/dist/drivers/index.d.ts +2 -2
  221. package/dist/drivers/index.js +6 -6
  222. package/dist/drivers/shared/notifications.d.ts +1 -1
  223. package/dist/drivers/shared/rpx-gateway.d.ts +1 -0
  224. package/dist/fleet/fleet.test.d.ts +1 -0
  225. package/dist/fleet/index.d.ts +144 -0
  226. package/dist/fleet/queue.d.ts +3 -0
  227. package/dist/fleet/ssh-driver.d.ts +34 -0
  228. package/dist/index.d.ts +28 -4
  229. package/dist/index.js +1132 -424
  230. package/dist/jobs/adapters.d.ts +23 -0
  231. package/dist/jobs/index.d.ts +7 -0
  232. package/dist/jobs/jobs.test.d.ts +1 -0
  233. package/dist/jobs/model.d.ts +100 -0
  234. package/dist/jobs/provider-adapters.d.ts +49 -0
  235. package/dist/jobs/reconcile.d.ts +19 -0
  236. package/dist/jobs/schedule.d.ts +9 -0
  237. package/dist/jobs/service.d.ts +30 -0
  238. package/dist/jobs/store.d.ts +48 -0
  239. package/dist/maintenance/drivers.d.ts +117 -0
  240. package/dist/maintenance/index.d.ts +6 -0
  241. package/dist/maintenance/maintenance.test.d.ts +1 -0
  242. package/dist/maintenance/manifest.d.ts +15 -0
  243. package/dist/maintenance/queue.d.ts +9 -0
  244. package/dist/maintenance/service.d.ts +31 -0
  245. package/dist/maintenance/store.d.ts +84 -0
  246. package/dist/maintenance/types.d.ts +192 -0
  247. package/dist/media.d.ts +62 -0
  248. package/dist/media.test.d.ts +1 -0
  249. package/dist/object-storage/index.d.ts +0 -24
  250. package/dist/onboarding/archive.d.ts +12 -0
  251. package/dist/onboarding/artifact-store.d.ts +22 -0
  252. package/dist/onboarding/detection.d.ts +8 -0
  253. package/dist/onboarding/index.d.ts +9 -0
  254. package/dist/onboarding/migrations.d.ts +3 -0
  255. package/dist/onboarding/onboarding.test.d.ts +1 -0
  256. package/dist/onboarding/plan.d.ts +3 -0
  257. package/dist/onboarding/registry.d.ts +41 -0
  258. package/dist/onboarding/service.d.ts +16 -0
  259. package/dist/onboarding/store.d.ts +30 -0
  260. package/dist/onboarding/types.d.ts +204 -0
  261. package/dist/placement/builds.d.ts +20 -0
  262. package/dist/placement/drivers.d.ts +54 -0
  263. package/dist/placement/index.d.ts +6 -0
  264. package/dist/placement/placement.test.d.ts +1 -0
  265. package/dist/placement/queue.d.ts +4 -0
  266. package/dist/placement/service.d.ts +34 -0
  267. package/dist/placement/store.d.ts +49 -0
  268. package/dist/placement/types.d.ts +109 -0
  269. package/dist/preview/index.d.ts +3 -0
  270. package/dist/preview/service.d.ts +45 -0
  271. package/dist/preview/service.test.d.ts +1 -0
  272. package/dist/preview/store.d.ts +47 -0
  273. package/dist/preview/store.test.d.ts +1 -0
  274. package/dist/preview/types.d.ts +99 -0
  275. package/dist/push/apns.d.ts +0 -26
  276. package/dist/push/fcm.d.ts +0 -23
  277. package/dist/push/index.d.ts +2 -2
  278. package/dist/push/index.js +1 -1
  279. package/dist/queue/deployment-handlers.d.ts +27 -0
  280. package/dist/queue/deployment-handlers.test.d.ts +1 -0
  281. package/dist/queue/index.d.ts +4 -0
  282. package/dist/queue/queue.d.ts +57 -0
  283. package/dist/queue/queue.test.d.ts +1 -0
  284. package/dist/queue/types.d.ts +93 -0
  285. package/dist/queue/worker.d.ts +32 -0
  286. package/dist/queue/worker.test.d.ts +1 -0
  287. package/dist/regions/drivers.d.ts +139 -0
  288. package/dist/regions/index.d.ts +5 -0
  289. package/dist/regions/queue.d.ts +4 -0
  290. package/dist/regions/regions.test.d.ts +1 -0
  291. package/dist/regions/service.d.ts +23 -0
  292. package/dist/regions/store.d.ts +41 -0
  293. package/dist/regions/types.d.ts +132 -0
  294. package/dist/release/index.d.ts +6 -0
  295. package/dist/release/queue.d.ts +15 -0
  296. package/dist/release/queue.test.d.ts +1 -0
  297. package/dist/release/runtime.d.ts +35 -0
  298. package/dist/release/runtime.test.d.ts +1 -0
  299. package/dist/release/service.d.ts +28 -0
  300. package/dist/release/store.d.ts +88 -0
  301. package/dist/release/store.test.d.ts +1 -0
  302. package/dist/release/strategy.d.ts +8 -0
  303. package/dist/release/types.d.ts +103 -0
  304. package/dist/runtime/adapters/aws.d.ts +5 -0
  305. package/dist/runtime/adapters/docker.d.ts +53 -0
  306. package/dist/runtime/adapters/systemd.d.ts +26 -0
  307. package/dist/runtime/index.d.ts +9 -0
  308. package/dist/runtime/inventory.d.ts +6 -0
  309. package/dist/runtime/model.d.ts +130 -0
  310. package/dist/runtime/normalize.d.ts +5 -0
  311. package/dist/runtime/operations.d.ts +113 -0
  312. package/dist/runtime/service.d.ts +32 -0
  313. package/dist/runtime/streams.d.ts +49 -0
  314. package/dist/security/artifacts.d.ts +105 -0
  315. package/dist/security/artifacts.test.d.ts +1 -0
  316. package/dist/security/container-release.d.ts +35 -0
  317. package/dist/security/container-release.test.d.ts +1 -0
  318. package/dist/security/index.d.ts +8 -0
  319. package/dist/security/integration.d.ts +41 -0
  320. package/dist/security/integration.test.d.ts +1 -0
  321. package/dist/security/posture-store.d.ts +80 -0
  322. package/dist/security/posture-store.test.d.ts +1 -0
  323. package/dist/security/pre-deploy-scanner.d.ts +0 -4
  324. package/dist/security/scanners.d.ts +81 -0
  325. package/dist/security/scanners.test.d.ts +1 -0
  326. package/dist/security/types.d.ts +150 -0
  327. package/dist/source/git-workspace.d.ts +26 -0
  328. package/dist/source/git-workspace.test.d.ts +1 -0
  329. package/dist/source/index.d.ts +6 -0
  330. package/dist/source/providers.d.ts +199 -0
  331. package/dist/source/providers.test.d.ts +1 -0
  332. package/dist/source/service.d.ts +18 -0
  333. package/dist/source/store.d.ts +149 -0
  334. package/dist/source/store.test.d.ts +1 -0
  335. package/dist/source/types.d.ts +191 -0
  336. package/dist/source/webhooks.d.ts +33 -0
  337. package/dist/source/webhooks.test.d.ts +1 -0
  338. package/dist/ssl/acme-client.d.ts +0 -6
  339. package/dist/storage/compose.d.ts +4 -0
  340. package/dist/storage/compose.test.d.ts +1 -0
  341. package/dist/storage/drivers.d.ts +107 -0
  342. package/dist/storage/drivers.test.d.ts +1 -0
  343. package/dist/storage/index.d.ts +5 -0
  344. package/dist/storage/model.d.ts +112 -0
  345. package/dist/storage/service.d.ts +95 -0
  346. package/dist/storage/storage.test.d.ts +1 -0
  347. package/dist/storage/store.d.ts +40 -0
  348. package/dist/telemetry/correlation.test.d.ts +1 -0
  349. package/dist/telemetry/index.d.ts +4 -0
  350. package/dist/telemetry/model.d.ts +145 -0
  351. package/dist/telemetry/policy.d.ts +8 -0
  352. package/dist/telemetry/policy.test.d.ts +1 -0
  353. package/dist/telemetry/redaction.d.ts +9 -0
  354. package/dist/telemetry/store.d.ts +34 -0
  355. package/dist/telemetry/store.test.d.ts +1 -0
  356. package/dist/ui/404.html +1506 -17
  357. package/dist/ui/accept-invitation.html +1163 -0
  358. package/dist/ui/{server/backups.html → access-denied.html} +344 -55
  359. package/dist/ui/account/automation.html +1669 -0
  360. package/dist/ui/account/security.html +1646 -0
  361. package/dist/ui/applications/compose.html +1590 -0
  362. package/dist/ui/applications/new.html +1868 -0
  363. package/dist/ui/data/backups.html +1757 -0
  364. package/dist/ui/data/services.html +1723 -0
  365. package/dist/ui/data/volumes.html +1639 -0
  366. package/dist/ui/index.html +392 -29
  367. package/dist/ui/integrations.html +1865 -0
  368. package/dist/ui/operations/alerts.html +1610 -0
  369. package/dist/ui/operations/configuration.html +1746 -0
  370. package/dist/ui/operations/jobs.html +1709 -0
  371. package/dist/ui/operations/maintenance.html +1540 -0
  372. package/dist/ui/operations/observability.html +1742 -0
  373. package/dist/ui/{serverless/scheduler.html → operations/previews.html} +447 -46
  374. package/dist/ui/operations/queue.html +1615 -0
  375. package/dist/ui/{server/workers.html → operations/regions.html} +413 -49
  376. package/dist/ui/operations/releases.html +1596 -0
  377. package/dist/ui/operations/workloads.html +1775 -0
  378. package/dist/ui/security.html +1767 -0
  379. package/dist/ui/server/actions.html +446 -57
  380. package/dist/ui/server/activity.html +346 -1
  381. package/dist/ui/server/capacity.html +1542 -0
  382. package/dist/ui/server/database.html +443 -36
  383. package/dist/ui/server/deployments.html +439 -53
  384. package/dist/ui/server/diagnostics.html +346 -1
  385. package/dist/ui/server/firewall.html +476 -50
  386. package/dist/ui/server/fleet.html +1577 -0
  387. package/dist/ui/server/logs.html +389 -25
  388. package/dist/ui/server/metrics.html +346 -1
  389. package/dist/ui/server/security.html +346 -1
  390. package/dist/ui/server/services.html +421 -46
  391. package/dist/ui/server/sites.html +476 -95
  392. package/dist/ui/server/ssh-keys.html +476 -46
  393. package/dist/ui/server/team.html +700 -77
  394. package/dist/ui/server/terminal.html +444 -54
  395. package/dist/ui/serverless/alarms.html +430 -42
  396. package/dist/ui/serverless/assets.html +421 -46
  397. package/dist/ui/serverless/cost.html +346 -1
  398. package/dist/ui/serverless/data.html +422 -47
  399. package/dist/ui/serverless/deployments.html +421 -46
  400. package/dist/ui/serverless/firewall.html +346 -1
  401. package/dist/ui/serverless/functions.html +423 -48
  402. package/dist/ui/serverless/logs.html +389 -25
  403. package/dist/ui/serverless/metrics.html +346 -1
  404. package/dist/ui/serverless/queues.html +448 -62
  405. package/dist/ui/serverless/secrets.html +448 -42
  406. package/dist/ui/serverless/traces.html +350 -5
  407. package/dist/ui/serverless.html +434 -58
  408. package/dist/ui-src/pages/404.stx +18 -0
  409. package/dist/ui-src/pages/accept-invitation.stx +50 -0
  410. package/dist/ui-src/pages/access-denied.stx +18 -0
  411. package/dist/ui-src/pages/account/automation.stx +187 -0
  412. package/dist/ui-src/pages/account/security.stx +249 -0
  413. package/dist/ui-src/pages/applications/compose.stx +38 -0
  414. package/dist/ui-src/pages/applications/new.stx +76 -0
  415. package/dist/ui-src/pages/data/backups.stx +214 -0
  416. package/dist/ui-src/pages/data/services.stx +257 -0
  417. package/dist/ui-src/pages/data/volumes.stx +40 -0
  418. package/dist/ui-src/pages/index.stx +24 -10
  419. package/dist/ui-src/pages/integrations.stx +186 -0
  420. package/dist/ui-src/pages/operations/alerts.stx +40 -0
  421. package/dist/ui-src/pages/operations/configuration.stx +164 -0
  422. package/dist/ui-src/pages/operations/jobs.stx +238 -0
  423. package/dist/ui-src/pages/operations/maintenance.stx +15 -0
  424. package/dist/ui-src/pages/operations/observability.stx +76 -0
  425. package/dist/ui-src/pages/operations/previews.stx +62 -0
  426. package/dist/ui-src/pages/operations/queue.stx +158 -0
  427. package/dist/ui-src/pages/operations/regions.stx +12 -0
  428. package/dist/ui-src/pages/operations/releases.stx +39 -0
  429. package/dist/ui-src/pages/operations/workloads.stx +151 -0
  430. package/dist/ui-src/pages/partials/head.stx +148 -15
  431. package/dist/ui-src/pages/partials/nav.stx +491 -74
  432. package/dist/ui-src/pages/partials/op-confirm.stx +6 -6
  433. package/dist/ui-src/pages/security.stx +264 -0
  434. package/dist/ui-src/pages/server/actions.stx +17 -26
  435. package/dist/ui-src/pages/server/capacity.stx +16 -0
  436. package/dist/ui-src/pages/server/database.stx +31 -16
  437. package/dist/ui-src/pages/server/deployments.stx +28 -30
  438. package/dist/ui-src/pages/server/firewall.stx +25 -30
  439. package/dist/ui-src/pages/server/fleet.stx +10 -0
  440. package/dist/ui-src/pages/server/logs.stx +11 -9
  441. package/dist/ui-src/pages/server/metrics.stx +8 -16
  442. package/dist/ui-src/pages/server/services.stx +19 -28
  443. package/dist/ui-src/pages/server/sites.stx +75 -72
  444. package/dist/ui-src/pages/server/ssh-keys.stx +24 -30
  445. package/dist/ui-src/pages/server/team.stx +286 -149
  446. package/dist/ui-src/pages/server/terminal.stx +6 -28
  447. package/dist/ui-src/pages/serverless/alarms.stx +17 -31
  448. package/dist/ui-src/pages/serverless/assets.stx +13 -22
  449. package/dist/ui-src/pages/serverless/cost.stx +15 -3
  450. package/dist/ui-src/pages/serverless/data.stx +12 -25
  451. package/dist/ui-src/pages/serverless/deployments.stx +14 -23
  452. package/dist/ui-src/pages/serverless/firewall.stx +5 -1
  453. package/dist/ui-src/pages/serverless/functions.stx +20 -26
  454. package/dist/ui-src/pages/serverless/logs.stx +11 -10
  455. package/dist/ui-src/pages/serverless/metrics.stx +18 -17
  456. package/dist/ui-src/pages/serverless/queues.stx +34 -42
  457. package/dist/ui-src/pages/serverless/secrets.stx +31 -34
  458. package/dist/ui-src/pages/serverless/traces.stx +2 -6
  459. package/dist/ui-src/pages/serverless.stx +40 -74
  460. package/package.json +11 -11
  461. package/dist/chunk-b17vf1g1.js +0 -13787
  462. package/dist/chunk-b82pbxyp.js +0 -1572
  463. package/dist/chunk-pqfzdg68.js +0 -12
  464. package/dist/chunk-z58fqnjm.js +0 -10
  465. package/dist/ui-src/pages/server/backups.stx +0 -91
  466. package/dist/ui-src/pages/server/workers.stx +0 -99
  467. package/dist/ui-src/pages/serverless/scheduler.stx +0 -89
@@ -6,60 +6,67 @@ const server = __d?.server ?? { name: 'stacks-production-app' }
6
6
  // so the box-owner affordances - adding and removing sites - are not offered.
7
7
  // Presentation only: the server enforces this regardless of what is rendered.
8
8
  const isMember = (__d?.viewer?.role ?? 'admin') === 'member'
9
+ const viewerCapabilities = __d?.viewer?.capabilities ?? []
10
+ const canDeploy = !isMember || viewerCapabilities.includes('deployments:create')
11
+ const canEdit = !isMember || viewerCapabilities.includes('config:write')
9
12
  const sites = __d?.sitesDetail ?? [
10
13
  { name: 'main', route: 'stacksjs.com', href: 'https://stacksjs.com', kind: 'stacks', runtime: 'bun', tls: 'https', deploy: 'service', root: '/var/www/main/current', branch: 'main', status: 'live' },
11
14
  { name: 'api', route: 'internal', kind: 'api', runtime: 'bun', tls: 'loopback', deploy: 'service', root: '/var/www/api/current', branch: 'main', status: 'live' },
12
15
  { name: 'docs', route: 'stacksjs.com/docs', href: 'https://stacksjs.com/docs', kind: 'bunpress', runtime: 'static/bun', tls: 'https', deploy: 'server static', root: '/var/www/docs', branch: 'build artifact', status: 'live' },
13
16
  ]
17
+ const initialSites = sites
14
18
  function tone(s) { return s === 'live' ? 'ok' : (s === 'failed' ? 'bad' : 'warn') }
15
19
  </script>
16
20
  <script client>
21
+ import { useOpConfirm } from '../../functions/useOpConfirm.ts'
22
+
17
23
  // Reactive site management - add, per-site deploy/edit/remove - via signals +
18
- // directives. Mutations re-render the server-built page (location.reload) once
19
- // the cloud config has changed.
24
+ // directives. Mutation responses replace the site signal without reloading, so
25
+ // status and success feedback remain visible.
20
26
  const addName = state(''); const addRoot = state(''); const addDomain = state(''); const addPath = state('')
21
27
  const addDeploy = state('server'); const addPort = state(''); const addBuild = state(''); const addStart = state('')
22
28
  const addMsg = state(''); const addMsgKind = state('')
29
+ const addBusy = state(false)
30
+ const siteRows = state(initialSites)
23
31
  async function addSite() {
24
- addMsg.set('Adding site...'); addMsgKind.set('')
32
+ if (addBusy()) return
33
+ addBusy.set(true); addMsg.set('Adding site...'); addMsgKind.set('')
25
34
  const payload = { name: addName(), root: addRoot(), domain: addDomain(), path: addPath(), deploy: addDeploy(), port: addPort(), build: addBuild(), start: addStart() }
26
35
  try {
27
36
  const res = await fetch('/api/sites', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload) })
28
37
  const b = await res.json()
29
38
  if (!b.ok) throw new Error(b.error || 'Could not add site')
30
- addMsg.set('Added ' + b.site + '. Refreshing...'); addMsgKind.set('ok'); location.reload()
39
+ if (Array.isArray(b.data?.sitesDetail)) siteRows.set(b.data.sitesDetail)
40
+ addMsg.set('Added ' + b.site + '.'); addMsgKind.set('ok')
31
41
  } catch (e) { addMsg.set((e && e.message) || String(e)); addMsgKind.set('bad') }
42
+ finally { addBusy.set(false) }
32
43
  }
33
44
 
34
45
  // Deploy / remove run through the shared op-confirm bar.
35
- const opOutput = state(''); const opShown = state(false); const pending = state(null); const typed = state('')
36
- const confirmTok = derived(() => { const p = pending(); return p ? p.confirm : '' })
37
- const confirmVerb = derived(() => { const p = pending(); return p ? p.verb : '' })
38
- const canRun = derived(() => { const p = pending(); return !!p && typed() === p.confirm })
39
- function askDeploy(name) { pending.set({ kind: 'deploy', name, confirm: name, verb: 'deploy ' + name }); typed.set('') }
40
- function askRemove(name) { pending.set({ kind: 'remove', name, confirm: name, verb: 'remove ' + name }); typed.set('') }
41
- function cancelOp() { pending.set(null) }
42
- async function runOp() {
43
- const p = pending(); if (!p || typed() !== p.confirm) return
44
- pending.set(null); typed.set('')
45
- opShown.set(true); opOutput.set((p.kind === 'deploy' ? 'Deploying ' : 'Removing ') + p.name + '...')
46
- try {
47
- if (p.kind === 'deploy') {
48
- const res = await fetch('/api/sites/deploy', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ name: p.name, confirm: p.name }) })
49
- const b = await res.json()
50
- opOutput.set((b.ok ? 'OK ' : 'FAILED ') + (b.command || ('deploy ' + p.name)) + '\n\n' + (b.stdout || '') + (b.stderr ? '\n' + b.stderr : '') + (b.error ? '\n' + b.error : ''))
51
- } else {
52
- const res = await fetch('/api/sites', { method: 'DELETE', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ name: p.name }) })
53
- const b = await res.json()
54
- if (b.ok) { opOutput.set('Removed ' + p.name + ' from cloud config. Refreshing...'); location.reload() } else opOutput.set(b.error || 'Could not remove site')
55
- }
56
- } catch (e) { opOutput.set('FAILED ' + p.name + '\n\n' + ((e && e.message) || e)) }
57
- }
46
+ const { opOutput, opShown, pending, typed, busy, confirmTok, confirmVerb, confirmDanger, confirmLabel, canRun, askOp, cancelOp, runOp } = useOpConfirm(async p => {
47
+ if (p.operation.startsWith('site:deploy:')) {
48
+ const res = await fetch('/api/sites/deploy', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ name: p.name, confirm: p.apiConfirm }) })
49
+ const body = await res.json()
50
+ return (body.ok ? 'OK ' : 'FAILED ') + (body.command || ('deploy ' + p.name)) + '\n\n' + (body.stdout || '') + (body.stderr ? '\n' + body.stderr : '') + (body.error ? '\n' + body.error : '')
51
+ }
52
+ if (p.operation.startsWith('site:edit:')) {
53
+ const res = await fetch('/api/sites', { method: 'PATCH', headers: { 'content-type': 'application/json' }, body: JSON.stringify(p.payload) })
54
+ const body = await res.json()
55
+ if (body.ok && Array.isArray(body.data?.sitesDetail)) siteRows.set(body.data.sitesDetail)
56
+ return body.ok ? 'Updated ' + p.name + '.' : (body.error || 'Could not update site')
57
+ }
58
+ const res = await fetch('/api/sites', { method: 'DELETE', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ name: p.name }) })
59
+ const body = await res.json()
60
+ if (body.ok && Array.isArray(body.data?.sitesDetail)) siteRows.set(body.data.sitesDetail)
61
+ return body.ok ? 'Removed ' + p.name + ' from cloud config.' : (body.error || 'Could not remove site')
62
+ })
63
+ function askDeploy(name) { askOp('site:deploy:' + name, name, 'deploy ' + name, null, name, { name }) }
64
+ function askRemove(name) { askOp('site:remove:' + name, name, 'remove ' + name, null, name, { name, danger: true }) }
58
65
 
59
66
  // Inline per-site edit (TLS / domain / env).
60
67
  const editing = state(''); const editSsl = state(''); const editDomain = state(''); const editEnv = state(''); const editPhp = state(''); const editAliases = state(''); const editRedirects = state('')
61
68
  function toggleEdit(name) { editing.set(editing() === name ? '' : name); editSsl.set(''); editDomain.set(''); editEnv.set(''); editPhp.set(''); editAliases.set(''); editRedirects.set('') }
62
- async function saveEdit(name) {
69
+ function editPayload(name) {
63
70
  const payload = { name }
64
71
  if (editSsl() === 'false') payload.ssl = false; else if (editSsl()) payload.ssl = { provider: editSsl() }
65
72
  if (editDomain()) payload.domain = editDomain()
@@ -67,12 +74,12 @@ async function saveEdit(name) {
67
74
  if (editAliases().trim()) payload.aliases = editAliases().split(/[\s,]+/).filter(Boolean)
68
75
  if (editRedirects().trim()) { payload.redirects = {}; for (const line of editRedirects().split('\n')) { const i = line.indexOf('='); if (i > 0) payload.redirects[line.slice(0, i).trim()] = line.slice(i + 1).trim() } }
69
76
  if (editEnv()) { payload.env = {}; for (const line of editEnv().split('\n')) { const i = line.indexOf('='); if (i > 0) payload.env[line.slice(0, i).trim()] = line.slice(i + 1).trim() } }
70
- opShown.set(true); opOutput.set('Updating ' + name + '...')
71
- try {
72
- const res = await fetch('/api/sites', { method: 'PATCH', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload) })
73
- const b = await res.json()
74
- if (b.ok) { opOutput.set('Updated ' + name + '. Refreshing...'); location.reload() } else opOutput.set(b.error || 'Could not update site')
75
- } catch (e) { opOutput.set('FAILED ' + name + '\n\n' + ((e && e.message) || e)) }
77
+ return payload
78
+ }
79
+ async function saveEdit(name) {
80
+ const payload = editPayload(name)
81
+ const verb = payload.ssl === false ? 'disable TLS for ' + name : 'save configuration changes for ' + name
82
+ askOp('site:edit:' + name, name, verb, null, name, { name, payload, danger: payload.ssl === false })
76
83
  }
77
84
  </script>
78
85
  <!DOCTYPE html>
@@ -99,72 +106,67 @@ async function saveEdit(name) {
99
106
  <h2>Add site</h2>
100
107
  <div class="panel">
101
108
  <form class="form-grid" @submit.prevent="addSite()">
102
- <div class="field-block"><label>Name</label><input placeholder="docs" :value="addName()" @input="addName.set($event.target.value)"></div>
103
- <div class="field-block"><label>Root</label><input placeholder="dist/docs" :value="addRoot()" @input="addRoot.set($event.target.value)"></div>
104
- <div class="field-block"><label>Domain</label><input placeholder="example.com" :value="addDomain()" @input="addDomain.set($event.target.value)"></div>
105
- <div class="field-block"><label>Path</label><input placeholder="/docs" :value="addPath()" @input="addPath.set($event.target.value)"></div>
106
- <div class="field-block"><label>Deploy</label><input :value="addDeploy()" @input="addDeploy.set($event.target.value)"></div>
107
- <div class="field-block"><label>Port</label><input placeholder="3000" :value="addPort()" @input="addPort.set($event.target.value)"></div>
108
- <div class="field-block wide"><label>Build command</label><input placeholder="bun run build" :value="addBuild()" @input="addBuild.set($event.target.value)"></div>
109
- <div class="field-block wide"><label>Start command</label><input placeholder="bun run start" :value="addStart()" @input="addStart.set($event.target.value)"></div>
110
- <div class="form-actions"><button class="btn" type="submit">Add site</button><span class="msg" :class="addMsgKind()">{{ addMsg() }}</span></div>
109
+ <div class="field-block"><label for="site-add-name">Name</label><input id="site-add-name" placeholder="docs" :value="addName()" @input="addName.set($event.target.value)"></div>
110
+ <div class="field-block"><label for="site-add-root">Root</label><input id="site-add-root" placeholder="dist/docs" :value="addRoot()" @input="addRoot.set($event.target.value)"></div>
111
+ <div class="field-block"><label for="site-add-domain">Domain</label><input id="site-add-domain" placeholder="example.com" :value="addDomain()" @input="addDomain.set($event.target.value)"></div>
112
+ <div class="field-block"><label for="site-add-path">Path</label><input id="site-add-path" placeholder="/docs" :value="addPath()" @input="addPath.set($event.target.value)"></div>
113
+ <div class="field-block"><label for="site-add-deploy">Deploy</label><input id="site-add-deploy" :value="addDeploy()" @input="addDeploy.set($event.target.value)"></div>
114
+ <div class="field-block"><label for="site-add-port">Port</label><input id="site-add-port" placeholder="3000" :value="addPort()" @input="addPort.set($event.target.value)"></div>
115
+ <div class="field-block wide"><label for="site-add-build">Build command</label><input id="site-add-build" placeholder="bun run build" :value="addBuild()" @input="addBuild.set($event.target.value)"></div>
116
+ <div class="field-block wide"><label for="site-add-start">Start command</label><input id="site-add-start" placeholder="bun run start" :value="addStart()" @input="addStart.set($event.target.value)"></div>
117
+ <div class="form-actions"><button class="btn" type="submit" :disabled="addBusy()">Add site</button><span class="msg" :class="addMsgKind()" role="status">{{ addMsg() }}</span></div>
111
118
  </form>
112
119
  </div>
113
120
  </div>
114
121
  @endif
115
- @if (isMember && sites.length === 0)
116
- <div class="empty">
122
+ @if (isMember)
123
+ <div class="empty" @show="siteRows().length === 0">
117
124
  <strong>No sites yet</strong>
118
125
  <span>You have not been given access to a site on this server. Ask the server owner to invite you to one.</span>
119
126
  </div>
120
127
  @endif
121
- @foreach (sites as site)
128
+ <template :for="site in siteRows()">
122
129
  <div class="section">
123
- <h2>{{ site.name }} <span class="more"><span class="pill {{ tone(site.status) }}">{{ site.status }}</span></span></h2>
130
+ <h2>{{ site.name }} <span class="more"><span class="pill" :class="tone(site.status)">{{ site.status }}</span></span></h2>
124
131
  <div class="cols">
125
132
  <div class="panel">
126
- <div class="kv"><span>route</span> <b class="mono">@if (site.href)<a href="{{ site.href }}">{{ site.route }}</a>@else{{ site.route }}@endif</b></div>
133
+ <div class="kv"><span>route</span> <b class="mono"><a :href="site.href" @show="!!site.href">{{ site.route }}</a><span @show="!site.href">{{ site.route }}</span></b></div>
127
134
  <div class="kv"><span>kind</span> <b><span class="tag">{{ site.kind ?? site.type }}</span></b></div>
128
135
  <div class="kv"><span>runtime</span> <b class="mono">{{ site.runtime }}</b></div>
129
- <div class="kv"><span>tls</span> <b><span class="{{ site.tls === 'https' ? 'ok' : 'warn' }} pill">{{ site.tls }}</span></b></div>
136
+ <div class="kv"><span>tls</span> <b><span class="pill" :class="site.tls === 'https' ? 'ok' : 'warn'">{{ site.tls }}</span></b></div>
130
137
  </div>
131
138
  <div class="panel">
132
139
  <div class="kv"><span>web root</span> <b class="mono" style="font-size:11px">{{ site.root }}</b></div>
133
140
  <div class="kv"><span>source</span> <b class="mono">{{ site.branch }}</b></div>
134
141
  <div class="kv"><span>deploy</span> <b>{{ site.deploy }}</b></div>
135
- @if (site.envKeys && site.envKeys.length)
136
- <div class="kv"><span>env vars</span> <b class="mono">{{ site.envKeys.join(', ') }}</b></div>
137
- @endif
138
- @if (site.aliases && site.aliases.length)
139
- <div class="kv"><span>aliases</span> <b class="mono">{{ site.aliases.join(', ') }}</b></div>
140
- @endif
141
- @if (site.redirects && Object.keys(site.redirects).length)
142
- <div class="kv"><span>redirects</span> <b class="mono">{{ Object.keys(site.redirects).length }}</b></div>
143
- @endif
144
- @if (site.shadowedBy)
145
- <div class="kv"><span>shadowed by</span> <b class="mono">{{ site.shadowedBy }}</b></div>
146
- @endif
142
+ <div class="kv" @show="site.envKeys && site.envKeys.length"><span>env vars</span> <b class="mono">{{ (site.envKeys || []).join(', ') }}</b></div>
143
+ <div class="kv" @show="site.aliases && site.aliases.length"><span>aliases</span> <b class="mono">{{ (site.aliases || []).join(', ') }}</b></div>
144
+ <div class="kv" @show="site.redirects && Object.keys(site.redirects).length"><span>redirects</span> <b class="mono">{{ Object.keys(site.redirects || {}).length }}</b></div>
145
+ <div class="kv" @show="!!site.shadowedBy"><span>shadowed by</span> <b class="mono">{{ site.shadowedBy }}</b></div>
147
146
  </div>
148
147
  </div>
149
148
  <div class="row-actions" style="margin-top:12px;">
150
- <button class="btn sm" type="button" @click="askDeploy('{{ site.name }}')">Deploy</button>
151
- <button class="btn ghost sm" type="button" @click="toggleEdit('{{ site.name }}')">Edit</button>
149
+ <a class="btn ghost sm" :href="'/operations/workloads?service=' + encodeURIComponent(site.name)">Backing workloads</a>
150
+ @if (canDeploy)<button class="btn sm" type="button" @click="askDeploy(site.name)">Deploy</button>@endif
151
+ @if (canEdit)<button class="btn ghost sm" type="button" @click="toggleEdit(site.name)">Edit</button>@endif
152
152
  @if (!isMember)
153
- <button class="btn danger sm" type="button" @click="askRemove('{{ site.name }}')">Remove</button>
153
+ <button class="btn danger sm" type="button" :aria-label="'Remove site ' + site.name" @click="askRemove(site.name)">Remove</button>
154
154
  @endif
155
155
  </div>
156
- <form class="form-grid" style="margin-top:14px;" @show="editing() === '{{ site.name }}'" @submit.prevent="saveEdit('{{ site.name }}')">
156
+ @if (!canDeploy && !canEdit)<p class="note">This membership is read-only for {{ site.name }}. Ask an organization owner for deployment or configuration access.</p>@endif
157
+ <form class="form-grid" style="margin-top:14px;" @show="editing() === site.name" @submit.prevent="saveEdit(site.name)">
157
158
  <div class="field-block">
158
- <label>TLS</label>
159
+ <label>TLS
159
160
  <select :value="editSsl()" @change="editSsl.set($event.target.value)">
160
161
  <option value="">(unchanged)</option>
161
162
  <option value="letsencrypt">letsencrypt</option>
162
163
  <option value="false">disable</option>
163
164
  </select>
165
+ </label>
164
166
  </div>
165
- <div class="field-block"><label>Domain</label><input placeholder="{{ site.domain }}" :value="editDomain()" @input="editDomain.set($event.target.value)"></div>
167
+ <div class="field-block"><label>Domain<input :placeholder="site.domain" :value="editDomain()" @input="editDomain.set($event.target.value)"></label></div>
166
168
  <div class="field-block">
167
- <label>PHP version</label>
169
+ <label>PHP version
168
170
  <select :value="editPhp()" @change="editPhp.set($event.target.value)">
169
171
  <option value="">(unchanged)</option>
170
172
  <option value="8.1">8.1</option>
@@ -172,14 +174,15 @@ async function saveEdit(name) {
172
174
  <option value="8.3">8.3</option>
173
175
  <option value="8.4">8.4</option>
174
176
  </select>
177
+ </label>
175
178
  </div>
176
- <div class="field-block wide"><label>Domain aliases (space or comma separated)</label><input placeholder="www.example.com, cdn.example.com" :value="editAliases()" @input="editAliases.set($event.target.value)"></div>
177
- <div class="field-block wide"><label>Redirects (from = to per line)</label><textarea rows="2" placeholder="/old = /new" :value="editRedirects()" @input="editRedirects.set($event.target.value)"></textarea></div>
178
- <div class="field-block wide"><label>Env vars (KEY=value per line)</label><textarea rows="3" placeholder="NODE_ENV=production" :value="editEnv()" @input="editEnv.set($event.target.value)"></textarea></div>
179
+ <div class="field-block wide"><label>Domain aliases (space or comma separated)<input placeholder="www.example.com, cdn.example.com" :value="editAliases()" @input="editAliases.set($event.target.value)"></label></div>
180
+ <div class="field-block wide"><label>Redirects (from = to per line)<textarea rows="2" placeholder="/old = /new" :value="editRedirects()" @input="editRedirects.set($event.target.value)"></textarea></label></div>
181
+ <div class="field-block wide"><label>Env vars (KEY=value per line)<textarea rows="3" placeholder="NODE_ENV=production" :value="editEnv()" @input="editEnv.set($event.target.value)"></textarea></label></div>
179
182
  <div class="form-actions"><button class="btn" type="submit">Save changes</button></div>
180
183
  </form>
181
184
  </div>
182
- @endforeach
185
+ </template>
183
186
  @include('../partials/op-confirm')
184
187
  </div>
185
188
  </body>
@@ -5,6 +5,9 @@ const server = __d?.server ?? { name: 'acme-production-app' }
5
5
  const initialKeys = __d?.sshKeys ?? []
6
6
  </script>
7
7
  <script client>
8
+ import { useOpConfirm } from '../../functions/useOpConfirm.ts'
9
+ import { requestJson } from '../../functions/requestJson.ts'
10
+
8
11
  // Reactive SSH key management - list + add + remove, via signals + directives.
9
12
  // Seeded from build-time data (stx server→client bridge); load() reconciles
10
13
  // against the live cloud config (same describeSshKeys shape).
@@ -23,35 +26,31 @@ async function load() {
23
26
  } catch (e) { setMessage((e && e.message) || 'Could not read SSH keys.', 'bad') }
24
27
  }
25
28
  async function addKey() {
26
- setMessage('Saving...', '')
27
- const res = await fetch('/api/ssh-keys', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ name: name(), publicKey: pub() }) })
28
- const data = await res.json().catch(() => ({}))
29
- if (!res.ok || data.ok === false) { setMessage(data.error || 'Could not add key.', 'bad'); return }
30
- keys.set(data.keys || []); name.set(''); pub.set('')
31
- setMessage('Saved to cloud config. Run cloud deploy to apply.', 'ok')
29
+ if (busy()) return
30
+ busy.set(true); setMessage('Saving...', '')
31
+ try {
32
+ const data = await requestJson('/api/ssh-keys', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ name: name(), publicKey: pub() }) })
33
+ keys.set(data.keys || []); name.set(''); pub.set('')
34
+ setMessage('Saved to cloud config. Run cloud deploy to apply.', 'ok')
35
+ } catch (error) { setMessage(error?.message || 'Could not add key.', 'bad') }
36
+ finally { busy.set(false) }
32
37
  }
33
38
  async function removeKey(n) {
34
39
  setMessage('Removing...', '')
35
- const res = await fetch('/api/ssh-keys', { method: 'DELETE', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ name: n }) })
36
- const data = await res.json().catch(() => ({}))
37
- if (!res.ok || data.ok === false) { setMessage(data.error || 'Could not remove key.', 'bad'); return }
38
- keys.set(data.keys || [])
39
- setMessage('Removed from cloud config. Run cloud deploy to apply.', 'ok')
40
+ try {
41
+ const data = await requestJson('/api/ssh-keys', { method: 'DELETE', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ name: n }) })
42
+ keys.set(data.keys || [])
43
+ setMessage('Removed from cloud config. Run cloud deploy to apply.', 'ok')
44
+ } catch (error) { setMessage(error?.message || 'Could not remove key.', 'bad') }
40
45
  }
41
46
  // Removal runs through a typed-confirm bar (same pattern as firewall/team):
42
47
  // type the key name to confirm. Removing the wrong key can lock every operator
43
48
  // out of the box, so it should never be one misclick away.
44
- const pendingRemove = state(null)
45
- const typedRemove = state('')
46
- const canRemove = derived(() => { const k = pendingRemove(); return k !== null && typedRemove() === String(k.name) })
47
- function askRemove(key) { pendingRemove.set(key); typedRemove.set('') }
48
- function cancelRemove() { pendingRemove.set(null); typedRemove.set('') }
49
- async function confirmRemove() {
50
- const k = pendingRemove()
51
- if (!k || typedRemove() !== String(k.name)) return
52
- pendingRemove.set(null); typedRemove.set('')
53
- await removeKey(k.name)
54
- }
49
+ const { opOutput, opShown, pending, typed, busy, confirmTok, confirmVerb, confirmDanger, confirmLabel, canRun, askOp, cancelOp, runOp } = useOpConfirm(async p => {
50
+ await removeKey(String(p.name))
51
+ return message()
52
+ })
53
+ function askRemove(key) { askOp('ssh-key:remove:' + key.name, key.name, 'remove SSH key ' + key.name + ' from the box', null, key.name, { name: key.name, danger: true, label: 'Remove SSH key' }) }
55
54
 
56
55
  onMount(() => { load() })
57
56
  </script>
@@ -76,7 +75,7 @@ onMount(() => { load() })
76
75
  <textarea id="ssh-public-key" rows="4" placeholder="ssh-ed25519 AAAA... chris@macbook" :value="pub()" @input="pub.set($event.target.value)" required></textarea>
77
76
  </div>
78
77
  <div class="form-actions">
79
- <button class="btn" type="submit">Add key</button>
78
+ <button class="btn" type="submit" :disabled="busy()">Add key</button>
80
79
  <span class="msg" :class="messageKind()" role="status">{{ message() }}</span>
81
80
  </div>
82
81
  </form>
@@ -86,7 +85,7 @@ onMount(() => { load() })
86
85
  <h2>Configured keys</h2>
87
86
  <div class="panel">
88
87
  <table>
89
- <thead><tr><th>Name</th><th>Type</th><th>Fingerprint</th><th>Added</th><th></th></tr></thead>
88
+ <thead><tr><th scope="col">Name</th><th scope="col">Type</th><th scope="col">Fingerprint</th><th scope="col">Added</th><th scope="col"></th></tr></thead>
90
89
  <tbody>
91
90
  <template :for="k in keys()">
92
91
  <tr>
@@ -100,12 +99,7 @@ onMount(() => { load() })
100
99
  </tbody>
101
100
  </table>
102
101
  <div class="compact empty" @show="keys().length === 0"><strong>No SSH keys configured</strong><span>Add a public key above to update <span class="mono">infrastructure.compute.sshKeys</span>.</span></div>
103
- <div class="op-confirm" @show="pendingRemove() !== null" style="margin-top:14px">
104
- <span>Type <b class="mono">{{ pendingRemove()?.name }}</b> to remove this key from the box:</span>
105
- <input class="op-confirm-input" :value="typedRemove()" @input="typedRemove.set($event.target.value)" @keydown.enter="confirmRemove()" placeholder="confirm" autocomplete="off" aria-label="Type the key name to confirm removal">
106
- <button type="button" class="btn danger sm" :disabled="!canRemove()" @click="confirmRemove()">Remove</button>
107
- <button type="button" class="btn ghost sm" @click="cancelRemove()">Cancel</button>
108
- </div>
102
+ @include('../partials/op-confirm')
109
103
  <p class="note">Keys are declarative: this page edits <span class="mono">infrastructure.compute.sshKeys</span> in cloud config. Run <span class="mono">cloud deploy</span> to apply changes to the box. Connect with <span class="mono">cloud server:ssh {{ server.name }}</span>.</p>
110
104
  </div>
111
105
  </div>