From 1b73e929f0b75f454a1cb09500fe853cecc7ce4e Mon Sep 17 00:00:00 2001 From: cucadmuh <49571317+cucadmuh@users.noreply.github.com> Date: Wed, 15 Jul 2026 11:15:05 +0300 Subject: [PATCH] fix(api): psysonic/undefined client id on Windows release builds (#1290) --- CHANGELOG.md | 6 ++++++ scripts/check-boot-chunk-lucide.mjs | 11 +++++++++++ scripts/generate-release-notes-bundle.mjs | 12 ++++++++++++ src/config/settingsCredits.ts | 1 + src/lib/api/subsonicClient.ts | 4 ++-- 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33bb0def..9ee6119a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -345,6 +345,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Windows `.msi` builds no longer fail on channel versions like `1.50.0-dev` — WiX requires a numeric fourth version field, so the bundler maps `-dev` / `-rc.N` to numeric semver in `bundle.windows.wix.version` while Settings → About still shows the real package version. * Release builds no longer warn that the album feature barrel defeats a lazy import in the new-albums easter egg (direct import of the export helper). +### Windows — Subsonic client id no longer `psysonic/undefined` + +**By [@cucadmuh](https://github.com/cucadmuh), PR [#1290](https://github.com/Psychotoxical/psysonic/pull/1290)** + +* Windows release builds could send `psysonic/undefined` as the Subsonic client id (visible in **Who is listening?**) when `package.json` version was read during a circular authStore boot-chunk init — prebuild now emits a leaf `SUBSONIC_CLIENT_ID` literal and the boot-chunk guard rejects unresolved client-id templates. + ### Internet Radio — equalizer presets now apply to radio playback **By [@cucadmuh](https://github.com/cucadmuh), PR [#1284](https://github.com/Psychotoxical/psysonic/pull/1284)** diff --git a/scripts/check-boot-chunk-lucide.mjs b/scripts/check-boot-chunk-lucide.mjs index f9da5109..c5f41393 100644 --- a/scripts/check-boot-chunk-lucide.mjs +++ b/scripts/check-boot-chunk-lucide.mjs @@ -27,6 +27,12 @@ const LUCIDE_SIGNALS = [ '("download"', ]; +/** Subsonic client id must be a compile-time literal, not a cyclic package.json import. */ +const CLIENT_ID_SIGNALS = [ + 'psysonic/undefined', + 'psysonic/${', +]; + let files; try { files = readdirSync(DIST).filter(f => f.endsWith('.js')); @@ -45,6 +51,11 @@ for (const file of files) { violations.push({ file, signal }); } } + for (const signal of CLIENT_ID_SIGNALS) { + if (text.includes(signal)) { + violations.push({ file, signal: `client-id: ${signal}` }); + } + } } if (violations.length > 0) { diff --git a/scripts/generate-release-notes-bundle.mjs b/scripts/generate-release-notes-bundle.mjs index 3819ad0b..6779ec89 100644 --- a/scripts/generate-release-notes-bundle.mjs +++ b/scripts/generate-release-notes-bundle.mjs @@ -43,3 +43,15 @@ export const CHANGELOG_RAW: string = ${JSON.stringify(changelogRaw)}; writeFileSync(join(outDir, 'releaseNotesBundle.ts'), ts, 'utf8'); console.log(`wrote src/generated/releaseNotesBundle.ts (sliced for ${version})`); + +// Leaf module for boot-critical client id — must not import package.json at runtime +// in the authStore chunk (circular init → psysonic/undefined on Windows WebView2). +const appVersionTs = `/** @generated — run: node scripts/generate-release-notes-bundle.mjs */ +export const APP_VERSION = ${JSON.stringify(version)}; + +/** Subsonic REST \`c\` param and OpenSubsonic client id (\`psysonic/\`). */ +export const SUBSONIC_CLIENT_ID = ${JSON.stringify(`psysonic/${version}`)}; +`; + +writeFileSync(join(outDir, 'appVersion.ts'), appVersionTs, 'utf8'); +console.log(`wrote src/generated/appVersion.ts (${version})`); diff --git a/src/config/settingsCredits.ts b/src/config/settingsCredits.ts index 8c1f0101..52e2a430 100644 --- a/src/config/settingsCredits.ts +++ b/src/config/settingsCredits.ts @@ -200,6 +200,7 @@ const CONTRIBUTOR_ENTRIES = [ 'Queue toolbar — Navidrome public share: hide Save Playlist, copy original share URL (PR #1279)', 'Windows startup hang after #1274 — boot barrel split, stable Wasapi device IDs, legacy EQ key match (PR #1277)', 'Windows MSI bundle on dev/RC versions — numeric WiX mapping; album easter-egg import chunk (PR #1278)', + 'Windows release builds — Subsonic client id no longer psysonic/undefined in Who is listening (PR #1290)', 'Track lists — optional album cover thumbnails via standard cover pipeline; queue rows use playback scope (PR #1280)', 'Internet Radio — Web Audio EQ on HTML5 streams; presets apply without reconnect (PR #1284)', 'Player bar — hideable stop button, optional album line, drag-reorderable action buttons (request: mikmik on Psysonic Discord, PR #1287)', diff --git a/src/lib/api/subsonicClient.ts b/src/lib/api/subsonicClient.ts index 35df6d6a..4ced9c29 100644 --- a/src/lib/api/subsonicClient.ts +++ b/src/lib/api/subsonicClient.ts @@ -1,7 +1,7 @@ import axios from 'axios'; import { getLuckyMixLibraryScopeOverride } from '@/lib/library/luckyMixScopeOverride'; import md5 from 'md5'; -import { version } from '@/../package.json'; +import { SUBSONIC_CLIENT_ID } from '@/generated/appVersion'; import { commands } from '@/generated/bindings'; import { useAuthStore } from '@/store/authStore'; import type { ServerProfile } from '@/store/authStoreTypes'; @@ -9,7 +9,7 @@ import { connectBaseUrlForServer } from '@/lib/server/serverEndpoint'; import { headersForServerRequest, serverHttpContextWireForProbe } from '@/lib/server/serverHttpHeaders'; import { findServerByIdOrIndexKey, resolveServerIdForIndexKey } from '@/lib/server/serverLookup'; -export const SUBSONIC_CLIENT = `psysonic/${version}`; +export const SUBSONIC_CLIENT = SUBSONIC_CLIENT_ID; /** Subset of `ServerProfile` needed to attach gate headers on credential-based REST calls. */ export type ServerHttpHeaderProfile = Pick<