Fix auth landing flow and up.sh service fallback

This commit is contained in:
Jage9
2026-02-24 22:21:38 -05:00
parent d7be6d999a
commit b424a0ae34
7 changed files with 11 additions and 54 deletions

View File

@@ -37,10 +37,6 @@
</div> </div>
<button id="showLoginButton" type="button">Back to login</button> <button id="showLoginButton" type="button">Back to login</button>
</section> </section>
<div id="nicknameContainer" class="nickname-row">
<label for="preconnectNickname">Nickname</label>
<input id="preconnectNickname" type="text" maxlength="32" autocomplete="nickname" />
</div>
<div class="controls" id="button-container"> <div class="controls" id="button-container">
<button id="connectButton">Connect</button> <button id="connectButton">Connect</button>
<button id="logoutButton">Log out</button> <button id="logoutButton">Log out</button>

View File

@@ -1,5 +1,5 @@
// Maintainer-controlled web client version. // Maintainer-controlled web client version.
// Format: YYYY.MM.DD Rn (example: 2026.02.20 R2) // Format: YYYY.MM.DD Rn (example: 2026.02.20 R2)
window.CHGRID_WEB_VERSION = "2026.02.25 R243"; window.CHGRID_WEB_VERSION = "2026.02.25 R244";
// Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid. // Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid.
window.CHGRID_TIME_ZONE = "America/Detroit"; window.CHGRID_TIME_ZONE = "America/Detroit";

View File

@@ -56,7 +56,7 @@ import {
import { createItemPropertyEditor } from './items/itemPropertyEditor'; import { createItemPropertyEditor } from './items/itemPropertyEditor';
import { createItemPropertyPresentation } from './items/itemPropertyPresentation'; import { createItemPropertyPresentation } from './items/itemPropertyPresentation';
import { ItemBehaviorRegistry } from './items/types/behaviorRegistry'; import { ItemBehaviorRegistry } from './items/types/behaviorRegistry';
import { NICKNAME_STORAGE_KEY, SettingsStore } from './settings/settingsStore'; import { SettingsStore } from './settings/settingsStore';
import { runConnectFlow, runDisconnectFlow, type ConnectFlowDeps } from './session/connectionFlow'; import { runConnectFlow, runDisconnectFlow, type ConnectFlowDeps } from './session/connectionFlow';
import { MediaSession } from './session/mediaSession'; import { MediaSession } from './session/mediaSession';
import { type AudioLayerState } from './types/audio'; import { type AudioLayerState } from './types/audio';
@@ -102,8 +102,6 @@ type Dom = {
updatesSection: HTMLElement; updatesSection: HTMLElement;
updatesToggle: HTMLButtonElement; updatesToggle: HTMLButtonElement;
updatesPanel: HTMLDivElement; updatesPanel: HTMLDivElement;
nicknameContainer: HTMLDivElement;
preconnectNickname: HTMLInputElement;
connectButton: HTMLButtonElement; connectButton: HTMLButtonElement;
logoutButton: HTMLButtonElement; logoutButton: HTMLButtonElement;
disconnectButton: HTMLButtonElement; disconnectButton: HTMLButtonElement;
@@ -135,8 +133,6 @@ const dom: Dom = {
updatesSection: requiredById('updatesSection'), updatesSection: requiredById('updatesSection'),
updatesToggle: requiredById('updatesToggle'), updatesToggle: requiredById('updatesToggle'),
updatesPanel: requiredById('updatesPanel'), updatesPanel: requiredById('updatesPanel'),
nicknameContainer: requiredById('nicknameContainer'),
preconnectNickname: requiredById('preconnectNickname'),
connectButton: requiredById('connectButton'), connectButton: requiredById('connectButton'),
logoutButton: requiredById('logoutButton'), logoutButton: requiredById('logoutButton'),
disconnectButton: requiredById('disconnectButton'), disconnectButton: requiredById('disconnectButton'),
@@ -519,6 +515,7 @@ function sanitizeAuthUsername(value: string): string {
function updateConnectAvailability(): void { function updateConnectAvailability(): void {
dom.logoutButton.disabled = !authSessionToken.trim() && !state.running; dom.logoutButton.disabled = !authSessionToken.trim() && !state.running;
if (state.running) { if (state.running) {
dom.connectButton.textContent = 'Connect';
dom.connectButton.disabled = true; dom.connectButton.disabled = true;
dom.loginView.classList.add('hidden'); dom.loginView.classList.add('hidden');
dom.registerView.classList.add('hidden'); dom.registerView.classList.add('hidden');
@@ -532,6 +529,7 @@ function updateConnectAvailability(): void {
const hasRegisterCredentials = const hasRegisterCredentials =
sanitizeAuthUsername(dom.registerUsername.value).length >= 2 && dom.registerPassword.value.trim().length >= 8; sanitizeAuthUsername(dom.registerUsername.value).length >= 2 && dom.registerPassword.value.trim().length >= 8;
const authReady = hasSessionToken || (authMode === 'login' ? hasLoginCredentials : hasRegisterCredentials); const authReady = hasSessionToken || (authMode === 'login' ? hasLoginCredentials : hasRegisterCredentials);
dom.connectButton.textContent = hasSessionToken ? 'Connect' : authMode === 'login' ? 'Log In & Connect' : 'Register & Connect';
dom.connectButton.disabled = mediaSession.isConnecting() || !authReady; dom.connectButton.disabled = mediaSession.isConnecting() || !authReady;
} }
@@ -1419,8 +1417,6 @@ async function handleAuthResult(message: Extract<IncomingMessage, { type: 'auth_
const resolved = sanitizeName(message.nickname); const resolved = sanitizeName(message.nickname);
if (resolved) { if (resolved) {
state.player.nickname = resolved; state.player.nickname = resolved;
dom.preconnectNickname.value = resolved;
settings.saveNickname(resolved);
} }
} }
dom.authPassword.value = ''; dom.authPassword.value = '';
@@ -1561,7 +1557,6 @@ const onAppMessage = createOnMessageHandler({
audioUiBlip: () => audio.sfxUiBlip(), audioUiBlip: () => audio.sfxUiBlip(),
audioUiConfirm: () => audio.sfxUiConfirm(), audioUiConfirm: () => audio.sfxUiConfirm(),
audioUiCancel: () => audio.sfxUiCancel(), audioUiCancel: () => audio.sfxUiCancel(),
NICKNAME_STORAGE_KEY,
getCarriedItemId: () => getCarriedItem()?.id ?? null, getCarriedItemId: () => getCarriedItem()?.id ?? null,
recomputeActiveItemPropertyKeys, recomputeActiveItemPropertyKeys,
itemPropertyLabel, itemPropertyLabel,
@@ -2558,8 +2553,6 @@ function closeSettings(): void {
function setupUiHandlers(): void { function setupUiHandlers(): void {
setupDomUiHandlers({ setupDomUiHandlers({
dom, dom,
sanitizeName,
nicknameStorageKey: NICKNAME_STORAGE_KEY,
updateConnectAvailability, updateConnectAvailability,
connect, connect,
disconnect, disconnect,
@@ -2615,11 +2608,6 @@ setupInputHandlers();
setupUiHandlers(); setupUiHandlers();
dom.authUsername.value = sanitizeAuthUsername(authUsername); dom.authUsername.value = sanitizeAuthUsername(authUsername);
dom.registerUsername.value = sanitizeAuthUsername(authUsername); dom.registerUsername.value = sanitizeAuthUsername(authUsername);
const storedNickname = sanitizeName(settings.loadNickname());
dom.preconnectNickname.value = storedNickname;
if (storedNickname) {
state.player.nickname = storedNickname;
}
setAuthMode('login'); setAuthMode('login');
updateConnectAvailability(); updateConnectAvailability();
updateDeviceSummary(); updateDeviceSummary();

View File

@@ -25,13 +25,11 @@ type MessageHandlerDeps = {
carriedItemId: string | null; carriedItemId: string | null;
}; };
dom: { dom: {
nicknameContainer: HTMLElement;
connectButton: HTMLElement; connectButton: HTMLElement;
disconnectButton: HTMLElement; disconnectButton: HTMLElement;
focusGridButton: HTMLElement; focusGridButton: HTMLElement;
canvas: HTMLCanvasElement; canvas: HTMLCanvasElement;
instructions: HTMLElement; instructions: HTMLElement;
preconnectNickname: HTMLInputElement;
}; };
signalingSend: (message: unknown) => void; signalingSend: (message: unknown) => void;
peerManager: { peerManager: {
@@ -63,7 +61,6 @@ type MessageHandlerDeps = {
audioUiBlip: () => void; audioUiBlip: () => void;
audioUiConfirm: () => void; audioUiConfirm: () => void;
audioUiCancel: () => void; audioUiCancel: () => void;
NICKNAME_STORAGE_KEY: string;
getCarriedItemId: () => string | null; getCarriedItemId: () => string | null;
recomputeActiveItemPropertyKeys: (itemId: string) => void; recomputeActiveItemPropertyKeys: (itemId: string) => void;
itemPropertyLabel: (key: string) => string; itemPropertyLabel: (key: string) => string;
@@ -113,7 +110,6 @@ export function createOnMessageHandler(deps: MessageHandlerDeps): (message: Inco
const targetY = persistedPosition?.y ?? message.player.y; const targetY = persistedPosition?.y ?? message.player.y;
deps.state.player.x = Math.max(0, Math.min(deps.getWorldGridSize() - 1, targetX)); deps.state.player.x = Math.max(0, Math.min(deps.getWorldGridSize() - 1, targetX));
deps.state.player.y = Math.max(0, Math.min(deps.getWorldGridSize() - 1, targetY)); deps.state.player.y = Math.max(0, Math.min(deps.getWorldGridSize() - 1, targetY));
deps.dom.nicknameContainer.classList.add('hidden');
deps.dom.connectButton.classList.add('hidden'); deps.dom.connectButton.classList.add('hidden');
deps.dom.disconnectButton.classList.remove('hidden'); deps.dom.disconnectButton.classList.remove('hidden');
deps.dom.focusGridButton.classList.remove('hidden'); deps.dom.focusGridButton.classList.remove('hidden');
@@ -228,8 +224,8 @@ export function createOnMessageHandler(deps: MessageHandlerDeps): (message: Inco
case 'nickname_result': { case 'nickname_result': {
deps.state.player.nickname = deps.sanitizeName(message.effectiveNickname) || 'user...'; deps.state.player.nickname = deps.sanitizeName(message.effectiveNickname) || 'user...';
if (message.accepted) { if (message.accepted) {
deps.dom.preconnectNickname.value = deps.state.player.nickname; deps.updateStatus(`Nickname set to ${deps.state.player.nickname}`);
localStorage.setItem(deps.NICKNAME_STORAGE_KEY, deps.state.player.nickname); deps.audioUiConfirm();
} else { } else {
deps.pushChatMessage(message.reason || 'Nickname unavailable.'); deps.pushChatMessage(message.reason || 'Nickname unavailable.');
deps.audioUiCancel(); deps.audioUiCancel();

View File

@@ -3,8 +3,6 @@ import type { GameState } from '../state/gameState';
const WELCOME_TIMEOUT_MS = 8_000; const WELCOME_TIMEOUT_MS = 8_000;
type DomRefs = { type DomRefs = {
preconnectNickname: HTMLInputElement;
nicknameContainer: HTMLDivElement;
connectButton: HTMLButtonElement; connectButton: HTMLButtonElement;
disconnectButton: HTMLButtonElement; disconnectButton: HTMLButtonElement;
focusGridButton: HTMLButtonElement; focusGridButton: HTMLButtonElement;
@@ -40,15 +38,14 @@ export type ConnectFlowDeps = {
}; };
/** /**
* Runs connect flow: validate nickname, preflight mic/device setup, then signaling connect. * Runs connect flow: preflight media setup, then signaling connect/auth.
*/ */
export async function runConnectFlow(deps: ConnectFlowDeps): Promise<void> { export async function runConnectFlow(deps: ConnectFlowDeps): Promise<void> {
if (deps.mediaIsConnecting() || deps.state.running) { if (deps.mediaIsConnecting() || deps.state.running) {
return; return;
} }
const nickname = deps.sanitizeName(deps.dom.preconnectNickname.value); const nickname = deps.sanitizeName(deps.state.player.nickname);
deps.state.player.nickname = nickname || deps.state.player.nickname; deps.state.player.nickname = nickname || deps.state.player.nickname;
deps.dom.preconnectNickname.value = nickname;
if (nickname) { if (nickname) {
deps.settingsSaveNickname(nickname); deps.settingsSaveNickname(nickname);
} }
@@ -138,7 +135,6 @@ export function runDisconnectFlow(deps: ConnectFlowDeps): void {
deps.state.effectSelectIndex = 0; deps.state.effectSelectIndex = 0;
deps.mediaSetConnecting(false); deps.mediaSetConnecting(false);
deps.dom.nicknameContainer.classList.remove('hidden');
deps.dom.connectButton.classList.remove('hidden'); deps.dom.connectButton.classList.remove('hidden');
deps.dom.disconnectButton.classList.add('hidden'); deps.dom.disconnectButton.classList.add('hidden');
deps.dom.focusGridButton.classList.add('hidden'); deps.dom.focusGridButton.classList.add('hidden');

View File

@@ -3,7 +3,6 @@
*/ */
type UiDom = { type UiDom = {
connectButton: HTMLButtonElement; connectButton: HTMLButtonElement;
preconnectNickname: HTMLInputElement;
disconnectButton: HTMLButtonElement; disconnectButton: HTMLButtonElement;
focusGridButton: HTMLButtonElement; focusGridButton: HTMLButtonElement;
settingsButton: HTMLButtonElement; settingsButton: HTMLButtonElement;
@@ -19,8 +18,6 @@ type UiDom = {
*/ */
type UiBindingsDeps = { type UiBindingsDeps = {
dom: UiDom; dom: UiDom;
sanitizeName: (value: string) => string;
nicknameStorageKey: string;
updateConnectAvailability: () => void; updateConnectAvailability: () => void;
connect: () => Promise<void>; connect: () => Promise<void>;
disconnect: () => void; disconnect: () => void;
@@ -46,25 +43,6 @@ export function setupUiHandlers(deps: UiBindingsDeps): void {
deps.dom.connectButton.addEventListener('click', () => { deps.dom.connectButton.addEventListener('click', () => {
void deps.connect(); void deps.connect();
}); });
deps.dom.preconnectNickname.addEventListener('input', () => {
deps.updateConnectAvailability();
});
deps.dom.preconnectNickname.addEventListener('change', () => {
const clean = deps.sanitizeName(deps.dom.preconnectNickname.value);
deps.dom.preconnectNickname.value = clean;
if (clean) {
localStorage.setItem(deps.nicknameStorageKey, clean);
} else {
localStorage.removeItem(deps.nicknameStorageKey);
}
deps.updateConnectAvailability();
});
deps.dom.preconnectNickname.addEventListener('keydown', (event) => {
if (event.key === 'Enter' && !deps.dom.connectButton.disabled) {
event.preventDefault();
void deps.connect();
}
});
deps.dom.disconnectButton.addEventListener('click', () => { deps.dom.disconnectButton.addEventListener('click', () => {
deps.disconnect(); deps.disconnect();

View File

@@ -5,6 +5,9 @@ REPO_ROOT="${1:-/home/bestmidi/chgrid}"
PUBLISH_DIR="${2:-/home/bestmidi/public_html/chgrid}" PUBLISH_DIR="${2:-/home/bestmidi/public_html/chgrid}"
BASE_PATH="${3:-/chgrid/}" BASE_PATH="${3:-/chgrid/}"
SERVICE_NAME="${4:-chat-grid.service}" SERVICE_NAME="${4:-chat-grid.service}"
if [[ -z "${SERVICE_NAME// }" || "$SERVICE_NAME" == "-" || "$SERVICE_NAME" == ".service" ]]; then
SERVICE_NAME="chat-grid.service"
fi
"$REPO_ROOT/deploy/scripts/deploy_client.sh" "$REPO_ROOT" "$PUBLISH_DIR" "$BASE_PATH" "$REPO_ROOT/deploy/scripts/deploy_client.sh" "$REPO_ROOT" "$PUBLISH_DIR" "$BASE_PATH"
sudo systemctl restart "$SERVICE_NAME" sudo systemctl restart "$SERVICE_NAME"