Built from source via a git submodule pinned to a tag, not a published image — the Dockerfile, main.ts, and manifest should never need to change for an ordinary version bump, only the submodule pin (see UPDATING.md). One volume, one interface serving the browser client + lobby/intent API + SSE stream from a single origin, no dependencies. The server-wide join secret (D14) is seeded on install, exposed via the Get Join Secret action, and blocks start behind a critical task until retrieved — the same first-set/rotation pattern as actual-budget-startos's admin password. Verified on phoenix.local: installs, the critical task correctly blocks an ordinary start, force-starting confirms the daemon binds its port and serves the client, and store.json correctly holds the install-seeded join secret. Not verified: the Get Join Secret action's execution end-to-end — start-cli's `package action run` fails with a client-side deserialization error that reproduces identically against actual-budget's already-shipped equivalent action, so this looks like a start-cli issue rather than a defect here. icon.svg is still the scaffold's hello-world placeholder — no real Station Master icon exists yet to ship in its place.
27 lines
1.1 KiB
TypeScript
27 lines
1.1 KiB
TypeScript
import { utils } from '@start9labs/start-sdk'
|
|
import { getJoinSecret } from '../actions/getJoinSecret'
|
|
import { i18n } from '../i18n'
|
|
import { sdk } from '../sdk'
|
|
import { storeJson } from '../fileModels/store.json'
|
|
|
|
/**
|
|
* The server exits immediately if `JOIN_SECRET` is unset (`src/server/index.ts` in the game
|
|
* repo), so a value has to exist before main.ts's daemon ever starts — seeded here rather than
|
|
* left for the user to generate via the action first.
|
|
*/
|
|
export const seedJoinSecret = sdk.setupOnInit(async (effects, kind) => {
|
|
if (kind === 'install') {
|
|
await storeJson.merge(effects, {
|
|
joinSecret: utils.getDefaultString({ charset: 'a-z,A-Z,0-9', len: 24 }),
|
|
})
|
|
await sdk.action.createOwnTask(effects, getJoinSecret, 'critical', {
|
|
reason: i18n('Get the join secret to share with players'),
|
|
})
|
|
} else {
|
|
// 'update' and 'restore' — repairs a corrupted store.json without touching an existing
|
|
// joinSecret. A restored volume already carries one (it lives inside the backed-up volume,
|
|
// see backups.ts), so there is nothing to seed.
|
|
await storeJson.merge(effects, {})
|
|
}
|
|
})
|