@stacksjs/ts-cloud 0.7.105 → 0.7.109

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 (149) hide show
  1. package/dist/alerts/delivery.d.ts +10 -0
  2. package/dist/alerts/model.d.ts +1 -1
  3. package/dist/api/client.d.ts +53 -0
  4. package/dist/api/handler.d.ts +10 -0
  5. package/dist/api/service.d.ts +1 -0
  6. package/dist/aws/index.js +10 -10
  7. package/dist/aws/lambda.d.ts +19 -0
  8. package/dist/bin/cli.js +1677 -1370
  9. package/dist/bin/dashboard-server.js +926 -620
  10. package/dist/{chunk-fmt40tpw.js → chunk-53jatzaw.js} +2 -2
  11. package/dist/{chunk-ef2dwfrg.js → chunk-8kh577qh.js} +5 -5
  12. package/dist/{chunk-s9c2x5jv.js → chunk-9v2pwxv9.js} +2 -2
  13. package/dist/chunk-aa2dkn7b.js +205 -0
  14. package/dist/{chunk-vkd2y0fs.js → chunk-cktwk9hy.js} +7169 -14800
  15. package/dist/{chunk-dmzez5f8.js → chunk-d3vx2ekv.js} +123 -28
  16. package/dist/chunk-grx1rp09.js +12163 -0
  17. package/dist/{chunk-c6db5m63.js → chunk-t2s3gdq6.js} +253 -8
  18. package/dist/chunk-va2yd85b.js +200 -0
  19. package/dist/{chunk-3g4r09dd.js → chunk-wmbep3b5.js} +1 -1
  20. package/dist/{chunk-ybcz6sxc.js → chunk-x6yzgv7y.js} +33 -0
  21. package/dist/chunk-xrtwv3v2.js +420 -0
  22. package/dist/control-plane/types.d.ts +1 -1
  23. package/dist/deploy/dashboard-bundle-encoding.test.d.ts +1 -0
  24. package/dist/deploy/dashboard-payload.d.ts +20 -0
  25. package/dist/deploy/dashboard-payload.test.d.ts +1 -0
  26. package/dist/deploy/dashboard-protection.test.d.ts +1 -0
  27. package/dist/deploy/dashboard-spend.test.d.ts +1 -0
  28. package/dist/deploy/dashboard-topology.d.ts +85 -0
  29. package/dist/deploy/dashboard-topology.test.d.ts +1 -0
  30. package/dist/deploy/egress-collection.d.ts +60 -0
  31. package/dist/deploy/index.d.ts +2 -0
  32. package/dist/deploy/index.js +23 -8
  33. package/dist/deploy/local-dashboard-server.d.ts +2 -0
  34. package/dist/drivers/index.js +4 -2
  35. package/dist/drivers/shared/protection.d.ts +43 -0
  36. package/dist/drivers/shared/protection.test.d.ts +1 -0
  37. package/dist/index.d.ts +3 -0
  38. package/dist/index.js +364 -102
  39. package/dist/protection/controls.d.ts +113 -0
  40. package/dist/protection/controls.test.d.ts +1 -0
  41. package/dist/protection/ddos.d.ts +130 -0
  42. package/dist/protection/ddos.test.d.ts +1 -0
  43. package/dist/protection/index.d.ts +11 -0
  44. package/dist/protection/index.js +87 -0
  45. package/dist/protection/ratelimit.d.ts +154 -0
  46. package/dist/protection/ratelimit.test.d.ts +1 -0
  47. package/dist/protection/waf.d.ts +143 -0
  48. package/dist/protection/waf.test.d.ts +1 -0
  49. package/dist/spend/anomaly-config.d.ts +130 -0
  50. package/dist/spend/anomaly-config.test.d.ts +1 -0
  51. package/dist/spend/anomaly.d.ts +114 -0
  52. package/dist/spend/anomaly.test.d.ts +1 -0
  53. package/dist/spend/api.d.ts +42 -0
  54. package/dist/spend/api.test.d.ts +1 -0
  55. package/dist/spend/appliers.d.ts +126 -0
  56. package/dist/spend/docs.test.d.ts +1 -0
  57. package/dist/spend/enforcement.d.ts +111 -0
  58. package/dist/spend/enforcement.integration.test.d.ts +1 -0
  59. package/dist/spend/evaluator.d.ts +70 -0
  60. package/dist/spend/evaluator.test.d.ts +1 -0
  61. package/dist/spend/focus.d.ts +93 -0
  62. package/dist/spend/focus.test.d.ts +1 -0
  63. package/dist/spend/gate.d.ts +96 -0
  64. package/dist/spend/index.d.ts +20 -0
  65. package/dist/spend/index.js +173 -0
  66. package/dist/spend/lease.d.ts +54 -0
  67. package/dist/spend/lease.test.d.ts +1 -0
  68. package/dist/spend/meter.d.ts +70 -0
  69. package/dist/spend/meter.test.d.ts +1 -0
  70. package/dist/spend/model.d.ts +228 -0
  71. package/dist/spend/notifications.d.ts +58 -0
  72. package/dist/spend/pricing.d.ts +109 -0
  73. package/dist/spend/pricing.test.d.ts +1 -0
  74. package/dist/spend/projection.d.ts +36 -0
  75. package/dist/spend/runner.d.ts +130 -0
  76. package/dist/spend/service.d.ts +129 -0
  77. package/dist/spend/signals.d.ts +110 -0
  78. package/dist/spend/signals.test.d.ts +1 -0
  79. package/dist/spend/sms-sdk.test.d.ts +1 -0
  80. package/dist/spend/spend.integration.test.d.ts +1 -0
  81. package/dist/spend/store.d.ts +166 -0
  82. package/dist/spend/transports.d.ts +169 -0
  83. package/dist/spend/transports.test.d.ts +1 -0
  84. package/dist/spend/window.d.ts +52 -0
  85. package/dist/spend/window.test.d.ts +1 -0
  86. package/dist/ui/404.html +2 -0
  87. package/dist/ui/access-denied.html +2 -2
  88. package/dist/ui/account/automation.html +4 -4
  89. package/dist/ui/account/security.html +2 -2
  90. package/dist/ui/applications/compose.html +4 -4
  91. package/dist/ui/applications/new.html +2 -2
  92. package/dist/ui/data/backups.html +22 -9
  93. package/dist/ui/data/services.html +22 -9
  94. package/dist/ui/data/volumes.html +22 -9
  95. package/dist/ui/index.html +22 -9
  96. package/dist/ui/infrastructure/topology.html +2223 -0
  97. package/dist/ui/integrations.html +2 -2
  98. package/dist/ui/operations/alerts.html +22 -9
  99. package/dist/ui/operations/configuration.html +4 -4
  100. package/dist/ui/operations/jobs.html +22 -9
  101. package/dist/ui/operations/maintenance.html +4 -4
  102. package/dist/ui/operations/observability.html +22 -9
  103. package/dist/ui/operations/previews.html +4 -4
  104. package/dist/ui/operations/queue.html +4 -4
  105. package/dist/ui/operations/regions.html +3 -3
  106. package/dist/ui/operations/releases.html +3 -3
  107. package/dist/ui/operations/spend.html +1634 -0
  108. package/dist/ui/operations/workloads.html +22 -9
  109. package/dist/ui/security.html +2 -2
  110. package/dist/ui/server/actions.html +4 -4
  111. package/dist/ui/server/activity.html +2 -2
  112. package/dist/ui/server/capacity.html +4 -4
  113. package/dist/ui/server/database.html +4 -4
  114. package/dist/ui/server/deployments.html +4 -4
  115. package/dist/ui/server/diagnostics.html +2 -2
  116. package/dist/ui/server/firewall.html +100 -161
  117. package/dist/ui/server/fleet.html +22 -9
  118. package/dist/ui/server/logs.html +22 -9
  119. package/dist/ui/server/metrics.html +130 -14
  120. package/dist/ui/server/security.html +2 -2
  121. package/dist/ui/server/services.html +1 -1
  122. package/dist/ui/server/sites.html +22 -9
  123. package/dist/ui/server/ssh-keys.html +3 -3
  124. package/dist/ui/server/team.html +4 -4
  125. package/dist/ui/server/terminal.html +2 -2
  126. package/dist/ui/serverless/alarms.html +4 -4
  127. package/dist/ui/serverless/assets.html +2 -2
  128. package/dist/ui/serverless/cost.html +2 -2
  129. package/dist/ui/serverless/data.html +4 -4
  130. package/dist/ui/serverless/deployments.html +2 -2
  131. package/dist/ui/serverless/firewall.html +2 -2
  132. package/dist/ui/serverless/functions.html +4 -4
  133. package/dist/ui/serverless/logs.html +22 -9
  134. package/dist/ui/serverless/metrics.html +2 -2
  135. package/dist/ui/serverless/queues.html +4 -4
  136. package/dist/ui/serverless/secrets.html +4 -4
  137. package/dist/ui/serverless/traces.html +4 -4
  138. package/dist/ui/serverless.html +4 -4
  139. package/dist/ui-src/functions/requestJson.ts +41 -0
  140. package/dist/ui-src/functions/useOpConfirm.ts +132 -0
  141. package/dist/ui-src/functions/usePolling.ts +98 -0
  142. package/dist/ui-src/functions/useTerminal.ts +79 -0
  143. package/dist/ui-src/pages/infrastructure/topology.stx +517 -0
  144. package/dist/ui-src/pages/operations/spend.stx +225 -0
  145. package/dist/ui-src/pages/partials/nav.stx +4 -0
  146. package/dist/ui-src/pages/server/firewall.stx +89 -0
  147. package/dist/ui-src/pages/server/metrics.stx +140 -6
  148. package/dist/ui-src/src/topology.ts +485 -0
  149. package/package.json +11 -3
@@ -0,0 +1,132 @@
1
+ export interface OperationConfirmation {
2
+ operation: string
3
+ confirm: string
4
+ verb: string
5
+ to?: string | null
6
+ apiConfirm?: string
7
+ danger?: boolean
8
+ label?: string
9
+ [key: string]: unknown
10
+ }
11
+
12
+ export interface OperationResult {
13
+ output: string
14
+ ok?: boolean
15
+ }
16
+
17
+ export type Signal<T> = (() => T) & { set: (value: T) => void }
18
+
19
+ interface HTMLElement {
20
+ focus: () => void
21
+ scrollIntoView: (options?: { behavior?: string; block?: string }) => void
22
+ }
23
+
24
+ type HTMLInputElement = HTMLElement
25
+
26
+ export interface OperationConfirmationController {
27
+ opOutput: Signal<string>
28
+ opShown: Signal<boolean>
29
+ pending: Signal<OperationConfirmation | null>
30
+ typed: Signal<string>
31
+ busy: Signal<boolean>
32
+ confirmTok: Signal<string>
33
+ confirmVerb: Signal<string>
34
+ confirmDanger: Signal<boolean>
35
+ confirmLabel: Signal<string>
36
+ canRun: Signal<boolean>
37
+ askOp: (
38
+ operation: string,
39
+ confirm: string,
40
+ verb: string,
41
+ to?: string | null,
42
+ apiConfirm?: string,
43
+ options?: Partial<OperationConfirmation>,
44
+ ) => void
45
+ cancelOp: () => void
46
+ runOp: () => Promise<void>
47
+ }
48
+
49
+ declare function state<T>(_value: T): Signal<T>
50
+ declare function derived<T>(_value: () => T): Signal<T>
51
+ declare function useRef<T = HTMLElement>(_name: string): { current: T | null }
52
+
53
+ const DANGEROUS_OPERATION = /(?:^|:)(?:delete|disable|destroy|purge|remove|restore|rollback|stop)(?::|$)/i
54
+
55
+ export function operationIsDangerous(operation: Pick<OperationConfirmation, 'operation' | 'danger'>): boolean {
56
+ return operation.danger ?? DANGEROUS_OPERATION.test(operation.operation)
57
+ }
58
+
59
+ /**
60
+ * One confirmation lifecycle for dashboard operations. The caller owns only
61
+ * the API request; this composable owns staging, exact-token validation,
62
+ * in-flight locking, focus, output, cancellation, and error presentation.
63
+ */
64
+ export function useOpConfirm(
65
+ execute: (operation: OperationConfirmation) => Promise<string | OperationResult>,
66
+ ): OperationConfirmationController {
67
+ const opOutput = state('')
68
+ const opShown = state(false)
69
+ const pending = state<OperationConfirmation | null>(null)
70
+ const typed = state('')
71
+ const busy = state(false)
72
+ const confirmInput = useRef<HTMLInputElement>('opConfirmInput')
73
+ const confirmTok = derived(() => pending()?.confirm ?? '')
74
+ const confirmVerb = derived(() => pending()?.verb ?? '')
75
+ const confirmDanger = derived(() => (pending() ? operationIsDangerous(pending()!) : false))
76
+ const confirmLabel = derived(() => pending()?.label ?? (confirmDanger() ? 'Confirm operation' : 'Run operation'))
77
+ const canRun = derived(() => !!pending() && !busy() && typed() === pending()!.confirm)
78
+
79
+ function askOp(
80
+ operation: string,
81
+ confirm: string,
82
+ verb: string,
83
+ to?: string | null,
84
+ apiConfirm?: string,
85
+ options: Partial<OperationConfirmation> = {},
86
+ ) {
87
+ pending.set({ ...options, operation, confirm, verb, to: to ?? null, apiConfirm: apiConfirm || confirm })
88
+ typed.set('')
89
+ confirmInput.current?.focus()
90
+ confirmInput.current?.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
91
+ }
92
+
93
+ function cancelOp() {
94
+ if (busy()) return
95
+ pending.set(null)
96
+ typed.set('')
97
+ }
98
+
99
+ async function runOp() {
100
+ const operation = pending()
101
+ if (!operation || busy() || typed() !== operation.confirm) return
102
+ busy.set(true)
103
+ opShown.set(true)
104
+ opOutput.set(`Running ${operation.operation}...`)
105
+ try {
106
+ const result = await execute(operation)
107
+ opOutput.set(typeof result === 'string' ? result : result.output)
108
+ pending.set(null)
109
+ typed.set('')
110
+ } catch (error) {
111
+ opOutput.set(`FAILED ${operation.operation}\n\n${error instanceof Error ? error.message : String(error)}`)
112
+ } finally {
113
+ busy.set(false)
114
+ }
115
+ }
116
+
117
+ return {
118
+ opOutput,
119
+ opShown,
120
+ pending,
121
+ typed,
122
+ busy,
123
+ confirmTok,
124
+ confirmVerb,
125
+ confirmDanger,
126
+ confirmLabel,
127
+ canRun,
128
+ askOp,
129
+ cancelOp,
130
+ runOp,
131
+ }
132
+ }
@@ -0,0 +1,98 @@
1
+ export type Signal<T> = (() => T) & { set: (value: T) => void }
2
+ declare function state<T>(_value: T): Signal<T>
3
+ declare function derived<T>(_value: () => T): Signal<T>
4
+ declare function onMount(_callback: () => void | (() => void)): void
5
+ declare function useInterval(
6
+ _interval: number,
7
+ _options?: { immediate?: boolean },
8
+ ): { subscribe: (callback: () => void) => () => void; pause: () => void }
9
+
10
+ /**
11
+ * `snapshot` means the cockpit was exported without its control plane — the
12
+ * static + htpasswd deploy (`TS_CLOUD_UI_STATIC`). The data baked into the page
13
+ * is real, it just cannot be refreshed, which is a different thing from a
14
+ * refresh that failed and must not be reported as an error.
15
+ */
16
+ export type PollingState = 'loading' | 'live' | 'stale' | 'snapshot'
17
+
18
+ export interface PollingController {
19
+ pollingState: Signal<PollingState>
20
+ pollingError: Signal<string>
21
+ pollingLabel: Signal<PollingState>
22
+ lastUpdatedAt: Signal<Date | null>
23
+ /** True once the deployment has told us it serves no API. */
24
+ isSnapshot: Signal<boolean>
25
+ refresh: () => Promise<void>
26
+ }
27
+
28
+ export interface PollingOptions {
29
+ /**
30
+ * Treat a missing API route as "this build has no control plane" instead of
31
+ * as an error.
32
+ *
33
+ * Opt in only from a page whose data is fully baked in at build time, so
34
+ * there is genuinely nothing lost by not polling — the infrastructure map,
35
+ * for instance. A page that manages live resources must NOT set this: its
36
+ * buttons post to that same missing API, so a 404 there is a real fault and
37
+ * calling it a snapshot would hide it. Off by default for that reason.
38
+ */
39
+ snapshotWhenApiMissing?: boolean
40
+ }
41
+
42
+ /**
43
+ * A build served without its control plane answers the API route itself rather
44
+ * than failing in transit: a static host 404s the path, and a proxy that knows
45
+ * the route but not the method answers 405/501. Anything else — a 500, a
46
+ * dropped connection, malformed JSON — is a real failure and stays one.
47
+ *
48
+ * Only errors carrying an HTTP status qualify, so the caller must be using
49
+ * `requestJson` (which raises `DashboardRequestError`); a bare `fetch` that
50
+ * throws a plain `Error` keeps the stale-with-error behaviour.
51
+ */
52
+ function servedWithoutApi(error: unknown): boolean {
53
+ const status = (error as { status?: unknown })?.status
54
+ return status === 404 || status === 405 || status === 501
55
+ }
56
+
57
+ /** Poll immediately and on a lifecycle-owned interval, retaining stale data on failure. */
58
+ export function usePolling(
59
+ task: () => Promise<void>,
60
+ intervalMs: number,
61
+ options: PollingOptions = {},
62
+ ): PollingController {
63
+ const pollingState = state<PollingState>('loading')
64
+ const pollingError = state('')
65
+ const lastUpdatedAt = state<Date | null>(null)
66
+ const isSnapshot = state(false)
67
+ const pollingLabel = derived<PollingState>(() => pollingState())
68
+
69
+ const interval = useInterval(intervalMs)
70
+
71
+ async function refresh() {
72
+ try {
73
+ await task()
74
+ pollingState.set('live')
75
+ pollingError.set('')
76
+ isSnapshot.set(false)
77
+ lastUpdatedAt.set(new Date())
78
+ } catch (error) {
79
+ if (options.snapshotWhenApiMissing && servedWithoutApi(error)) {
80
+ // Nothing here will ever answer, so stop asking. The page keeps the
81
+ // data it was built with and says it is a snapshot, not an outage.
82
+ isSnapshot.set(true)
83
+ pollingState.set('snapshot')
84
+ pollingError.set('')
85
+ interval.pause()
86
+ return
87
+ }
88
+ pollingState.set('stale')
89
+ pollingError.set(error instanceof Error ? error.message : String(error))
90
+ }
91
+ }
92
+
93
+ interval.subscribe(refresh)
94
+ onMount(() => {
95
+ refresh()
96
+ })
97
+ return { pollingState, pollingError, pollingLabel, lastUpdatedAt, isSnapshot, refresh }
98
+ }
@@ -0,0 +1,79 @@
1
+ export type Signal<T> = (() => T) & { set: (value: T) => void }
2
+
3
+ interface HTMLElement {
4
+ scrollTop: number
5
+ scrollHeight: number
6
+ }
7
+
8
+ declare const location: { protocol: string; host: string }
9
+ declare function state<T>(_value: T): Signal<T>
10
+ declare function derived<T>(_value: () => T): Signal<T>
11
+ declare function effect(_callback: () => void): void
12
+ declare function useRef<T = HTMLElement>(_name: string): { current: T | null }
13
+ declare function useWebSocket(
14
+ _url: string,
15
+ _options?: Record<string, unknown>,
16
+ ): {
17
+ status: Signal<'CONNECTING' | 'OPEN' | 'CLOSING' | 'CLOSED'>
18
+ send: (data: string) => void
19
+ close: () => void
20
+ connect: () => void
21
+ }
22
+
23
+ export interface TerminalController {
24
+ buf: Signal<string>
25
+ cmd: Signal<string>
26
+ status: Signal<string>
27
+ send: () => void
28
+ reconnect: () => void
29
+ clearOut: () => void
30
+ statusTone: (value: string) => 'ok' | 'bad' | 'warn'
31
+ }
32
+
33
+ /** Terminal transport and viewport behavior, isolated from the stx template. */
34
+ export function useTerminal(path: string = '/api/terminal'): TerminalController {
35
+ const buf = state('')
36
+ const cmd = state('')
37
+ const output = useRef<HTMLElement>('terminalOutput')
38
+ const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'
39
+ const url = `${protocol}//${location.host}${path}`
40
+ const socket = useWebSocket(url, {
41
+ reconnect: true,
42
+ maxReconnects: 10,
43
+ reconnectDelay: 1000,
44
+ onMessage(data: unknown) {
45
+ buf.set((buf() + String(data)).slice(-40000))
46
+ },
47
+ })
48
+ const status = derived(
49
+ () =>
50
+ ({ CONNECTING: 'connecting', OPEN: 'connected', CLOSING: 'disconnecting', CLOSED: 'disconnected' })[
51
+ socket.status()
52
+ ] || 'error',
53
+ )
54
+
55
+ effect(() => {
56
+ buf()
57
+ const element = output.current
58
+ if (element) element.scrollTop = element.scrollHeight
59
+ })
60
+
61
+ function send() {
62
+ const command = cmd()
63
+ if (!command.trim() || socket.status() !== 'OPEN') return
64
+ socket.send(command + '\n')
65
+ cmd.set('')
66
+ }
67
+ function reconnect() {
68
+ socket.close()
69
+ buf.set('')
70
+ socket.connect()
71
+ }
72
+ function clearOut() {
73
+ buf.set('')
74
+ }
75
+ function statusTone(value: string): 'ok' | 'bad' | 'warn' {
76
+ return value === 'connected' ? 'ok' : value === 'disconnected' || value === 'error' ? 'bad' : 'warn'
77
+ }
78
+ return { buf, cmd, status, send, reconnect, clearOut, statusTone }
79
+ }