Skip to content

Commit 6775736

Browse files
os-zhuangclaude
andauthored
ci(framework): assert capability packages ship a runtime entry (no dts-only / half-built) (#2432)
Capability packages (services / triggers / plugins) are loaded by the multi-tenant runtime via a DYNAMIC import of their published entry. If a package ships a dts-only / half-built / 0-byte dist — an interrupted build, or a package retired in source but still referenced — the import resolves to nothing and the capability SILENTLY fails to load (e.g. record-change automation never fires, with no user-visible signal). The shared tsup config always emits JS, so this can only happen by accident, and nothing in CI caught it. Extend "Verify build outputs" (which runs right after the full `pnpm build`) with a filesystem assertion that every buildable capability package actually produced its declared `main` runtime entry. Self-maintaining: reads each package's own manifest, skips dirs with no package.json (e.g. a retired service-feed / service-ai leftover) and packages without a build script. Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent b007dbd commit 6775736

1 file changed

Lines changed: 26 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,32 @@ jobs:
237237
fi
238238
echo "Build outputs verified successfully"
239239
240+
# Capability packages (services / triggers / plugins) are loaded by the
241+
# multi-tenant runtime via a DYNAMIC import of their published entry. If a
242+
# package ships a dts-only / half-built / 0-byte `dist` (an interrupted
243+
# build, or a package retired in source but still referenced), that import
244+
# resolves to nothing and the capability SILENTLY fails to load — e.g.
245+
# record-change automation never fires, with no user-visible signal. The
246+
# build config always emits JS, so this can only happen by accident; assert
247+
# every buildable capability package actually produced its declared runtime
248+
# entry. Self-maintaining: reads each package's own `main`, skips dirs with
249+
# no package.json (e.g. a retired service-feed/service-ai leftover).
250+
- name: Verify capability packages ship a runtime entry (no dts-only / half-built)
251+
run: |
252+
fail=0
253+
for d in packages/triggers/* packages/services/* packages/plugins/*; do
254+
[ -f "$d/package.json" ] || continue
255+
has_build=$(node -p "Boolean((require('./$d/package.json').scripts||{}).build)" 2>/dev/null || echo false)
256+
[ "$has_build" = "true" ] || continue
257+
main=$(node -p "require('./$d/package.json').main || 'dist/index.js'" 2>/dev/null || echo dist/index.js)
258+
if [ ! -s "$d/$main" ]; then
259+
echo "✗ $d: missing/empty runtime entry '$main' — dts-only or unbuilt? dynamic import would silently fail"
260+
fail=1
261+
fi
262+
done
263+
if [ "$fail" -ne 0 ]; then exit 1; fi
264+
echo "✓ all buildable capability packages ship a runtime JS entry"
265+
240266
- name: Analyze bundle size
241267
run: pnpm --filter @objectstack/spec analyze
242268

0 commit comments

Comments
 (0)