@antelopejs/dms 0.5.0 → 0.5.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.
- package/CHANGELOG.md +50 -0
- package/dist/implementations/dms/page.js +69 -22
- package/dist/implementations/dms/page.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/pages/settings/users/member-invite-form.d.ts +5 -0
- package/dist/pages/settings/users/member-invite-form.js +11 -2
- package/dist/pages/settings/users/member-invite-form.js.map +1 -1
- package/dist/pages/settings/users/members.d.ts +2 -0
- package/dist/pages/settings/users/members.js +11 -0
- package/dist/pages/settings/users/members.js.map +1 -1
- package/dist/realtime/index.js +2 -0
- package/dist/realtime/index.js.map +1 -1
- package/dist/realtime/sessions.d.ts +3 -0
- package/dist/realtime/sessions.js +5 -0
- package/dist/realtime/sessions.js.map +1 -1
- package/dist/realtime/sse.d.ts +1 -1
- package/dist/realtime/sse.js +9 -3
- package/dist/realtime/sse.js.map +1 -1
- package/dist/routes/realtime.js +8 -3
- package/dist/routes/realtime.js.map +1 -1
- package/dist/test/helpers/reload-host.d.ts +7 -2
- package/dist/test/helpers/reload-host.js +23 -4
- package/dist/test/helpers/reload-host.js.map +1 -1
- package/dist/test/reload-host/index.js +27 -1
- package/dist/test/reload-host/index.js.map +1 -1
- package/dist/test/reload-host/package.json +1 -1
- package/dist/test/unit/implementations/dms/missing-category.test.d.ts +1 -0
- package/dist/test/unit/implementations/dms/missing-category.test.js +174 -0
- package/dist/test/unit/implementations/dms/missing-category.test.js.map +1 -0
- package/dist/test/unit/interfaces/dms/database-initialized-hook.test.d.ts +1 -0
- package/dist/test/unit/interfaces/dms/database-initialized-hook.test.js +92 -0
- package/dist/test/unit/interfaces/dms/database-initialized-hook.test.js.map +1 -0
- package/dist/test/unit/interfaces/dms/invite-extension.test.js +59 -0
- package/dist/test/unit/interfaces/dms/invite-extension.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms/module-reload-registrations.test.js +2 -2
- package/dist/test/unit/interfaces/dms/module-reload-registrations.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms/page-extension-ownership.test.d.ts +1 -0
- package/dist/test/unit/interfaces/dms/page-extension-ownership.test.js +153 -0
- package/dist/test/unit/interfaces/dms/page-extension-ownership.test.js.map +1 -0
- package/dist/test/unit/pages/settings/invite-availability.test.d.ts +1 -0
- package/dist/test/unit/pages/settings/invite-availability.test.js +112 -0
- package/dist/test/unit/pages/settings/invite-availability.test.js.map +1 -0
- package/dist/test/unit/realtime/stop-closes-streams.test.d.ts +1 -0
- package/dist/test/unit/realtime/stop-closes-streams.test.js +99 -0
- package/dist/test/unit/realtime/stop-closes-streams.test.js.map +1 -0
- package/dist/test/unit/skills/dms-dev-script.test.d.ts +1 -0
- package/dist/test/unit/skills/dms-dev-script.test.js +137 -0
- package/dist/test/unit/skills/dms-dev-script.test.js.map +1 -0
- package/dist/validation/auth.schema.d.ts +2 -2
- package/frontend-vue/dms.frontend.ts +4 -3
- package/frontend-vue/layers/dms-core/app/composables/realtime/useUserRealtime.ts +116 -44
- package/frontend-vue/layers/dms-layout/app/pages/[...slug].vue +2 -0
- package/frontend-vue/layers/dms-ui/app/build/components/table/Actions.vue +18 -8
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViewRowActions.ts +12 -0
- package/frontend-vue/layers/dms-ui/app/composables/table-view/types/custom-button.ts +4 -0
- package/frontend-vue/layers/dms-ui/app/plugins/shortcuts.ts +1 -1
- package/frontend-vue/layers/dms-ui/app/types/shortcuts-aggregated.d.ts +8 -0
- package/frontend-vue/tests/realtime-reconnect.test.ts +215 -0
- package/frontend-vue/tests/shortcuts-aggregate.test.ts +41 -0
- package/frontend-vue/vitest.config.ts +4 -0
- package/package.json +4 -4
- package/skills/dms-dev/SKILL.md +28 -16
- package/skills/dms-dev/scripts/dms-dev.sh +275 -83
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# dms-dev — start / stop / restart the AntelopeJS DMS dev servers.
|
|
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
4
|
# `pnpm dev` / `pnpm frontend:dev` scripts — a convention our playground projects adopt, which
|
|
5
5
|
# expand to `ajs project dev …` (the AntelopeJS backend; `ajs project run` is the legacy
|
|
6
6
|
# alias) and `ajs dms dev` (the Inertia frontend loader — it auto-discovers the backend, -b optional).
|
|
7
7
|
# Those script names aren't shipped by the DMS, so override the actual commands with
|
|
8
8
|
# DMS_BACK_CMD / DMS_FRONT_CMD when a project starts its servers differently.
|
|
9
|
-
#
|
|
10
|
-
#
|
|
9
|
+
#
|
|
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.
|
|
11
14
|
|
|
12
15
|
set -uo pipefail
|
|
13
16
|
|
|
@@ -17,14 +20,24 @@ FRONT_CMD="${DMS_FRONT_CMD:-pnpm frontend:dev}"
|
|
|
17
20
|
BACK_LOG="${DMS_BACK_LOG:-/tmp/dms-back.log}"
|
|
18
21
|
FRONT_LOG="${DMS_FRONT_LOG:-/tmp/dms-front.log}"
|
|
19
22
|
BACK_READY_PATTERN='Server started, listening'
|
|
20
|
-
FRONT_READY_PATTERN='Local:.*localhost:'
|
|
23
|
+
FRONT_READY_PATTERN='Server ready on|Local:.*localhost:'
|
|
21
24
|
# Patterns that indicate a fatal startup error — detecting any of these aborts
|
|
22
25
|
# the wait immediately instead of burning the full timeout.
|
|
23
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'
|
|
24
27
|
FRONT_ERROR_PATTERN='Cannot find module|Failed to compile|Vite error|ENOENT.*package\.json|EADDRINUSE'
|
|
25
28
|
WAIT_TIMEOUT="${DMS_DEV_TIMEOUT:-180}"
|
|
29
|
+
STOP_GRACE="${DMS_DEV_STOP_GRACE:-10}"
|
|
30
|
+
DEV_JSON_WAIT=5
|
|
31
|
+
DEFAULT_BACK_URL='http://localhost:5010'
|
|
32
|
+
DEFAULT_FRONT_URL='http://localhost:3001'
|
|
26
33
|
|
|
27
|
-
|
|
34
|
+
# Only picks candidates when no pid file exists, and is always combined with the
|
|
35
|
+
# DMS_BACK_DIR scope check: on its own it would match every project on the machine.
|
|
36
|
+
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)'
|
|
37
|
+
|
|
38
|
+
PROJECT_ROOT=""
|
|
39
|
+
PID_FILE=""
|
|
40
|
+
LAUNCHED_PID=""
|
|
28
41
|
|
|
29
42
|
log() { printf '[dms-dev] %s\n' "$*"; }
|
|
30
43
|
|
|
@@ -42,84 +55,274 @@ require_dms_back_dir() {
|
|
|
42
55
|
log "error: DMS_BACK_DIR=$DMS_BACK_DIR has no package.json — not a DMS backend project."
|
|
43
56
|
exit 2
|
|
44
57
|
fi
|
|
58
|
+
PROJECT_ROOT="$(cd "$DMS_BACK_DIR" && pwd -P)"
|
|
59
|
+
PID_FILE="$PROJECT_ROOT/.antelope/dms-dev.pid"
|
|
45
60
|
}
|
|
46
61
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if
|
|
55
|
-
|
|
56
|
-
pgrep -af "$PROC_PATTERN" | sed 's/^/ /'
|
|
57
|
-
pgrep -af "$PROC_PATTERN" | awk '{print $1}' | xargs -r kill -9 2>/dev/null || true
|
|
58
|
-
sleep 2
|
|
62
|
+
is_alive() { [ -n "$1" ] && kill -0 "$1" 2>/dev/null; }
|
|
63
|
+
|
|
64
|
+
process_cwd() {
|
|
65
|
+
if [ -e "/proc/$1/cwd" ]; then
|
|
66
|
+
readlink "/proc/$1/cwd" 2>/dev/null
|
|
67
|
+
return
|
|
68
|
+
fi
|
|
69
|
+
if command -v lsof >/dev/null 2>&1; then
|
|
70
|
+
lsof -a -p "$1" -d cwd -Fn 2>/dev/null | sed -n 's/^n//p' | head -1
|
|
59
71
|
fi
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
process_args() { ps -o args= -p "$1" 2>/dev/null; }
|
|
75
|
+
|
|
76
|
+
is_in_project() {
|
|
77
|
+
case "$(process_cwd "$1")/" in "$PROJECT_ROOT"/*) return 0 ;; esac
|
|
78
|
+
case "$(process_args "$1") " in *"$PROJECT_ROOT"/* | *"$PROJECT_ROOT "*) return 0 ;; esac
|
|
79
|
+
return 1
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# The given roots plus every process whose parent chain or process group leads to one.
|
|
83
|
+
expand_tree() {
|
|
84
|
+
ps -A -o pid=,ppid=,pgid= | awk -v roots="$*" '
|
|
85
|
+
BEGIN { n = split(roots, r, " "); for (i = 1; i <= n; i++) keep[r[i]] = 1 }
|
|
86
|
+
{ parent[$1] = $2; group[$1] = $3 }
|
|
87
|
+
END {
|
|
88
|
+
do {
|
|
89
|
+
grew = 0
|
|
90
|
+
for (p in parent)
|
|
91
|
+
if (!(p in keep) && ((parent[p] in keep) || (group[p] in keep))) { keep[p] = 1; grew = 1 }
|
|
92
|
+
} while (grew)
|
|
93
|
+
for (p in keep) if (p in parent) print p
|
|
94
|
+
}'
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
pid_file_roots() {
|
|
98
|
+
[ -f "$PID_FILE" ] || return 0
|
|
99
|
+
local name pid
|
|
100
|
+
while read -r name pid; do
|
|
101
|
+
[ -n "${pid:-}" ] || continue
|
|
102
|
+
if is_alive "$pid" && is_in_project "$pid"; then
|
|
103
|
+
echo "$pid"
|
|
104
|
+
else
|
|
105
|
+
log "ignoring stale $name pid $pid from $PID_FILE" >&2
|
|
106
|
+
fi
|
|
107
|
+
done < "$PID_FILE"
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
scanned_roots() {
|
|
111
|
+
local listing pid
|
|
112
|
+
# Captured first so the grep below never sees its own command line.
|
|
113
|
+
listing="$(ps -A -o pid=,args=)"
|
|
114
|
+
printf '%s\n' "$listing" | grep -E "$PROC_PATTERN" | awk '{print $1}' | while read -r pid; do
|
|
115
|
+
is_in_project "$pid" && echo "$pid"
|
|
116
|
+
done
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
project_pids() {
|
|
120
|
+
local roots
|
|
121
|
+
roots="$(pid_file_roots)"
|
|
122
|
+
[ -n "$roots" ] || roots="$(scanned_roots)"
|
|
123
|
+
[ -n "$roots" ] || return 0
|
|
124
|
+
# shellcheck disable=SC2086 # one pid per word
|
|
125
|
+
expand_tree $roots | grep -vx "$$"
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
self_ancestors() {
|
|
129
|
+
local pid="$$"
|
|
130
|
+
while [ -n "$pid" ] && [ "$pid" -gt 1 ]; do
|
|
131
|
+
echo "$pid"
|
|
132
|
+
pid="$(ps -o ppid= -p "$pid" 2>/dev/null | tr -d ' ')"
|
|
133
|
+
done
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
# An agent spawned by the backend (e.g. the dms-ai sidecar) would take its own host down.
|
|
137
|
+
refuse_if_hosting_self() {
|
|
138
|
+
local hosting
|
|
139
|
+
hosting="$(printf '%s\n' "$@" | grep -Fx -f <(self_ancestors) | head -1)"
|
|
140
|
+
[ -z "$hosting" ] && return 0
|
|
141
|
+
log "error: this shell runs inside the dev servers it was asked to stop (pid $hosting)."
|
|
142
|
+
log " An agent running inside the DMS must not stop or restart them: rely on hot reload."
|
|
143
|
+
return 1
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
alive_among() {
|
|
147
|
+
local pid
|
|
148
|
+
for pid in "$@"; do is_alive "$pid" && echo "$pid"; done
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
signal_and_wait() {
|
|
152
|
+
local deadline survivors
|
|
153
|
+
kill -TERM "$@" 2>/dev/null
|
|
154
|
+
deadline=$(($(date +%s) + STOP_GRACE))
|
|
155
|
+
survivors="$(alive_among "$@")"
|
|
156
|
+
while [ -n "$survivors" ] && [ "$(date +%s)" -lt "$deadline" ]; do
|
|
157
|
+
sleep 1
|
|
158
|
+
survivors="$(alive_among "$@")"
|
|
159
|
+
done
|
|
160
|
+
[ -n "$survivors" ] || return 0
|
|
161
|
+
log "still running after ${STOP_GRACE}s, sending SIGKILL to: $(echo "$survivors" | tr '\n' ' ')"
|
|
162
|
+
# shellcheck disable=SC2086 # one pid per word
|
|
163
|
+
kill -KILL $survivors 2>/dev/null
|
|
164
|
+
sleep 1
|
|
165
|
+
# shellcheck disable=SC2086
|
|
166
|
+
survivors="$(alive_among $survivors)"
|
|
167
|
+
[ -z "$survivors" ] && return 0
|
|
168
|
+
log "error: could not stop: $(echo "$survivors" | tr '\n' ' ')"
|
|
169
|
+
return 1
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
stop_servers() {
|
|
173
|
+
require_dms_back_dir stop
|
|
174
|
+
log "stopping dev servers of $PROJECT_ROOT…"
|
|
175
|
+
local targets
|
|
176
|
+
targets="$(project_pids)"
|
|
177
|
+
if [ -z "$targets" ]; then
|
|
178
|
+
rm -f "$PID_FILE"
|
|
179
|
+
log "nothing running."
|
|
180
|
+
return 0
|
|
64
181
|
fi
|
|
182
|
+
# shellcheck disable=SC2086 # one pid per word
|
|
183
|
+
refuse_if_hosting_self $targets || exit 3
|
|
184
|
+
# shellcheck disable=SC2086
|
|
185
|
+
signal_and_wait $targets || return 1
|
|
186
|
+
rm -f "$PID_FILE"
|
|
65
187
|
log "stopped."
|
|
66
188
|
}
|
|
67
189
|
|
|
190
|
+
# Detaches the command into its own session so it survives this shell, and records its
|
|
191
|
+
# pid. `exec` keeps that pid stable through setsid/nohup down to the command itself.
|
|
192
|
+
launch_detached() {
|
|
193
|
+
local name="$1" cmd="$2" log_file="$3"
|
|
194
|
+
if command -v setsid >/dev/null 2>&1; then
|
|
195
|
+
# shellcheck disable=SC2086 # word-splitting of the command is intentional
|
|
196
|
+
(cd "$PROJECT_ROOT" && exec setsid nohup $cmd >> "$log_file" 2>&1 < /dev/null) &
|
|
197
|
+
elif command -v perl >/dev/null 2>&1; then
|
|
198
|
+
# macOS ships no setsid(1); perl's POSIX::setsid does the same before exec.
|
|
199
|
+
# shellcheck disable=SC2086
|
|
200
|
+
(cd "$PROJECT_ROOT" && exec perl -MPOSIX -e 'POSIX::setsid(); exec { $ARGV[0] } @ARGV or die "exec $ARGV[0]: $!\n"' \
|
|
201
|
+
nohup $cmd >> "$log_file" 2>&1 < /dev/null) &
|
|
202
|
+
else
|
|
203
|
+
# shellcheck disable=SC2086
|
|
204
|
+
(cd "$PROJECT_ROOT" && exec nohup $cmd >> "$log_file" 2>&1 < /dev/null) &
|
|
205
|
+
fi
|
|
206
|
+
LAUNCHED_PID=$!
|
|
207
|
+
mkdir -p "$(dirname "$PID_FILE")"
|
|
208
|
+
echo "$name $LAUNCHED_PID" >> "$PID_FILE"
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
fail_start() {
|
|
212
|
+
local label="$1" log_file="$2" reason="$3"
|
|
213
|
+
log "FAILED TO START: $label — $reason. Tail of $log_file:"
|
|
214
|
+
tail -40 "$log_file" | sed 's/^/ /'
|
|
215
|
+
}
|
|
216
|
+
|
|
68
217
|
wait_for() {
|
|
69
|
-
local log_file="$1" pattern="$2" label="$3" error_pattern="$4"
|
|
218
|
+
local log_file="$1" pattern="$2" label="$3" error_pattern="$4" pid="$5" started
|
|
70
219
|
started=$(date +%s)
|
|
71
|
-
# Grace period: pnpm forks/execs into the actual dev process, so pgrep can
|
|
72
|
-
# legitimately return nothing for the first second or two. Don't treat that
|
|
73
|
-
# as a failure.
|
|
74
|
-
local grace_until=$((started + 8))
|
|
75
220
|
while ! grep -qE "$pattern" "$log_file" 2>/dev/null; do
|
|
76
221
|
if grep -qE "$error_pattern" "$log_file" 2>/dev/null; then
|
|
77
|
-
log "
|
|
222
|
+
log "fatal error detected in $log_file:"
|
|
78
223
|
grep -nE "$error_pattern" "$log_file" | head -5 | sed 's/^/ /'
|
|
79
|
-
|
|
80
|
-
tail -40 "$log_file" | sed 's/^/ /'
|
|
224
|
+
fail_start "$label" "$log_file" "fatal error"
|
|
81
225
|
return 1
|
|
82
226
|
fi
|
|
83
|
-
if
|
|
84
|
-
|
|
85
|
-
tail -40 "$log_file" | sed 's/^/ /'
|
|
227
|
+
if ! is_alive "$pid"; then
|
|
228
|
+
fail_start "$label" "$log_file" "process $pid exited before becoming ready"
|
|
86
229
|
return 1
|
|
87
230
|
fi
|
|
88
231
|
if [ $(($(date +%s) - started)) -gt "$WAIT_TIMEOUT" ]; then
|
|
89
|
-
|
|
90
|
-
tail -40 "$log_file" | sed 's/^/ /'
|
|
232
|
+
fail_start "$label" "$log_file" "timed out after ${WAIT_TIMEOUT}s waiting for readiness pattern"
|
|
91
233
|
return 1
|
|
92
234
|
fi
|
|
93
|
-
sleep
|
|
235
|
+
sleep 1
|
|
236
|
+
done
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
# Prints "<pid> <url>" for the api endpoint a dev.json records.
|
|
240
|
+
read_dev_json() {
|
|
241
|
+
command -v node >/dev/null 2>&1 || return 0
|
|
242
|
+
# shellcheck disable=SC2016 # a JavaScript template literal, not a shell expansion
|
|
243
|
+
node -e '
|
|
244
|
+
const dev = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"));
|
|
245
|
+
const servers = dev.servers ?? {};
|
|
246
|
+
const endpoint = (servers.api ?? Object.values(servers)[0])?.endpoints?.[0];
|
|
247
|
+
if (!endpoint) process.exit(0);
|
|
248
|
+
const wildcard = ["0.0.0.0", "::", ""].includes(endpoint.host ?? "");
|
|
249
|
+
const host = wildcard ? "localhost" : endpoint.host;
|
|
250
|
+
console.log(`${dev.pid} ${endpoint.protocol ?? "http"}://${host}:${endpoint.port}`);
|
|
251
|
+
' "$1" 2>/dev/null
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
# The project may live in DMS_BACK_DIR or one level below (`ajs project dev -p playground`).
|
|
255
|
+
# A dev.json outlives its backend, so only one whose writer is alive and ours is trusted.
|
|
256
|
+
dev_json_url() {
|
|
257
|
+
local file pid url
|
|
258
|
+
for file in "$PROJECT_ROOT/.antelope/dev.json" "$PROJECT_ROOT"/*/.antelope/dev.json; do
|
|
259
|
+
[ -f "$file" ] || continue
|
|
260
|
+
read -r pid url <<< "$(read_dev_json "$file")"
|
|
261
|
+
if [ -n "${url:-}" ] && is_alive "$pid" && is_in_project "$pid"; then
|
|
262
|
+
echo "$url"
|
|
263
|
+
return
|
|
264
|
+
fi
|
|
265
|
+
done
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
backend_url() {
|
|
269
|
+
local url deadline
|
|
270
|
+
deadline=$(($(date +%s) + DEV_JSON_WAIT))
|
|
271
|
+
url="$(dev_json_url)"
|
|
272
|
+
while [ -z "$url" ] && [ "$(date +%s)" -lt "$deadline" ]; do
|
|
273
|
+
sleep 1
|
|
274
|
+
url="$(dev_json_url)"
|
|
94
275
|
done
|
|
95
|
-
|
|
276
|
+
[ -n "$url" ] || url="$(grep -oE "$BACK_READY_PATTERN on https?://[^ /]+" "$BACK_LOG" | tail -1 | awk '{print $NF}')"
|
|
277
|
+
echo "${url:-$DEFAULT_BACK_URL (assumed: no .antelope/dev.json found)}"
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
frontend_url() {
|
|
281
|
+
local url
|
|
282
|
+
url="$(grep -oE '(Server ready on|Local:)[[:space:]]+https?://[^ /]+' "$FRONT_LOG" | tail -1 | awk '{print $NF}')"
|
|
283
|
+
echo "${url:-$DEFAULT_FRONT_URL (assumed: no ready line with a URL)}"
|
|
96
284
|
}
|
|
97
285
|
|
|
98
286
|
start_backend() {
|
|
99
|
-
|
|
100
|
-
log "starting backend in $DMS_BACK_DIR (logs → $BACK_LOG)…"
|
|
287
|
+
log "starting backend in $PROJECT_ROOT (logs → $BACK_LOG)…"
|
|
101
288
|
: > "$BACK_LOG"
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
"$BACK_ERROR_PATTERN" 'pnpm.*\bdev\b|antelope-runner|ajs project (run|dev)'
|
|
289
|
+
launch_detached backend "$BACK_CMD" "$BACK_LOG"
|
|
290
|
+
wait_for "$BACK_LOG" "$BACK_READY_PATTERN" "backend" "$BACK_ERROR_PATTERN" "$LAUNCHED_PID" || return 1
|
|
291
|
+
log "backend ready on $(backend_url)."
|
|
106
292
|
}
|
|
107
293
|
|
|
108
294
|
start_frontend() {
|
|
109
|
-
|
|
110
|
-
log "starting frontend in $DMS_BACK_DIR (logs → $FRONT_LOG)…"
|
|
295
|
+
log "starting frontend in $PROJECT_ROOT (logs → $FRONT_LOG)…"
|
|
111
296
|
: > "$FRONT_LOG"
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
297
|
+
launch_detached frontend "$FRONT_CMD" "$FRONT_LOG"
|
|
298
|
+
wait_for "$FRONT_LOG" "$FRONT_READY_PATTERN" "frontend" "$FRONT_ERROR_PATTERN" "$LAUNCHED_PID" || return 1
|
|
299
|
+
log "frontend ready on $(frontend_url)."
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
start_servers() {
|
|
303
|
+
local verb="$1"
|
|
304
|
+
rm -f "$PID_FILE"
|
|
305
|
+
if ! start_backend; then
|
|
306
|
+
log "aborting $verb: backend failed to start."
|
|
307
|
+
exit 1
|
|
308
|
+
fi
|
|
309
|
+
if ! start_frontend; then
|
|
310
|
+
log "aborting $verb: frontend failed to start."
|
|
311
|
+
exit 1
|
|
312
|
+
fi
|
|
116
313
|
}
|
|
117
314
|
|
|
118
315
|
status() {
|
|
119
|
-
|
|
120
|
-
|
|
316
|
+
require_dms_back_dir status
|
|
317
|
+
log "dev processes of $PROJECT_ROOT:"
|
|
318
|
+
local targets
|
|
319
|
+
targets="$(project_pids)"
|
|
320
|
+
if [ -z "$targets" ]; then
|
|
121
321
|
echo " (none)"
|
|
322
|
+
return
|
|
122
323
|
fi
|
|
324
|
+
# shellcheck disable=SC2086 # one pid per word
|
|
325
|
+
ps -o pid=,args= -p "$(echo $targets | tr ' ' ',')" | sed 's/^/ /'
|
|
123
326
|
}
|
|
124
327
|
|
|
125
328
|
usage() {
|
|
@@ -127,24 +330,26 @@ usage() {
|
|
|
127
330
|
Usage: $(basename "$0") <command>
|
|
128
331
|
|
|
129
332
|
Commands:
|
|
130
|
-
restart Stop
|
|
131
|
-
|
|
333
|
+
restart Stop this project's servers, start backend, wait, start frontend, wait.
|
|
334
|
+
Only when hot reload cannot apply a change, and never from an agent
|
|
335
|
+
running inside the DMS: it would stop its own host.
|
|
132
336
|
start Same as restart but does not stop first (errors if already running).
|
|
133
|
-
stop
|
|
134
|
-
status Show
|
|
337
|
+
stop Stop this project's servers: SIGTERM, then SIGKILL after the grace period.
|
|
338
|
+
status Show this project's dev processes.
|
|
135
339
|
back-log [N] Tail the last N (default 60) lines of the backend log.
|
|
136
340
|
front-log [N] Tail the last N (default 60) lines of the frontend log.
|
|
137
341
|
|
|
138
342
|
Environment:
|
|
139
|
-
DMS_BACK_DIR
|
|
140
|
-
|
|
141
|
-
DMS_BACK_CMD
|
|
142
|
-
|
|
143
|
-
DMS_FRONT_CMD
|
|
144
|
-
|
|
145
|
-
DMS_BACK_LOG
|
|
146
|
-
DMS_FRONT_LOG
|
|
147
|
-
DMS_DEV_TIMEOUT
|
|
343
|
+
DMS_BACK_DIR REQUIRED for start/restart/stop/status. Absolute path to the DMS backend
|
|
344
|
+
package directory of the AntelopeJS DMS project to run.
|
|
345
|
+
DMS_BACK_CMD Command to start the backend, run in DMS_BACK_DIR (default: "pnpm dev",
|
|
346
|
+
the playground convention for "ajs project dev -w" / legacy "run -w").
|
|
347
|
+
DMS_FRONT_CMD Command to start the frontend, run in DMS_BACK_DIR (default:
|
|
348
|
+
"pnpm frontend:dev", the playground convention for "ajs dms dev").
|
|
349
|
+
DMS_BACK_LOG (default: /tmp/dms-back.log)
|
|
350
|
+
DMS_FRONT_LOG (default: /tmp/dms-front.log)
|
|
351
|
+
DMS_DEV_TIMEOUT (default: 180 seconds per server)
|
|
352
|
+
DMS_DEV_STOP_GRACE (default: 10 seconds between SIGTERM and SIGKILL)
|
|
148
353
|
EOF
|
|
149
354
|
}
|
|
150
355
|
|
|
@@ -152,29 +357,16 @@ cmd="${1:-}"
|
|
|
152
357
|
case "$cmd" in
|
|
153
358
|
restart)
|
|
154
359
|
stop_servers || true
|
|
155
|
-
|
|
156
|
-
log "aborting restart: backend failed to start."
|
|
157
|
-
exit 1
|
|
158
|
-
fi
|
|
159
|
-
if ! start_frontend; then
|
|
160
|
-
log "aborting restart: frontend failed to start."
|
|
161
|
-
exit 1
|
|
162
|
-
fi
|
|
360
|
+
start_servers restart
|
|
163
361
|
;;
|
|
164
362
|
start)
|
|
165
|
-
|
|
363
|
+
require_dms_back_dir start
|
|
364
|
+
if [ -n "$(project_pids)" ]; then
|
|
166
365
|
log "error: servers already running. Use restart, or stop first."
|
|
167
366
|
status
|
|
168
367
|
exit 1
|
|
169
368
|
fi
|
|
170
|
-
|
|
171
|
-
log "aborting start: backend failed to start."
|
|
172
|
-
exit 1
|
|
173
|
-
fi
|
|
174
|
-
if ! start_frontend; then
|
|
175
|
-
log "aborting start: frontend failed to start."
|
|
176
|
-
exit 1
|
|
177
|
-
fi
|
|
369
|
+
start_servers start
|
|
178
370
|
;;
|
|
179
371
|
stop)
|
|
180
372
|
stop_servers
|
|
@@ -185,12 +377,12 @@ case "$cmd" in
|
|
|
185
377
|
back-log)
|
|
186
378
|
tail -n "${2:-60}" "$BACK_LOG"
|
|
187
379
|
;;
|
|
188
|
-
front-log)
|
|
189
|
-
tail -n "${2:-60}" "$FRONT_LOG"
|
|
190
|
-
;;
|
|
191
380
|
""|-h|--help|help)
|
|
192
381
|
usage
|
|
193
382
|
;;
|
|
383
|
+
front-log)
|
|
384
|
+
tail -n "${2:-60}" "$FRONT_LOG"
|
|
385
|
+
;;
|
|
194
386
|
*)
|
|
195
387
|
usage
|
|
196
388
|
exit 2
|