@jskit-ai/create-app 0.1.2 → 0.1.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/bin/jskit-create-app.js +2 -2
- package/package.json +7 -5
- package/src/client/index.js +1 -0
- package/src/index.js +1 -0
- package/src/{shared → server}/index.js +56 -61
- package/templates/base-shell/.jskit/lock.json +31 -0
- package/templates/base-shell/README.md +24 -20
- package/templates/base-shell/app.scripts.config.mjs +1 -1
- package/templates/base-shell/config/public.js +30 -0
- package/templates/base-shell/config/server.js +1 -0
- package/templates/base-shell/config/surfaceAccessPolicies.js +12 -0
- package/templates/base-shell/eslint.config.mjs +1 -1
- package/templates/base-shell/gitignore +2 -0
- package/templates/base-shell/index.html +1 -1
- package/templates/base-shell/jsconfig.json +8 -0
- package/templates/base-shell/package.json +43 -18
- package/templates/base-shell/packages/main/package.descriptor.mjs +55 -0
- package/templates/base-shell/packages/main/package.json +12 -0
- package/templates/base-shell/packages/main/src/client/index.js +13 -0
- package/templates/base-shell/packages/main/src/client/providers/MainClientProvider.js +33 -0
- package/templates/base-shell/packages/main/src/server/controllers/index.js +9 -0
- package/templates/base-shell/packages/main/src/server/index.js +1 -0
- package/templates/base-shell/packages/main/src/server/providers/MainServiceProvider.js +22 -0
- package/templates/base-shell/packages/main/src/server/routes/index.js +9 -0
- package/templates/base-shell/packages/main/src/server/services/index.js +9 -0
- package/templates/base-shell/packages/main/src/server/support/loadAppConfig.js +55 -0
- package/templates/base-shell/packages/main/src/shared/index.js +8 -0
- package/templates/base-shell/packages/main/src/shared/schemas/index.js +20 -0
- package/templates/base-shell/scripts/dev-bootstrap-jskit.sh +110 -0
- package/templates/base-shell/scripts/just_run_verde +37 -0
- package/templates/base-shell/scripts/link-local-jskit-packages.sh +90 -0
- package/templates/base-shell/scripts/update-jskit-packages.sh +73 -0
- package/templates/base-shell/scripts/verdaccio/config.yaml +26 -0
- package/templates/base-shell/scripts/verdaccio-reset-and-publish-packages.sh +314 -0
- package/templates/base-shell/server/lib/runtimeEnv.js +29 -0
- package/templates/base-shell/server/lib/surfaceRuntime.js +10 -0
- package/templates/base-shell/server.js +39 -68
- package/templates/base-shell/src/App.vue +11 -22
- package/templates/base-shell/src/main.js +87 -1
- package/templates/base-shell/src/pages/console/index.vue +12 -0
- package/templates/base-shell/src/pages/console.vue +13 -0
- package/templates/base-shell/src/pages/home/index.vue +12 -0
- package/templates/base-shell/src/pages/home.vue +13 -0
- package/templates/base-shell/src/views/NotFound.vue +13 -0
- package/templates/base-shell/tests/server/{minimalShell.contract.test.js → minimalShell.validator.test.js} +44 -6
- package/templates/base-shell/tests/server/smoke.test.js +3 -6
- package/templates/base-shell/vite.config.mjs +24 -3
- package/templates/base-shell/vite.shared.mjs +51 -1
- package/README.md +0 -24
- package/templates/base-shell/package.json.ACTUAL_CORRECT +0 -38
- /package/src/{shared → server}/cliEntrypoint.js +0 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
+
DEFAULT_VERDACCIO_CONFIG="$ROOT_DIR/scripts/verdaccio/config.yaml"
|
|
6
|
+
if [[ -f "$DEFAULT_VERDACCIO_CONFIG" ]]; then
|
|
7
|
+
VERDACCIO_CONFIG="${VERDACCIO_CONFIG:-$DEFAULT_VERDACCIO_CONFIG}"
|
|
8
|
+
else
|
|
9
|
+
VERDACCIO_CONFIG="${VERDACCIO_CONFIG:-$HOME/.config/verdaccio/config.yaml}"
|
|
10
|
+
fi
|
|
11
|
+
VERDACCIO_LISTEN="${VERDACCIO_LISTEN:-127.0.0.1:4873}"
|
|
12
|
+
VERDACCIO_REGISTRY="${VERDACCIO_REGISTRY:-http://$VERDACCIO_LISTEN}"
|
|
13
|
+
VERDACCIO_REGISTRY="${VERDACCIO_REGISTRY%/}"
|
|
14
|
+
VERDACCIO_LOG_FILE="${VERDACCIO_LOG_FILE:-/tmp/verdaccio-jskit.log}"
|
|
15
|
+
VERDACCIO_PID_FILE="${VERDACCIO_PID_FILE:-/tmp/verdaccio-jskit.pid}"
|
|
16
|
+
PUBLISH_CONCURRENCY="${PUBLISH_CONCURRENCY:-10}"
|
|
17
|
+
JSKIT_REPO_ROOT="${JSKIT_REPO_ROOT:-}"
|
|
18
|
+
PACKAGES_DIR="${PACKAGES_DIR:-}"
|
|
19
|
+
TOOLING_DIR="${TOOLING_DIR:-}"
|
|
20
|
+
|
|
21
|
+
is_valid_jskit_repo_root() {
|
|
22
|
+
local candidate_root="$1"
|
|
23
|
+
[[ -d "$candidate_root/packages" && -d "$candidate_root/packages/kernel" && -d "$candidate_root/tooling" ]]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
resolve_jskit_repo_root() {
|
|
27
|
+
if [[ -n "$JSKIT_REPO_ROOT" ]]; then
|
|
28
|
+
echo "$JSKIT_REPO_ROOT"
|
|
29
|
+
return 0
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
local current_dir="$ROOT_DIR"
|
|
33
|
+
while true; do
|
|
34
|
+
if is_valid_jskit_repo_root "$current_dir"; then
|
|
35
|
+
echo "$current_dir"
|
|
36
|
+
return 0
|
|
37
|
+
fi
|
|
38
|
+
if [[ "$current_dir" == "/" ]]; then
|
|
39
|
+
return 1
|
|
40
|
+
fi
|
|
41
|
+
current_dir="$(dirname "$current_dir")"
|
|
42
|
+
done
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
configure_source_dirs() {
|
|
46
|
+
if [[ -z "$PACKAGES_DIR" || -z "$TOOLING_DIR" ]]; then
|
|
47
|
+
local detected_root
|
|
48
|
+
detected_root="$(resolve_jskit_repo_root || true)"
|
|
49
|
+
if [[ -n "$detected_root" ]]; then
|
|
50
|
+
JSKIT_REPO_ROOT="$detected_root"
|
|
51
|
+
if [[ -z "$PACKAGES_DIR" ]]; then
|
|
52
|
+
PACKAGES_DIR="$JSKIT_REPO_ROOT/packages"
|
|
53
|
+
fi
|
|
54
|
+
if [[ -z "$TOOLING_DIR" ]]; then
|
|
55
|
+
TOOLING_DIR="$JSKIT_REPO_ROOT/tooling"
|
|
56
|
+
fi
|
|
57
|
+
fi
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
if [[ -z "$PACKAGES_DIR" ]]; then
|
|
61
|
+
echo "Packages directory not configured." >&2
|
|
62
|
+
echo "Set PACKAGES_DIR directly, or set JSKIT_REPO_ROOT to a local jskit-ai checkout." >&2
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
if [[ -z "$TOOLING_DIR" ]]; then
|
|
67
|
+
TOOLING_DIR="/dev/null"
|
|
68
|
+
fi
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
resolve_storage_dir() {
|
|
72
|
+
if [[ -n "${VERDACCIO_STORAGE_DIR:-}" ]]; then
|
|
73
|
+
echo "$VERDACCIO_STORAGE_DIR"
|
|
74
|
+
return
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
if [[ -f "$VERDACCIO_CONFIG" ]]; then
|
|
78
|
+
local configured_storage=""
|
|
79
|
+
configured_storage="$(sed -nE 's/^[[:space:]]*storage:[[:space:]]*([^#]+).*$/\1/p' "$VERDACCIO_CONFIG" | head -n 1 | xargs || true)"
|
|
80
|
+
if [[ -n "$configured_storage" ]]; then
|
|
81
|
+
if [[ "$configured_storage" = /* ]]; then
|
|
82
|
+
echo "$configured_storage"
|
|
83
|
+
else
|
|
84
|
+
echo "$(cd "$(dirname "$VERDACCIO_CONFIG")" && pwd)/$configured_storage"
|
|
85
|
+
fi
|
|
86
|
+
return
|
|
87
|
+
fi
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
echo "$HOME/.local/share/verdaccio/storage"
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
stop_verdaccio() {
|
|
94
|
+
local listen_port
|
|
95
|
+
listen_port="${VERDACCIO_LISTEN##*:}"
|
|
96
|
+
|
|
97
|
+
if [[ -f "$VERDACCIO_PID_FILE" ]]; then
|
|
98
|
+
local pid
|
|
99
|
+
pid="$(cat "$VERDACCIO_PID_FILE" || true)"
|
|
100
|
+
if [[ -n "${pid:-}" ]] && kill -0 "$pid" 2>/dev/null; then
|
|
101
|
+
kill "$pid" || true
|
|
102
|
+
fi
|
|
103
|
+
rm -f "$VERDACCIO_PID_FILE"
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
if command -v lsof >/dev/null 2>&1; then
|
|
107
|
+
local listener_pids
|
|
108
|
+
listener_pids="$(lsof -tiTCP:"$listen_port" -sTCP:LISTEN 2>/dev/null || true)"
|
|
109
|
+
if [[ -n "$listener_pids" ]]; then
|
|
110
|
+
for pid in $listener_pids; do
|
|
111
|
+
if [[ "$pid" != "$$" ]]; then
|
|
112
|
+
kill "$pid" >/dev/null 2>&1 || true
|
|
113
|
+
fi
|
|
114
|
+
done
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
local attempts=0
|
|
118
|
+
while lsof -tiTCP:"$listen_port" -sTCP:LISTEN >/dev/null 2>&1; do
|
|
119
|
+
attempts=$((attempts + 1))
|
|
120
|
+
if (( attempts > 20 )); then
|
|
121
|
+
break
|
|
122
|
+
fi
|
|
123
|
+
sleep 0.25
|
|
124
|
+
done
|
|
125
|
+
|
|
126
|
+
listener_pids="$(lsof -tiTCP:"$listen_port" -sTCP:LISTEN 2>/dev/null || true)"
|
|
127
|
+
if [[ -n "$listener_pids" ]]; then
|
|
128
|
+
for pid in $listener_pids; do
|
|
129
|
+
if [[ "$pid" != "$$" ]]; then
|
|
130
|
+
kill -9 "$pid" >/dev/null 2>&1 || true
|
|
131
|
+
fi
|
|
132
|
+
done
|
|
133
|
+
fi
|
|
134
|
+
fi
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
start_verdaccio() {
|
|
138
|
+
local cmd=(npx --yes verdaccio --listen "$VERDACCIO_LISTEN")
|
|
139
|
+
local config_dir
|
|
140
|
+
config_dir="$(pwd)"
|
|
141
|
+
if [[ -f "$VERDACCIO_CONFIG" ]]; then
|
|
142
|
+
cmd+=(--config "$VERDACCIO_CONFIG")
|
|
143
|
+
config_dir="$(cd "$(dirname "$VERDACCIO_CONFIG")" && pwd)"
|
|
144
|
+
fi
|
|
145
|
+
|
|
146
|
+
(
|
|
147
|
+
cd "$config_dir"
|
|
148
|
+
nohup "${cmd[@]}" >"$VERDACCIO_LOG_FILE" 2>&1 &
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
local attempts=0
|
|
152
|
+
until curl -fsS "$VERDACCIO_REGISTRY/-/ping" >/dev/null 2>&1; do
|
|
153
|
+
attempts=$((attempts + 1))
|
|
154
|
+
if (( attempts > 60 )); then
|
|
155
|
+
echo "Verdaccio did not become ready at $VERDACCIO_REGISTRY within 60s." >&2
|
|
156
|
+
echo "See log: $VERDACCIO_LOG_FILE" >&2
|
|
157
|
+
exit 1
|
|
158
|
+
fi
|
|
159
|
+
sleep 1
|
|
160
|
+
done
|
|
161
|
+
|
|
162
|
+
local listen_port
|
|
163
|
+
listen_port="${VERDACCIO_LISTEN##*:}"
|
|
164
|
+
local listener_pid
|
|
165
|
+
listener_pid="$(lsof -tiTCP:"$listen_port" -sTCP:LISTEN 2>/dev/null | head -n 1 || true)"
|
|
166
|
+
if [[ -n "$listener_pid" ]]; then
|
|
167
|
+
echo "$listener_pid" >"$VERDACCIO_PID_FILE"
|
|
168
|
+
fi
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
publish_packages() {
|
|
172
|
+
if [[ ! -d "$PACKAGES_DIR" ]]; then
|
|
173
|
+
echo "Packages directory not found: $PACKAGES_DIR" >&2
|
|
174
|
+
echo "Set PACKAGES_DIR to your monorepo packages path, or set JSKIT_REPO_ROOT." >&2
|
|
175
|
+
exit 1
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
local dirs=()
|
|
179
|
+
if [[ -d "$TOOLING_DIR" ]]; then
|
|
180
|
+
while IFS= read -r dir; do
|
|
181
|
+
if [[ ! -f "$dir/package.json" ]]; then
|
|
182
|
+
continue
|
|
183
|
+
fi
|
|
184
|
+
local package_name
|
|
185
|
+
package_name="$(cd "$dir" && node -p "require('./package.json').name || ''" 2>/dev/null || true)"
|
|
186
|
+
if [[ "$package_name" == @jskit-ai/* ]]; then
|
|
187
|
+
dirs+=("$dir")
|
|
188
|
+
fi
|
|
189
|
+
done < <(find "$TOOLING_DIR" -mindepth 1 -maxdepth 1 -type d | sort)
|
|
190
|
+
fi
|
|
191
|
+
while IFS= read -r dir; do
|
|
192
|
+
dirs+=("$dir")
|
|
193
|
+
done < <(find "$PACKAGES_DIR" -mindepth 1 -maxdepth 1 -type d | sort)
|
|
194
|
+
|
|
195
|
+
if (( ${#dirs[@]} > 1 )); then
|
|
196
|
+
local deduped=()
|
|
197
|
+
local seen=":"
|
|
198
|
+
for dir in "${dirs[@]}"; do
|
|
199
|
+
if [[ "$seen" != *":$dir:"* ]]; then
|
|
200
|
+
deduped+=("$dir")
|
|
201
|
+
seen="${seen}${dir}:"
|
|
202
|
+
fi
|
|
203
|
+
done
|
|
204
|
+
dirs=("${deduped[@]}")
|
|
205
|
+
fi
|
|
206
|
+
|
|
207
|
+
if (( ${#dirs[@]} == 0 )); then
|
|
208
|
+
echo "No package directories found under $PACKAGES_DIR" >&2
|
|
209
|
+
exit 1
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
local npm_userconfig
|
|
213
|
+
local registry_with_slash
|
|
214
|
+
local verdaccio_auth_token
|
|
215
|
+
npm_userconfig="$(mktemp)"
|
|
216
|
+
registry_with_slash="${VERDACCIO_REGISTRY%/}/"
|
|
217
|
+
verdaccio_auth_token="${VERDACCIO_AUTH_TOKEN:-dev-local-token}"
|
|
218
|
+
printf "@jskit-ai:registry=%s\nregistry=%s\n//%s/:_authToken=%s\n" \
|
|
219
|
+
"$registry_with_slash" \
|
|
220
|
+
"$registry_with_slash" \
|
|
221
|
+
"${VERDACCIO_LISTEN}" \
|
|
222
|
+
"$verdaccio_auth_token" >"$npm_userconfig"
|
|
223
|
+
|
|
224
|
+
if [[ ! "$PUBLISH_CONCURRENCY" =~ ^[0-9]+$ ]] || (( PUBLISH_CONCURRENCY < 1 )); then
|
|
225
|
+
echo "PUBLISH_CONCURRENCY must be a positive integer (got: $PUBLISH_CONCURRENCY)." >&2
|
|
226
|
+
exit 1
|
|
227
|
+
fi
|
|
228
|
+
|
|
229
|
+
echo "Publishing with concurrency=$PUBLISH_CONCURRENCY"
|
|
230
|
+
|
|
231
|
+
publish_one_package() {
|
|
232
|
+
local dir="$1"
|
|
233
|
+
local npm_userconfig="$2"
|
|
234
|
+
if [[ ! -f "$dir/package.json" ]]; then
|
|
235
|
+
return 0
|
|
236
|
+
fi
|
|
237
|
+
|
|
238
|
+
local package_name
|
|
239
|
+
local publish_dir
|
|
240
|
+
package_name="$(cd "$dir" && node -p "require('./package.json').name || ''")"
|
|
241
|
+
echo "Publishing $package_name from $dir"
|
|
242
|
+
|
|
243
|
+
publish_dir="$(mktemp -d)"
|
|
244
|
+
(
|
|
245
|
+
cd "$dir"
|
|
246
|
+
tar --exclude='./node_modules' -cf - .
|
|
247
|
+
) | (
|
|
248
|
+
cd "$publish_dir"
|
|
249
|
+
tar -xf -
|
|
250
|
+
)
|
|
251
|
+
node -e 'const fs=require("node:fs");const p=process.argv[1];const j=JSON.parse(fs.readFileSync(p,"utf8"));delete j.private;fs.writeFileSync(p,`${JSON.stringify(j,null,2)}\n`);' "$publish_dir/package.json"
|
|
252
|
+
(
|
|
253
|
+
cd "$publish_dir"
|
|
254
|
+
npm publish \
|
|
255
|
+
--registry "$VERDACCIO_REGISTRY" \
|
|
256
|
+
--access public \
|
|
257
|
+
--workspaces=false \
|
|
258
|
+
--userconfig "$npm_userconfig"
|
|
259
|
+
)
|
|
260
|
+
rm -rf "$publish_dir"
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
local running_jobs=0
|
|
264
|
+
local publish_failed=0
|
|
265
|
+
for dir in "${dirs[@]}"; do
|
|
266
|
+
publish_one_package "$dir" "$npm_userconfig" &
|
|
267
|
+
running_jobs=$((running_jobs + 1))
|
|
268
|
+
|
|
269
|
+
if (( running_jobs >= PUBLISH_CONCURRENCY )); then
|
|
270
|
+
if ! wait -n; then
|
|
271
|
+
publish_failed=1
|
|
272
|
+
fi
|
|
273
|
+
running_jobs=$((running_jobs - 1))
|
|
274
|
+
fi
|
|
275
|
+
done
|
|
276
|
+
|
|
277
|
+
while (( running_jobs > 0 )); do
|
|
278
|
+
if ! wait -n; then
|
|
279
|
+
publish_failed=1
|
|
280
|
+
fi
|
|
281
|
+
running_jobs=$((running_jobs - 1))
|
|
282
|
+
done
|
|
283
|
+
|
|
284
|
+
if (( publish_failed != 0 )); then
|
|
285
|
+
echo "One or more package publishes failed." >&2
|
|
286
|
+
exit 1
|
|
287
|
+
fi
|
|
288
|
+
|
|
289
|
+
rm -f "$npm_userconfig"
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
main() {
|
|
293
|
+
configure_source_dirs
|
|
294
|
+
|
|
295
|
+
local storage_dir
|
|
296
|
+
storage_dir="$(resolve_storage_dir)"
|
|
297
|
+
|
|
298
|
+
echo "Stopping Verdaccio..."
|
|
299
|
+
stop_verdaccio
|
|
300
|
+
|
|
301
|
+
echo "Clearing Verdaccio storage: $storage_dir"
|
|
302
|
+
rm -rf "$storage_dir"
|
|
303
|
+
mkdir -p "$storage_dir"
|
|
304
|
+
|
|
305
|
+
echo "Starting Verdaccio at $VERDACCIO_REGISTRY..."
|
|
306
|
+
start_verdaccio
|
|
307
|
+
|
|
308
|
+
echo "Publishing packages from $PACKAGES_DIR and tooling in $TOOLING_DIR..."
|
|
309
|
+
publish_packages
|
|
310
|
+
|
|
311
|
+
echo "Done. Verdaccio is running at $VERDACCIO_REGISTRY"
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
main "$@"
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { surfaceRuntime } from "./surfaceRuntime.js";
|
|
3
|
+
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
|
|
1
6
|
function toPort(value, fallback = 3000) {
|
|
2
7
|
const parsed = Number.parseInt(String(value || "").trim(), 10);
|
|
3
8
|
if (Number.isInteger(parsed) && parsed > 0) {
|
|
@@ -6,8 +11,32 @@ function toPort(value, fallback = 3000) {
|
|
|
6
11
|
return fallback;
|
|
7
12
|
}
|
|
8
13
|
|
|
14
|
+
let envLoaded = false;
|
|
15
|
+
|
|
16
|
+
function ensureRuntimeEnvLoaded() {
|
|
17
|
+
if (envLoaded) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const dotenvModule = require("dotenv");
|
|
22
|
+
const loadDotEnv = dotenvModule?.config;
|
|
23
|
+
if (typeof loadDotEnv === "function") {
|
|
24
|
+
loadDotEnv();
|
|
25
|
+
}
|
|
26
|
+
} catch {
|
|
27
|
+
// dotenv is optional in base-shell; bundles can add it when needed.
|
|
28
|
+
}
|
|
29
|
+
envLoaded = true;
|
|
30
|
+
}
|
|
31
|
+
|
|
9
32
|
function resolveRuntimeEnv() {
|
|
33
|
+
ensureRuntimeEnvLoaded();
|
|
34
|
+
const serverSurface = surfaceRuntime.normalizeSurfaceMode(
|
|
35
|
+
process.env.JSKIT_SERVER_SURFACE || process.env.SERVER_SURFACE
|
|
36
|
+
);
|
|
10
37
|
return {
|
|
38
|
+
...process.env,
|
|
39
|
+
SERVER_SURFACE: serverSurface,
|
|
11
40
|
PORT: toPort(process.env.PORT, 3000),
|
|
12
41
|
HOST: String(process.env.HOST || "").trim() || "0.0.0.0"
|
|
13
42
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createSurfaceRuntime } from "@jskit-ai/kernel/shared/surface/runtime";
|
|
2
|
+
import { config } from "../../config/public.js";
|
|
3
|
+
|
|
4
|
+
const surfaceRuntime = createSurfaceRuntime({
|
|
5
|
+
allMode: config.surfaceModeAll,
|
|
6
|
+
surfaces: config.surfaceDefinitions,
|
|
7
|
+
defaultSurfaceId: config.surfaceDefaultId
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export { surfaceRuntime };
|
|
@@ -1,86 +1,57 @@
|
|
|
1
1
|
import Fastify from "fastify";
|
|
2
|
+
import { TypeBoxValidatorCompiler } from "@fastify/type-provider-typebox";
|
|
3
|
+
import { registerTypeBoxFormats } from "@jskit-ai/http-runtime/shared/validators/typeboxFormats";
|
|
2
4
|
import { resolveRuntimeEnv } from "./server/lib/runtimeEnv.js";
|
|
3
|
-
import { registerApiRouteDefinitions } from "@jskit-ai/server-runtime-core/apiRouteRegistration";
|
|
4
|
-
import { createServerRuntimeFromApp, applyContributedRuntimeLifecycle } from "@jskit-ai/server-runtime-core/serverContributions";
|
|
5
5
|
import path from "node:path";
|
|
6
|
+
import {
|
|
7
|
+
registerSurfaceRequestConstraint,
|
|
8
|
+
resolveRuntimeProfileFromSurface,
|
|
9
|
+
tryCreateProviderRuntimeFromApp
|
|
10
|
+
} from "@jskit-ai/kernel/server/platform";
|
|
11
|
+
import { surfaceRuntime } from "./server/lib/surfaceRuntime.js";
|
|
6
12
|
|
|
7
|
-
function
|
|
8
|
-
app
|
|
13
|
+
async function createServer() {
|
|
14
|
+
const app = Fastify({ logger: true });
|
|
15
|
+
registerTypeBoxFormats();
|
|
16
|
+
app.setValidatorCompiler(TypeBoxValidatorCompiler);
|
|
17
|
+
|
|
18
|
+
app.get("/api/health", async () => {
|
|
9
19
|
return {
|
|
10
20
|
ok: true,
|
|
11
21
|
app: "__APP_NAME__"
|
|
12
22
|
};
|
|
13
23
|
});
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const routeCount = Array.isArray(composed.routes) ? composed.routes.length : 0;
|
|
29
|
-
if (routeCount > 0) {
|
|
30
|
-
registerApiRouteDefinitions(app, {
|
|
31
|
-
routes: composed.routes
|
|
32
|
-
});
|
|
33
|
-
}
|
|
24
|
+
const runtimeEnv = resolveRuntimeEnv();
|
|
25
|
+
const appRoot = path.resolve(process.cwd());
|
|
26
|
+
const runtime = await tryCreateProviderRuntimeFromApp({
|
|
27
|
+
appRoot,
|
|
28
|
+
profile: resolveRuntimeProfileFromSurface({
|
|
29
|
+
surfaceRuntime,
|
|
30
|
+
serverSurface: runtimeEnv.SERVER_SURFACE,
|
|
31
|
+
defaultProfile: "app"
|
|
32
|
+
}),
|
|
33
|
+
env: runtimeEnv,
|
|
34
|
+
logger: app.log,
|
|
35
|
+
fastify: app
|
|
36
|
+
});
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
});
|
|
38
|
+
registerSurfaceRequestConstraint({
|
|
39
|
+
fastify: app,
|
|
40
|
+
surfaceRuntime,
|
|
41
|
+
serverSurface: runtimeEnv.SERVER_SURFACE,
|
|
42
|
+
globalUiPaths: runtime?.globalUiPaths || []
|
|
43
|
+
});
|
|
43
44
|
|
|
45
|
+
if (runtime) {
|
|
44
46
|
app.log.info(
|
|
45
47
|
{
|
|
46
|
-
routeCount,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
packageOrder: composed.packageOrder
|
|
48
|
+
routeCount: runtime.routeCount,
|
|
49
|
+
surface: surfaceRuntime.normalizeSurfaceMode(runtimeEnv.SERVER_SURFACE),
|
|
50
|
+
providerPackages: runtime.providerPackageOrder,
|
|
51
|
+
packageOrder: runtime.packageOrder
|
|
51
52
|
},
|
|
52
|
-
"Registered JSKIT
|
|
53
|
+
"Registered JSKIT provider server runtime."
|
|
53
54
|
);
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
enabled: true,
|
|
57
|
-
routeCount,
|
|
58
|
-
pluginCount: lifecycleResult.pluginCount,
|
|
59
|
-
workerCount: lifecycleResult.workerCount,
|
|
60
|
-
onBootCount: lifecycleResult.onBootCount
|
|
61
|
-
};
|
|
62
|
-
} catch (error) {
|
|
63
|
-
const message = String(error?.message || "");
|
|
64
|
-
if (message.includes("Lock file not found:")) {
|
|
65
|
-
return {
|
|
66
|
-
enabled: false,
|
|
67
|
-
routeCount: 0
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
throw error;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async function createServer() {
|
|
75
|
-
const app = Fastify({ logger: true });
|
|
76
|
-
const runtimeEnv = resolveRuntimeEnv();
|
|
77
|
-
const appRoot = path.resolve(process.cwd());
|
|
78
|
-
const contributed = await registerContributedRuntime(app, {
|
|
79
|
-
appRoot,
|
|
80
|
-
runtimeEnv
|
|
81
|
-
});
|
|
82
|
-
if (!contributed.enabled || contributed.routeCount < 1) {
|
|
83
|
-
registerFallbackHealthRoute(app);
|
|
84
55
|
}
|
|
85
56
|
|
|
86
57
|
return app;
|
|
@@ -1,24 +1,13 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import { onMounted, ref } from "vue";
|
|
3
|
-
|
|
4
|
-
const appTitle = "__APP_TITLE__";
|
|
5
|
-
const health = ref("loading...");
|
|
6
|
-
|
|
7
|
-
onMounted(async () => {
|
|
8
|
-
try {
|
|
9
|
-
const response = await fetch("/api/v1/health");
|
|
10
|
-
const payload = await response.json();
|
|
11
|
-
health.value = payload?.ok ? "ok" : "unhealthy";
|
|
12
|
-
} catch {
|
|
13
|
-
health.value = "unreachable";
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
</script>
|
|
17
|
-
|
|
18
1
|
<template>
|
|
19
|
-
<
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
2
|
+
<v-app>
|
|
3
|
+
<v-main>
|
|
4
|
+
<v-container class="py-10 py-md-14">
|
|
5
|
+
<v-row justify="center">
|
|
6
|
+
<v-col cols="12" sm="11" md="10" lg="8" xl="7">
|
|
7
|
+
<RouterView />
|
|
8
|
+
</v-col>
|
|
9
|
+
</v-row>
|
|
10
|
+
</v-container>
|
|
11
|
+
</v-main>
|
|
12
|
+
</v-app>
|
|
24
13
|
</template>
|
|
@@ -1,4 +1,90 @@
|
|
|
1
1
|
import { createApp } from "vue";
|
|
2
|
+
import { createRouter, createWebHistory } from "vue-router/auto";
|
|
3
|
+
import { routes } from "vue-router/auto-routes";
|
|
4
|
+
import "vuetify/styles";
|
|
5
|
+
import { createVuetify } from "vuetify";
|
|
6
|
+
import * as components from "vuetify/components";
|
|
7
|
+
import * as directives from "vuetify/directives";
|
|
8
|
+
import { aliases as mdiAliases, mdi } from "vuetify/iconsets/mdi-svg";
|
|
2
9
|
import App from "./App.vue";
|
|
10
|
+
import NotFoundView from "./views/NotFound.vue";
|
|
11
|
+
import { bootInstalledClientModules } from "virtual:jskit-client-bootstrap";
|
|
12
|
+
import { createSurfaceRuntime } from "@jskit-ai/kernel/shared/surface/runtime";
|
|
13
|
+
import {
|
|
14
|
+
bootstrapClientShellApp,
|
|
15
|
+
createShellRouter
|
|
16
|
+
} from "@jskit-ai/kernel/client";
|
|
17
|
+
import { config } from "../config/public.js";
|
|
3
18
|
|
|
4
|
-
|
|
19
|
+
const surfaceRuntime = createSurfaceRuntime({
|
|
20
|
+
allMode: config.surfaceModeAll,
|
|
21
|
+
surfaces: config.surfaceDefinitions,
|
|
22
|
+
defaultSurfaceId: config.surfaceDefaultId
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const surfaceMode = surfaceRuntime.normalizeSurfaceMode(import.meta.env.VITE_SURFACE);
|
|
26
|
+
const { router, fallbackRoute } = createShellRouter({
|
|
27
|
+
createRouter,
|
|
28
|
+
history: createWebHistory(),
|
|
29
|
+
routes,
|
|
30
|
+
surfaceRuntime,
|
|
31
|
+
surfaceMode,
|
|
32
|
+
notFoundComponent: NotFoundView,
|
|
33
|
+
guard: {
|
|
34
|
+
surfaceDefinitions: config.surfaceDefinitions,
|
|
35
|
+
defaultSurfaceId: config.surfaceDefaultId,
|
|
36
|
+
webRootAllowed: config.webRootAllowed
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const vuetify = createVuetify({
|
|
41
|
+
components,
|
|
42
|
+
directives,
|
|
43
|
+
theme: {
|
|
44
|
+
defaultTheme: "light",
|
|
45
|
+
themes: {
|
|
46
|
+
light: {
|
|
47
|
+
colors: {
|
|
48
|
+
primary: "#0f6b54",
|
|
49
|
+
secondary: "#3f5150",
|
|
50
|
+
background: "#eef3ee",
|
|
51
|
+
surface: "#f7fbf6",
|
|
52
|
+
"surface-variant": "#dfe8df",
|
|
53
|
+
"on-surface-variant": "#3b4c44",
|
|
54
|
+
error: "#9f1d1d"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
dark: {
|
|
58
|
+
colors: {
|
|
59
|
+
primary: "#6fd0b5",
|
|
60
|
+
secondary: "#9db2af",
|
|
61
|
+
background: "#0f1715",
|
|
62
|
+
surface: "#16211e",
|
|
63
|
+
"surface-variant": "#253430",
|
|
64
|
+
"on-surface-variant": "#c5d6d2",
|
|
65
|
+
error: "#ffb4ab"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
icons: {
|
|
71
|
+
defaultSet: "mdi",
|
|
72
|
+
aliases: mdiAliases,
|
|
73
|
+
sets: { mdi }
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
void bootstrapClientShellApp({
|
|
78
|
+
createApp,
|
|
79
|
+
rootComponent: App,
|
|
80
|
+
appConfig: config,
|
|
81
|
+
appPlugins: [vuetify],
|
|
82
|
+
router,
|
|
83
|
+
bootClientModules: bootInstalledClientModules,
|
|
84
|
+
surfaceRuntime,
|
|
85
|
+
surfaceMode,
|
|
86
|
+
env: import.meta.env,
|
|
87
|
+
fallbackRoute
|
|
88
|
+
}).catch((error) => {
|
|
89
|
+
console.error("Failed to bootstrap client app.", error);
|
|
90
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-card class="mx-auto" max-width="960" rounded="xl" border elevation="1">
|
|
3
|
+
<v-card-item class="px-6 py-5 px-md-8 py-md-7">
|
|
4
|
+
<v-card-title class="text-h4">console</v-card-title>
|
|
5
|
+
<v-card-subtitle class="text-subtitle-1 mt-2">operations surface</v-card-subtitle>
|
|
6
|
+
</v-card-item>
|
|
7
|
+
<v-divider />
|
|
8
|
+
<v-card-text class="px-6 py-5 px-md-8 py-md-7 text-body-1 text-medium-emphasis">
|
|
9
|
+
This surface is intended for operational tooling.
|
|
10
|
+
</v-card-text>
|
|
11
|
+
</v-card>
|
|
12
|
+
</template>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-card class="mx-auto" max-width="960" rounded="xl" border elevation="1">
|
|
3
|
+
<v-card-item class="px-6 py-5 px-md-8 py-md-7">
|
|
4
|
+
<v-card-title class="text-h4">welcome</v-card-title>
|
|
5
|
+
<v-card-subtitle class="text-subtitle-1 mt-2">starter app</v-card-subtitle>
|
|
6
|
+
</v-card-item>
|
|
7
|
+
<v-divider />
|
|
8
|
+
<v-card-text class="px-6 py-5 px-md-8 py-md-7 text-body-1 text-medium-emphasis">
|
|
9
|
+
Start by adding packages and pages to this app.
|
|
10
|
+
</v-card-text>
|
|
11
|
+
</v-card>
|
|
12
|
+
</template>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const title = "Not Found";
|
|
3
|
+
const message = "The page you requested does not exist.";
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<template>
|
|
7
|
+
<v-container class="fill-height d-flex align-center justify-center">
|
|
8
|
+
<v-card class="pa-6 text-center" max-width="560" rounded="lg">
|
|
9
|
+
<v-card-title class="text-h4">{{ title }}</v-card-title>
|
|
10
|
+
<v-card-text class="text-medium-emphasis">{{ message }}</v-card-text>
|
|
11
|
+
</v-card>
|
|
12
|
+
</v-container>
|
|
13
|
+
</template>
|