Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
cdc36aa
web: replace electron runtime with ArkWeb + on-device Node.js (hqzing…
zxdong262 Aug 28, 2026
4228433
docs: describe dev2 web variant (ArkWeb + ohos-node)
zxdong262 Aug 28, 2026
47e8462
fix: restore build/ dir, commit build/web sources, untrack local buil…
zxdong262 Aug 28, 2026
b7a2eb1
fix: generate src/client/electerm-react in CI (build/bin/install.js s…
zxdong262 Aug 28, 2026
3b2204c
fix: track rawfile/loading.html (ArkWeb initial page)
zxdong262 Aug 28, 2026
7fc33d8
fix: name the final .app -signed and drop the unsigned copy
zxdong262 Aug 28, 2026
ccb5b47
fix: derive signed app name correctly (strip -unsigned)
zxdong262 Aug 28, 2026
d59314d
fix: resfile script path was entry/resource (singular) — HAP layout i…
zxdong262 Aug 28, 2026
2f21361
diagnostics: pass el2-junction dataDir, show boot-log last line on sc…
zxdong262 Aug 28, 2026
6f1a5a0
fix: locate libnode.so in the child namespace (dladdr + maps scan + n…
zxdong262 Aug 28, 2026
537f0ee
loader-exec fallback: exec signed system musl loader with node as arg…
zxdong262 Aug 28, 2026
538061e
code-sign libnode.so with binary-sign-tool (XPM exec fix)
zxdong262 Aug 28, 2026
a6988fe
fix: portable mktemp (GNU rejects -t templates without X's)
zxdong262 Aug 28, 2026
50812a3
run node in-process via dlopen + node::Start (exec is blocked on device)
zxdong262 Aug 28, 2026
569b6c1
exec diagnosis: bundle installs node 0644 (no +x) → EACCES; loader pa…
zxdong262 Aug 28, 2026
0c0f24b
SIGSYS shim: turn seccomp-trapped syscalls into logged ENOSYS
zxdong262 Aug 28, 2026
9fb25d7
hardened stdio for embedded node + crash signal markers
zxdong262 Aug 28, 2026
f594260
log seccomp-trapped syscall names in the SIGSYS shim
zxdong262 Aug 28, 2026
cd36857
feat: run node in-process in the main app (napi), child fallback
zxdong262 Aug 28, 2026
cff07ef
fix: survive node crashes in-process — park the node thread, log to h…
zxdong262 Aug 28, 2026
7d54eca
diag: periodic boot-log tail dumps to hilog + 14-line failure overlay
zxdong262 Aug 28, 2026
f143bfa
diag: capture node's stderr in embed mode — dup2 boot log onto fd 1/2
zxdong262 Aug 28, 2026
4a5a8d4
diag: stream stdio to hilog line-by-line; chunk tail dumps under hilo…
zxdong262 Aug 28, 2026
8fcdda5
fix: forward-declare logWrite (broke compile in 4a5a8d4)
zxdong262 Aug 28, 2026
b3ba359
embed: capture native backtrace at crash + guarantee std fds 0-2 open
zxdong262 Aug 28, 2026
521ce7a
shim: SIGSYS fallback must return exactly -1, not -ENOSYS — root caus…
zxdong262 Aug 28, 2026
8d0b3c4
fix signal-handler reentrancy crash + make the boot log readable
zxdong262 Aug 28, 2026
eb78639
Fix
zxdong262 Aug 29, 2026
ece5489
[skip ci]
zxdong262 Aug 29, 2026
398d27f
Use self build arm64 nodejs for harmony
zxdong262 Aug 30, 2026
2fd1c5a
Fix app hanging on the splash screen at startup
zxdong262 Aug 30, 2026
138b522
CI: pin NODE_VERSION to 24.2.0 (the 24.19.0 asset 404s)
zxdong262 Aug 30, 2026
d48cd1c
Make the boot overlay self-diagnosing; drop the setTimeout indirection
zxdong262 Aug 30, 2026
4d14174
Locate the node::Start SIGSEGV instead of guessing at it
zxdong262 Aug 30, 2026
499ac22
Fix the SIGSYS handler: it was killing the very thread it protects
zxdong262 Aug 30, 2026
d9fd1b5
CI: stop building the full HarmonyOS APP on dev2
zxdong262 Aug 31, 2026
059d5bc
Fix CI
zxdong262 Aug 31, 2026
3af592b
Fix
zxdong262 Aug 31, 2026
20ab978
Fix 1
zxdong262 Aug 31, 2026
7a75abc
Remove dead code
zxdong262 Aug 31, 2026
9d080dd
Update readme
zxdong262 Aug 31, 2026
340e123
USe xternal src
zxdong262 Aug 31, 2026
7cdbcc0
fix3
zxdong262 Aug 31, 2026
4d15c8d
Fix 4
zxdong262 Aug 31, 2026
8e62302
Fix db wrapper
zxdong262 Aug 31, 2026
f06860a
fix 5
zxdong262 Aug 31, 2026
95fb50a
Fix db path
zxdong262 Aug 31, 2026
34d47a7
Fix language select
zxdong262 Aug 31, 2026
1032ba4
Fix db path
zxdong262 Aug 31, 2026
9333924
FIx db path
zxdong262 Aug 31, 2026
4856db1
FIx d
zxdong262 Aug 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
288 changes: 288 additions & 0 deletions .github/workflows/build-web.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
name: Build HarmonyOS Web APP (ArkWeb + on-device Node.js)

# Web variant of the app — no electron-harmony runtime:
# ArkWeb (Web component) + our shared libnode.so running the electerm-web
# backend as a native child process (childProcessManager.startNativeChildProcess).
#
# Triggers on dev2 pushes. Uploads the signed .app as an artifact.

on:
push:
branches:
- dev2
- build
workflow_dispatch:

# Cancel previous runs on the same branch
concurrency:
group: build-web-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

env:
# Our own shared libnode.so release used as the on-device Node.js runtime.
# MUST stay in sync with the default in scripts/prepare-node.sh: the script
# derives the release tag as "ohos-node-shared-v${NODE_VERSION}", so a
# mismatch turns into a 404 on the asset download.
# 24.19.0 was the last hqzing/ohos-node release; 24.2.0 is the first
# self-built --shared libnode (a real shared library, not a PIE).
NODE_VERSION: '24.2.0'

jobs:
build:
# HarmonyOS Command Line Tools are x64-only.
runs-on: ubuntu-latest
timeout-minutes: 60

steps:
# ── Checkout ──────────────────────────────────────────────────────────
- name: Checkout electerm-harmony
uses: actions/checkout@v4

# ── Setup Node.js (for building the web app) ─────────────────────────
- name: Setup Node.js 24
uses: actions/setup-node@v4
with:
node-version: '24'
cache: npm

# ── Install system deps ───────────────────────────────────────────────
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
unzip \
jq \
xz-utils \
python3 \
make \
g++

# ── Setup JDK (for hap-sign-tool.jar) ────────────────────────────────
- name: Setup JDK 21
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '21'

# ── Step 1: Cache / download HarmonyOS Command Line Tools (~2 GB) ────
- name: Compute Command Line Tools cache key
id: cmdkey
env:
OHOS_CMDLINE_TOOLS_URL: ${{ secrets.OHOS_CMDLINE_TOOLS_URL }}
run: |
if [ -z "${OHOS_CMDLINE_TOOLS_URL}" ]; then
echo "::error::OHOS_CMDLINE_TOOLS_URL secret is not set."
exit 1
fi
HASH="$(echo -n "${OHOS_CMDLINE_TOOLS_URL}" | md5sum | cut -d' ' -f1)"
echo "key=cmdline-tools-${HASH}" >> "$GITHUB_OUTPUT"

- name: Restore HarmonyOS Command Line Tools cache
id: cmdline_cache
uses: actions/cache/restore@v4
with:
path: .cache/commandline-tools
key: ${{ steps.cmdkey.outputs.key }}

- name: Download & extract HarmonyOS Command Line Tools
if: steps.cmdline_cache.outputs.cache-hit != 'true'
env:
OHOS_CMDLINE_TOOLS_URL: ${{ secrets.OHOS_CMDLINE_TOOLS_URL }}
run: |
set -euo pipefail
mkdir -p .cache
ZIP=".cache/commandline-tools.zip"
echo "Cache miss — downloading HarmonyOS Command Line Tools (~2 GB) ..."
curl -L --retry 10 --retry-all-errors --retry-delay 5 -C - \
-A "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36" \
-o "$ZIP" "${OHOS_CMDLINE_TOOLS_URL}"
echo "Verifying archive integrity ..."
if ! unzip -t "$ZIP" >/dev/null 2>&1; then
echo "::error::Downloaded archive is corrupt; retrying once without resume."
curl -L --retry 10 --retry-all-errors --retry-delay 5 \
-A "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36" \
-o "$ZIP" "${OHOS_CMDLINE_TOOLS_URL}"
unzip -t "$ZIP" >/dev/null 2>&1 || { echo "::error::Still corrupt after retry"; exit 1; }
fi
rm -rf .cache/commandline-tools
mkdir -p .cache/commandline-tools
unzip -o -q "$ZIP" -d .cache/commandline-tools
rm -f "$ZIP"
echo "Downloaded and extracted HarmonyOS Command Line Tools"

- name: Save HarmonyOS Command Line Tools cache
if: steps.cmdline_cache.outputs.cache-hit != 'true' && always()
uses: actions/cache/save@v4
with:
path: .cache/commandline-tools
key: ${{ steps.cmdkey.outputs.key }}

- name: Configure Command Line Tools environment
run: |
set -euo pipefail
COMMANDLINE_TOOLS="$(pwd)/.cache/commandline-tools/command-line-tools"
if [ ! -d "$COMMANDLINE_TOOLS" ]; then
COMMANDLINE_TOOLS="$(cd "$(dirname "$(find .cache/commandline-tools -name ohpm -type f | head -1)")/.." && pwd)"
fi
# Fix: Project root package.json has "type": "module", which makes
# Node.js treat hvigorw.js as an ES module (breaks with "require is
# not defined"). Adding a CommonJS package.json to the tools dirs
# prevents Node from traversing up to the project root.
echo '{"type":"commonjs"}' > "$COMMANDLINE_TOOLS/hvigor/package.json" 2>/dev/null || true
echo '{"type":"commonjs"}' > "$COMMANDLINE_TOOLS/package.json"
echo "COMMANDLINE_TOOLS=$COMMANDLINE_TOOLS" >> "$GITHUB_ENV"
echo "OHOS_SDK_HOME=$COMMANDLINE_TOOLS/sdk" >> "$GITHUB_ENV"
echo "DEVECO_NODE_HOME=$COMMANDLINE_TOOLS/tool/node" >> "$GITHUB_ENV"
echo "DEVECO_SDK_HOME=$COMMANDLINE_TOOLS/sdk" >> "$GITHUB_ENV"
echo "$COMMANDLINE_TOOLS/bin" >> "$GITHUB_PATH"
echo "$COMMANDLINE_TOOLS/hvigor/bin" >> "$GITHUB_PATH"
echo "HarmonyOS Command Line Tools ready at $COMMANDLINE_TOOLS"

- name: Configure ohpm registry
run: |
ohpm config set registry https://ohpm.openharmony.cn/ohpm/ || true
ohpm --version || true

- name: Restore ohpm modules cache
id: ohpm_cache
uses: actions/cache/restore@v4
with:
path: |
oh_modules
entry/oh_modules
~/.ohpm
key: ohpm-web-${{ hashFiles('**/oh-package.json5', '**/oh-package.json') }}
restore-keys: |
ohpm-web-

# ── Step 2: Prepare the OpenHarmony Node.js runtime ───────────────────
# shared libnode.so release → entry/libs/arm64-v8a/libnode.so
- name: Restore Node runtime cache
id: node_cache
uses: actions/cache/restore@v4
with:
path: .cache/node-runtime
key: ohos-node-${{ env.NODE_VERSION }}

- name: Prepare Node.js runtime (shared libnode.so)
run: ./scripts/prepare-node.sh

- name: Save Node runtime cache
if: steps.node_cache.outputs.cache-hit != 'true' && always()
uses: actions/cache/save@v4
with:
path: .cache/node-runtime
key: ohos-node-${{ env.NODE_VERSION }}

- name: Inject safe-storage secret
env:
STORAGE_SECRET: ${{ secrets.OHOS_SERVER_SECRET }}
run: node scripts/inject-safe-storage-secret.mjs

# ── Step 3: Build web app (frontend + backend bundle → resfile) ──────
- name: Prepare web app
run: ./scripts/prepare-web.sh
env:
SERVER_SECRET: ${{ secrets.OHOS_SERVER_SECRET }}

# ── Step 4: Decode signing materials ────────────────────────────────
- name: Decode signing materials
env:
OHOS_KEYSTORE_B64: ${{ secrets.OHOS_KEYSTORE_B64 }}
OHOS_CERT_B64: ${{ secrets.OHOS_CERT_B64 }}
OHOS_PROFILE_B64: ${{ secrets.OHOS_PROFILE_B64 }}
run: |
mkdir -p signing
if [ -z "${OHOS_KEYSTORE_B64}" ] || [ -z "${OHOS_CERT_B64}" ] || [ -z "${OHOS_PROFILE_B64}" ]; then
echo "One or more signing material secrets are not set"
exit 1
fi
echo "${OHOS_KEYSTORE_B64}" | base64 -d > signing/electerm.p12
echo "${OHOS_CERT_B64}" | base64 -d > signing/electerm_publish.cer
echo "${OHOS_PROFILE_B64}" | base64 -d > signing/electermRelease.p7b

for f in signing/electerm.p12 signing/electerm_publish.cer signing/electermRelease.p7b; do
if [ ! -s "${f}" ]; then
echo "::error::Failed to decode ${f} — check GitHub Secrets."
exit 1
fi
echo " ✓ $(basename ${f}): $(du -h ${f} | cut -f1)"
done

# ── Step 5: Set bundle name from secret ──────────────────────────────
- name: Configure bundle name
env:
BUNDLE_NAME: ${{ secrets.OHOS_BUNDLE_NAME }}
run: |
if [ -n "${BUNDLE_NAME}" ]; then
sed -i "s/\"bundleName\": \".*\"/\"bundleName\": \"${BUNDLE_NAME}\"/" \
AppScope/app.json5
echo "Bundle name set to: ${BUNDLE_NAME}"
else
echo "Using default bundle name from app.json5"
fi
cat AppScope/app.json5

# ── Step 6: Build & sign the APP ─────────────────────────────────────
- name: Build HarmonyOS web app
run: ./scripts/build-web-app.sh --release
env:
COMMANDLINE_TOOLS: ${{ env.COMMANDLINE_TOOLS }}
OHOS_SDK_HOME: ${{ env.OHOS_SDK_HOME }}
KEYSTORE_PASSWORD: ${{ secrets.OHOS_KEYSTORE_PASSWORD }}
KEY_PASSWORD: ${{ secrets.OHOS_KEY_PASSWORD }}
KEY_ALIAS: ${{ secrets.OHOS_KEY_ALIAS }}

- name: Save ohpm modules cache
if: steps.ohpm_cache.outputs.cache-hit != 'true' && always()
uses: actions/cache/save@v4
with:
path: |
oh_modules
entry/oh_modules
~/.ohpm
key: ohpm-web-${{ hashFiles('**/oh-package.json5', '**/oh-package.json') }}

# ── Step 7: Upload artifact ──────────────────────────────────────────
- name: Find APP file
id: find_app
run: |
APP_FILE=$(find build/outputs -name "*.app" -type f | head -1)
if [ -z "${APP_FILE}" ]; then
echo "::error::No .app file found!"
exit 1
fi
APP_NAME=$(basename "${APP_FILE}")
echo "app_path=${APP_FILE}" >> $GITHUB_OUTPUT
echo "app_name=${APP_NAME}" >> $GITHUB_OUTPUT
echo "artifact_name=${APP_NAME}" >> $GITHUB_OUTPUT
echo "Found APP: ${APP_FILE} ($(du -h ${APP_FILE} | cut -f1))"

- name: Upload APP artifact
uses: actions/upload-artifact@v4
with:
name: ${{ steps.find_app.outputs.artifact_name }}
path: ${{ steps.find_app.outputs.app_path }}
retention-days: 30

# ── Summary ──────────────────────────────────────────────────────────
- name: Build summary
if: always()
run: |
echo "## Build Summary (web)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Item | Value |" >> $GITHUB_STEP_SUMMARY
echo "|------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Branch | \`${{ github.ref_name }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Commit | \`${{ github.sha }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Runtime | \`shared libnode.so v${{ env.NODE_VERSION }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Web app | \`electerm-web backend + ArkWeb frontend\` |" >> $GITHUB_STEP_SUMMARY
echo "| App version | \`$(python3 -c "import json; print(json.load(open('package.json'))['version'])" 2>/dev/null || echo unknown)\` |" >> $GITHUB_STEP_SUMMARY
if [ -f "${{ steps.find_app.outputs.app_path }}" ]; then
echo "| APP file | \`${{ steps.find_app.outputs.app_name }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| APP size | \`$(du -h ${{ steps.find_app.outputs.app_path }} | cut -f1)\` |" >> $GITHUB_STEP_SUMMARY
fi
Loading
Loading