privatization
This commit is contained in:
1
package-lock.json
generated
1
package-lock.json
generated
@@ -25,6 +25,7 @@
|
|||||||
"@types/luxon": "^3.7.1",
|
"@types/luxon": "^3.7.1",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.10.1",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
|
"openapi-types": "^12.1.3",
|
||||||
"tsx": "^4.20.6",
|
"tsx": "^4.20.6",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
"@types/luxon": "^3.7.1",
|
"@types/luxon": "^3.7.1",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.10.1",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
|
"openapi-types": "^12.1.3",
|
||||||
"tsx": "^4.20.6",
|
"tsx": "^4.20.6",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { FastifyInstance } from "fastify";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import type { GristService } from "./service";
|
import type { GristService } from "./service";
|
||||||
|
|
||||||
export async function gristRoutes(
|
export async function privateGristRoutes(
|
||||||
fastify: FastifyInstance,
|
fastify: FastifyInstance,
|
||||||
{
|
{
|
||||||
gristService,
|
gristService,
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import type { HomeAssistantDeskPositionResult } from "@dpu/shared";
|
import type { HomeAssistantDeskPositionResult } from "@dpu/shared";
|
||||||
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import type { HomeAssistantService } from "../homeassistant/service.js";
|
import type { HomeAssistantService } from "./service.js";
|
||||||
|
|
||||||
export async function homeAssistantRoutes(
|
export async function privateHomeAssistantRoutes(
|
||||||
fastify: FastifyInstance,
|
fastify: FastifyInstance,
|
||||||
{
|
{
|
||||||
haService,
|
haService,
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import type {
|
import type {
|
||||||
API_HA_DeskPosition,
|
|
||||||
ComponentUpdate,
|
ComponentUpdate,
|
||||||
GristRecord_PersonalGoals,
|
GristRecord_PersonalGoals,
|
||||||
HA_Update,
|
HA_Update,
|
||||||
@@ -14,7 +13,7 @@ import type { GristService } from "../grist/service.js";
|
|||||||
import type { HomeAssistantService } from "../homeassistant/service.js";
|
import type { HomeAssistantService } from "../homeassistant/service.js";
|
||||||
import type { HomepageService } from "./service.js";
|
import type { HomepageService } from "./service.js";
|
||||||
|
|
||||||
export async function homepageRoutes(
|
export async function privateHomepageRoutes(
|
||||||
fastify: FastifyInstance,
|
fastify: FastifyInstance,
|
||||||
{
|
{
|
||||||
hpService,
|
hpService,
|
||||||
@@ -31,39 +30,6 @@ export async function homepageRoutes(
|
|||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
fastify.get(
|
|
||||||
"/homepage/status",
|
|
||||||
{
|
|
||||||
schema: {
|
|
||||||
description: "Get all current information for dpu status page",
|
|
||||||
tags: ["homepage"],
|
|
||||||
response: {
|
|
||||||
200: z.object({
|
|
||||||
ha_desk_position: z.custom<API_HA_DeskPosition>().nullable(),
|
|
||||||
ha_temp: z.string().nullable(),
|
|
||||||
tidal_current: z.custom<TidalGetCurrent>().nullable(),
|
|
||||||
grist_personal_goals: z
|
|
||||||
.custom<GristRecord_PersonalGoals>()
|
|
||||||
.nullable(),
|
|
||||||
}),
|
|
||||||
418: z.object({
|
|
||||||
error: z.string(),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
async (_request, reply) => {
|
|
||||||
const service_result = await hpService.getFullInformation();
|
|
||||||
|
|
||||||
if (!service_result.successful) {
|
|
||||||
reply.code(418);
|
|
||||||
return { error: service_result.result };
|
|
||||||
}
|
|
||||||
|
|
||||||
return service_result.result;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
fastify.post(
|
fastify.post(
|
||||||
"/homepage/update/grist",
|
"/homepage/update/grist",
|
||||||
{
|
{
|
||||||
50
src/homepage/public-routes.ts
Normal file
50
src/homepage/public-routes.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import type {
|
||||||
|
API_HA_DeskPosition,
|
||||||
|
GristRecord_PersonalGoals,
|
||||||
|
TidalGetCurrent,
|
||||||
|
} from "@dpu/shared";
|
||||||
|
import type { FastifyInstance } from "fastify";
|
||||||
|
import { z } from "zod";
|
||||||
|
import type { HomepageService } from "./service.js";
|
||||||
|
|
||||||
|
export async function publicHomepageRoutes(
|
||||||
|
fastify: FastifyInstance,
|
||||||
|
{
|
||||||
|
hpService,
|
||||||
|
}: {
|
||||||
|
hpService: HomepageService;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
fastify.get(
|
||||||
|
"/homepage/status",
|
||||||
|
{
|
||||||
|
schema: {
|
||||||
|
description: "Get all current information for dpu status page",
|
||||||
|
tags: ["homepage"],
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
ha_desk_position: z.custom<API_HA_DeskPosition>().nullable(),
|
||||||
|
ha_temp: z.string().nullable(),
|
||||||
|
tidal_current: z.custom<TidalGetCurrent>().nullable(),
|
||||||
|
grist_personal_goals: z
|
||||||
|
.custom<GristRecord_PersonalGoals>()
|
||||||
|
.nullable(),
|
||||||
|
}),
|
||||||
|
418: z.object({
|
||||||
|
error: z.string(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async (_request, reply) => {
|
||||||
|
const service_result = await hpService.getFullInformation();
|
||||||
|
|
||||||
|
if (!service_result.successful) {
|
||||||
|
reply.code(418);
|
||||||
|
return { error: service_result.result };
|
||||||
|
}
|
||||||
|
|
||||||
|
return service_result.result;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
163
src/index.ts
163
src/index.ts
@@ -1,66 +1,100 @@
|
|||||||
import { WsService } from "@dpu/shared";
|
import { WsService } from "@dpu/shared";
|
||||||
import { logError } from "@dpu/shared/dist/logger.js";
|
import { logError } from "@dpu/shared/dist/logger.js";
|
||||||
import fastifyCors from "@fastify/cors";
|
import fastifyCors, { type FastifyCorsOptions } from "@fastify/cors";
|
||||||
import fastifySwagger from "@fastify/swagger";
|
import fastifySwagger, { type SwaggerOptions } from "@fastify/swagger";
|
||||||
import fastifySwaggerUi from "@fastify/swagger-ui";
|
import fastifySwaggerUi, {
|
||||||
|
type FastifySwaggerUiOptions,
|
||||||
|
} from "@fastify/swagger-ui";
|
||||||
import fastifyWebsocket from "@fastify/websocket";
|
import fastifyWebsocket from "@fastify/websocket";
|
||||||
import type { FastifyReply, FastifyRequest } from "fastify";
|
import type { FastifyReply, FastifyRequest } from "fastify";
|
||||||
import Fastify from "fastify";
|
import Fastify from "fastify";
|
||||||
import fastifyAxios from "fastify-axios";
|
import fastifyAxios, { type FastifyAxiosOptions } from "fastify-axios";
|
||||||
import {
|
import {
|
||||||
jsonSchemaTransform,
|
jsonSchemaTransform,
|
||||||
serializerCompiler,
|
serializerCompiler,
|
||||||
validatorCompiler,
|
validatorCompiler,
|
||||||
type ZodTypeProvider,
|
type ZodTypeProvider,
|
||||||
} from "fastify-type-provider-zod";
|
} from "fastify-type-provider-zod";
|
||||||
|
import type { OpenAPIV3 } from "openapi-types";
|
||||||
import { SwaggerTheme, SwaggerThemeNameEnum } from "swagger-themes";
|
import { SwaggerTheme, SwaggerThemeNameEnum } from "swagger-themes";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { Config } from "./config.js";
|
import { Config } from "./config.js";
|
||||||
import { GristClient } from "./grist/client.js";
|
import { GristClient } from "./grist/client.js";
|
||||||
import { gristRoutes } from "./grist/routes.js";
|
import { privateGristRoutes } from "./grist/private-routes.js";
|
||||||
import { GristService } from "./grist/service.js";
|
import { GristService } from "./grist/service.js";
|
||||||
import { HomeAssistantClient } from "./homeassistant/client.js";
|
import { HomeAssistantClient } from "./homeassistant/client.js";
|
||||||
import { homeAssistantRoutes } from "./homeassistant/routes.js";
|
import { privateHomeAssistantRoutes } from "./homeassistant/private-routes.js";
|
||||||
import { HomeAssistantService } from "./homeassistant/service.js";
|
import { HomeAssistantService } from "./homeassistant/service.js";
|
||||||
import { homepageRoutes } from "./homepage/routes.js";
|
import { privateHomepageRoutes } from "./homepage/private-routes.js";
|
||||||
|
import { publicHomepageRoutes } from "./homepage/public-routes.js";
|
||||||
import { HomepageService } from "./homepage/service.js";
|
import { HomepageService } from "./homepage/service.js";
|
||||||
import { TidalClient } from "./tidal/client.js";
|
import { TidalClient } from "./tidal/client.js";
|
||||||
import { tidalRoutes } from "./tidal/routes.js";
|
import { privateTidalRoutes } from "./tidal/private-routes.js";
|
||||||
import { TidalService } from "./tidal/service.js";
|
import { TidalService } from "./tidal/service.js";
|
||||||
import { wsRoutes } from "./websocket/routes.js";
|
import { publicWsRoutes } from "./websocket/public-routes.js";
|
||||||
|
|
||||||
const fastify = Fastify().withTypeProvider<ZodTypeProvider>();
|
// Initialize with Zod
|
||||||
|
const publicServer = Fastify().withTypeProvider<ZodTypeProvider>();
|
||||||
|
const privateServer = Fastify().withTypeProvider<ZodTypeProvider>();
|
||||||
|
publicServer.setValidatorCompiler(validatorCompiler);
|
||||||
|
publicServer.setSerializerCompiler(serializerCompiler);
|
||||||
|
privateServer.setValidatorCompiler(validatorCompiler);
|
||||||
|
privateServer.setSerializerCompiler(serializerCompiler);
|
||||||
|
|
||||||
fastify.setValidatorCompiler(validatorCompiler);
|
// Cors
|
||||||
fastify.setSerializerCompiler(serializerCompiler);
|
function getCorsObject(urls: string[]): FastifyCorsOptions {
|
||||||
|
return {
|
||||||
await fastify.register(fastifyCors, {
|
origin: urls,
|
||||||
origin: ["http://localhost:4321", "https://dariusbag.dev"],
|
|
||||||
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
||||||
allowedHeaders: ["Content-Type", "Authorization"],
|
allowedHeaders: ["Content-Type", "Authorization"],
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
|
||||||
await fastify.register(fastifySwagger, {
|
await publicServer.register(
|
||||||
|
fastifyCors,
|
||||||
|
getCorsObject(["https://dariusbag.dev"]),
|
||||||
|
);
|
||||||
|
await privateServer.register(
|
||||||
|
fastifyCors,
|
||||||
|
getCorsObject(["http://localhost:4321"]),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Swagger
|
||||||
|
function getSwaggerObject(servers: OpenAPIV3.ServerObject[]): SwaggerOptions {
|
||||||
|
return {
|
||||||
openapi: {
|
openapi: {
|
||||||
info: {
|
info: {
|
||||||
title: "DPU API",
|
title: "DPU API",
|
||||||
description: "API Documentation",
|
description: "API Documentation",
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
},
|
},
|
||||||
servers: [
|
servers: servers,
|
||||||
{ url: "http://localhost:8080", description: "dev" },
|
|
||||||
{ url: "https://dpu.dariusbag.dev/api", description: "prod" },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
transform: jsonSchemaTransform,
|
transform: jsonSchemaTransform,
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
await publicServer.register(
|
||||||
|
fastifySwagger,
|
||||||
|
getSwaggerObject([
|
||||||
|
{ url: "https://dpu.dariusbag.dev/api", description: "prod" },
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
await privateServer.register(
|
||||||
|
fastifySwagger,
|
||||||
|
getSwaggerObject([
|
||||||
|
{ url: "http://192.168.178.161:20001", description: "prod" },
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Swagger UI
|
||||||
const theme = new SwaggerTheme();
|
const theme = new SwaggerTheme();
|
||||||
const content = theme.getBuffer(SwaggerThemeNameEnum.ONE_DARK);
|
const content = theme.getBuffer(SwaggerThemeNameEnum.ONE_DARK);
|
||||||
|
|
||||||
await fastify.register(fastifySwaggerUi, {
|
function getSwaggerUiObject(indexPrefix: string): FastifySwaggerUiOptions {
|
||||||
|
return {
|
||||||
routePrefix: "/docs",
|
routePrefix: "/docs",
|
||||||
indexPrefix: `${Config.env_dev ? "" : "/api"}`,
|
indexPrefix: indexPrefix,
|
||||||
uiConfig: {
|
uiConfig: {
|
||||||
docExpansion: "list",
|
docExpansion: "list",
|
||||||
deepLinking: false,
|
deepLinking: false,
|
||||||
@@ -68,9 +102,15 @@ await fastify.register(fastifySwaggerUi, {
|
|||||||
theme: {
|
theme: {
|
||||||
css: [{ filename: "theme.css", content: content }],
|
css: [{ filename: "theme.css", content: content }],
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
|
||||||
await fastify.register(fastifyAxios, {
|
await publicServer.register(fastifySwaggerUi, getSwaggerUiObject("/api"));
|
||||||
|
await privateServer.register(fastifySwaggerUi, getSwaggerUiObject(""));
|
||||||
|
|
||||||
|
// axios
|
||||||
|
function getAxiosConfig(): FastifyAxiosOptions {
|
||||||
|
return {
|
||||||
clients: {
|
clients: {
|
||||||
grist: {
|
grist: {
|
||||||
baseURL: Config.grist.api_url,
|
baseURL: Config.grist.api_url,
|
||||||
@@ -88,17 +128,22 @@ await fastify.register(fastifyAxios, {
|
|||||||
baseURL: `${Config.tidal.address}`,
|
baseURL: `${Config.tidal.address}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
|
||||||
await fastify.register(fastifyWebsocket);
|
await privateServer.register(fastifyAxios, getAxiosConfig());
|
||||||
|
|
||||||
const gristClient = new GristClient(fastify.axios.grist);
|
// Websockets
|
||||||
|
await publicServer.register(fastifyWebsocket);
|
||||||
|
|
||||||
|
// Clients and Services
|
||||||
|
const gristClient = new GristClient(privateServer.axios.grist);
|
||||||
const gristService = new GristService(gristClient);
|
const gristService = new GristService(gristClient);
|
||||||
|
|
||||||
const haClient = new HomeAssistantClient(fastify.axios.homeassistant);
|
const haClient = new HomeAssistantClient(privateServer.axios.homeassistant);
|
||||||
const haService = new HomeAssistantService(haClient);
|
const haService = new HomeAssistantService(haClient);
|
||||||
|
|
||||||
const tidalClient = new TidalClient(fastify.axios.tidal);
|
const tidalClient = new TidalClient(privateServer.axios.tidal);
|
||||||
const tidalService = new TidalService(tidalClient);
|
const tidalService = new TidalService(tidalClient);
|
||||||
|
|
||||||
const wsService = new WsService();
|
const wsService = new WsService();
|
||||||
@@ -122,21 +167,45 @@ async function verifyAPIKey(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const port = parseInt(Config.port, 10);
|
|
||||||
|
|
||||||
// Register routes
|
// Register routes
|
||||||
await fastify.register(gristRoutes, { gristService });
|
await publicServer.register(publicWsRoutes, { wsService });
|
||||||
await fastify.register(homeAssistantRoutes, { haService, verifyAPIKey });
|
await publicServer.register(publicHomepageRoutes, {
|
||||||
await fastify.register(tidalRoutes, { tidalService, verifyAPIKey });
|
hpService,
|
||||||
await fastify.register(wsRoutes, { wsService });
|
});
|
||||||
await fastify.register(homepageRoutes, {
|
|
||||||
|
await privateServer.register(privateGristRoutes, { gristService });
|
||||||
|
await privateServer.register(privateHomeAssistantRoutes, {
|
||||||
|
haService,
|
||||||
|
verifyAPIKey,
|
||||||
|
});
|
||||||
|
await privateServer.register(privateTidalRoutes, {
|
||||||
|
tidalService,
|
||||||
|
verifyAPIKey,
|
||||||
|
});
|
||||||
|
await privateServer.register(privateHomepageRoutes, {
|
||||||
hpService,
|
hpService,
|
||||||
gristService,
|
gristService,
|
||||||
haService,
|
haService,
|
||||||
verifyAPIKey,
|
verifyAPIKey,
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.get(
|
// Ping Routes
|
||||||
|
publicServer.get(
|
||||||
|
"/ping",
|
||||||
|
{
|
||||||
|
schema: {
|
||||||
|
description: "Health check endpoint",
|
||||||
|
tags: ["default"],
|
||||||
|
response: {
|
||||||
|
200: z.literal("pong"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async (_request, _reply) => {
|
||||||
|
return "pong" as const;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
privateServer.get(
|
||||||
"/ping",
|
"/ping",
|
||||||
{
|
{
|
||||||
schema: {
|
schema: {
|
||||||
@@ -152,8 +221,20 @@ fastify.get(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
await fastify.ready();
|
const port = parseInt(Config.port, 10);
|
||||||
fastify.listen({ port: port, host: "0.0.0.0" }, (err, address) => {
|
const publicPort = port + 1;
|
||||||
|
|
||||||
|
await publicServer.ready();
|
||||||
|
await privateServer.ready();
|
||||||
|
|
||||||
|
publicServer.listen({ port: publicPort, host: "0.0.0.0" }, (err, address) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log(`Server listening at ${address}`);
|
||||||
|
});
|
||||||
|
privateServer.listen({ port: port, host: "0.0.0.0" }, (err, address) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import type { TidalService } from "../tidal/service.js";
|
import type { TidalService } from "./service.js";
|
||||||
|
|
||||||
export async function tidalRoutes(
|
export async function privateTidalRoutes(
|
||||||
fastify: FastifyInstance,
|
fastify: FastifyInstance,
|
||||||
{
|
{
|
||||||
tidalService,
|
tidalService,
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { logInfo, type WsService } from "@dpu/shared";
|
import { logInfo, type WsService } from "@dpu/shared";
|
||||||
import type { FastifyInstance } from "fastify";
|
import type { FastifyInstance } from "fastify";
|
||||||
|
|
||||||
export async function wsRoutes(
|
export async function publicWsRoutes(
|
||||||
fastify: FastifyInstance,
|
fastify: FastifyInstance,
|
||||||
{
|
{
|
||||||
wsService,
|
wsService,
|
||||||
Reference in New Issue
Block a user