package -> pkg

This commit is contained in:
2025-08-29 20:45:53 -04:00
parent 0d6d3d6d32
commit f38a5a69df
54 changed files with 5 additions and 5 deletions

146
pkg/server/src/api.ts Normal file
View File

@@ -0,0 +1,146 @@
import { Elysia, t } from "elysia";
import {
getSimplePlayerView,
SimpleAction,
SimpleConfiguration,
SimpleGameState,
} from "@games/shared/games/simple";
import { human } from "./human";
import dayjs from "dayjs";
import db from "./db";
import { liveTable, WsOut, WsIn } from "./table";
import { Human } from "@prisma/client";
import { combine } from "kefir";
const api = new Elysia({ prefix: "/api" })
.post("/whoami", async ({ cookie: { token } }) => {
let human: Human | null;
if (
token.value == null ||
(human = await db.human.findUnique({
where: {
token: token.value,
},
})) == null
) {
human = await db.human.create({
data: {},
});
token.set({
value: human.token,
expires: dayjs().add(1, "year").toDate(),
httpOnly: true,
});
}
return human.key;
})
.use(human)
.post(
"/setName",
({ body: { name }, humanKey }) =>
db.human.update({
where: {
key: humanKey,
},
data: {
name,
},
}),
{
body: t.Object({
name: t.String(),
}),
}
)
.get("/profile", ({ humanKey, query: { otherHumanKey } }) =>
db.human
.findFirst({ where: { key: otherHumanKey ?? humanKey } })
.then((human) => {
if (human == null) {
return null;
}
const { token, ...safeProfile } = human;
return safeProfile;
})
)
.get("/games", () => [{ key: "simple", name: "simple" }])
.ws("/ws/:tableKey", {
async open({
data: {
params: { tableKey },
humanKey,
},
send,
}) {
const table = liveTable<
SimpleConfiguration,
SimpleGameState,
SimpleAction
>(tableKey);
table.inputs.connectionChanges.emit({
humanKey,
presence: "joined",
});
table.outputs.playersPresent.onValue((players) =>
send({ players })
);
table.outputs.playersReady
.skipDuplicates()
.onValue((readys) => send({ playersReady: readys }));
combine(
[table.outputs.gameState],
[table.outputs.gameConfig],
(state, config) =>
state &&
config &&
getSimplePlayerView(config, state, humanKey)
)
.toProperty()
.onValue((view) => send({ view }));
},
response: WsOut,
body: WsIn,
message(
{
data: {
humanKey,
params: { tableKey },
},
},
body
) {
const {
inputs: { readys, actions, quits },
} = liveTable(tableKey);
if ("ready" in body) {
readys.emit({ humanKey, ...body });
} else if ("action" in body) {
actions.emit({ humanKey, ...body.action });
} else if ("quit" in body) {
quits.emit({ humanKey });
}
},
async close({
data: {
params: { tableKey },
humanKey,
},
}) {
liveTable(tableKey).inputs.connectionChanges.emit({
humanKey,
presence: "left",
});
},
});
export default api;
export type Api = typeof api;