@stacksjs/ts-cloud 0.7.32 → 0.7.34
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.
- package/dist/bin/cli.js +709 -693
- package/dist/{chunk-dah449r1.js → chunk-e6xhm3qe.js} +47 -11
- package/dist/{chunk-jgenfdz6.js → chunk-jvp3s3na.js} +4 -2
- package/dist/deploy/index.js +2 -2
- package/dist/drivers/index.js +1 -1
- package/dist/drivers/shared/ubuntu-bootstrap.d.ts +10 -0
- package/dist/index.js +2 -2
- package/dist/ui/index.html +3 -3
- package/dist/ui/server/actions.html +23 -6
- package/dist/ui/server/backups.html +3 -3
- package/dist/ui/server/database.html +3 -3
- package/dist/ui/server/deployments.html +3 -3
- package/dist/ui/server/firewall.html +3 -3
- package/dist/ui/server/logs.html +3 -3
- package/dist/ui/server/services.html +3 -3
- package/dist/ui/server/sites.html +3 -3
- package/dist/ui/server/ssh-keys.html +26 -4
- package/dist/ui/server/team.html +26 -4
- package/dist/ui/server/terminal.html +3 -3
- package/dist/ui/server/workers.html +3 -3
- package/dist/ui/serverless/alarms.html +3 -3
- package/dist/ui/serverless/assets.html +3 -3
- package/dist/ui/serverless/data.html +3 -3
- package/dist/ui/serverless/deployments.html +3 -3
- package/dist/ui/serverless/functions.html +3 -3
- package/dist/ui/serverless/logs.html +3 -3
- package/dist/ui/serverless/queues.html +3 -3
- package/dist/ui/serverless/scheduler.html +3 -3
- package/dist/ui/serverless/secrets.html +3 -3
- package/dist/ui/serverless/traces.html +3 -3
- package/dist/ui/serverless.html +23 -6
- package/dist/ui-src/pages/server/actions.stx +27 -4
- package/dist/ui-src/pages/server/ssh-keys.stx +22 -1
- package/dist/ui-src/pages/server/team.stx +23 -1
- package/dist/ui-src/pages/serverless.stx +27 -4
- package/package.json +3 -3
|
@@ -67,6 +67,22 @@ async function revoke(name) {
|
|
|
67
67
|
load()
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
// Removal runs through a typed-confirm bar (same pattern as firewall/secrets):
|
|
71
|
+
// type the username to confirm. Revoking pulls someone's access to every site
|
|
72
|
+
// on the box at once and invalidates their password, so it should never be one
|
|
73
|
+
// misclick away.
|
|
74
|
+
const pendingRevoke = state(null)
|
|
75
|
+
const typedRevoke = state('')
|
|
76
|
+
const canRevoke = derived(() => { const u = pendingRevoke(); return u !== null && typedRevoke() === String(u.username) })
|
|
77
|
+
function askRevoke(user) { pendingRevoke.set(user); typedRevoke.set('') }
|
|
78
|
+
function cancelRevoke() { pendingRevoke.set(null); typedRevoke.set('') }
|
|
79
|
+
async function confirmRevoke() {
|
|
80
|
+
const u = pendingRevoke()
|
|
81
|
+
if (!u || typedRevoke() !== String(u.username)) return
|
|
82
|
+
pendingRevoke.set(null); typedRevoke.set('')
|
|
83
|
+
await revoke(u.username)
|
|
84
|
+
}
|
|
85
|
+
|
|
70
86
|
onMount(() => { load() })
|
|
71
87
|
</script>
|
|
72
88
|
<!DOCTYPE html>
|
|
@@ -135,12 +151,18 @@ onMount(() => { load() })
|
|
|
135
151
|
<td><b>{{ u.name }}</b><span class="mono uname">{{ u.username }}</span></td>
|
|
136
152
|
<td><span class="tag">{{ u.role === 'admin' ? 'box owner' : 'member' }}</span></td>
|
|
137
153
|
<td class="mono">{{ u.role === 'admin' ? 'every site' : siteList(u) }}</td>
|
|
138
|
-
<td class="table-actions"><button type="button" class="btn danger sm" @click="
|
|
154
|
+
<td class="table-actions"><button type="button" class="btn danger sm" @click="askRevoke(u)">Remove</button></td>
|
|
139
155
|
</tr>
|
|
140
156
|
</template>
|
|
141
157
|
</tbody>
|
|
142
158
|
</table>
|
|
143
159
|
<div class="compact empty" @show="users().length === 0"><strong>No one invited yet</strong><span>Invite someone above to give them access to a site.</span></div>
|
|
160
|
+
<div class="op-confirm" @show="pendingRevoke() !== null" style="margin-top:14px">
|
|
161
|
+
<span>Type <b class="mono">{{ pendingRevoke()?.username }}</b> to remove <b>{{ pendingRevoke()?.name }}</b> from every site:</span>
|
|
162
|
+
<input class="op-confirm-input" :value="typedRevoke()" @input="typedRevoke.set($event.target.value)" @keydown.enter="confirmRevoke()" placeholder="confirm" autocomplete="off">
|
|
163
|
+
<button class="btn danger sm" :disabled="!canRevoke()" @click="confirmRevoke()">Remove</button>
|
|
164
|
+
<button class="btn ghost sm" @click="cancelRevoke()">Cancel</button>
|
|
165
|
+
</div>
|
|
144
166
|
<p class="note">Box owners reach everything on this server. Members reach only the sites listed here, and never the shell, SSH keys, firewall or databases. Access is checked on every request.</p>
|
|
145
167
|
</div>
|
|
146
168
|
</div>
|
|
@@ -87,12 +87,29 @@ const appCmd = state('')
|
|
|
87
87
|
const cmdOut = state('')
|
|
88
88
|
const cmdShown = state(false)
|
|
89
89
|
const cmdBusy = state(false)
|
|
90
|
-
|
|
90
|
+
// The API already requires a typed confirmation here ('Type "run" to execute
|
|
91
|
+
// this command.'), but the UI supplied the token itself, so the gate always
|
|
92
|
+
// passed and Enter ran an arbitrary app command (migrate:fresh, queue:flush)
|
|
93
|
+
// against production. Stage it, make the operator type the word, send what they
|
|
94
|
+
// actually typed.
|
|
95
|
+
const cmdPending = state(null)
|
|
96
|
+
const cmdTyped = state('')
|
|
97
|
+
const cmdCanRun = derived(() => cmdPending() !== null && cmdTyped().trim() === 'run')
|
|
98
|
+
function askAppCmd() {
|
|
91
99
|
const c = appCmd().trim()
|
|
92
100
|
if (!c) return
|
|
101
|
+
cmdPending.set(c); cmdTyped.set('')
|
|
102
|
+
}
|
|
103
|
+
function cancelAppCmd() { cmdPending.set(null); cmdTyped.set('') }
|
|
104
|
+
|
|
105
|
+
async function runAppCmd() {
|
|
106
|
+
const c = cmdPending()
|
|
107
|
+
const confirm = cmdTyped().trim()
|
|
108
|
+
if (!c || confirm !== 'run') return
|
|
109
|
+
cmdPending.set(null); cmdTyped.set('')
|
|
93
110
|
cmdBusy.set(true); cmdShown.set(true); cmdOut.set('Running ' + c + '...')
|
|
94
111
|
try {
|
|
95
|
-
const res = await fetch('/api/serverless/command', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ command: c, confirm
|
|
112
|
+
const res = await fetch('/api/serverless/command', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ command: c, confirm }) })
|
|
96
113
|
const b = await res.json()
|
|
97
114
|
cmdOut.set((b.ok ? 'OK ' : 'FAILED ') + (b.command || c) + '\n\n' + (b.stdout || '') + (b.error ? '\n' + b.error : ''))
|
|
98
115
|
} catch (e) { cmdOut.set('FAILED ' + c + '\n\n' + ((e && e.message) || e)) }
|
|
@@ -273,8 +290,14 @@ async function runAppCmd() {
|
|
|
273
290
|
<h2>Run a command</h2>
|
|
274
291
|
<div class="panel">
|
|
275
292
|
<div class="field">
|
|
276
|
-
<input :value="appCmd()" @input="appCmd.set($event.target.value)" @keydown.enter="
|
|
277
|
-
<button class="btn" type="button" :disabled="cmdBusy()" @click="
|
|
293
|
+
<input :value="appCmd()" @input="appCmd.set($event.target.value)" @keydown.enter="askAppCmd()" placeholder="e.g. migrate --force, cache:clear, queue:retry all" autocomplete="off" aria-label="App command to run">
|
|
294
|
+
<button class="btn" type="button" :disabled="cmdBusy()" @click="askAppCmd()">Run</button>
|
|
295
|
+
</div>
|
|
296
|
+
<div class="op-confirm" @show="cmdPending() !== null" style="margin-top:14px">
|
|
297
|
+
<span>Type <b class="mono">run</b> to execute <b class="mono">{{ cmdPending() }}</b> against production:</span>
|
|
298
|
+
<input class="op-confirm-input" :value="cmdTyped()" @input="cmdTyped.set($event.target.value)" @keydown.enter="runAppCmd()" placeholder="confirm" autocomplete="off" aria-label="Type run to confirm executing this command">
|
|
299
|
+
<button type="button" class="btn danger sm" :disabled="!cmdCanRun()" @click="runAppCmd()">Run command</button>
|
|
300
|
+
<button type="button" class="btn ghost sm" @click="cancelAppCmd()">Cancel</button>
|
|
278
301
|
</div>
|
|
279
302
|
<pre class="action-output" @show="cmdShown()">{{ cmdOut() }}</pre>
|
|
280
303
|
<p class="note">Invokes the app command through the CLI Lambda function (RequestResponse), the same path as <span class="mono">cloud command "..."</span>. Output is clamped.</p>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/ts-cloud",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.34",
|
|
5
5
|
"description": "A lightweight, performant infrastructure-as-code library and CLI for deploying both server-based (EC2) and serverless applications.",
|
|
6
6
|
"author": "Chris Breuer <chris@stacksjs.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -89,8 +89,8 @@
|
|
|
89
89
|
"test": "bun test"
|
|
90
90
|
},
|
|
91
91
|
"dependencies": {
|
|
92
|
-
"@ts-cloud/aws-types": "0.7.
|
|
93
|
-
"@ts-cloud/core": "0.7.
|
|
92
|
+
"@ts-cloud/aws-types": "0.7.34",
|
|
93
|
+
"@ts-cloud/core": "0.7.34",
|
|
94
94
|
"@stacksjs/ts-xml": "^0.1.0"
|
|
95
95
|
},
|
|
96
96
|
"devDependencies": {
|