@stacksjs/ts-cloud 0.7.56 → 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
@@ -1,92 +1,509 @@
1
1
  <script server>
2
- // Mode- and scope-aware, fully server-rendered nav. The deployment mode,
3
- // environment list and viewer role are injected with the dashboard data; the
4
- // environment switcher is plain links (`?env=<name>`) the server handles - no
5
- // client JavaScript needed.
6
- //
7
- // The nav offers only what the viewer can actually reach. A member (a
8
- // collaborator invited to specific sites) has no box-level access, so the
9
- // server, database and environment-switching surfaces are not shown - the
10
- // server would refuse them anyway, and offering a link that 403s is worse than
11
- // not offering it. This is presentation only: access is enforced server-side.
12
2
  let __nav = null
13
3
  try { __nav = JSON.parse(process.env.TSCLOUD_DASHBOARD_DATA || '') } catch { __nav = null }
14
- // Server and serverless are mutually exclusive; the dashboard shows one or the other.
4
+
15
5
  const navMode = __nav?.mode ?? 'server'
16
6
  const isMember = (__nav?.viewer?.role ?? 'admin') === 'member'
17
- const showServer = navMode === 'server' && !isMember
18
- const showServerless = navMode === 'serverless' && !isMember
7
+ const viewerCapabilities = __nav?.viewer?.capabilities ?? []
8
+ const legacyMember = __nav?.viewer?.organizationSource === 'legacy'
9
+ const legacyVisibleCapabilities = new Set(['project:read', 'config:read', 'deployments:read', 'deployments:create', 'runtime:read', 'runtime:logs'])
10
+ const canView = capability => !isMember || (viewerCapabilities.includes(capability) && (!legacyMember || legacyVisibleCapabilities.has(capability)))
19
11
  const navEnvs = __nav?.environments ?? []
20
- const navEnv = __nav?.environment ?? ''
21
- // Only the box owner can switch the active environment (it is process-wide).
22
- const showEnvSwitch = navEnvs.length > 1 && !isMember
12
+ const navEnv = __nav?.environment ?? env ?? 'production'
13
+ const navProject = __nav?.project?.name ?? __nav?.project?.slug ?? name ?? 'Project'
14
+ const navProvider = __nav?.server?.provider ?? __nav?.provider ?? ''
15
+ const navRegion = __nav?.server?.region ?? __nav?.project?.region ?? __nav?.region ?? ''
16
+ const envHref = path => `${path}?env=${encodeURIComponent(navEnv)}`
17
+ const isActive = (...keys) => keys.includes(active ?? '')
23
18
  </script>
24
- <nav>
25
- <div class="brand"><span class="dot"></span> ts-cloud</div>
26
- <div class="tabs">
27
- @if (showServer)
28
- @if ((active ?? '') === 'server')
29
- <a href="/" class="active">Server</a>
30
- @else
31
- <a href="/">Server</a>
32
- @endif
19
+
20
+ <a class="skip-link" href="#main-content">Skip to content</a>
21
+ <button class="nav-toggle-button" type="button" aria-label="Open navigation" aria-controls="primary-navigation" aria-expanded="false"><span></span><span></span><span></span></button>
22
+ <button class="nav-scrim" type="button" aria-label="Close navigation"></button>
23
+
24
+ <aside class="app-sidebar" id="primary-navigation" aria-label="Primary navigation">
25
+ <a class="brand" href="{{ envHref(navMode === 'serverless' ? '/serverless' : '/') }}"><span class="dot"></span><span>ts-cloud</span></a>
26
+
27
+ <div class="sidebar-context">
28
+ <span class="context-label">Project</span>
29
+ <strong>{{ navProject }}</strong>
30
+ @if (navProvider || navRegion)
31
+ <span class="context-detail">{{ [navProvider, navRegion].filter(Boolean).join(' · ') }}</span>
33
32
  @endif
34
- @if (showServerless)
35
- @if ((active ?? '') === 'serverless')
36
- <a href="/serverless" class="active">Serverless</a>
37
- @else
38
- <a href="/serverless">Serverless</a>
33
+ </div>
34
+
35
+ <div class="environment-picker" aria-label="Environment">
36
+ <span class="context-label">Environment</span>
37
+ <details>
38
+ <summary class="environment-current {{ navEnv === 'production' ? 'production' : '' }}">
39
+ <span>{{ navEnv === 'production' ? 'PROD' : 'ENV' }}</span>
40
+ <strong>{{ navEnv }}</strong>
41
+ </summary>
42
+ @if (navEnvs.length > 1)
43
+ <div class="environment-menu">
44
+ @foreach (navEnvs as e)
45
+ <a class="{{ e === navEnv ? 'active' : '' }}" href="?env={{ encodeURIComponent(e) }}">
46
+ <span>{{ e }}</span>@if (e === 'production')<small>Production</small>@else<small>Environment</small>@endif
47
+ </a>
48
+ @endforeach
49
+ </div>
39
50
  @endif
40
- @endif
41
- @if (isMember)
42
- @if ((active ?? '') === 'sites')
43
- <a href="/server/sites" class="active">Sites</a>
44
- @else
45
- <a href="/server/sites">Sites</a>
51
+ </details>
52
+ </div>
53
+
54
+ <button class="command-trigger" type="button" aria-keyshortcuts="Meta+K Control+K">
55
+ <span>Search resources</span><kbd>⌘ K</kbd>
56
+ </button>
57
+
58
+ <div class="nav-groups">
59
+ @if (navMode === 'server')
60
+ @if (canView('runtime:read') || canView('audit:read'))
61
+ <section class="nav-group">
62
+ <h2>Overview</h2>
63
+ @if (canView('runtime:read'))<a class="{{ isActive('server') ? 'active' : '' }}" href="{{ envHref('/') }}">Dashboard</a>@endif
64
+ @if (canView('audit:read'))<a href="{{ envHref('/server/activity') }}">Activity</a>@endif
65
+ </section>
46
66
  @endif
47
- @if ((active ?? '') === 'deployments')
48
- <a href="/server/deployments" class="active">Deployments</a>
49
- @else
50
- <a href="/server/deployments">Deployments</a>
67
+ <section class="nav-group">
68
+ <h2>Applications</h2>
69
+ @if (canView('project:read'))<a class="{{ isActive('sites') ? 'active' : '' }}" href="{{ envHref('/server/sites') }}">Services</a>@endif
70
+ @if (canView('deployments:read'))<a class="{{ isActive('deployments') ? 'active' : '' }}" href="{{ envHref('/server/deployments') }}">Deployments</a>@endif
71
+ @if (canView('runtime:logs'))<a class="{{ isActive('logs') ? 'active' : '' }}" href="{{ envHref('/server/logs') }}">Logs</a>@endif
72
+ @if (canView('sources:read'))<a class="{{ isActive('integrations') ? 'active' : '' }}" href="{{ envHref('/integrations') }}">Git integrations</a>@endif
73
+ @if (canView('applications:read'))<a class="{{ isActive('application-create') ? 'active' : '' }}" href="{{ envHref('/applications/new') }}">Create application</a>@endif
74
+ @if (canView('applications:read'))<a class="{{ isActive('compose-applications') ? 'active' : '' }}" href="{{ envHref('/applications/compose') }}">Compose applications</a>@endif
75
+ </section>
76
+ @if (canView('deployments:read') || canView('runtime:read') || canView('automation:read') || canView('backups:read') || canView('runtime:restart'))
77
+ <section class="nav-group">
78
+ <h2>Operations</h2>
79
+ @if (canView('deployments:read'))<a class="{{ isActive('operation-queue') ? 'active' : '' }}" href="{{ envHref('/operations/queue') }}">Deployment queue</a>@endif
80
+ @if (canView('deployments:read'))<a class="{{ isActive('previews') ? 'active' : '' }}" href="{{ envHref('/operations/previews') }}">Preview environments</a>@endif
81
+ @if (canView('deployments:read'))<a class="{{ isActive('releases') ? 'active' : '' }}" href="{{ envHref('/operations/releases') }}">Releases & promotion</a>@endif
82
+ @if (canView('deployments:read'))<a class="{{ isActive('regions') ? 'active' : '' }}" href="{{ envHref('/operations/regions') }}">Regions & failover</a>@endif
83
+ @if (canView('deployments:read'))<a class="{{ isActive('maintenance') ? 'active' : '' }}" href="{{ envHref('/operations/maintenance') }}">Maintenance & DR</a>@endif
84
+ @if (canView('runtime:read'))<a class="{{ isActive('workloads') ? 'active' : '' }}" href="{{ envHref('/operations/workloads') }}">Workloads</a>@endif
85
+ @if (canView('runtime:logs'))<a class="{{ isActive('observability') ? 'active' : '' }}" href="{{ envHref('/operations/observability') }}">Observability</a>@endif
86
+ @if (canView('runtime:read'))<a class="{{ isActive('alerts') ? 'active' : '' }}" href="{{ envHref('/operations/alerts') }}">Alerts & health</a>@endif
87
+ @if (canView('runtime:read'))<a href="{{ envHref('/server/metrics') }}">Metrics</a><a href="{{ envHref('/server/services') }}">Runtime services</a>@endif
88
+ @if (canView('automation:read'))<a class="{{ isActive('jobs') ? 'active' : '' }}" href="{{ envHref('/operations/jobs') }}">Workers & schedules</a>@endif
89
+ @if (canView('config:read'))<a class="{{ isActive('configuration') ? 'active' : '' }}" href="{{ envHref('/operations/configuration') }}">Environment &amp; secrets</a>@endif
90
+ @if (canView('backups:read'))<a class="{{ isActive('backups') ? 'active' : '' }}" href="{{ envHref('/data/backups') }}">Backups &amp; recovery</a>@endif
91
+ @if (canView('data:read'))<a class="{{ isActive('volumes') ? 'active' : '' }}" href="{{ envHref('/data/volumes') }}">Persistent volumes</a>@endif
92
+ @if (canView('runtime:restart'))<a href="{{ envHref('/server/actions') }}">Run operations</a>@endif
93
+ </section>
51
94
  @endif
52
- @if ((active ?? '') === 'logs')
53
- <a href="/server/logs" class="active">Logs</a>
54
- @else
55
- <a href="/server/logs">Logs</a>
95
+ @if (canView('data:read') || canView('fleet:read') || canView('security:read') || canView('runtime:terminal'))
96
+ <section class="nav-group">
97
+ <h2>Infrastructure</h2>
98
+ @if (canView('data:read'))<a class="{{ isActive('data-services') ? 'active' : '' }}" href="{{ envHref('/data/services') }}">Data services</a>@endif
99
+ @if (canView('data:read'))<a class="{{ isActive('volumes') ? 'active' : '' }}" href="{{ envHref('/data/volumes') }}">Persistent volumes</a>@endif
100
+ @if (canView('fleet:read'))<a href="{{ envHref('/server/firewall') }}">Network & firewall</a><a href="{{ envHref('/server/ssh-keys') }}">SSH keys</a>@endif
101
+ @if (canView('fleet:read'))<a class="{{ isActive('fleet') ? 'active' : '' }}" href="{{ envHref('/server/fleet') }}">Fleet inventory</a><a class="{{ isActive('capacity') ? 'active' : '' }}" href="{{ envHref('/server/capacity') }}">Capacity & placement</a>@endif
102
+ @if (canView('security:read'))<a href="{{ envHref('/security') }}">Security posture</a>@endif
103
+ @if (canView('runtime:terminal'))<a href="{{ envHref('/server/terminal') }}">Terminal</a>@endif
104
+ </section>
56
105
  @endif
57
- @endif
58
- @if (showServer)
59
- @if ((active ?? '') === 'database')
60
- <a href="/server/database" class="active">Databases</a>
61
- @else
62
- <a href="/server/database">Databases</a>
106
+ @else
107
+ @if (canView('project:read') || canView('deployments:read') || canView('runtime:read'))
108
+ <section class="nav-group">
109
+ <h2>Overview</h2>
110
+ @if (canView('project:read'))<a class="{{ isActive('serverless') ? 'active' : '' }}" href="{{ envHref('/serverless') }}">Dashboard</a>@endif
111
+ @if (canView('deployments:read'))<a href="{{ envHref('/serverless/deployments') }}">Deployments</a>@endif
112
+ @if (canView('runtime:logs'))<a href="{{ envHref('/serverless/logs') }}">Logs</a>@endif
113
+ @if (canView('runtime:read'))<a href="{{ envHref('/serverless/metrics') }}">Metrics</a><a href="{{ envHref('/serverless/traces') }}">Traces</a>@endif
114
+ </section>
63
115
  @endif
64
- @endif
65
- @if (!isMember)
66
- @if ((active ?? '') === 'team')
67
- <a href="/server/team" class="active">Team</a>
68
- @else
69
- <a href="/server/team">Team</a>
116
+ @if (canView('config:read') || canView('data:read') || canView('automation:read') || canView('backups:read') || canView('project:read'))
117
+ <section class="nav-group">
118
+ <h2>Compute & data</h2>
119
+ @if (canView('config:read'))<a href="{{ envHref('/serverless/functions') }}">Functions</a>@endif
120
+ @if (canView('data:read'))<a href="{{ envHref('/serverless/queues') }}">Queues</a><a class="{{ isActive('data-services') ? 'active' : '' }}" href="{{ envHref('/data/services') }}">Data services</a>@endif
121
+ @if (canView('backups:read'))<a class="{{ isActive('backups') ? 'active' : '' }}" href="{{ envHref('/data/backups') }}">Backups &amp; recovery</a>@endif
122
+ @if (canView('project:read'))<a href="{{ envHref('/serverless/assets') }}">Assets</a>@endif
123
+ </section>
124
+ @endif
125
+ @if (canView('secrets:read') || canView('fleet:read') || canView('runtime:read'))
126
+ <section class="nav-group">
127
+ <h2>Settings</h2>
128
+ @if (canView('config:read'))<a class="{{ isActive('configuration') ? 'active' : '' }}" href="{{ envHref('/operations/configuration') }}">Environment &amp; secrets</a>@endif
129
+ @if (canView('fleet:read'))<a href="{{ envHref('/serverless/firewall') }}">Network</a>@endif
130
+ @if (canView('runtime:read'))<a href="{{ envHref('/serverless/alarms') }}">Alerts</a>@endif
131
+ @if (canView('project:read'))<a href="{{ envHref('/serverless/cost') }}">Costs</a>@endif
132
+ </section>
70
133
  @endif
71
134
  @endif
72
- </div>
73
- <div class="nav-meta">
74
- <span>{{ name ?? '' }}</span>
75
- @if (showEnvSwitch)
76
- <span class="env-switch" title="Switch environment">
77
- @foreach (navEnvs as e)
78
- @if (e === navEnv)
79
- <a class="active env-opt" href="?env={{ e }}">{{ e }}</a>
80
- @else
81
- <a class="env-opt" href="?env={{ e }}">{{ e }}</a>
82
- @endif
83
- @endforeach
84
- </span>
85
- @else
86
- <span class="env">{{ navEnv || env || '' }}</span>
135
+ @if (navMode === 'serverless' && canView('security:read'))
136
+ <section class="nav-group">
137
+ <h2>Security</h2>
138
+ <a class="{{ isActive('security-posture') ? 'active' : '' }}" href="{{ envHref('/security') }}">Posture & policy</a>
139
+ </section>
140
+ @endif
141
+ @if (navMode === 'serverless' && (canView('sources:read') || canView('applications:read')))
142
+ <section class="nav-group">
143
+ <h2>Delivery</h2>
144
+ @if (canView('applications:read'))<a class="{{ isActive('application-create') ? 'active' : '' }}" href="{{ envHref('/applications/new') }}">Create application</a>@endif
145
+ @if (canView('sources:read'))<a class="{{ isActive('integrations') ? 'active' : '' }}" href="{{ envHref('/integrations') }}">Git integrations</a>@endif
146
+ </section>
147
+ @endif
148
+ @if (navMode === 'serverless' && (canView('deployments:read') || canView('runtime:read') || canView('automation:read')))
149
+ <section class="nav-group">
150
+ <h2>Operations</h2>
151
+ @if (canView('deployments:read'))<a class="{{ isActive('operation-queue') ? 'active' : '' }}" href="{{ envHref('/operations/queue') }}">Deployment queue</a>@endif
152
+ @if (canView('deployments:read'))<a class="{{ isActive('previews') ? 'active' : '' }}" href="{{ envHref('/operations/previews') }}">Preview environments</a>@endif
153
+ @if (canView('deployments:read'))<a class="{{ isActive('releases') ? 'active' : '' }}" href="{{ envHref('/operations/releases') }}">Releases & promotion</a>@endif
154
+ @if (canView('deployments:read'))<a class="{{ isActive('regions') ? 'active' : '' }}" href="{{ envHref('/operations/regions') }}">Regions & failover</a>@endif
155
+ @if (canView('deployments:read'))<a class="{{ isActive('maintenance') ? 'active' : '' }}" href="{{ envHref('/operations/maintenance') }}">Maintenance & DR</a>@endif
156
+ @if (canView('runtime:read'))<a class="{{ isActive('workloads') ? 'active' : '' }}" href="{{ envHref('/operations/workloads') }}">Workloads</a>@endif
157
+ @if (canView('runtime:logs'))<a class="{{ isActive('observability') ? 'active' : '' }}" href="{{ envHref('/operations/observability') }}">Observability</a>@endif
158
+ @if (canView('runtime:read'))<a class="{{ isActive('alerts') ? 'active' : '' }}" href="{{ envHref('/operations/alerts') }}">Alerts & health</a>@endif
159
+ @if (canView('automation:read'))<a class="{{ isActive('jobs') ? 'active' : '' }}" href="{{ envHref('/operations/jobs') }}">Workers & schedules</a>@endif
160
+ </section>
87
161
  @endif
88
- <form method="post" action="/api/logout" class="signout">
89
- <button type="submit">Sign out</button>
162
+ @if (canView('users:read'))
163
+ <section class="nav-group">
164
+ <h2>Organization</h2>
165
+ <a class="{{ isActive('team') ? 'active' : '' }}" href="{{ envHref('/server/team') }}">People & access</a>
166
+ <a class="{{ isActive('automation') ? 'active' : '' }}" href="{{ envHref('/account/automation') }}">API & automation</a>
167
+ </section>
168
+ @endif
169
+ <section class="nav-group">
170
+ <h2>Account</h2>
171
+ <a class="{{ isActive('account-security') ? 'active' : '' }}" href="{{ envHref('/account/security') }}">Sign-in & security</a>
172
+ </section>
173
+ </div>
174
+
175
+ <form method="post" action="/api/logout" class="signout">
176
+ <button type="submit">Sign out</button>
177
+ </form>
178
+ </aside>
179
+
180
+ <dialog class="command-palette" aria-labelledby="command-title">
181
+ <div class="command-search">
182
+ <span aria-hidden="true">⌕</span>
183
+ <input type="search" placeholder="Search services, domains, deployments…" aria-label="Search resources" autocomplete="off">
184
+ <button type="button" class="command-close" aria-label="Close search">Esc</button>
185
+ </div>
186
+ <h2 id="command-title" class="sr-only">Search resources and navigation</h2>
187
+ <div class="command-status" role="status">Start typing to search this project.</div>
188
+ <section class="saved-views" aria-labelledby="saved-views-title">
189
+ <div class="saved-views-heading">
190
+ <h3 id="saved-views-title">Saved views</h3>
191
+ <form class="save-view-form">
192
+ <label class="sr-only" for="save-view-name">Saved view name</label>
193
+ <input id="save-view-name" maxlength="64" placeholder="Name this view" autocomplete="off">
194
+ <button type="submit">Save current filters</button>
195
+ </form>
196
+ </div>
197
+ <div class="saved-view-list"></div>
198
+ </section>
199
+ @if (!isMember)
200
+ <form class="tag-result-form">
201
+ <label for="tag-result-name">Tag selected resource</label>
202
+ <input id="tag-result-name" maxlength="32" placeholder="customer-facing" pattern="[A-Za-z0-9][A-Za-z0-9 -]{0,31}" autocomplete="off">
203
+ <input class="tag-color" type="color" value="#5a8be0" aria-label="Tag color">
204
+ <button type="submit">Add tag</button>
90
205
  </form>
206
+ @endif
207
+ <div class="command-results" role="listbox" aria-label="Search results"></div>
208
+ <footer><span>↑ ↓ navigate</span><span>Enter open</span><span>Esc close</span></footer>
209
+ </dialog>
210
+
211
+ <div class="context-bar" aria-label="Current scope">
212
+ <div class="context-path">
213
+ <div class="context-breadcrumb">
214
+ <span>{{ navProject }}</span><i>/</i><strong>{{ navEnv }}</strong>
215
+ @if (navProvider || navRegion)<small>{{ [navProvider, navRegion].filter(Boolean).join(' · ') }}</small>@endif
216
+ </div>
217
+ <div class="context-filters" aria-label="Active filters"></div>
91
218
  </div>
92
- </nav>
219
+ <span class="scope-safety {{ navEnv === 'production' ? 'production' : '' }}">{{ navEnv === 'production' ? 'Production scope' : `${navEnv} scope` }}</span>
220
+ </div>
221
+
222
+ <script>
223
+ (() => {
224
+ const environment = new URLSearchParams(location.search).get('env')
225
+ const scopedUrl = (value) => {
226
+ const url = new URL(value, location.href)
227
+ if (url.origin !== location.origin || !environment) return value
228
+ if (!url.searchParams.has('env')) url.searchParams.set('env', environment)
229
+ return url.href
230
+ }
231
+ const main = document.querySelector('.wrap')
232
+ if (main && !main.id) main.id = 'main-content'
233
+ const sidebar = document.querySelector('.app-sidebar')
234
+ const toggle = document.querySelector('.nav-toggle-button')
235
+ const scrim = document.querySelector('.nav-scrim')
236
+ const setMenu = (open) => {
237
+ document.body.classList.toggle('nav-open', open)
238
+ toggle?.setAttribute('aria-expanded', String(open))
239
+ toggle?.setAttribute('aria-label', open ? 'Close navigation' : 'Open navigation')
240
+ }
241
+ toggle?.addEventListener('click', () => setMenu(!document.body.classList.contains('nav-open')))
242
+ scrim?.addEventListener('click', () => { setMenu(false); toggle?.focus() })
243
+ for (const anchor of sidebar?.querySelectorAll('.nav-group a[href]') || []) {
244
+ const target = new URL(anchor.href, location.href)
245
+ anchor.classList.toggle('active', target.pathname === location.pathname)
246
+ if (target.pathname === location.pathname) anchor.setAttribute('aria-current', 'page')
247
+ else anchor.removeAttribute('aria-current')
248
+ }
249
+ document.addEventListener('keydown', (event) => {
250
+ if (event.key === 'Escape' && document.body.classList.contains('nav-open')) {
251
+ setMenu(false)
252
+ toggle?.focus()
253
+ }
254
+ })
255
+
256
+ const palette = document.querySelector('.command-palette')
257
+ const commandTrigger = document.querySelector('.command-trigger')
258
+ const commandInput = palette?.querySelector('input[type="search"]')
259
+ const commandResults = palette?.querySelector('.command-results')
260
+ const commandStatus = palette?.querySelector('.command-status')
261
+ const commandClose = palette?.querySelector('.command-close')
262
+ const savedViews = palette?.querySelector('.saved-views')
263
+ const savedViewList = palette?.querySelector('.saved-view-list')
264
+ const saveViewForm = palette?.querySelector('.save-view-form')
265
+ const saveViewName = palette?.querySelector('#save-view-name')
266
+ const tagResultForm = palette?.querySelector('.tag-result-form')
267
+ const tagResultName = palette?.querySelector('#tag-result-name')
268
+ const tagResultColor = palette?.querySelector('.tag-color')
269
+ const contextFilters = document.querySelector('.context-filters')
270
+ let searchTimer
271
+ let selectedResult = -1
272
+ let favoriteKeys = new Set()
273
+
274
+ const preferenceRequest = (body, method = 'POST') => fetch('/api/search/preferences', {
275
+ method,
276
+ headers: { 'content-type': 'application/json' },
277
+ body: JSON.stringify(body),
278
+ })
279
+
280
+ const renderFilterChips = () => {
281
+ contextFilters?.replaceChildren()
282
+ const ignored = new Set(['env', 'project'])
283
+ for (const [key, value] of new URLSearchParams(location.search)) {
284
+ if (ignored.has(key) || !value) continue
285
+ const chip = document.createElement('button')
286
+ chip.type = 'button'
287
+ chip.className = 'filter-chip'
288
+ chip.textContent = `${key}: ${value} ×`
289
+ chip.setAttribute('aria-label', `Remove ${key} filter ${value}`)
290
+ chip.addEventListener('click', () => {
291
+ const url = new URL(location.href)
292
+ url.searchParams.delete(key, value)
293
+ location.assign(url)
294
+ })
295
+ contextFilters?.append(chip)
296
+ }
297
+ }
298
+
299
+ const renderSavedViews = (filters) => {
300
+ savedViewList?.replaceChildren()
301
+ for (const filter of filters) {
302
+ const row = document.createElement('div')
303
+ row.className = 'saved-view-row'
304
+ const link = document.createElement('a')
305
+ const url = new URL(filter.routeId || '/', location.origin)
306
+ if (url.origin !== location.origin) continue
307
+ for (const [key, value] of Object.entries(filter.query || {})) url.searchParams.set(key, String(value))
308
+ link.href = scopedUrl(url.href)
309
+ link.textContent = filter.name
310
+ const remove = document.createElement('button')
311
+ remove.type = 'button'
312
+ remove.textContent = 'Remove'
313
+ remove.setAttribute('aria-label', `Remove saved view ${filter.name}`)
314
+ remove.addEventListener('click', async () => {
315
+ const response = await preferenceRequest({ id: filter.id }, 'DELETE')
316
+ if (response.ok) row.remove()
317
+ })
318
+ row.append(link, remove)
319
+ savedViewList?.append(row)
320
+ }
321
+ savedViews?.classList.toggle('empty', filters.length === 0)
322
+ }
323
+
324
+ const loadPreferences = async () => {
325
+ try {
326
+ const response = await fetch('/api/search/preferences')
327
+ if (!response.ok) return
328
+ const data = await response.json()
329
+ favoriteKeys = new Set((data.navigation || []).filter(item => item.favorite).map(item => `${item.entityType}:${item.entityId}`))
330
+ renderSavedViews(data.savedFilters || [])
331
+ } catch {}
332
+ }
333
+
334
+ const closePalette = () => {
335
+ palette?.close()
336
+ commandTrigger?.focus()
337
+ }
338
+ const openPalette = () => {
339
+ if (!palette?.open) palette?.showModal()
340
+ commandInput?.focus()
341
+ loadPreferences()
342
+ }
343
+ const selectResult = (index) => {
344
+ const links = [...(commandResults?.querySelectorAll('a[role="option"]') || [])]
345
+ if (!links.length) return
346
+ selectedResult = Math.max(0, Math.min(index, links.length - 1))
347
+ links.forEach((link, position) => link.classList.toggle('selected', position === selectedResult))
348
+ links[selectedResult]?.scrollIntoView({ block: 'nearest' })
349
+ const selectedType = links[selectedResult]?.dataset.entityType
350
+ const taggable = ['service', 'server', 'database'].includes(selectedType)
351
+ tagResultForm?.querySelector('button')?.toggleAttribute('disabled', !taggable)
352
+ }
353
+ const appendHighlighted = (parent, value, query) => {
354
+ const text = String(value || '')
355
+ const wanted = query.trim().toLowerCase()
356
+ const index = wanted ? text.toLowerCase().indexOf(wanted) : -1
357
+ if (index < 0) { parent.textContent = text; return }
358
+ parent.append(document.createTextNode(text.slice(0, index)))
359
+ const mark = document.createElement('mark')
360
+ mark.textContent = text.slice(index, index + wanted.length)
361
+ parent.append(mark, document.createTextNode(text.slice(index + wanted.length)))
362
+ }
363
+ const renderResults = (results) => {
364
+ commandResults.replaceChildren()
365
+ selectedResult = -1
366
+ if (!results.length) {
367
+ commandStatus.textContent = commandInput.value.trim() ? 'No matching resources in your current access scope.' : 'Start typing to search this project.'
368
+ return
369
+ }
370
+ commandStatus.textContent = `${results.length} result${results.length === 1 ? '' : 's'}`
371
+ const groups = new Map()
372
+ for (const result of results) {
373
+ if (!groups.has(result.type)) {
374
+ const group = document.createElement('section')
375
+ group.className = 'command-group'
376
+ group.setAttribute('role', 'group')
377
+ group.setAttribute('aria-label', `${result.type} results`)
378
+ const heading = document.createElement('h3')
379
+ heading.textContent = `${result.type}s`
380
+ group.append(heading)
381
+ groups.set(result.type, group)
382
+ commandResults.append(group)
383
+ }
384
+ const row = document.createElement('div')
385
+ row.className = 'command-result-row'
386
+ const link = document.createElement('a')
387
+ link.href = scopedUrl(result.href)
388
+ link.setAttribute('role', 'option')
389
+ link.dataset.entityType = result.type
390
+ link.dataset.entityId = result.id
391
+ const type = document.createElement('span')
392
+ type.className = 'command-type'
393
+ type.textContent = result.type
394
+ const copy = document.createElement('span')
395
+ copy.className = 'command-copy'
396
+ const title = document.createElement('strong')
397
+ appendHighlighted(title, result.title, commandInput.value)
398
+ const subtitle = document.createElement('small')
399
+ appendHighlighted(subtitle, [result.subtitle, result.environment, result.provider, ...(result.tags || []).map(tag => `#${tag.name}`)].filter(Boolean).join(' · '), commandInput.value)
400
+ copy.append(title, subtitle)
401
+ link.append(type, copy)
402
+ link.addEventListener('click', () => {
403
+ fetch('/api/search/preferences', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ action: 'visit', entityType: result.type, entityId: result.id }) }).catch(() => {})
404
+ })
405
+ const favorite = document.createElement('button')
406
+ const favoriteKey = `${result.type}:${result.id}`
407
+ const setFavoriteLabel = () => {
408
+ const active = favoriteKeys.has(favoriteKey)
409
+ favorite.textContent = active ? '★' : '☆'
410
+ favorite.setAttribute('aria-label', `${active ? 'Remove' : 'Add'} ${result.title} ${active ? 'from' : 'to'} favorites`)
411
+ favorite.classList.toggle('active', active)
412
+ }
413
+ favorite.type = 'button'
414
+ favorite.className = 'favorite-result'
415
+ setFavoriteLabel()
416
+ favorite.addEventListener('click', async () => {
417
+ const active = !favoriteKeys.has(favoriteKey)
418
+ const response = await preferenceRequest({ action: 'favorite', entityType: result.type, entityId: result.id, favorite: active })
419
+ if (!response.ok) return
420
+ if (active) favoriteKeys.add(favoriteKey)
421
+ else favoriteKeys.delete(favoriteKey)
422
+ setFavoriteLabel()
423
+ })
424
+ row.append(link, favorite)
425
+ groups.get(result.type).append(row)
426
+ }
427
+ selectResult(0)
428
+ }
429
+ const search = () => {
430
+ clearTimeout(searchTimer)
431
+ const query = commandInput?.value.trim() || ''
432
+ if (!query) { renderResults([]); return }
433
+ commandStatus.textContent = 'Searching…'
434
+ searchTimer = setTimeout(async () => {
435
+ try {
436
+ const response = await fetch(`/api/search?q=${encodeURIComponent(query)}`)
437
+ const data = await response.json()
438
+ renderResults(response.ok ? (data.results || []) : [])
439
+ }
440
+ catch { commandStatus.textContent = 'Search is temporarily unavailable.' }
441
+ }, 120)
442
+ }
443
+
444
+ commandTrigger?.addEventListener('click', openPalette)
445
+ commandClose?.addEventListener('click', closePalette)
446
+ commandInput?.addEventListener('input', search)
447
+ commandInput?.addEventListener('keydown', (event) => {
448
+ if (event.key === 'Escape') { event.preventDefault(); closePalette() }
449
+ else if (event.key === 'ArrowDown') { event.preventDefault(); selectResult(selectedResult + 1) }
450
+ else if (event.key === 'ArrowUp') { event.preventDefault(); selectResult(selectedResult - 1) }
451
+ else if (event.key === 'Enter' && selectedResult >= 0) {
452
+ event.preventDefault()
453
+ commandResults.querySelectorAll('a[role="option"]')[selectedResult]?.click()
454
+ }
455
+ })
456
+ saveViewForm?.addEventListener('submit', async (event) => {
457
+ event.preventDefault()
458
+ const name = saveViewName?.value.trim()
459
+ if (!name) { saveViewName?.focus(); return }
460
+ const query = Object.fromEntries(new URLSearchParams(location.search))
461
+ const response = await preferenceRequest({ action: 'save-filter', name, routeId: location.pathname, query })
462
+ if (!response.ok) { commandStatus.textContent = 'Could not save this view.'; return }
463
+ saveViewName.value = ''
464
+ await loadPreferences()
465
+ commandStatus.textContent = `Saved view “${name}”.`
466
+ })
467
+ tagResultForm?.addEventListener('submit', async (event) => {
468
+ event.preventDefault()
469
+ const selected = commandResults.querySelectorAll('a[role="option"]')[selectedResult]
470
+ const name = tagResultName?.value.trim()
471
+ if (!selected?.dataset.entityId || !name) { tagResultName?.focus(); return }
472
+ const response = await fetch('/api/tags', {
473
+ method: 'POST',
474
+ headers: { 'content-type': 'application/json' },
475
+ body: JSON.stringify({ resourceId: selected.dataset.entityId, name, color: tagResultColor?.value || '#5a8be0' }),
476
+ })
477
+ if (!response.ok) { commandStatus.textContent = 'Could not assign that tag.'; return }
478
+ tagResultName.value = ''
479
+ const subtitle = selected.querySelector('small')
480
+ if (subtitle && !subtitle.textContent.includes(`#${name}`)) subtitle.append(document.createTextNode(` · #${name}`))
481
+ commandStatus.textContent = `Tagged ${selected.querySelector('strong')?.textContent || 'resource'} with #${name}.`
482
+ })
483
+ palette?.addEventListener('cancel', (event) => { event.preventDefault(); closePalette() })
484
+ document.addEventListener('keydown', (event) => {
485
+ const shortcut = (event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 'k'
486
+ const slash = event.key === '/' && !['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement?.tagName)
487
+ if (shortcut || slash) { event.preventDefault(); openPalette() }
488
+ })
489
+ renderFilterChips()
490
+ window.addEventListener('ts-cloud:filters-changed', renderFilterChips)
491
+ if (!environment) return
492
+
493
+ const originalFetch = window.fetch.bind(window)
494
+ window.fetch = (input, init) => {
495
+ if (typeof input === 'string') return originalFetch(scopedUrl(input), init)
496
+ if (input instanceof URL) return originalFetch(new URL(scopedUrl(input.href)), init)
497
+ if (input instanceof Request) return originalFetch(new Request(scopedUrl(input.url), input), init)
498
+ return originalFetch(input, init)
499
+ }
500
+
501
+ document.addEventListener('click', (event) => {
502
+ const anchor = event.target.closest?.('a[href]')
503
+ if (!anchor || anchor.target || anchor.hasAttribute('download')) return
504
+ const href = anchor.getAttribute('href')
505
+ if (!href || href.startsWith('#') || href.startsWith('mailto:')) return
506
+ anchor.href = scopedUrl(href)
507
+ })
508
+ })()
509
+ </script>
@@ -1,7 +1,7 @@
1
- <div class="op-confirm panel" @show="pending() !== null">
2
- <span>Type <b class="mono">{{ confirmTok() }}</b> to {{ confirmVerb() }}:</span>
3
- <input class="op-confirm-input" :value="typed()" @input="typed.set($event.target.value)" @keydown.enter="runOp()" placeholder="confirm" autocomplete="off">
4
- <button class="btn sm" :disabled="!canRun()" @click="runOp()">Run</button>
5
- <button class="btn ghost sm" @click="cancelOp()">Cancel</button>
1
+ <div class="op-confirm panel" @show="pending() !== null" role="group" aria-labelledby="op-confirm-prompt">
2
+ <span id="op-confirm-prompt">Type <b class="mono">{{ confirmTok() }}</b> to {{ confirmVerb() }}:</span>
3
+ <input @ref="opConfirmInput" class="op-confirm-input" :value="typed()" @input="typed.set($event.target.value)" @keydown.enter="runOp()" placeholder="confirm" autocomplete="off" aria-labelledby="op-confirm-prompt">
4
+ <button type="button" class="btn sm" :class="{ danger: confirmDanger() }" :disabled="!canRun()" @click="runOp()">{{ confirmLabel() }}</button>
5
+ <button type="button" class="btn ghost sm" :disabled="busy()" @click="cancelOp()">Cancel</button>
6
6
  </div>
7
- <pre class="action-output op-output" @show="opShown()">{{ opOutput() }}</pre>
7
+ <pre class="action-output op-output" @show="opShown()" aria-live="polite">{{ opOutput() }}</pre>