@antelopejs/dms 0.16.0 → 0.16.2

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 (36) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +14 -14
  3. package/dist/store/cache.d.ts +5 -1
  4. package/dist/store/cache.js +23 -14
  5. package/dist/store/cache.js.map +1 -1
  6. package/dist/store/frontend-compatibility.d.ts +3 -1
  7. package/dist/store/frontend-compatibility.js +6 -8
  8. package/dist/store/frontend-compatibility.js.map +1 -1
  9. package/dist/store/index.d.ts +1 -0
  10. package/dist/store/index.js +1 -0
  11. package/dist/store/index.js.map +1 -1
  12. package/dist/store/interfaces.d.ts +3 -2
  13. package/dist/store/interfaces.js +16 -14
  14. package/dist/store/interfaces.js.map +1 -1
  15. package/dist/store/listing.js +6 -4
  16. package/dist/store/listing.js.map +1 -1
  17. package/dist/store/operations.js +1 -1
  18. package/dist/store/operations.js.map +1 -1
  19. package/dist/store/registry.d.ts +2 -1
  20. package/dist/store/registry.js +7 -26
  21. package/dist/store/registry.js.map +1 -1
  22. package/dist/store/requirements.js +3 -3
  23. package/dist/store/requirements.js.map +1 -1
  24. package/frontend-vue/layers/dms-core/app/build/utils/storedAccounts.ts +62 -0
  25. package/frontend-vue/layers/dms-core/app/composables/auth/useMultiAccount.ts +12 -9
  26. package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardHeader.vue +30 -3
  27. package/frontend-vue/layers/dms-layout/app/build/components/layout/HeaderActionIcon.vue +75 -0
  28. package/frontend-vue/layers/dms-layout/app/composables/useHeaderActions.ts +9 -0
  29. package/frontend-vue/layers/dms-layout/app/plugins/seo.ts +7 -0
  30. package/frontend-vue/layers/dms-layout/app/theme/surfaces.ts +10 -0
  31. package/frontend-vue/package.json +1 -1
  32. package/package.json +5 -5
  33. package/skills/dms-project/DEV-SERVERS.md +30 -4
  34. package/skills/dms-project/SKILL.md +8 -1
  35. package/skills/dms-project/scripts/dms-dev-usage.sh +5 -2
  36. package/skills/dms-project/scripts/dms-dev.sh +82 -69
@@ -1,45 +1,39 @@
1
1
  #!/usr/bin/env bash
2
2
  # dms-dev — start / stop / restart the AntelopeJS DMS dev servers of ONE project.
3
3
  # Run from the DMS backend package dir (DMS_BACK_DIR). By default it invokes that project's
4
- # `pnpm dev` / `pnpm frontend:dev` scripts — a convention our playground projects adopt, which
5
- # expand to `ajs project dev …` (the AntelopeJS backend; `ajs project run` is the legacy
6
- # alias) and `ajs dms dev` (the Inertia frontend loader — it auto-discovers the backend, -b optional).
7
- # Those script names aren't shipped by the DMS, so override the actual commands with
8
- # DMS_BACK_CMD / DMS_FRONT_CMD when a project starts its servers differently.
4
+ # `pnpm dev` / `pnpm frontend:dev` scripts (`ajs project dev …` and `ajs dms dev`, which
5
+ # auto-discovers the backend). Those script names aren't shipped by the DMS: override the
6
+ # commands with DMS_BACK_CMD / DMS_FRONT_CMD when a project starts its servers differently.
9
7
  #
10
- # Scope: the script only signals the processes of DMS_BACK_DIR. The pids it starts are
11
- # recorded in DMS_BACK_DIR/.antelope/dms-dev.pid; without that file it falls back to the dev
12
- # processes whose working directory or command line lies under DMS_BACK_DIR. Other projects'
13
- # dev servers on the same machine are never touched.
8
+ # Scope: it only signals the processes of DMS_BACK_DIR. The pids it starts are recorded in
9
+ # DMS_BACK_DIR/.antelope/dms-dev.pid; without that file it falls back to the dev processes
10
+ # whose working directory or command line lies under DMS_BACK_DIR.
14
11
  #
15
- # Windows (Git Bash, MSYS2, Cygwin): their ps lists only their own processes and takes no -o,
16
- # while the dev servers run as native node.exe processes. There the script reads the Windows
17
- # process table (PowerShell's Get-CimInstance Win32_Process), works in Windows pids, and stops
18
- # a server's whole tree with taskkill /T /F.
12
+ # Windows (Git Bash, MSYS2, Cygwin): ps lists only their own processes, while the servers run
13
+ # as native node.exe. There it reads the Windows process table (Get-CimInstance
14
+ # Win32_Process), works in Windows pids, and stops a server's tree with taskkill /T /F.
19
15
 
20
16
  set -uo pipefail
21
17
 
22
18
  DMS_BACK_DIR="${DMS_BACK_DIR:-}"
23
19
  BACK_CMD="${DMS_BACK_CMD:-pnpm dev}"
24
20
  FRONT_CMD="${DMS_FRONT_CMD:-pnpm frontend:dev}"
25
- BACK_LOG="${DMS_BACK_LOG:-/tmp/dms-back.log}"
26
- FRONT_LOG="${DMS_FRONT_LOG:-/tmp/dms-front.log}"
27
- BACK_READY_PATTERN='Server started, listening'
21
+ BACK_LOG="${DMS_BACK_LOG:-}"
22
+ FRONT_LOG="${DMS_FRONT_LOG:-}"
23
+ BACK_READY_PATTERN='Server started, listening|Port [0-9]+ in use, listening on'
28
24
  FRONT_READY_PATTERN='Server ready on|Local:.*localhost:'
29
- # Patterns that indicate a fatal startup error — detecting any of these aborts
30
- # the wait immediately instead of burning the full timeout.
25
+ # A match of these aborts the wait at once instead of burning the full timeout.
31
26
  BACK_ERROR_PATTERN='Failed to load module|Module load failed|Error loading module|UnhandledPromiseRejection|Cannot find module|ENOENT.*package\.json|TypeError:.*at .*ajs|FATAL'
32
27
  FRONT_ERROR_PATTERN='Cannot find module|Failed to compile|Vite error|ENOENT.*package\.json|EADDRINUSE'
33
28
  WAIT_TIMEOUT="${DMS_DEV_TIMEOUT:-180}"
34
29
  STOP_GRACE="${DMS_DEV_STOP_GRACE:-10}"
35
30
  DEV_JSON_WAIT=5
36
- DEFAULT_BACK_URL='http://localhost:5010'
37
- DEFAULT_FRONT_URL='http://localhost:3001'
31
+ DEFAULT_BACK_URL="http://localhost:${DMS_BACK_PORT:-5010}"
32
+ DEFAULT_FRONT_URL="http://localhost:${DMS_FRONT_PORT:-3001}"
38
33
 
39
- # Only picks candidates when no pid file exists, and is always combined with the
40
- # DMS_BACK_DIR scope check: on its own it would match every project on the machine.
34
+ # Candidates when no pid file exists; always combined with the DMS_BACK_DIR scope check.
41
35
  PROC_PATTERN='antelope-runner|ajs project (run|dev)|(^|[[:space:]/])(ajs dms|ajs-dms) dev|dms-frontend/dist/index\.js dev|pnpm( run)? (dev|frontend:dev)'
42
- # The same, split per server, for the commands that restart only one of them.
36
+ # The same, per server, for restarting only one.
43
37
  BACK_PROC_PATTERN='antelope-runner|ajs project (run|dev)|pnpm( run)? dev'
44
38
  FRONT_PROC_PATTERN='(^|[[:space:]/])(ajs dms|ajs-dms) dev|dms-frontend/dist/index\.js dev|pnpm( run)? frontend:dev'
45
39
 
@@ -48,8 +42,8 @@ case "$(uname -s 2>/dev/null)" in
48
42
  *) IS_WINDOWS="" ;;
49
43
  esac
50
44
 
51
- # One line per process: "pid<TAB>ppid<TAB>created<TAB>command line". The creation time, a
52
- # fixed-width UTC timestamp, tells a child from an older process holding a dead parent's pid.
45
+ # One line per process: "pid<TAB>ppid<TAB>created<TAB>command line"; the fixed-width UTC
46
+ # creation time tells a child from an older process holding a dead parent's pid.
53
47
  # shellcheck disable=SC2016 # PowerShell code, not shell expansions
54
48
  WIN_PROCESS_QUERY='[Console]::OutputEncoding = [Text.Encoding]::UTF8
55
49
  $tab = [char]9
@@ -62,8 +56,7 @@ Get-CimInstance Win32_Process | ForEach-Object {
62
56
  PROJECT_ROOT=""
63
57
  PID_FILE=""
64
58
  LAUNCHED_PID=""
65
- # Windows only: the process table (see refresh_process_table) and the project root as a
66
- # lowercase Windows path with forward slashes, the form command lines are compared in.
59
+ # Windows only: the process table and the project root as a lowercase forward-slash path.
67
60
  WIN_TABLE=""
68
61
  WIN_ROOT=""
69
62
 
@@ -85,13 +78,15 @@ require_dms_back_dir() {
85
78
  fi
86
79
  PROJECT_ROOT="$(cd "$DMS_BACK_DIR" && pwd -P)"
87
80
  PID_FILE="$PROJECT_ROOT/.antelope/dms-dev.pid"
81
+ BACK_LOG="${BACK_LOG:-$PROJECT_ROOT/.antelope/logs/back.log}"
82
+ FRONT_LOG="${FRONT_LOG:-$PROJECT_ROOT/.antelope/logs/front.log}"
88
83
  [ -z "$IS_WINDOWS" ] || WIN_ROOT="$(cygpath -m "$PROJECT_ROOT" | tr '[:upper:]' '[:lower:]')"
89
84
  }
90
85
 
91
86
  is_alive() { [ -n "$1" ] && kill -0 "$1" 2>/dev/null; }
92
87
 
93
- # Reads the Windows process table once for the lookups that follow; nothing elsewhere.
94
- # Call it in the shell that runs them: a command substitution's copy is lost with it.
88
+ # Reads the Windows process table for the lookups that follow; call it in the shell that
89
+ # runs them, since a command substitution's copy is lost with it.
95
90
  refresh_process_table() {
96
91
  [ -n "$IS_WINDOWS" ] || return 0
97
92
  WIN_TABLE="$(powershell.exe -NoProfile -NonInteractive -EncodedCommand \
@@ -108,7 +103,7 @@ win_alive() {
108
103
 
109
104
  win_args() { printf '%s\n' "$WIN_TABLE" | awk -F'\t' -v pid="$1" '$1 == pid { print $4; exit }'; }
110
105
 
111
- # A native process exposes no working directory: only its command line can name the project.
106
+ # A native process has no working directory: only its command line names the project.
112
107
  win_in_project() {
113
108
  local args
114
109
  # shellcheck disable=SC1003 # tr's escaped backslash, not a quote
@@ -117,8 +112,7 @@ win_in_project() {
117
112
  return 1
118
113
  }
119
114
 
120
- # The given Windows pids plus every process whose parent chain leads to one (Windows has no
121
- # process groups), each child created after its parent.
115
+ # The given Windows pids plus their descendants, each child created after its parent.
122
116
  win_expand_tree() {
123
117
  printf '%s\n' "$WIN_TABLE" | awk -F'\t' -v roots="$*" '
124
118
  BEGIN { n = split(roots, r, " "); for (i = 1; i <= n; i++) keep[r[i]] = 1 }
@@ -155,7 +149,7 @@ is_in_project() {
155
149
  return 1
156
150
  }
157
151
 
158
- # The given roots plus every process whose parent chain or process group leads to one.
152
+ # The given roots plus their descendants and process-group members.
159
153
  expand_tree() {
160
154
  ps -A -o pid=,ppid=,pgid= | awk -v roots="$*" '
161
155
  BEGIN { n = split(roots, r, " "); for (i = 1; i <= n; i++) keep[r[i]] = 1 }
@@ -170,8 +164,7 @@ expand_tree() {
170
164
  }'
171
165
  }
172
166
 
173
- # The live pids the pid file records, of every server or only of the one named; on Windows,
174
- # as Windows pids.
167
+ # The live pids the pid file records, of every server or the one named (Windows pids on Windows).
175
168
  pid_file_roots() {
176
169
  [ -f "$PID_FILE" ] || return 0
177
170
  local only="${1:-}" name pid
@@ -212,8 +205,7 @@ server_pattern() {
212
205
  esac
213
206
  }
214
207
 
215
- # Every process of this project's servers, or of the one named (backend or frontend). On
216
- # Windows they are Windows pids, read from the table refresh_process_table last read.
208
+ # Every process of this project's servers, or of the one named (Windows pids on Windows).
217
209
  project_pids() {
218
210
  local name="${1:-}" roots
219
211
  roots="$(pid_file_roots "$name")"
@@ -248,7 +240,7 @@ self_ancestors() {
248
240
  done
249
241
  }
250
242
 
251
- # An agent spawned by the backend (e.g. the dms-ai sidecar) would take its own host down.
243
+ # An agent spawned by the backend (e.g. dms-ai) would take its own host down.
252
244
  refuse_if_hosting_self() {
253
245
  local hosting
254
246
  hosting="$(printf '%s\n' "$@" | grep -Fx -f <(self_ancestors) | head -1)"
@@ -284,7 +276,7 @@ signal_and_wait() {
284
276
  return 1
285
277
  }
286
278
 
287
- # Windows has no SIGTERM a console node process would handle: each tree is ended at once.
279
+ # A console node process handles no SIGTERM on Windows: each tree is ended at once.
288
280
  win_kill_and_wait() {
289
281
  local pid survivors
290
282
  for pid in "$@"; do taskkill //T //F //PID "$pid" >/dev/null 2>&1; done
@@ -334,22 +326,22 @@ stop_servers() {
334
326
  log "stopped."
335
327
  }
336
328
 
337
- # Detaches the command into its own session so it survives this shell, and records its
338
- # pid. `exec` keeps that pid stable through setsid/nohup down to the command itself.
329
+ # Runs in a launch subshell: a non-empty port becomes that child's PORT alone.
330
+ enter_project() { cd "$PROJECT_ROOT" && { [ -z "$1" ] || export PORT="$1"; }; }
331
+
332
+ # Detaches the command into its own session and records its pid; `exec` keeps the pid stable.
339
333
  launch_detached() {
340
- local name="$1" cmd="$2" log_file="$3"
334
+ local name="$1" cmd="$2" log_file="$3" port="${4:-}"
335
+ local -a detach=(nohup)
341
336
  if command -v setsid >/dev/null 2>&1; then
342
- # shellcheck disable=SC2086 # word-splitting of the command is intentional
343
- (cd "$PROJECT_ROOT" && exec setsid nohup $cmd >> "$log_file" 2>&1 < /dev/null) &
337
+ detach=(setsid nohup)
344
338
  elif command -v perl >/dev/null 2>&1; then
345
339
  # macOS ships no setsid(1); perl's POSIX::setsid does the same before exec.
346
- # shellcheck disable=SC2086
347
- (cd "$PROJECT_ROOT" && exec perl -MPOSIX -e 'POSIX::setsid(); exec { $ARGV[0] } @ARGV or die "exec $ARGV[0]: $!\n"' \
348
- nohup $cmd >> "$log_file" 2>&1 < /dev/null) &
349
- else
350
- # shellcheck disable=SC2086
351
- (cd "$PROJECT_ROOT" && exec nohup $cmd >> "$log_file" 2>&1 < /dev/null) &
340
+ detach=(perl -MPOSIX -e 'POSIX::setsid(); exec { $ARGV[0] } @ARGV or die "exec $ARGV[0]: $!\n"' nohup)
352
341
  fi
342
+ mkdir -p "$(dirname "$log_file")" && : > "$log_file"
343
+ # shellcheck disable=SC2086 # word-splitting of the command is intentional
344
+ (enter_project "$port" && exec "${detach[@]}" $cmd >> "$log_file" 2>&1 < /dev/null) &
353
345
  LAUNCHED_PID=$!
354
346
  mkdir -p "$(dirname "$PID_FILE")"
355
347
  echo "$name $LAUNCHED_PID" >> "$PID_FILE"
@@ -361,16 +353,18 @@ fail_start() {
361
353
  tail -40 "$log_file" | sed 's/^/ /'
362
354
  }
363
355
 
356
+ fatal_in() {
357
+ grep -qE "$3" "$2" 2>/dev/null || return 1
358
+ log "fatal error detected in $2:"
359
+ grep -nE "$3" "$2" | head -5 | sed 's/^/ /'
360
+ fail_start "$1" "$2" "fatal error"
361
+ }
362
+
364
363
  wait_for() {
365
364
  local log_file="$1" pattern="$2" label="$3" error_pattern="$4" pid="$5" started
366
365
  started=$(date +%s)
367
366
  while ! grep -qE "$pattern" "$log_file" 2>/dev/null; do
368
- if grep -qE "$error_pattern" "$log_file" 2>/dev/null; then
369
- log "fatal error detected in $log_file:"
370
- grep -nE "$error_pattern" "$log_file" | head -5 | sed 's/^/ /'
371
- fail_start "$label" "$log_file" "fatal error"
372
- return 1
373
- fi
367
+ fatal_in "$label" "$log_file" "$error_pattern" && return 1
374
368
  if ! is_alive "$pid"; then
375
369
  fail_start "$label" "$log_file" "process $pid exited before becoming ready"
376
370
  return 1
@@ -398,8 +392,8 @@ read_dev_json() {
398
392
  ' "$1" 2>/dev/null
399
393
  }
400
394
 
401
- # The project may live in DMS_BACK_DIR or one level below (`ajs project dev -p playground`).
402
- # A dev.json outlives its backend, so only one whose writer is alive and ours is trusted.
395
+ # The project may live in DMS_BACK_DIR or one level below; only a dev.json whose writer is
396
+ # alive and ours is trusted, since it outlives its backend.
403
397
  dev_json_url() {
404
398
  local file pid url
405
399
  for file in "$PROJECT_ROOT/.antelope/dev.json" "$PROJECT_ROOT"/*/.antelope/dev.json; do
@@ -412,8 +406,7 @@ dev_json_url() {
412
406
  done
413
407
  }
414
408
 
415
- # Whether a pid a server wrote down itself (node's own, a Windows pid on Windows) is alive
416
- # and one of this project's.
409
+ # Whether a pid a server wrote down itself is alive and one of this project's.
417
410
  is_project_process() {
418
411
  if [ -z "$IS_WINDOWS" ]; then
419
412
  is_alive "$1" && is_in_project "$1"
@@ -432,7 +425,7 @@ backend_url() {
432
425
  sleep 1
433
426
  url="$(dev_json_url)"
434
427
  done
435
- [ -n "$url" ] || url="$(grep -oE "$BACK_READY_PATTERN on https?://[^ /]+" "$BACK_LOG" | tail -1 | awk '{print $NF}')"
428
+ [ -n "$url" ] || url="$(grep -oE "listening on https?://[^ /]+" "$BACK_LOG" | tail -1 | awk '{print $NF}')"
436
429
  echo "${url:-$DEFAULT_BACK_URL (assumed: no .antelope/dev.json found)}"
437
430
  }
438
431
 
@@ -442,24 +435,42 @@ frontend_url() {
442
435
  echo "${url:-$DEFAULT_FRONT_URL (assumed: no ready line with a URL)}"
443
436
  }
444
437
 
438
+ # The ready line can precede the module load; waits until the dashboard's first request
439
+ # succeeds (401/403 count: it sends the credential). Direct, like the dashboard's fetch.
440
+ # No curl, or nothing accepting connections (a stub): skips.
441
+ wait_for_manifest() {
442
+ local url="$1/dms/frontend?renderer=vue&rendererVersion=3" pid="$2" code rc
443
+ command -v curl >/dev/null 2>&1 || return 0
444
+ while :; do
445
+ code="$(curl -s --noproxy '*' -o /dev/null -m 5 -w '%{http_code}' "$url")"; rc=$?
446
+ case "$rc:$code" in 7:* | *:200 | *:401 | *:403) return 0 ;; esac
447
+ fatal_in backend "$BACK_LOG" "$BACK_ERROR_PATTERN" && return 1
448
+ is_alive "$pid" || { fail_start backend "$BACK_LOG" "process $pid exited before serving $url"; return 1; }
449
+ [ $(($(date +%s) - BACK_STARTED)) -le "$WAIT_TIMEOUT" ] ||
450
+ { fail_start backend "$BACK_LOG" "$url still answered ${code} after ${WAIT_TIMEOUT}s"; return 1; }
451
+ sleep 1
452
+ done
453
+ }
454
+
445
455
  start_backend() {
456
+ local url
446
457
  log "starting backend in $PROJECT_ROOT (logs → $BACK_LOG)…"
447
- : > "$BACK_LOG"
448
- launch_detached backend "$BACK_CMD" "$BACK_LOG"
458
+ BACK_STARTED=$(date +%s)
459
+ launch_detached backend "$BACK_CMD" "$BACK_LOG" "${DMS_BACK_PORT:-}"
449
460
  wait_for "$BACK_LOG" "$BACK_READY_PATTERN" "backend" "$BACK_ERROR_PATTERN" "$LAUNCHED_PID" || return 1
450
- log "backend ready on $(backend_url)."
461
+ url="$(backend_url)"
462
+ case "$url" in *" "*) ;; *) wait_for_manifest "$url" "$LAUNCHED_PID" || return 1 ;; esac
463
+ log "backend ready on $url."
451
464
  }
452
465
 
453
466
  start_frontend() {
454
467
  log "starting frontend in $PROJECT_ROOT (logs → $FRONT_LOG)…"
455
- : > "$FRONT_LOG"
456
- launch_detached frontend "$FRONT_CMD" "$FRONT_LOG"
468
+ launch_detached frontend "$FRONT_CMD" "$FRONT_LOG" "${DMS_FRONT_PORT:-}"
457
469
  wait_for "$FRONT_LOG" "$FRONT_READY_PATTERN" "frontend" "$FRONT_ERROR_PATTERN" "$LAUNCHED_PID" || return 1
458
470
  log "frontend ready on $(frontend_url)."
459
471
  }
460
472
 
461
- # Stops the server named (backend or frontend) if it runs, and starts it again: the other
462
- # one keeps running.
473
+ # Restarts the server named (backend or frontend); the other keeps running.
463
474
  restart_server() {
464
475
  local name="$1"
465
476
  stop_servers "$name" || true
@@ -484,7 +495,7 @@ start_servers() {
484
495
 
485
496
  status() {
486
497
  require_dms_back_dir status
487
- log "dev processes of $PROJECT_ROOT:"
498
+ log "dev processes of $PROJECT_ROOT (logs: $BACK_LOG, $FRONT_LOG):"
488
499
  local targets
489
500
  refresh_process_table
490
501
  targets="$(project_pids)"
@@ -541,12 +552,14 @@ case "$cmd" in
541
552
  status
542
553
  ;;
543
554
  back-log)
555
+ [ -n "$BACK_LOG" ] || require_dms_back_dir back-log
544
556
  tail -n "${2:-60}" "$BACK_LOG"
545
557
  ;;
546
558
  ""|-h|--help|help)
547
559
  usage
548
560
  ;;
549
561
  front-log)
562
+ [ -n "$FRONT_LOG" ] || require_dms_back_dir front-log
550
563
  tail -n "${2:-60}" "$FRONT_LOG"
551
564
  ;;
552
565
  *)