vela 0.11.4 → 0.11.6
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/README.md +12 -1
- package/dist/bin.js +1282 -785
- package/dist/bin.js.map +4 -4
- package/package.json +17 -5
- package/templates/minimal/package.template.json +1 -1
- package/templates/minimal/vite.config.ts +1 -1
- package/templates/server/apply.sh +71 -30
- package/templates/server/lib.sh +16 -5
- package/templates/server/rollback.sh +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vela",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A CLI for creating and updating SvelteKit projects",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@clack/prompts": "^1.7.0",
|
|
38
38
|
"@faker-js/faker": "^10.6.0",
|
|
39
|
-
"@velastack/patterns": "^0.2.
|
|
39
|
+
"@velastack/patterns": "^0.2.5",
|
|
40
40
|
"@velastack/pocketbase-codegen": "^0.1.0",
|
|
41
41
|
"annotate-json-schema": "^0.1.0",
|
|
42
42
|
"commander": "^13.1.0",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"dotenv": "^17.4.2",
|
|
46
46
|
"fetch-cookie": "^3.2.0",
|
|
47
47
|
"json-schema-faker": "^0.6.3",
|
|
48
|
-
"magic-string": "^
|
|
48
|
+
"magic-string": "^1.2.3",
|
|
49
49
|
"package-manager-detector": "^1.8.0",
|
|
50
50
|
"picocolors": "^1.1.1",
|
|
51
51
|
"pocketbase": "^0.28.0",
|
|
@@ -62,10 +62,10 @@
|
|
|
62
62
|
"@types/node": "^22.0.0",
|
|
63
63
|
"esbuild": "^0.28.2",
|
|
64
64
|
"prettier": "^3.9.6",
|
|
65
|
+
"shellcheck": "^4.1.0",
|
|
65
66
|
"typescript": "^5.6.0",
|
|
66
67
|
"vite": "^8.2.2",
|
|
67
|
-
"vitest": "^4.1.11"
|
|
68
|
-
"shellcheck": "^4.1.0"
|
|
68
|
+
"vitest": "^4.1.11"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
71
|
"@sveltejs/kit": "^2.57.1",
|
|
@@ -79,6 +79,18 @@
|
|
|
79
79
|
"optional": true
|
|
80
80
|
}
|
|
81
81
|
},
|
|
82
|
+
"overrides": {
|
|
83
|
+
"global-agent": "^4.1.3",
|
|
84
|
+
"@xhmikosr/decompress-unzip": {
|
|
85
|
+
"file-type": "^21.3.1"
|
|
86
|
+
},
|
|
87
|
+
"@xhmikosr/decompress-tar": {
|
|
88
|
+
"file-type": "^21.3.1"
|
|
89
|
+
},
|
|
90
|
+
"@felipecrs/decompress-tarxz": {
|
|
91
|
+
"file-type": "^21.3.1"
|
|
92
|
+
}
|
|
93
|
+
},
|
|
82
94
|
"keywords": [
|
|
83
95
|
"svelte",
|
|
84
96
|
"sveltekit",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineConfig } from 'vite';
|
|
2
2
|
import tailwindcss from '@tailwindcss/vite';
|
|
3
3
|
import { sveltekit } from '@sveltejs/kit/vite';
|
|
4
|
-
import adapter from '@sveltejs/adapter-
|
|
4
|
+
import adapter from '@sveltejs/adapter-node';
|
|
5
5
|
|
|
6
6
|
export default defineConfig({
|
|
7
7
|
plugins: [
|
|
@@ -84,28 +84,68 @@ if [ -n "$ACTIVE" ] && [ -L "$APP/current" ] && ! [[ "$RELEASE" > "$ACTIVE" ]];
|
|
|
84
84
|
die "release $RELEASE is not newer than the active release $ACTIVE on $INSTANCE - a newer deploy went live first, so this one was dropped"
|
|
85
85
|
fi
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
# Whether the release this one replaces had a PocketBase backend. The CLI
|
|
88
|
+
# detects the backend from the project on every deploy, so an instance can gain
|
|
89
|
+
# one (`vela bless` between two deploys) or lose one; both are handled below.
|
|
90
|
+
# Empty on a first deploy.
|
|
91
|
+
PREVIOUS_BACKEND=""
|
|
92
|
+
if [ -f "$(state_file "$INSTANCE")" ]; then
|
|
93
|
+
PREVIOUS_BACKEND=$(instance_backend "$INSTANCE")
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# Where this app keeps state that has to outlive a release.
|
|
97
|
+
#
|
|
98
|
+
# An app that works this out from its own working directory puts it inside the
|
|
99
|
+
# release, which is the one place it cannot survive: `current` moves on the next
|
|
100
|
+
# deploy and the pruner deletes what it left behind. An instance with a database
|
|
101
|
+
# shares PocketBase's directory, so anything the app writes there is inside the
|
|
102
|
+
# archives `vela backup` takes and inside the directory `vela restore` swaps. An
|
|
103
|
+
# instance without one gets a directory of its own, which nothing backs up -
|
|
104
|
+
# there is no database to back it up alongside.
|
|
105
|
+
if [ "$BACKEND" = "1" ]; then
|
|
106
|
+
APP_DATA_DIR="$APP/shared/pb_data"
|
|
107
|
+
else
|
|
108
|
+
APP_DATA_DIR="$APP/shared/data"
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
mkdir -p "$APP"/{releases,shared,bin,deps} "$APP_DATA_DIR"
|
|
88
112
|
mkdir -p "$ETC"
|
|
89
113
|
chmod 0700 "$ETC"
|
|
90
114
|
|
|
91
115
|
# Only the directories just created need their ownership set, and only at the
|
|
92
|
-
# top level: everything below
|
|
93
|
-
# already. Recursing here would walk every uploaded file
|
|
94
|
-
# makes deploy time grow with the size of the app's
|
|
116
|
+
# top level: everything below the data directory is written by PocketBase (or
|
|
117
|
+
# the app) as $VELA_USER already. Recursing here would walk every uploaded file
|
|
118
|
+
# on every deploy, which makes deploy time grow with the size of the app's
|
|
119
|
+
# storage forever.
|
|
95
120
|
chown "$VELA_USER:$VELA_USER" \
|
|
96
|
-
"$APP" "$APP/releases" "$APP/shared" "$
|
|
121
|
+
"$APP" "$APP/releases" "$APP/shared" "$APP_DATA_DIR" "$APP/bin" "$APP/deps"
|
|
97
122
|
# The release is the exception - rsync uploaded it as whoever we ssh'd in as.
|
|
98
123
|
chown -R "$VELA_USER:$VELA_USER" "$RELEASE_DIR"
|
|
99
124
|
|
|
100
|
-
# A
|
|
101
|
-
# 500 rather than anything that names a cause. This is what the blanket
|
|
102
|
-
# above used to paper over; checking costs one stat, repairing costs a
|
|
103
|
-
# now happens only when something is actually wrong.
|
|
104
|
-
if ! runuser -u "$VELA_USER" -- test -w "$
|
|
125
|
+
# A data directory the app cannot write is a dead instance, and it fails as an
|
|
126
|
+
# opaque 500 rather than anything that names a cause. This is what the blanket
|
|
127
|
+
# recurse above used to paper over; checking costs one stat, repairing costs a
|
|
128
|
+
# walk that now happens only when something is actually wrong.
|
|
129
|
+
if ! runuser -u "$VELA_USER" -- test -w "$APP_DATA_DIR"; then
|
|
105
130
|
log "repairing ownership under shared/"
|
|
106
131
|
chown -R "$VELA_USER:$VELA_USER" "$APP/shared"
|
|
107
132
|
fi
|
|
108
133
|
|
|
134
|
+
# An instance gaining a backend moves its data directory: VELA_DATA_DIR was
|
|
135
|
+
# shared/data and is now shared/pb_data, which is what `vela backup` archives.
|
|
136
|
+
# Whatever the app kept follows it, into a pb_data that PocketBase has not yet
|
|
137
|
+
# written - once there is a database in there, nothing is moved over it.
|
|
138
|
+
if [ "$PREVIOUS_BACKEND" = "false" ] && [ "$BACKEND" = "1" ] \
|
|
139
|
+
&& [ -d "$APP/shared/data" ] && [ -n "$(ls -A "$APP/shared/data")" ]; then
|
|
140
|
+
if [ ! -e "$APP/shared/pb_data/data.db" ]; then
|
|
141
|
+
log "adding a backend - moving shared/data into shared/pb_data"
|
|
142
|
+
find "$APP/shared/data" -mindepth 1 -maxdepth 1 -exec mv -t "$APP/shared/pb_data" {} +
|
|
143
|
+
else
|
|
144
|
+
log "warning: this instance now has a backend, and its data directory is $APP/shared/pb_data"
|
|
145
|
+
log "warning: what the app kept in $APP/shared/data was left there"
|
|
146
|
+
fi
|
|
147
|
+
fi
|
|
148
|
+
|
|
109
149
|
# ---------------------------------------------------------------- ports & env
|
|
110
150
|
|
|
111
151
|
PORTS=$(allocate_ports "$INSTANCE")
|
|
@@ -126,23 +166,6 @@ fi
|
|
|
126
166
|
# Nothing here reads or rewrites that file.
|
|
127
167
|
[ -f "$ETC/env" ] || { : > "$ETC/env"; chmod 0600 "$ETC/env"; chown root:root "$ETC/env"; }
|
|
128
168
|
|
|
129
|
-
# Where this app keeps state that has to outlive a release.
|
|
130
|
-
#
|
|
131
|
-
# An app that works this out from its own working directory puts it inside the
|
|
132
|
-
# release, which is the one place it cannot survive: `current` moves on the next
|
|
133
|
-
# deploy and the pruner deletes what it left behind. An instance with a database
|
|
134
|
-
# shares PocketBase's directory, so anything the app writes there is inside the
|
|
135
|
-
# archives `vela backup` takes and inside the directory `vela restore` swaps. An
|
|
136
|
-
# instance without one gets a directory of its own, which nothing backs up -
|
|
137
|
-
# there is no database to back it up alongside.
|
|
138
|
-
if [ "$BACKEND" = "1" ]; then
|
|
139
|
-
APP_DATA_DIR="$APP/shared/pb_data"
|
|
140
|
-
else
|
|
141
|
-
APP_DATA_DIR="$APP/shared/data"
|
|
142
|
-
mkdir -p "$APP_DATA_DIR"
|
|
143
|
-
chown "$VELA_USER:$VELA_USER" "$APP_DATA_DIR"
|
|
144
|
-
fi
|
|
145
|
-
|
|
146
169
|
runtime_tmp=$(mktemp "$ETC/.runtime.XXXXXX")
|
|
147
170
|
{
|
|
148
171
|
printf '# Generated by vela on each deploy. Edit /etc/vela/apps/%s/env instead.\n' "$INSTANCE"
|
|
@@ -150,8 +173,14 @@ runtime_tmp=$(mktemp "$ETC/.runtime.XXXXXX")
|
|
|
150
173
|
printf 'HOST=127.0.0.1\n'
|
|
151
174
|
printf 'PORT=%s\n' "$WEB_PORT"
|
|
152
175
|
printf 'ORIGIN=%s\n' "$ORIGIN"
|
|
153
|
-
|
|
154
|
-
|
|
176
|
+
# Only an instance with a PocketBase gets pointed at one: a URL to a port
|
|
177
|
+
# nothing listens on is not a setting, it is a trap. Kept for one more
|
|
178
|
+
# deploy when the backend is being removed, so that a failed deploy can put
|
|
179
|
+
# the previous release - which still needs it - back.
|
|
180
|
+
if [ "$BACKEND" = "1" ] || [ "$PREVIOUS_BACKEND" = "true" ]; then
|
|
181
|
+
printf 'PB_PORT=%s\n' "$PB_PORT"
|
|
182
|
+
printf 'POCKETBASE_URL=http://127.0.0.1:%s\n' "$PB_PORT"
|
|
183
|
+
fi
|
|
155
184
|
printf 'VELA_DATA_DIR=%s\n' "$APP_DATA_DIR"
|
|
156
185
|
printf 'VELA_APP_ID=%s\n' "$APP_ID"
|
|
157
186
|
printf 'VELA_APP_NAME=%s\n' "$APP_NAME"
|
|
@@ -253,7 +282,10 @@ restore() {
|
|
|
253
282
|
# runtime.env was already written for the release that failed; the
|
|
254
283
|
# services about to restart must read the one they will actually run.
|
|
255
284
|
set_runtime_release "$ETC" "$PREVIOUS"
|
|
256
|
-
|
|
285
|
+
# The previous release needs its PocketBase whether or not this one did.
|
|
286
|
+
if [ "$BACKEND" = "1" ] || [ "$PREVIOUS_BACKEND" = "true" ]; then
|
|
287
|
+
systemctl restart "$PB_UNIT" >/dev/null 2>&1 || true
|
|
288
|
+
fi
|
|
257
289
|
systemctl restart "$WEB_UNIT" >/dev/null 2>&1 || true
|
|
258
290
|
else
|
|
259
291
|
systemctl stop "$WEB_UNIT" >/dev/null 2>&1 || true
|
|
@@ -365,6 +397,15 @@ wait_for_http "http://127.0.0.1:$WEB_PORT$HEALTH_PATH" 60 0.5 \
|
|
|
365
397
|
|
|
366
398
|
ACTIVATED=1
|
|
367
399
|
|
|
400
|
+
# An instance that no longer has a backend keeps its database on disk - only
|
|
401
|
+
# `vela destroy deployment --purge` removes data - but the unit serving it is
|
|
402
|
+
# retired, or `vela status` would keep reporting a PocketBase and every restart
|
|
403
|
+
# would bring it back up.
|
|
404
|
+
if [ "$PREVIOUS_BACKEND" = "true" ] && [ "$BACKEND" = "0" ]; then
|
|
405
|
+
log "removing the backend - stopping PocketBase; $APP/shared/pb_data is kept"
|
|
406
|
+
systemctl disable --now "$PB_UNIT" >/dev/null 2>&1 || true
|
|
407
|
+
fi
|
|
408
|
+
|
|
368
409
|
# --------------------------------------------------------------------- state
|
|
369
410
|
|
|
370
411
|
state_merge "$INSTANCE" "$(jq -c -n \
|
package/templates/server/lib.sh
CHANGED
|
@@ -58,11 +58,20 @@ require_provisioned() {
|
|
|
58
58
|
[ -f "$VELA_ETC/provisioned" ] || die "server is not provisioned - run 'vela provision' first"
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
#
|
|
62
|
-
#
|
|
61
|
+
# Whether an instance was last deployed with a PocketBase backend: `true` or
|
|
62
|
+
# `false`. Absent state, or state from before the flag existed, is treated as
|
|
63
|
+
# having one, so this only ever answers `false` for an instance that was
|
|
64
|
+
# deployed with --backend 0.
|
|
65
|
+
instance_backend() {
|
|
66
|
+
local instance=$1 value
|
|
67
|
+
value=$(state_get "$instance" backend 2>/dev/null || echo true)
|
|
68
|
+
[ "$value" = "false" ] && printf 'false' || printf 'true'
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# Refuse on a frontend-only instance.
|
|
63
72
|
require_backend() {
|
|
64
73
|
local instance=$1
|
|
65
|
-
[ "$(
|
|
74
|
+
[ "$(instance_backend "$instance")" = "true" ] \
|
|
66
75
|
|| die "$instance has no database - there is nothing to back up or restore"
|
|
67
76
|
}
|
|
68
77
|
|
|
@@ -71,8 +80,10 @@ state_get() {
|
|
|
71
80
|
local instance=$1 key=$2 file
|
|
72
81
|
file=$(state_file "$instance")
|
|
73
82
|
[ -f "$file" ] || return 1
|
|
74
|
-
# `// empty` would swallow a legitimate
|
|
75
|
-
|
|
83
|
+
# Presence is checked on its own: `// empty` would swallow a legitimate
|
|
84
|
+
# `false`, and so would `-e` on the read, which exits non-zero for one.
|
|
85
|
+
jq -e --arg k "$key" 'has($k) and .[$k] != null' "$file" >/dev/null 2>&1 || return 1
|
|
86
|
+
jq -r --arg k "$key" '.[$k]' "$file" 2>/dev/null
|
|
76
87
|
}
|
|
77
88
|
|
|
78
89
|
# Merge a JSON object into an instance's state file, atomically.
|
|
@@ -41,10 +41,10 @@ CURRENT=$(state_get "$INSTANCE" activeRelease || echo "")
|
|
|
41
41
|
[ -d "$APP/releases/$TARGET" ] || die "release $TARGET is no longer on disk"
|
|
42
42
|
[ "$TARGET" != "$CURRENT" ] || die "$TARGET is already the active release"
|
|
43
43
|
|
|
44
|
-
BACKEND=$(
|
|
44
|
+
BACKEND=$(instance_backend "$INSTANCE")
|
|
45
45
|
HEALTH_PATH=$(state_get "$INSTANCE" healthCheckPath 2>/dev/null || echo "/")
|
|
46
46
|
WEB_PORT=$(state_get "$INSTANCE" webPort)
|
|
47
|
-
PB_PORT=$(state_get "$INSTANCE" pbPort)
|
|
47
|
+
PB_PORT=$(state_get "$INSTANCE" pbPort 2>/dev/null || echo "")
|
|
48
48
|
WEB_UNIT=$(unit_web "$INSTANCE")
|
|
49
49
|
PB_UNIT=$(unit_pb "$INSTANCE")
|
|
50
50
|
|