chore: Update configuration defaults and Docker port handling
- Modify Dockerfile to use dynamic port configuration - Update Home Assistant host default to use local hostname - Enhance JWT secret default length requirement - Remove boilerplate and test setup configuration files
This commit is contained in:
@@ -64,7 +64,7 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
|||||||
CMD curl -f http://localhost:4000/health || exit 1
|
CMD curl -f http://localhost:4000/health || exit 1
|
||||||
|
|
||||||
# Expose port
|
# Expose port
|
||||||
EXPOSE 4000
|
EXPOSE ${PORT:-4000}
|
||||||
|
|
||||||
# Start the application with optimized flags
|
# Start the application with optimized flags
|
||||||
CMD ["bun", "--smol", "run", "start"]
|
CMD ["bun", "--smol", "run", "start"]
|
||||||
@@ -115,7 +115,7 @@ router.get("/subscribe_events", middleware.wsRateLimiter, (req, res) => {
|
|||||||
res.writeHead(200, {
|
res.writeHead(200, {
|
||||||
"Content-Type": "text/event-stream",
|
"Content-Type": "text/event-stream",
|
||||||
"Cache-Control": "no-cache",
|
"Cache-Control": "no-cache",
|
||||||
Connection: "keep-alive",
|
"Connection": "keep-alive",
|
||||||
"Access-Control-Allow-Origin": "*",
|
"Access-Control-Allow-Origin": "*",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const AppConfigSchema = z.object({
|
|||||||
.default("development"),
|
.default("development"),
|
||||||
|
|
||||||
/** Home Assistant Configuration */
|
/** Home Assistant Configuration */
|
||||||
HASS_HOST: z.string().default("http://192.168.178.63:8123"),
|
HASS_HOST: z.string().default("http://homeassistant.local:8123"),
|
||||||
HASS_TOKEN: z.string().optional(),
|
HASS_TOKEN: z.string().optional(),
|
||||||
|
|
||||||
/** Speech Features Configuration */
|
/** Speech Features Configuration */
|
||||||
@@ -31,7 +31,7 @@ export const AppConfigSchema = z.object({
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
/** Security Configuration */
|
/** Security Configuration */
|
||||||
JWT_SECRET: z.string().default("your-secret-key"),
|
JWT_SECRET: z.string().default("your-secret-key-must-be-32-char-min"),
|
||||||
RATE_LIMIT: z.object({
|
RATE_LIMIT: z.object({
|
||||||
/** Time window for rate limiting in milliseconds */
|
/** Time window for rate limiting in milliseconds */
|
||||||
windowMs: z.number().default(15 * 60 * 1000), // 15 minutes
|
windowMs: z.number().default(15 * 60 * 1000), // 15 minutes
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
export const BOILERPLATE_CONFIG = {
|
|
||||||
configuration: {
|
|
||||||
LOG_LEVEL: {
|
|
||||||
type: "string" as const,
|
|
||||||
default: "debug",
|
|
||||||
description: "Logging level",
|
|
||||||
enum: ["error", "warn", "info", "debug", "trace"],
|
|
||||||
},
|
|
||||||
CACHE_DIRECTORY: {
|
|
||||||
type: "string" as const,
|
|
||||||
default: ".cache",
|
|
||||||
description: "Directory for cache files",
|
|
||||||
},
|
|
||||||
CONFIG_DIRECTORY: {
|
|
||||||
type: "string" as const,
|
|
||||||
default: ".config",
|
|
||||||
description: "Directory for configuration files",
|
|
||||||
},
|
|
||||||
DATA_DIRECTORY: {
|
|
||||||
type: "string" as const,
|
|
||||||
default: ".data",
|
|
||||||
description: "Directory for data files",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
internal: {
|
|
||||||
boilerplate: {
|
|
||||||
configuration: {
|
|
||||||
LOG_LEVEL: "debug",
|
|
||||||
CACHE_DIRECTORY: ".cache",
|
|
||||||
CONFIG_DIRECTORY: ".config",
|
|
||||||
DATA_DIRECTORY: ".data",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
import { afterEach, mock, expect } from "bun:test";
|
|
||||||
|
|
||||||
// Setup global mocks
|
|
||||||
global.fetch = mock(() => Promise.resolve(new Response()));
|
|
||||||
|
|
||||||
// Mock WebSocket
|
|
||||||
class MockWebSocket {
|
|
||||||
static CONNECTING = 0;
|
|
||||||
static OPEN = 1;
|
|
||||||
static CLOSING = 2;
|
|
||||||
static CLOSED = 3;
|
|
||||||
|
|
||||||
url: string;
|
|
||||||
readyState: number = MockWebSocket.CLOSED;
|
|
||||||
onopen: ((event: any) => void) | null = null;
|
|
||||||
onclose: ((event: any) => void) | null = null;
|
|
||||||
onmessage: ((event: any) => void) | null = null;
|
|
||||||
onerror: ((event: any) => void) | null = null;
|
|
||||||
|
|
||||||
constructor(url: string) {
|
|
||||||
this.url = url;
|
|
||||||
setTimeout(() => {
|
|
||||||
this.readyState = MockWebSocket.OPEN;
|
|
||||||
this.onopen?.({ type: 'open' });
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
send = mock((data: string) => {
|
|
||||||
if (this.readyState !== MockWebSocket.OPEN) {
|
|
||||||
throw new Error('WebSocket is not open');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
close = mock(() => {
|
|
||||||
this.readyState = MockWebSocket.CLOSED;
|
|
||||||
this.onclose?.({ type: 'close', code: 1000, reason: '', wasClean: true });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add WebSocket to global
|
|
||||||
(global as any).WebSocket = MockWebSocket;
|
|
||||||
|
|
||||||
// Reset all mocks after each test
|
|
||||||
afterEach(() => {
|
|
||||||
mock.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add custom matchers
|
|
||||||
expect.extend({
|
|
||||||
toBeValidResponse(received: Response) {
|
|
||||||
const pass = received instanceof Response && received.ok;
|
|
||||||
return {
|
|
||||||
message: () =>
|
|
||||||
`expected ${received instanceof Response ? 'Response' : typeof received} to${pass ? ' not' : ''} be a valid Response`,
|
|
||||||
pass
|
|
||||||
};
|
|
||||||
},
|
|
||||||
toBeValidWebSocket(received: any) {
|
|
||||||
const pass = received instanceof MockWebSocket;
|
|
||||||
return {
|
|
||||||
message: () =>
|
|
||||||
`expected ${received instanceof MockWebSocket ? 'MockWebSocket' : typeof received} to${pass ? ' not' : ''} be a valid WebSocket`,
|
|
||||||
pass
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user