diff --git a/js/docs/src/pages/back-to-home.astro b/js/docs/src/pages/back-to-home.astro index af7773f9..c942f18f 100644 --- a/js/docs/src/pages/back-to-home.astro +++ b/js/docs/src/pages/back-to-home.astro @@ -17,6 +17,6 @@ const redirectUrl = hostname.endsWith('.stream.place') window.location.href = redirectUrl; -

Redirecting to Streamplace...

+

Redirecting to Streamplace... 

Click here if you are not redirected automatically -- 2.51.2 From 990f19f5bc157a76b695bc1bb1a35a6213b94f02 Mon Sep 17 00:00:00 2001 From: Eli Mallon Date: Thu, 27 Aug 2026 16:35:25 -0700 Subject: [PATCH 02/10] ci: pin Node 22 via .node-version for Cloudflare Pages docs build Cloudflare Pages resolves engines.node '>=22.0.0' to the newest available Node (now 24.x), where better-sqlite3@10.1.0 has no prebuilds and fails to compile against V8. Pin 22 in-repo; mise honors the same file. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01NaDYk2PGWfSLEXeN5CBJFN --- .node-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .node-version diff --git a/.node-version b/.node-version new file mode 100644 index 00000000..2bd5a0a9 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +22 -- 2.51.2 From 8a62dd942aa4592f43316825a127b07b611ec46e Mon Sep 17 00:00:00 2001 From: Eli Mallon Date: Thu, 27 Aug 2026 16:45:07 -0700 Subject: [PATCH 03/10] docs: no-op change for CI --- js/docs/src/pages/back-to-home.astro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/docs/src/pages/back-to-home.astro b/js/docs/src/pages/back-to-home.astro index c942f18f..af7773f9 100644 --- a/js/docs/src/pages/back-to-home.astro +++ b/js/docs/src/pages/back-to-home.astro @@ -17,6 +17,6 @@ const redirectUrl = hostname.endsWith('.stream.place') window.location.href = redirectUrl; -

Redirecting to Streamplace... 

+

Redirecting to Streamplace...

Click here if you are not redirected automatically -- 2.51.2 From f718c6029ccb107597f9c400b429a441670d4e40 Mon Sep 17 00:00:00 2001 From: Eli Mallon Date: Thu, 27 Aug 2026 16:57:59 -0700 Subject: [PATCH 04/10] build: pin meson to 1.11.2 Meson 1.12.0 (released since the last builder-image rebuild) fails to configure the glib 2.86.3 subproject ('Summary section already have key', then libpcre2-8 fallback not found), breaking all binary builds. Last green build on next used 1.11.2. Pin it in the builder image and mise.toml until glib/gstreamer catch up. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01NaDYk2PGWfSLEXeN5CBJFN --- .ci/dockerfile-hash.yaml | 2 +- docker/build.Dockerfile | 2 +- mise.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.ci/dockerfile-hash.yaml b/.ci/dockerfile-hash.yaml index a923c418..5e27d0dc 100644 --- a/.ci/dockerfile-hash.yaml +++ b/.ci/dockerfile-hash.yaml @@ -1,2 +1,2 @@ variables: - DOCKERFILE_HASH: a06ea168babbacb457bea7e6762aea47493f5097 \ No newline at end of file + DOCKERFILE_HASH: 28cc8e519521a047f1da9084773cbf08b0428ee7 \ No newline at end of file diff --git a/docker/build.Dockerfile b/docker/build.Dockerfile index a06ea168..28cc8e51 100644 --- a/docker/build.Dockerfile +++ b/docker/build.Dockerfile @@ -38,7 +38,7 @@ RUN apt update \ libc6:arm64 libstdc++6:arm64 \ cmake libssl-dev libssl-dev:arm64 \ ruby-rubygems postgresql sudo \ - && pip install meson tomli \ + && pip install meson==1.11.2 tomli \ && curl -L --fail https://go.dev/dl/go$GO_VERSION.linux-$TARGETARCH.tar.gz -o go.tar.gz \ && tar -C /usr/local -xf go.tar.gz \ && rm go.tar.gz diff --git a/mise.toml b/mise.toml index 107d7636..114a690f 100644 --- a/mise.toml +++ b/mise.toml @@ -2,7 +2,7 @@ go = "latest" rust = "latest" node = "22" -meson = "latest" +meson = "1.11.2" ninja = "latest" pnpm = "latest" java = "17" -- 2.51.2 From 85dd86a6b74348702ecd51b601b8b24455032b92 Mon Sep 17 00:00:00 2001 From: Eli Mallon Date: Sat, 29 Aug 2026 12:59:29 -0700 Subject: [PATCH 05/10] ci: fix golangci-lint job hang (stdin redirect + job timeout) Since runner image 20260823, the golangci-lint-action's node-spawned invocation of the podman-exec wrapper hangs with no output on its very first call ('config path'), burning the full 360m job limit, while bash-spawned podman execs in the same job work fine. Redirect stdin from /dev/null in the wrapper so podman exec can't wait on the action's inherited stdin pipe, add a bash-side sanity invocation before the action to localize any future hang, and cap the job at 60m. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01NaDYk2PGWfSLEXeN5CBJFN --- .github/workflows/golangci-lint.yaml | 6 ++++++ hack/golangci-lint | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yaml b/.github/workflows/golangci-lint.yaml index 53d2fbd1..af7de5e6 100644 --- a/.github/workflows/golangci-lint.yaml +++ b/.github/workflows/golangci-lint.yaml @@ -8,6 +8,7 @@ jobs: golangci: name: lint runs-on: ubuntu-latest + timeout-minutes: 60 steps: - name: Maximize build space run: | @@ -33,6 +34,11 @@ jobs: sudo ln -s $(realpath ./hack/golangci-lint) /usr/bin/golangci-lint make golangci-lint-container BUILDER_TARGET=builder-no-darwin DOCKER_BUILD_OPTS="--layers --cache-to ghcr.io/streamplace/streamplace --cache-from ghcr.io/streamplace/streamplace" + - name: sanity-check wrapper from bash + run: + timeout 120 /usr/bin/golangci-lint config path + --config=./.golangci.yaml + - name: golangci-lint uses: golangci/golangci-lint-action@v8 with: diff --git a/hack/golangci-lint b/hack/golangci-lint index 4e243231..c6f7988f 100755 --- a/hack/golangci-lint +++ b/hack/golangci-lint @@ -5,4 +5,7 @@ set -euo pipefail -exec podman exec golangci-lint golangci-lint "$@" +# stdin must not be a live pipe: when golangci-lint-action spawns this wrapper, +# podman exec waits on the inherited stdin and hangs forever (observed on +# runner image 20260823+); bash-spawned invocations were unaffected +exec podman exec golangci-lint golangci-lint "$@" < /dev/null -- 2.51.2 From 78db03702e4effa51977a6e51a7868f8688adaeb Mon Sep 17 00:00:00 2001 From: Eli Mallon Date: Sat, 29 Aug 2026 14:02:37 -0700 Subject: [PATCH 06/10] ci: hang-proof the golangci-lint wrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The action's node-spawned podman exec still hangs even with stdin redirected (the bash sanity step running the identical command one second earlier succeeds). Move podman's stderr to a file — removing the action's pipe from podman's fd table — add a 3-minute timeout so a hang fails fast, and dump podman's --log-level=debug trace on failure to show where it wedges. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01NaDYk2PGWfSLEXeN5CBJFN --- hack/golangci-lint | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/hack/golangci-lint b/hack/golangci-lint index c6f7988f..2adfaf13 100755 --- a/hack/golangci-lint +++ b/hack/golangci-lint @@ -3,9 +3,23 @@ # This script is used to trick the GitHub action for golangci-lint to run inside a container # so that we can use the local build of streamplace -set -euo pipefail +set -uo pipefail -# stdin must not be a live pipe: when golangci-lint-action spawns this wrapper, -# podman exec waits on the inherited stdin and hangs forever (observed on -# runner image 20260823+); bash-spawned invocations were unaffected -exec podman exec golangci-lint golangci-lint "$@" < /dev/null +# The golangci-lint-action's node-spawned invocations of podman exec hang +# forever on runner images >= 20260823 while bash-spawned ones are fine +# (compare the sanity-check step in golangci-lint.yaml). Point podman's +# stderr at a file instead of the action's pipe, guard with a timeout so a +# hang fails in minutes instead of hours, and dump podman's debug trace on +# failure so we can see where it stuck. +DBG="$(mktemp)" +timeout -k 10 180 podman --log-level=debug exec golangci-lint golangci-lint "$@" "$DBG" +code=$? +if [ "$code" -ne 0 ]; then + echo "wrapper: podman exec exited $code; podman debug log follows" >&2 + cat "$DBG" >&2 +else + # forward golangci-lint's own stderr, minus podman's debug chatter + grep -v '^time=' "$DBG" >&2 || true +fi +rm -f "$DBG" +exit $code -- 2.51.2 From b1d449e70ff552c25233537bcf27c09f0fda90af Mon Sep 17 00:00:00 2001 From: Eli Mallon Date: Sat, 29 Aug 2026 14:26:45 -0700 Subject: [PATCH 07/10] ci: keep podman's stdio away from the action's socketpairs golangci-lint-action invokes commands via node child_process.exec; its stdio pipes are libuv socketpairs, and podman exec wedges right after startup when attached to them (bash-spawned runs of the same command in the same job succeed). Buffer podman's stdout/stderr into temp files and replay them, and on a residual hang SIGQUIT podman for a goroutine dump before failing fast. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01NaDYk2PGWfSLEXeN5CBJFN --- hack/golangci-lint | 52 ++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/hack/golangci-lint b/hack/golangci-lint index 2adfaf13..f626d157 100755 --- a/hack/golangci-lint +++ b/hack/golangci-lint @@ -1,25 +1,41 @@ #!/bin/bash -# This script is used to trick the GitHub action for golangci-lint to run inside a container -# so that we can use the local build of streamplace +# This script is used to trick the GitHub action for golangci-lint to run +# inside a container so that we can use the local build of streamplace. +# +# The golangci-lint-action spawns this via node's child_process.exec, whose +# stdio "pipes" are actually libuv socketpairs; podman exec wedges right +# after startup when attached to them on runner images >= 20260823, while +# bash-spawned runs of the identical command are fine. Keep podman's stdio +# pointed at real files and replay them when it finishes. If podman still +# hangs, SIGQUIT it for a Go goroutine dump and fail fast instead of eating +# the job's timeout. set -uo pipefail -# The golangci-lint-action's node-spawned invocations of podman exec hang -# forever on runner images >= 20260823 while bash-spawned ones are fine -# (compare the sanity-check step in golangci-lint.yaml). Point podman's -# stderr at a file instead of the action's pipe, guard with a timeout so a -# hang fails in minutes instead of hours, and dump podman's debug trace on -# failure so we can see where it stuck. -DBG="$(mktemp)" -timeout -k 10 180 podman --log-level=debug exec golangci-lint golangci-lint "$@" "$DBG" -code=$? -if [ "$code" -ne 0 ]; then - echo "wrapper: podman exec exited $code; podman debug log follows" >&2 - cat "$DBG" >&2 -else - # forward golangci-lint's own stderr, minus podman's debug chatter - grep -v '^time=' "$DBG" >&2 || true +OUT="$(mktemp)" +ERR="$(mktemp)" +trap 'rm -f "$OUT" "$ERR"' EXIT + +podman exec golangci-lint golangci-lint "$@" "$OUT" 2>"$ERR" & +pid=$! + +seconds=0 +while kill -0 "$pid" 2>/dev/null && [ "$seconds" -lt 900 ]; do + sleep 1 + seconds=$((seconds + 1)) +done + +if kill -0 "$pid" 2>/dev/null; then + echo "wrapper: podman exec still running after ${seconds}s; sending SIGQUIT for goroutine dump" >&2 + kill -QUIT "$pid" 2>/dev/null || true + sleep 5 + kill -KILL "$pid" 2>/dev/null || true fi -rm -f "$DBG" + +wait "$pid" +code=$? + +cat "$OUT" +cat "$ERR" >&2 exit $code -- 2.51.2 From 6c1abb12e6341adc97c460a3d9395960daa926d8 Mon Sep 17 00:00:00 2001 From: Eli Mallon Date: Sat, 29 Aug 2026 15:16:50 -0700 Subject: [PATCH 08/10] ci: identify the libpod lock holder when podman exec hangs Goroutine dump from the previous run shows the action-spawned podman exec stuck 15 minutes in sem_wait on the rootless SHM container lock inside ExecCreate. On hang, enumerate podman-family processes, list who has the libpod lock segment mapped, and dump kernel stacks to find the holder; fail after 5 minutes. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01NaDYk2PGWfSLEXeN5CBJFN --- hack/golangci-lint | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/hack/golangci-lint b/hack/golangci-lint index f626d157..f2fad0e9 100755 --- a/hack/golangci-lint +++ b/hack/golangci-lint @@ -3,13 +3,11 @@ # This script is used to trick the GitHub action for golangci-lint to run # inside a container so that we can use the local build of streamplace. # -# The golangci-lint-action spawns this via node's child_process.exec, whose -# stdio "pipes" are actually libuv socketpairs; podman exec wedges right -# after startup when attached to them on runner images >= 20260823, while -# bash-spawned runs of the identical command are fine. Keep podman's stdio -# pointed at real files and replay them when it finishes. If podman still -# hangs, SIGQUIT it for a Go goroutine dump and fail fast instead of eating -# the job's timeout. +# On runner images >= 20260823, the action-spawned podman exec wedges in +# sem_wait on the rootless SHM container lock (libpod LockSemaphore inside +# ExecCreate) — some other process takes the lock and never releases it. +# Buffer stdio through files, and on a hang dump diagnostics identifying +# the lock holder, then fail fast instead of eating the job timeout. set -uo pipefail @@ -21,13 +19,27 @@ podman exec golangci-lint golangci-lint "$@" "$OUT" 2>"$ERR" & pid=$! seconds=0 -while kill -0 "$pid" 2>/dev/null && [ "$seconds" -lt 900 ]; do +while kill -0 "$pid" 2>/dev/null && [ "$seconds" -lt 300 ]; do sleep 1 seconds=$((seconds + 1)) done if kill -0 "$pid" 2>/dev/null; then - echo "wrapper: podman exec still running after ${seconds}s; sending SIGQUIT for goroutine dump" >&2 + { + echo "wrapper: podman exec still running after ${seconds}s; diagnostics:" + echo "--- podman-family processes:" + pgrep -af 'podman|conmon|pasta|catatonit' || true + echo "--- processes with the libpod lock segment mapped:" + for p in $(sudo grep -l libpod /proc/[0-9]*/maps 2>/dev/null | cut -d/ -f3); do + echo "pid $p: $(tr '\0' ' ' <"/proc/$p/cmdline" 2>/dev/null)" + done + echo "--- kernel stacks:" + for p in $(pgrep 'podman|conmon'); do + echo "pid $p: $(tr '\0' ' ' <"/proc/$p/cmdline" 2>/dev/null)" + sudo cat "/proc/$p/stack" 2>/dev/null || true + done + echo "--- goroutine dump of the stuck client ($pid):" + } >&2 kill -QUIT "$pid" 2>/dev/null || true sleep 5 kill -KILL "$pid" 2>/dev/null || true -- 2.51.2 From ab0d501f3b5eb8a1df3c4515dd75471152090ee8 Mon Sep 17 00:00:00 2001 From: Eli Mallon Date: Sat, 29 Aug 2026 15:44:37 -0700 Subject: [PATCH 09/10] ci: use file-based libpod locks in the lint job Diagnostics from the hung run show the stuck podman exec is the ONLY process with the libpod lock segment mapped: the SHM container-lock semaphore was leaked by a process that died holding it, and SHM semaphores never auto-release. Switch libpod to lock_type=file (flock releases on holder death) before any podman use. Also raise the wrapper's hang guard back to 900s for cold-cache lint runs. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01NaDYk2PGWfSLEXeN5CBJFN --- .github/workflows/golangci-lint.yaml | 6 ++++++ hack/golangci-lint | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yaml b/.github/workflows/golangci-lint.yaml index af7de5e6..7dfb71fb 100644 --- a/.github/workflows/golangci-lint.yaml +++ b/.github/workflows/golangci-lint.yaml @@ -31,6 +31,12 @@ jobs: - name: run build for linting run: | sudo apt install podman -y + # libpod's default SHM semaphores leak when a lock holder dies + # (observed on runner images >= 20260823: an exec-session cleanup + # process dies holding the container lock and every later podman + # exec blocks forever in sem_wait); file locks auto-release + mkdir -p ~/.config/containers + printf '[engine]\nlock_type = "file"\n' >> ~/.config/containers/containers.conf sudo ln -s $(realpath ./hack/golangci-lint) /usr/bin/golangci-lint make golangci-lint-container BUILDER_TARGET=builder-no-darwin DOCKER_BUILD_OPTS="--layers --cache-to ghcr.io/streamplace/streamplace --cache-from ghcr.io/streamplace/streamplace" diff --git a/hack/golangci-lint b/hack/golangci-lint index f2fad0e9..0884b76f 100755 --- a/hack/golangci-lint +++ b/hack/golangci-lint @@ -19,7 +19,7 @@ podman exec golangci-lint golangci-lint "$@" "$OUT" 2>"$ERR" & pid=$! seconds=0 -while kill -0 "$pid" 2>/dev/null && [ "$seconds" -lt 300 ]; do +while kill -0 "$pid" 2>/dev/null && [ "$seconds" -lt 900 ]; do sleep 1 seconds=$((seconds + 1)) done -- 2.51.2 From 80fbee6853e453f6d47c5140c0ef6c890a108aad Mon Sep 17 00:00:00 2001 From: Eli Mallon Date: Tue, 1 Sep 2026 01:24:31 -0700 Subject: [PATCH 10/10] v0.11.29 --- js/app/package.json | 2 +- js/components/package.json | 2 +- js/docs/package.json | 2 +- lerna.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/js/app/package.json b/js/app/package.json index d6a4c713..d631648c 100644 --- a/js/app/package.json +++ b/js/app/package.json @@ -1,7 +1,7 @@ { "name": "@streamplace/app", "main": "./src/entrypoint.tsx", - "version": "0.11.28", + "version": "0.11.29", "runtimeVersion": "0.10.0", "scripts": { "start": "npx expo start -c --port 38081", diff --git a/js/components/package.json b/js/components/package.json index b2c19f3f..b43f6e1c 100644 --- a/js/components/package.json +++ b/js/components/package.json @@ -1,6 +1,6 @@ { "name": "@streamplace/components", - "version": "0.11.28", + "version": "0.11.29", "description": "Streamplace React (Native) Components", "main": "dist/index.js", "types": "src/index.tsx", diff --git a/js/docs/package.json b/js/docs/package.json index 6620713d..5d931403 100644 --- a/js/docs/package.json +++ b/js/docs/package.json @@ -1,7 +1,7 @@ { "name": "streamplace-docs", "type": "module", - "version": "0.11.28", + "version": "0.11.29", "scripts": { "dev": "astro dev --host 0.0.0.0 --port 38082", "start": "astro dev --host 0.0.0.0 --port 38082", diff --git a/lerna.json b/lerna.json index 33c62192..8f3ce688 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "0.11.28", + "version": "0.11.29", "npmClient": "pnpm" }