Add account auth with websocket login/register and sessions

This commit is contained in:
Jage9
2026-02-24 22:03:10 -05:00
parent 1938f239e6
commit bf3bc90f2a
21 changed files with 1053 additions and 24 deletions

View File

@@ -73,6 +73,8 @@ type MessageHandlerDeps = {
playLocateToneAt: (x: number, y: number) => void;
resolveIncomingSoundUrl: (url: string) => string;
playIncomingItemUseSound: (url: string, x: number, y: number) => void;
handleAuthRequired: (message: string) => void;
handleAuthResult: (message: Extract<IncomingMessage, { type: 'auth_result' }>) => Promise<void>;
};
/**
@@ -81,6 +83,14 @@ type MessageHandlerDeps = {
export function createOnMessageHandler(deps: MessageHandlerDeps): (message: IncomingMessage) => Promise<void> {
return async function onMessage(message: IncomingMessage): Promise<void> {
switch (message.type) {
case 'auth_required':
deps.handleAuthRequired(message.message);
break;
case 'auth_result':
await deps.handleAuthResult(message);
break;
case 'welcome':
if (message.worldConfig?.gridSize && Number.isInteger(message.worldConfig.gridSize) && message.worldConfig.gridSize > 0) {
deps.setWorldGridSize(message.worldConfig.gridSize);

View File

@@ -48,6 +48,14 @@ export const welcomeMessageSchema = z.object({
version: z.string().optional(),
})
.optional(),
auth: z
.object({
authenticated: z.boolean(),
userId: z.string().nullable().optional(),
username: z.string().nullable().optional(),
role: z.string().nullable().optional(),
})
.optional(),
uiDefinitions: z
.object({
itemTypeOrder: z.array(z.string().min(1)),
@@ -85,6 +93,21 @@ export const welcomeMessageSchema = z.object({
.optional(),
});
export const authRequiredSchema = z.object({
type: z.literal('auth_required'),
message: z.string(),
});
export const authResultSchema = z.object({
type: z.literal('auth_result'),
ok: z.boolean(),
message: z.string(),
sessionToken: z.string().optional(),
username: z.string().optional(),
role: z.string().optional(),
nickname: z.string().optional(),
});
export const signalMessageSchema = z.object({
type: z.literal('signal'),
senderId: z.string(),
@@ -203,6 +226,8 @@ export const itemPianoStatusSchema = z.object({
});
export const incomingMessageSchema = z.discriminatedUnion('type', [
authRequiredSchema,
authResultSchema,
welcomeMessageSchema,
signalMessageSchema,
updatePositionSchema,
@@ -223,6 +248,10 @@ export const incomingMessageSchema = z.discriminatedUnion('type', [
export type IncomingMessage = z.infer<typeof incomingMessageSchema>;
export type OutgoingMessage =
| { type: 'auth_register'; username: string; password: string; email?: string }
| { type: 'auth_login'; username: string; password: string }
| { type: 'auth_resume'; sessionToken: string }
| { type: 'auth_logout' }
| { type: 'signal'; targetId: string; sdp?: RTCSessionDescriptionInit; ice?: RTCIceCandidateInit }
| { type: 'update_position'; x: number; y: number }
| { type: 'teleport_complete'; x: number; y: number }