vela 0.15.1 → 0.15.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vela",
3
- "version": "0.15.1",
3
+ "version": "0.15.4",
4
4
  "type": "module",
5
5
  "description": "A CLI for creating and updating SvelteKit projects",
6
6
  "license": "MIT",
@@ -37,7 +37,7 @@
37
37
  "dependencies": {
38
38
  "@clack/prompts": "^1.7.0",
39
39
  "@faker-js/faker": "^10.6.0",
40
- "@velastack/patterns": "^0.4.0",
40
+ "@velastack/patterns": "^0.4.1",
41
41
  "@velastack/pocketbase-codegen": "^0.1.0",
42
42
  "annotate-json-schema": "^0.1.1",
43
43
  "commander": "^15.0.0",
@@ -50,7 +50,7 @@
50
50
  "package-manager-detector": "^1.8.0",
51
51
  "picocolors": "^1.1.1",
52
52
  "pocketbase": "^0.28.0",
53
- "pocketbase-server": "^0.40.5-beta.2",
53
+ "pocketbase-server": "^0.40.5-beta.5",
54
54
  "stripe": "^22.6.2",
55
55
  "sv": "~1.0.1",
56
56
  "svelte": "^5.56.10",
@@ -0,0 +1,7 @@
1
+ # What this app reads from its environment. Copy to .env for development; on a
2
+ # server, `vela env set KEY -t <target>`. Values here are examples, not defaults.
3
+
4
+ # PocketBase superuser the app authenticates as. `vela create` writes these to
5
+ # .env; a deploy creates its own on the server the first time.
6
+ POCKETBASE_SUPERUSER_EMAIL=admin@example.com
7
+ POCKETBASE_SUPERUSER_PASSWORD=change-me
@@ -36,7 +36,9 @@ require_release_id "$RELEASE"
36
36
 
37
37
  APP_NAME=$INSTANCE
38
38
  APP_ID=$INSTANCE
39
+ SITE_NAME=""
39
40
  ENV_TAG=prod
41
+ PREVIEW=0
40
42
  DOMAIN=""
41
43
  MANAGED=""
42
44
  HEALTH_PATH=/
@@ -54,6 +56,8 @@ while [ $# -gt 0 ]; do
54
56
  --name) APP_NAME=$2; shift 2 ;;
55
57
  --app-id) APP_ID=$2; shift 2 ;;
56
58
  --env) ENV_TAG=$2; shift 2 ;;
59
+ --site-name) SITE_NAME=$2; shift 2 ;;
60
+ --preview) PREVIEW=$2; shift 2 ;;
57
61
  --domain) DOMAIN=$2; shift 2 ;;
58
62
  --managed) MANAGED=$2; shift 2 ;;
59
63
  --health-path) HEALTH_PATH=$2; shift 2 ;;
@@ -183,10 +187,22 @@ else
183
187
  PRIMARY_URL="http://127.0.0.1:$WEB_PORT"
184
188
  fi
185
189
 
186
- # Production secrets live in $ETC/env and are managed only by `vela env`.
187
- # Nothing here reads or rewrites that file.
190
+ # The instance's own env layer is managed only by `vela env`. Nothing here
191
+ # reads or rewrites it; the file is created so a first `vela env list` has
192
+ # something to read.
188
193
  [ -f "$ETC/env" ] || { : > "$ETC/env"; chmod 0600 "$ETC/env"; chown root:root "$ETC/env"; }
189
194
 
195
+ # The shared layers - app-wide, and one for every preview - live under
196
+ # /etc/vela/scopes, and the units are templates on the instance name alone, so
197
+ # they reach those layers through fixed-name symlinks written here. A link to a
198
+ # layer nobody has written yet dangles, which systemd skips like a missing file.
199
+ link_scope "$APP_ID" all "$ETC"
200
+ if [ "$PREVIEW" = "1" ]; then
201
+ link_scope "$APP_ID" preview "$ETC"
202
+ else
203
+ rm -f "$ETC/scope.preview.env" "$ETC/scope.preview.public.env"
204
+ fi
205
+
190
206
  runtime_tmp=$(mktemp "$ETC/.runtime.XXXXXX")
191
207
  {
192
208
  printf '# Generated by vela on each deploy. Edit /etc/vela/apps/%s/env instead.\n' "$INSTANCE"
@@ -194,6 +210,12 @@ runtime_tmp=$(mktemp "$ETC/.runtime.XXXXXX")
194
210
  printf 'HOST=127.0.0.1\n'
195
211
  printf 'PORT=%s\n' "$WEB_PORT"
196
212
  runtime_origin_lines "$DOMAIN" "$PRIMARY_URL"
213
+ # Caddy is the only thing that reaches the app, so without these
214
+ # `getClientAddress()` is always 127.0.0.1. Caddy replaces any
215
+ # X-Forwarded-For a client sends with the address it saw (or, on a managed
216
+ # route, the one the Worker reports), so the last entry is the visitor.
217
+ printf 'ADDRESS_HEADER=x-forwarded-for\n'
218
+ printf 'XFF_DEPTH=1\n'
197
219
  # Only an instance with a PocketBase gets pointed at one: a URL to a port
198
220
  # nothing listens on is not a setting, it is a trap. Kept for one more
199
221
  # deploy when the backend is being removed, so that a failed deploy can put
@@ -203,6 +225,10 @@ runtime_tmp=$(mktemp "$ETC/.runtime.XXXXXX")
203
225
  printf 'POCKETBASE_URL=http://127.0.0.1:%s\n' "$PB_PORT"
204
226
  fi
205
227
  printf 'VELA_DATA_DIR=%s\n' "$APP_DATA_DIR"
228
+ # PocketBase names the app in its emails after APP_NAME, and links them to
229
+ # ORIGIN (above) unless APP_URL says otherwise. The name is the one
230
+ # src/lib/site.ts declares, so it is set from code on every deploy.
231
+ [ -z "$SITE_NAME" ] || printf 'APP_NAME=%s\n' "$SITE_NAME"
206
232
  printf 'VELA_APP_ID=%s\n' "$APP_ID"
207
233
  printf 'VELA_APP_NAME=%s\n' "$APP_NAME"
208
234
  printf 'VELA_ENV=%s\n' "$ENV_TAG"
@@ -401,6 +427,13 @@ if [ -n "$LINK_NAME" ]; then
401
427
  || rm -f "$link_tmp" || true
402
428
  fi
403
429
 
430
+ # The units come from the same upload as this script, so a server provisioned
431
+ # by an older CLI gets the current ones on its next deploy rather than running
432
+ # the old env file list against new layers nothing reads.
433
+ for unit in vela-web@.service vela-pb@.service; do
434
+ cmp -s "$SCRIPT_DIR/systemd/$unit" "/etc/systemd/system/$unit" \
435
+ || install -m 0644 "$SCRIPT_DIR/systemd/$unit" "/etc/systemd/system/$unit"
436
+ done
404
437
  systemctl daemon-reload
405
438
 
406
439
  if [ "$BACKEND" = "1" ]; then
@@ -456,7 +489,8 @@ state_merge "$INSTANCE" "$(jq -c -n \
456
489
  --arg health "$HEALTH_PATH" --arg pb "$PB_VERSION" \
457
490
  --arg sha "$GIT_SHA" --arg at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
458
491
  --argjson web "$WEB_PORT" --argjson pbport "$PB_PORT" --argjson backend "$BACKEND" \
459
- '{appId: $app, name: $name, env: $env, instance: $instance,
492
+ --argjson preview "$PREVIEW" \
493
+ '{appId: $app, name: $name, env: $env, instance: $instance, preview: ($preview == 1),
460
494
  activeRelease: $release, previousRelease: $previous, domain: $domain,
461
495
  managed: $managed, url: $url,
462
496
  healthCheckPath: $health, pocketbaseVersion: $pb, gitSha: $sha,
@@ -486,7 +520,17 @@ if [ -n "$DOMAIN" ]; then
486
520
  tmp=$(mktemp "$VELA_ETC/caddy/.snippet.XXXXXX")
487
521
  {
488
522
  printf '# Managed by vela - app %s (%s)\n' "$APP_NAME" "$INSTANCE"
489
- printf '%s {\n\treverse_proxy 127.0.0.1:%s\n}\n' "$hosts" "$WEB_PORT"
523
+ printf '%s {\n' "$hosts"
524
+ # The app precompresses its built assets but not rendered pages; Caddy
525
+ # passes an already-encoded response through untouched.
526
+ printf '\tencode zstd gzip\n'
527
+ # Files from static/ come back with an ETag and no Cache-Control, so a
528
+ # browser asks again on every view. Unhashed, so an hour rather than
529
+ # forever; `?` leaves whatever the app or PocketBase set alone.
530
+ printf '\t@static path *.jpg *.jpeg *.png *.gif *.webp *.avif *.svg *.ico *.woff *.woff2\n'
531
+ printf '\theader @static ?Cache-Control "public, max-age=3600"\n'
532
+ printf '\treverse_proxy 127.0.0.1:%s\n' "$WEB_PORT"
533
+ printf '}\n'
490
534
  } > "$tmp"
491
535
  caddy_install "$tmp" "$CADDY_SNIPPET" \
492
536
  || die "release $RELEASE is live, but the generated Caddy config for $DOMAIN is invalid and was not installed - routing is unchanged"
@@ -10,6 +10,19 @@ VELA_PORT_RANGE=${VELA_PORT_RANGE:-900}
10
10
 
11
11
  app_dir() { printf '%s/apps/%s' "$VELA_ROOT" "$1"; }
12
12
  etc_dir() { printf '%s/apps/%s' "$VELA_ETC" "$1"; }
13
+ # scope_dir <app-id> <all|preview> - an env layer shared by several instances.
14
+ # Its own tree because the production instance is named after the app id, so
15
+ # /etc/vela/apps/<app-id> is production's directory, not the app's.
16
+ scope_dir() { printf '%s/scopes/%s/%s' "$VELA_ETC" "$1" "$2"; }
17
+ # link_scope <app-id> <all|preview> <etc-dir> - point an instance's fixed-name
18
+ # scope.<layer>.env and scope.<layer>.public.env at that layer's files.
19
+ # `-n` replaces an existing link rather than following it; the targets are files,
20
+ # so there is never a directory for a plain `ln -sf` to descend into.
21
+ link_scope() {
22
+ local dir; dir=$(scope_dir "$1" "$2")
23
+ ln -sfn "$dir/env" "$3/scope.$2.env"
24
+ ln -sfn "$dir/env.public" "$3/scope.$2.public.env"
25
+ }
13
26
  state_file() { printf '%s/apps/%s/state.json' "$VELA_ROOT" "$1"; }
14
27
 
15
28
  log() { printf ' %s\n' "$*" >&2; }
@@ -227,13 +240,17 @@ unit_active() { systemctl is-active --quiet "$1"; }
227
240
  # A fourth argument is the public host to ask as, the way Caddy would. An app
228
241
  # serving several hosts has no pinned origin and tells its sites apart by
229
242
  # `Host`; asked as 127.0.0.1 it may rightly answer that it serves no such site.
243
+ #
244
+ # X-Forwarded-For always, as Caddy would send it: the app reads the client
245
+ # address from it (ADDRESS_HEADER), and adapter-node throws from
246
+ # `getClientAddress()` on a request without one.
230
247
  wait_for_http() {
231
248
  local url=$1 attempts=${2:-60} delay=${3:-0.5} host=${4:-} code
232
249
  local i=0
233
- local -a as=()
234
- [ -z "$host" ] || as=(-H "Host: $host" -H 'X-Forwarded-Proto: https')
250
+ local -a as=(-H 'X-Forwarded-For: 127.0.0.1')
251
+ [ -z "$host" ] || as+=(-H "Host: $host" -H 'X-Forwarded-Proto: https')
235
252
  while [ "$i" -lt "$attempts" ]; do
236
- code=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 5 ${as[@]+"${as[@]}"} "$url" 2>/dev/null || echo 000)
253
+ code=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 5 "${as[@]}" "$url" 2>/dev/null || echo 000)
237
254
  case "$code" in
238
255
  2*|3*|401|403) return 0 ;;
239
256
  esac
@@ -10,7 +10,15 @@ User=vela
10
10
  Group=vela
11
11
  WorkingDirectory=/var/lib/vela/apps/%i
12
12
 
13
+ # Three layers, each secret and public, then what vela derives. Later wins.
14
+ # The scope.* names are symlinks apply.sh writes into the app-wide and preview
15
+ # layers under /etc/vela/scopes; a layer that does not exist is skipped.
16
+ EnvironmentFile=-/etc/vela/apps/%i/scope.all.env
17
+ EnvironmentFile=-/etc/vela/apps/%i/scope.all.public.env
18
+ EnvironmentFile=-/etc/vela/apps/%i/scope.preview.env
19
+ EnvironmentFile=-/etc/vela/apps/%i/scope.preview.public.env
13
20
  EnvironmentFile=-/etc/vela/apps/%i/env
21
+ EnvironmentFile=-/etc/vela/apps/%i/env.public
14
22
  EnvironmentFile=/etc/vela/apps/%i/runtime.env
15
23
 
16
24
  ExecStart=/var/lib/vela/apps/%i/bin/pocketbase \
@@ -12,7 +12,15 @@ WorkingDirectory=/var/lib/vela/apps/%i/current
12
12
 
13
13
  # Production secrets first, vela-generated runtime settings second, so PORT and
14
14
  # POCKETBASE_URL always match what the server actually assigned.
15
+ # Three layers, each secret and public, then what vela derives. Later wins.
16
+ # The scope.* names are symlinks apply.sh writes into the app-wide and preview
17
+ # layers under /etc/vela/scopes; a layer that does not exist is skipped.
18
+ EnvironmentFile=-/etc/vela/apps/%i/scope.all.env
19
+ EnvironmentFile=-/etc/vela/apps/%i/scope.all.public.env
20
+ EnvironmentFile=-/etc/vela/apps/%i/scope.preview.env
21
+ EnvironmentFile=-/etc/vela/apps/%i/scope.preview.public.env
15
22
  EnvironmentFile=-/etc/vela/apps/%i/env
23
+ EnvironmentFile=-/etc/vela/apps/%i/env.public
16
24
  EnvironmentFile=/etc/vela/apps/%i/runtime.env
17
25
 
18
26
  ExecStart=/usr/bin/node /var/lib/vela/apps/%i/current/build/index.js
@@ -0,0 +1,2 @@
1
+ # What this app reads from its environment. Copy to .env for development; on a
2
+ # server, `vela env set KEY -t <target>`. Values here are examples, not defaults.