1919# scripts/build-console.sh
2020#
2121# Env:
22- # OBJECTUI_ROOT override path to objectui checkout
23- # OBJECTUI_REPO_URL override clone URL (default: https://github.com/objectstack-ai/objectui.git)
24- # OBJECTUI_BUILD_CMD override build command (default: pnpm exec turbo run build --filter=@object-ui/console)
22+ # OBJECTUI_ROOT override path to objectui checkout
23+ # OBJECTUI_REPO_URL override clone URL (default: https://github.com/objectstack-ai/objectui.git)
24+ # OBJECTUI_DEPS_BUILD_CMD override deps build (default: pnpm exec turbo run build --filter=@object-ui/console^...)
25+ # OBJECTUI_BUILD_CMD override console build (default: pnpm --filter @object-ui/console run build)
26+ # CONSOLE_BUNDLE_CANARY literal asserted in the built assets (default: import/jobs)
2527
2628set -euo pipefail
2729
@@ -40,7 +42,18 @@ if [[ -z "$PINNED_SHA" ]]; then
4042fi
4143
4244REPO_URL=" ${OBJECTUI_REPO_URL:- https:// github.com/ objectstack-ai/ objectui.git} "
43- BUILD_CMD=" ${OBJECTUI_BUILD_CMD:- pnpm exec turbo run build --filter=@ object-ui/ console} "
45+ # The console app itself must NOT build through turbo: turbo v2 runs tasks in
46+ # strict env mode and strips undeclared vars, so OBJECTSTACK_CLIENT_DIST
47+ # (exported below) never reaches vite unless the pinned objectui SHA happens
48+ # to declare it in turbo.json. Build the workspace deps through turbo
49+ # (cacheable, env-independent), then invoke the console's own build script
50+ # directly so the env survives.
51+ DEPS_BUILD_CMD=" ${OBJECTUI_DEPS_BUILD_CMD:- pnpm exec turbo run build --filter=@ object-ui/ console^...} "
52+ BUILD_CMD=" ${OBJECTUI_BUILD_CMD:- pnpm --filter @ object-ui/ console run build} "
53+ # Post-build canary: a literal that only exists in an up-to-date bundled
54+ # client. Guards against any future mechanism (turbo env stripping, a removed
55+ # vite hook, chunking changes) silently shipping a stale client again.
56+ BUNDLE_CANARY=" ${CONSOLE_BUNDLE_CANARY:- import/ jobs} "
4457
4558# Resolve a source checkout of objectui.
4659SOURCE_ROOT=" "
@@ -101,6 +114,32 @@ if [[ "$ACTUAL" != "$PINNED_SHA" ]]; then
101114fi
102115
103116echo " → Building @object-ui/console at ${PINNED_SHA: 0: 12} ..."
117+
118+ # ── Bundle THIS framework's client ───────────────────────────────────
119+ # The console SPA inlines @objectstack/client. Left to itself, the objectui
120+ # build resolves the client from objectui's own lockfile — which lags the
121+ # framework whenever a release adds new client APIs (the lockfile can't point
122+ # at a client that isn't published yet). That shipped 11.5.0 with the new
123+ # import UI bundled against client 11.2.0, so the console threw "does not
124+ # support async import jobs" at runtime. Alias the build to the client in
125+ # THIS tree instead: the bundled client then always matches the framework
126+ # release being published, with no objectui pin-bump round-trip.
127+ # objectui honors OBJECTSTACK_CLIENT_DIST in apps/console/vite.config.ts;
128+ # fail hard if the pinned SHA predates that hook rather than silently drift.
129+ CLIENT_PKG=" ${FRAMEWORK_ROOT} /packages/client"
130+ if ! grep -q " OBJECTSTACK_CLIENT_DIST" " ${BUILD_ROOT} /apps/console/vite.config.ts" ; then
131+ echo " ✗ objectui@${PINNED_SHA: 0: 12} has no OBJECTSTACK_CLIENT_DIST hook in apps/console/vite.config.ts —"
132+ echo " the bundled client would come from objectui's lockfile, not this framework."
133+ echo " Bump .objectui-sha to a commit that includes the hook."
134+ exit 1
135+ fi
136+ if [[ ! -f " ${CLIENT_PKG} /dist/index.mjs" ]]; then
137+ echo " → @objectstack/client dist missing — building it first..."
138+ (cd " $CLIENT_PKG " && pnpm build)
139+ fi
140+ export OBJECTSTACK_CLIENT_DIST=" $CLIENT_PKG "
141+ echo " → Console will bundle @objectstack/client from ${CLIENT_PKG} "
142+
104143pushd " $BUILD_ROOT " > /dev/null
105144
106145# objectui's root package.json may pin packages that aren't available on
@@ -109,7 +148,9 @@ NPM_CONFIG_REGISTRY_OVERRIDE="${OBJECTUI_NPM_REGISTRY:-https://registry.npmjs.or
109148npm_config_registry=" $NPM_CONFIG_REGISTRY_OVERRIDE " \
110149 pnpm install --frozen-lockfile --prefer-offline --prod=false
111150
112- # Build only the console SPA (turbo will pull in workspace deps).
151+ # Build the console's workspace deps via turbo, then the SPA itself directly
152+ # (see DEPS_BUILD_CMD/BUILD_CMD above for why these are split).
153+ eval " $DEPS_BUILD_CMD "
113154eval " $BUILD_CMD "
114155
115156popd > /dev/null
@@ -133,6 +174,14 @@ cp -R "$CONSOLE_DIST" "$TARGET"
133174# cloud/objectos Docker overlay that replaces dist/ restamps it too.
134175echo " $PINNED_SHA " > " ${TARGET} /.objectui-sha"
135176
177+ # Assert the injected client actually landed in the bundle (see BUNDLE_CANARY).
178+ if ! grep -rq " $BUNDLE_CANARY " " ${TARGET} /assets" ; then
179+ echo " ✗ Built console dist does not contain '${BUNDLE_CANARY} ' — the bundled"
180+ echo " @objectstack/client is stale (OBJECTSTACK_CLIENT_DIST injection failed)."
181+ exit 1
182+ fi
183+ echo " ✓ Bundle canary '${BUNDLE_CANARY} ' present — framework client is in the bundle."
184+
136185BYTES=" $( du -sk " $TARGET " 2> /dev/null | awk ' {print $1}' ) "
137186echo " ✓ @objectstack/console dist ready (${BYTES} KB) from objectui@${PINNED_SHA: 0: 12} "
138187
0 commit comments