@checkstack/backend 0.6.2 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/package.json +5 -5
- package/src/index.ts +25 -14
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @checkstack/backend
|
|
2
2
|
|
|
3
|
+
## 0.6.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- a713e0f: Fix static file Content-Length header stripped by Hono middleware
|
|
8
|
+
|
|
9
|
+
Hono's CORS middleware wraps raw `Response` objects and strips Bun's auto-generated headers. Switched to using `c.body()` + `c.header()` so Content-Type and Content-Length survive the middleware pipeline. Extracted a shared `serveFile` helper for all static file routes.
|
|
10
|
+
|
|
11
|
+
## 0.6.3
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 3da7582: Fix favicon not loading in production container and add NotFound page
|
|
16
|
+
|
|
17
|
+
- **Backend**: Fix static file serving so root-level files like `/favicon.svg` are served from the dist directory before the SPA fallback catches them
|
|
18
|
+
- **UI**: Add `NotFound` component with stacked-checkmark logo, physics-inspired falling "4" animation, and low-power device fallback
|
|
19
|
+
- **Frontend**: Add catch-all `*` route to display the NotFound page for unmatched routes, and add the Checkstack logo to the navbar
|
|
20
|
+
- **Favicon**: Redesign with stacked checkmarks in the brand purple/indigo palette
|
|
21
|
+
|
|
3
22
|
## 0.6.2
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/backend",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"checkstack": {
|
|
5
5
|
"type": "backend"
|
|
6
6
|
},
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@checkstack/api-docs-common": "0.1.9",
|
|
17
17
|
"@checkstack/auth-common": "0.6.1",
|
|
18
|
-
"@checkstack/backend-api": "0.
|
|
18
|
+
"@checkstack/backend-api": "0.12.0",
|
|
19
19
|
"@checkstack/common": "0.6.5",
|
|
20
20
|
"@checkstack/drizzle-helper": "0.0.4",
|
|
21
|
-
"@checkstack/queue-api": "0.2.
|
|
22
|
-
"@checkstack/signal-backend": "0.1.
|
|
21
|
+
"@checkstack/queue-api": "0.2.13",
|
|
22
|
+
"@checkstack/signal-backend": "0.1.19",
|
|
23
23
|
"@checkstack/signal-common": "0.1.9",
|
|
24
24
|
"@hono/zod-validator": "^0.7.6",
|
|
25
25
|
"@orpc/client": "^1.13.14",
|
|
@@ -40,6 +40,6 @@
|
|
|
40
40
|
"@types/bun": "latest",
|
|
41
41
|
"@checkstack/tsconfig": "0.0.5",
|
|
42
42
|
"@checkstack/scripts": "0.1.2",
|
|
43
|
-
"@checkstack/test-utils-backend": "0.1.
|
|
43
|
+
"@checkstack/test-utils-backend": "0.1.19"
|
|
44
44
|
}
|
|
45
45
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Server } from "bun";
|
|
2
|
-
import { Hono } from "hono";
|
|
2
|
+
import { type Context, Hono } from "hono";
|
|
3
3
|
import { PluginManager } from "./plugin-manager";
|
|
4
4
|
import { logger } from "hono/logger";
|
|
5
5
|
import { migrate } from "drizzle-orm/node-postgres/migrator";
|
|
@@ -174,6 +174,13 @@ app.get("/.well-known/jwks.json", async (c) => {
|
|
|
174
174
|
const frontendDistPath = process.env.CHECKSTACK_FRONTEND_DIST;
|
|
175
175
|
if (frontendDistPath && fs.existsSync(frontendDistPath)) {
|
|
176
176
|
rootLogger.info(`📦 Serving frontend from: ${frontendDistPath}`);
|
|
177
|
+
/** Serve a static file via Hono's context to preserve headers through middleware. */
|
|
178
|
+
const serveFile = async (c: Context, filePath: string) => {
|
|
179
|
+
const file = Bun.file(filePath);
|
|
180
|
+
c.header("Content-Type", file.type);
|
|
181
|
+
c.header("Content-Length", String(file.size));
|
|
182
|
+
return c.body(file.stream());
|
|
183
|
+
};
|
|
177
184
|
|
|
178
185
|
// Serve static assets (JS, CSS, images, etc.)
|
|
179
186
|
app.get("/assets/*", async (c) => {
|
|
@@ -181,10 +188,7 @@ if (frontendDistPath && fs.existsSync(frontendDistPath)) {
|
|
|
181
188
|
const filePath = path.join(frontendDistPath, "assets", assetPath);
|
|
182
189
|
|
|
183
190
|
if (fs.existsSync(filePath)) {
|
|
184
|
-
|
|
185
|
-
return new Response(file, {
|
|
186
|
-
headers: { "Content-Type": file.type },
|
|
187
|
-
});
|
|
191
|
+
return serveFile(c, filePath);
|
|
188
192
|
}
|
|
189
193
|
return c.notFound();
|
|
190
194
|
});
|
|
@@ -195,27 +199,34 @@ if (frontendDistPath && fs.existsSync(frontendDistPath)) {
|
|
|
195
199
|
const filePath = path.join(frontendDistPath, "vendor", vendorPath);
|
|
196
200
|
|
|
197
201
|
if (fs.existsSync(filePath)) {
|
|
198
|
-
|
|
199
|
-
return new Response(file, {
|
|
200
|
-
headers: { "Content-Type": file.type },
|
|
201
|
-
});
|
|
202
|
+
return serveFile(c, filePath);
|
|
202
203
|
}
|
|
203
204
|
return c.notFound();
|
|
204
205
|
});
|
|
205
206
|
|
|
206
|
-
// Serve
|
|
207
|
+
// Serve root-level static files (e.g., /favicon.svg) from the dist directory
|
|
208
|
+
// before the SPA fallback, so they don't get caught by the index.html handler
|
|
207
209
|
app.get("*", async (c, next) => {
|
|
208
210
|
// Skip API and WebSocket routes - let them pass through to actual handlers
|
|
209
211
|
if (c.req.path.startsWith("/api")) {
|
|
210
212
|
return next();
|
|
211
213
|
}
|
|
212
214
|
|
|
215
|
+
// Check if the request maps to an actual file in the dist root
|
|
216
|
+
// (e.g., /favicon.svg -> dist/favicon.svg)
|
|
217
|
+
const reqPath = c.req.path.slice(1); // Remove leading "/"
|
|
218
|
+
if (reqPath && reqPath !== "" && !reqPath.includes("..")) {
|
|
219
|
+
const staticFilePath = path.join(frontendDistPath, reqPath);
|
|
220
|
+
// Only serve if it's a file (not a directory) and exists
|
|
221
|
+
if (fs.existsSync(staticFilePath) && fs.statSync(staticFilePath).isFile()) {
|
|
222
|
+
return serveFile(c, staticFilePath);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// SPA fallback: serve index.html for all remaining non-API routes
|
|
213
227
|
const indexPath = path.join(frontendDistPath, "index.html");
|
|
214
228
|
if (fs.existsSync(indexPath)) {
|
|
215
|
-
|
|
216
|
-
return new Response(file, {
|
|
217
|
-
headers: { "Content-Type": "text/html" },
|
|
218
|
-
});
|
|
229
|
+
return serveFile(c, indexPath);
|
|
219
230
|
}
|
|
220
231
|
return c.notFound();
|
|
221
232
|
});
|