WarpEngine Client: the whole catalog, and a build that can point elsewhere
**The app is called WarpEngine Client.** "Store" named the thing it opens rather than the
thing you run, and the store is a catalog on a site, not a window on your machine. The
window title, the bundle, the packages and the menu entry follow; the repository already
did. The store being driven is named in the side menu, so the bar stopped repeating it as
a badge — the element stays in the page, hidden, because the window check reads it.
**Every title is listed, including the ones this machine cannot install.** They arrive
from the engine with `installable: false` and a reason, and they are drawn dimmed, with an
*unsupported platform* or *no build for this machine* badge, the engine's own sentence
underneath, and nothing to press: a disabled Install would invite a click that can never
work. They get a category of their own — *Not for this machine* — and they are kept out of
the native/hosted categories and counts, because a title with no build has no mode to be
counted under. An engine older than desktop 1.2.0 is unaffected: a missing `installable`
field reads as installable, which is what those engines mean.
**A build can be pointed at another site's registry:**
make dist STORES_API=https://games.example.org/api/stores
BuildConfiguration reads the packaged package.json, where electron-builder's
extraMetadata writes that address, so a client for somebody else's catalog needs no source
change and nothing set on the user's machine. Precedence is runtime environment, then
build, then ours — three audiences, most specific first.
Also: the scrollbars are the window's own, because the platform's light track down the
side menu of a dark window looked like a mistake.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { asRecord, readRecord, readString } from '../json/JsonRecord'
|
||||
|
||||
/**
|
||||
* What was decided when this package was built.
|
||||
*
|
||||
* The registry address is the one thing about a particular site left in the client, and
|
||||
* a build for a different site should not need a different source tree. So it is a field
|
||||
* in `package.json`, which `electron-builder` can overwrite at packaging time:
|
||||
*
|
||||
* make dist STORES_API=https://staging.example.org/api/stores
|
||||
*
|
||||
* Read from the package.json that ships inside the app, so a packaged build answers with
|
||||
* what it was built with. A runtime `STORES_API` still wins over it — that is for trying
|
||||
* something out, this is for shipping it.
|
||||
*/
|
||||
export class BuildConfiguration {
|
||||
private cached: Readonly<Record<string, unknown>> | null = null
|
||||
|
||||
public readRegistryUrl (): string | null {
|
||||
const section = readRecord(this.read(), 'warpEngine')
|
||||
if (section === null) return null
|
||||
const url = readString(section, 'registryUrl').trim()
|
||||
return url.length > 0 ? url : null
|
||||
}
|
||||
|
||||
private read (): Readonly<Record<string, unknown>> {
|
||||
if (this.cached !== null) return this.cached
|
||||
// build/infrastructure/config → the package root, packaged or not.
|
||||
const candidates = [
|
||||
path.join(__dirname, '..', '..', '..', 'package.json'),
|
||||
path.join(__dirname, '..', '..', 'package.json')
|
||||
]
|
||||
for (const candidate of candidates) {
|
||||
try {
|
||||
const parsed = asRecord(JSON.parse(fs.readFileSync(candidate, 'utf8')))
|
||||
if (parsed !== null) {
|
||||
this.cached = parsed
|
||||
return parsed
|
||||
}
|
||||
} catch {
|
||||
// Try the next one; a missing package.json is only fatal if none is found.
|
||||
}
|
||||
}
|
||||
this.cached = {}
|
||||
return this.cached
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user