Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
FROM oven/bun:1.3-alpine
LABEL org.opencontainers.image.source=https://github.com/mpoc/sleep-tracker
FROM oven/bun:1.3-alpine AS build
WORKDIR /usr/src/sleep-tracker
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile --production
COPY . .
RUN bun build --compile --asset-naming="[name].[ext]" src/index.ts ./src/static/*.png ./src/static/*.ico ./src/static/*.webmanifest --outfile server

FROM alpine
RUN apk add --no-cache libgcc libstdc++
LABEL org.opencontainers.image.source=https://github.com/mpoc/sleep-tracker
WORKDIR /usr/src/sleep-tracker
COPY --from=build /usr/src/sleep-tracker/server ./server
EXPOSE 8000
ENTRYPOINT ["bun", "src/index.ts"]
ENTRYPOINT ["./server"]
3 changes: 0 additions & 3 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "sleep-tracker",
"license": "Apache-2.0",
"scripts": {
"build": "bun build --target=bun --production --outdir=dist --sourcemap ./src/index.ts ./src/static/*",
"build": "bun build --compile --asset-naming='[name].[ext]' src/index.ts ./src/static/*.png ./src/static/*.ico ./src/static/*.webmanifest --outfile server",
"start": "bun src/index.ts",
"dev": "bun --watch src/index.ts",
"format": "biome format --write ."
Expand All @@ -22,7 +22,6 @@
},
"dependencies": {
"@elysiajs/bearer": "^1.4.3",
"@elysiajs/static": "^1.4.7",
"@openrouter/ai-sdk-provider": "^2.2.3",
"ai": "^6.0.105",
"croner": "^10.0.1",
Expand Down
4 changes: 3 additions & 1 deletion src/checkReminderLoop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ const checkReminderNotification = async () => {
};

export const checkReminderLoop = () => {
checkReminderNotification();
checkReminderNotification().catch((e) =>
console.error("checkReminderNotification failed:", e)
);
setTimeout(checkReminderLoop, ms(REMINDER_CHECK_INTERVAL));
};
21 changes: 19 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import "./ensureDataDir";
import { bearer } from "@elysiajs/bearer";
import { staticPlugin } from "@elysiajs/static";
import { Elysia } from "elysia";
import logixlysia from "logixlysia";
import swJs from "./static/sw.js" with { type: "file" };
import ms from "ms";
import { startAiNotificationCron } from "./aiNotifications";
import { checkReminderLoop } from "./checkReminderLoop";
Expand Down Expand Up @@ -93,7 +93,24 @@ new Elysia()
.get("/notifications", sleepReactHtml)
.get("/notification-feedback", sleepReactHtml)
.get("/", sleepReactHtml)
.use(staticPlugin({ assets: "./src/static/", prefix: "/" }))
.get("/*", async ({ params, set }) => {
const name = params["*"];
for (const blob of Bun.embeddedFiles) {
if (blob.name === name) {
return new Response(blob);
}
}
const embeddedByImport: Record<string, string> = { "sw.js": swJs };
if (name in embeddedByImport) {
return new Response(Bun.file(embeddedByImport[name]));
}
const file = Bun.file(`./src/static/${name}`);
if (await file.exists()) {
return new Response(file);
}
set.status = 404;
return "Not found";
})
.listen(PORT);

checkReminderLoop();
Expand Down
10 changes: 10 additions & 0 deletions src/views/js/frontend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("/sw.js");
}

for (const [rel, href] of [
["manifest", "/manifest.webmanifest"],
["apple-touch-icon", "/apple-touch-icon.png"],
] as const) {
const link = document.createElement("link");
link.rel = rel;
link.href = href;
document.head.appendChild(link);
}

const getPage = () => {
if (window.location.pathname === "/notifications") {
return <NotificationList />;
Expand Down
2 changes: 0 additions & 2 deletions src/views/sleepReact.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM"
crossorigin="anonymous"
>
<link rel="manifest" href="../static/manifest.webmanifest">
<meta name="theme-color" content="#212529">
<link rel="apple-touch-icon" href="../static/apple-touch-icon.png">
<title>Sleep</title>
</head>
<body data-bs-theme="dark">
Expand Down