From b5bf4ed0c6975e41122bb5603c8c6adc5df1c847 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Tue, 24 Mar 2026 23:07:11 +0200 Subject: [PATCH] Add config for cabotage --- .dockerignore | 12 ++++++++++++ Dockerfile | 18 ++++++++++++++++++ Procfile | 2 ++ bun.lock | 5 +++++ package.json | 1 + serve.ts | 43 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 81 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 Procfile create mode 100644 serve.ts diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..2bb9f71 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +node_modules/ +dist/ +.astro/ +.env +.env.* +.git/ +.gitignore +.DS_Store +README.md +Dockerfile +.dockerignore +npm-debug.log* diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8556727 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM oven/bun:1 AS build + +WORKDIR /app + +COPY package.json bun.lock ./ +RUN bun install --frozen-lockfile + +COPY . . +RUN bun run build + +FROM oven/bun:1-slim + +WORKDIR /app + +COPY --from=build /app/dist ./dist +COPY serve.ts ./ + +CMD ["bun", "run", "serve.ts"] diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..7ba436a --- /dev/null +++ b/Procfile @@ -0,0 +1,2 @@ +web: bun run serve.ts +release: echo 'deploy' diff --git a/bun.lock b/bun.lock index a3bec50..accb080 100644 --- a/bun.lock +++ b/bun.lock @@ -23,6 +23,7 @@ "devDependencies": { "@astrojs/check": "^0.9.6", "@tailwindcss/postcss": "^4.1.18", + "@types/bun": "^1.3.11", "@types/mdast": "^4.0.4", "@types/turndown": "^5.0.6", "fast-xml-parser": "^5.3.5", @@ -714,6 +715,8 @@ "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], + "@types/bun": ["@types/bun@1.3.11", "", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="], + "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], @@ -834,6 +837,8 @@ "browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="], + "bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="], + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], "camelcase": ["camelcase@8.0.0", "", {}, "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA=="], diff --git a/package.json b/package.json index 9da3aca..be2cc11 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "devDependencies": { "@astrojs/check": "^0.9.6", "@tailwindcss/postcss": "^4.1.18", + "@types/bun": "^1.3.11", "@types/mdast": "^4.0.4", "@types/turndown": "^5.0.6", "fast-xml-parser": "^5.3.5", diff --git a/serve.ts b/serve.ts new file mode 100644 index 0000000..157cb02 --- /dev/null +++ b/serve.ts @@ -0,0 +1,43 @@ +import { join, resolve } from "node:path"; + +const DIST = resolve(import.meta.dirname, "dist"); +const SOCK = "/var/run/cabotage/cabotage.sock"; + +async function serveFile(filePath: string): Promise { + const resolved = resolve(filePath); + if (!resolved.startsWith(DIST)) return null; + const file = Bun.file(resolved); + if (await file.exists()) return new Response(file); + return null; +} + +Bun.serve({ + unix: SOCK, + async fetch(req) { + const url = new URL(req.url); + const pathname = decodeURIComponent(url.pathname); + + // Try exact file + let resp = await serveFile(join(DIST, pathname)); + if (resp) return resp; + + // Try as directory with index.html + resp = await serveFile(join(DIST, pathname, "index.html")); + if (resp) return resp; + + // Try with .html extension + resp = await serveFile(join(DIST, pathname + ".html")); + if (resp) return resp; + + // 404 + const notFound = await serveFile(join(DIST, "404.html")); + if (notFound) + return new Response(notFound.body, { + status: 404, + headers: notFound.headers, + }); + return new Response("Not Found", { status: 404 }); + }, +}); + +console.log(`Listening on ${SOCK}`);