Skip to content

Commit 23a947e

Browse files
committed
Add a npm validation script/step to publish
Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
1 parent 0155d32 commit 23a947e

2 files changed

Lines changed: 156 additions & 0 deletions

File tree

.github/workflows/npm-publish.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,10 @@ jobs:
193193
npx --no-install napi prepublish -t npm --skip-gh-release
194194
ls -la index.js index.d.ts
195195
196+
- name: Validate packages
197+
working-directory: ${{ env.WORKING_DIR }}
198+
run: ./test-pack.sh
199+
196200
- name: Publish Linux GNU package
197201
if: ${{ !inputs['dry-run'] }}
198202
working-directory: ${{ env.WORKING_DIR }}/npm/linux-x64-gnu

src/js-host-api/test-pack.sh

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#!/bin/bash
2+
# Validate npm packages by packing to /tmp and installing into a clean project.
3+
# Simulates what a consumer would experience after `npm install @hyperlight/js-host-api`.
4+
#
5+
# Prerequisites: run `npm run build` first to produce the .node binary.
6+
7+
set -euo pipefail
8+
9+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10+
PACK_DIR="/tmp/hyperlight-npm-test-pack"
11+
INSTALL_DIR="/tmp/hyperlight-npm-test-install"
12+
13+
# ── Cleanup ──────────────────────────────────────────────────────────
14+
rm -rf "${PACK_DIR}" "${INSTALL_DIR}"
15+
mkdir -p "${PACK_DIR}" "${INSTALL_DIR}"
16+
17+
cd "${SCRIPT_DIR}"
18+
19+
# ── Preflight checks ────────────────────────────────────────────────
20+
if [ ! -f "package.json" ]; then
21+
echo "❌ Error: package.json not found. Run from src/js-host-api/" >&2
22+
exit 1
23+
fi
24+
25+
if ! ls ./*.node 1>/dev/null 2>&1; then
26+
echo "❌ Error: No .node binary found. Run 'npm run build' first." >&2
27+
exit 1
28+
fi
29+
30+
# ── Step 1: Copy the .node binary into the platform package ─────────
31+
echo "📦 Preparing platform package..."
32+
NATIVE_BINARY=$(ls ./*.node | head -1)
33+
BINARY_NAME=$(basename "${NATIVE_BINARY}")
34+
cp "${NATIVE_BINARY}" npm/linux-x64-gnu/"${BINARY_NAME}"
35+
36+
# ── Step 2: Pack platform package ───────────────────────────────────
37+
echo "📦 Packing platform package (linux-x64-gnu)..."
38+
PLATFORM_TGZ=$(npm pack ./npm/linux-x64-gnu --pack-destination "${PACK_DIR}" 2>/dev/null)
39+
PLATFORM_TGZ_PATH="${PACK_DIR}/${PLATFORM_TGZ}"
40+
echo "${PLATFORM_TGZ_PATH}"
41+
42+
# ── Step 3: Pack main package ───────────────────────────────────────
43+
echo "📦 Packing main package..."
44+
MAIN_TGZ=$(npm pack --pack-destination "${PACK_DIR}" 2>/dev/null)
45+
MAIN_TGZ_PATH="${PACK_DIR}/${MAIN_TGZ}"
46+
echo "${MAIN_TGZ_PATH}"
47+
48+
# ── Step 4: Inspect tarball contents ────────────────────────────────
49+
echo ""
50+
echo "🔍 Platform package contents:"
51+
tar tzf "${PLATFORM_TGZ_PATH}" | sed 's/^/ /'
52+
53+
echo ""
54+
echo "🔍 Main package contents:"
55+
tar tzf "${MAIN_TGZ_PATH}" | sed 's/^/ /'
56+
57+
# ── Step 5: Validate main package contents ──────────────────────────
58+
echo ""
59+
echo "✅ Validating main package contents..."
60+
MAIN_FILES=$(tar tzf "${MAIN_TGZ_PATH}")
61+
62+
REQUIRED_FILES=("package/package.json" "package/lib.js" "package/index.js" "package/index.d.ts" "package/lib.d.ts")
63+
for f in "${REQUIRED_FILES[@]}"; do
64+
if echo "${MAIN_FILES}" | grep -q "^${f}$"; then
65+
echo "${f}"
66+
else
67+
echo " ❌ MISSING: ${f}" >&2
68+
exit 1
69+
fi
70+
done
71+
72+
BANNED_PATTERNS=("package/src/" "package/tests/" "package/Cargo.toml" "package/node_modules/" "package/target/")
73+
for p in "${BANNED_PATTERNS[@]}"; do
74+
if echo "${MAIN_FILES}" | grep -q "^${p}"; then
75+
echo " ❌ LEAKED: ${p}" >&2
76+
exit 1
77+
else
78+
echo " ✅ No leak: ${p}"
79+
fi
80+
done
81+
82+
# ── Step 6: Validate platform package contents ──────────────────────
83+
echo ""
84+
echo "✅ Validating platform package contents..."
85+
PLATFORM_FILES=$(tar tzf "${PLATFORM_TGZ_PATH}")
86+
87+
if echo "${PLATFORM_FILES}" | grep -q '\.node$'; then
88+
echo " ✅ .node binary present"
89+
else
90+
echo " ❌ MISSING: .node binary" >&2
91+
exit 1
92+
fi
93+
94+
# ── Step 7: Install from tarballs into a clean directory ────────────
95+
echo ""
96+
echo "📥 Installing from tarballs into ${INSTALL_DIR}..."
97+
cd "${INSTALL_DIR}"
98+
npm init -y --silent >/dev/null 2>&1
99+
100+
# Install platform package first, then main package
101+
npm install "${PLATFORM_TGZ_PATH}" --no-save 2>&1 | sed 's/^/ /'
102+
npm install "${MAIN_TGZ_PATH}" --no-save 2>&1 | sed 's/^/ /'
103+
104+
# ── Step 8: Smoke test — require and check exports ──────────────────
105+
echo ""
106+
echo "🧪 Smoke test: require('@hyperlight/js-host-api')..."
107+
EXPORTS=$(node -e "
108+
const h = require('@hyperlight/js-host-api');
109+
const keys = Object.keys(h);
110+
if (keys.length === 0) {
111+
console.error('ERROR: No exports found');
112+
process.exit(1);
113+
}
114+
console.log('Exports:', keys.join(', '));
115+
")
116+
echo " ${EXPORTS}"
117+
118+
# ── Step 9: Hello World — end-to-end sandbox test ───────────────────
119+
echo ""
120+
echo "🧪 Hello World: create sandbox, load handler, call it..."
121+
node -e "
122+
const { SandboxBuilder } = require('@hyperlight/js-host-api');
123+
124+
async function main() {
125+
const builder = new SandboxBuilder();
126+
const proto = await builder.build();
127+
const jsSandbox = await proto.loadRuntime();
128+
129+
jsSandbox.addHandler(
130+
'hello',
131+
'function handler(event) { event.greeting = \"Hello from Hyperlight!\"; return event; }'
132+
);
133+
134+
const loaded = await jsSandbox.getLoadedSandbox();
135+
const result = await loaded.callHandler('hello', {}, { gc: false });
136+
137+
if (result.greeting !== 'Hello from Hyperlight!') {
138+
console.error('ERROR: unexpected result:', JSON.stringify(result));
139+
process.exit(1);
140+
}
141+
console.log(' ✅ Got:', result.greeting);
142+
}
143+
144+
main().catch(err => { console.error(' ❌', err.message); process.exit(1); });
145+
"
146+
147+
# ── Cleanup temp .node from platform dir ────────────────────────────
148+
rm -f "${SCRIPT_DIR}/npm/linux-x64-gnu/${BINARY_NAME}"
149+
150+
# ── Done ────────────────────────────────────────────────────────────
151+
echo ""
152+
echo "🎉 All checks passed! Package is ready to ship."

0 commit comments

Comments
 (0)