diff --git a/api/drizzle/0003_perfect_diamondback.sql b/api/drizzle/0003_perfect_diamondback.sql new file mode 100644 index 000000000..6a55409b7 --- /dev/null +++ b/api/drizzle/0003_perfect_diamondback.sql @@ -0,0 +1,6 @@ +CREATE TABLE `app_routes` ( + `id` integer PRIMARY KEY NOT NULL, + `method` text, + `path` text, + `handler` text +); diff --git a/api/drizzle/meta/0003_snapshot.json b/api/drizzle/meta/0003_snapshot.json new file mode 100644 index 000000000..d11a8a361 --- /dev/null +++ b/api/drizzle/meta/0003_snapshot.json @@ -0,0 +1,241 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "df4df4a0-817f-4821-a227-eb835f202a24", + "prevId": "f705eb7e-cb1a-4814-bfac-f1aa5d8e181f", + "tables": { + "app_routes": { + "name": "app_routes", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "method": { + "name": "method", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "handler": { + "name": "handler", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "github_issues": { + "name": "github_issues", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "repo": { + "name": "repo", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "state": { + "name": "state", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "labels": { + "name": "labels", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "closed_at": { + "name": "closed_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "mizu_logs": { + "name": "mizu_logs", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "level": { + "name": "level", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "timestamp": { + "name": "timestamp", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "trace_id": { + "name": "trace_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "service": { + "name": "service", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ignored": { + "name": "ignored", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "args": { + "name": "args", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "caller_location": { + "name": "caller_location", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "matching_issues": { + "name": "matching_issues", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/api/drizzle/meta/_journal.json b/api/drizzle/meta/_journal.json index 1572d9c77..88536e386 100644 --- a/api/drizzle/meta/_journal.json +++ b/api/drizzle/meta/_journal.json @@ -22,6 +22,13 @@ "when": 1717696888892, "tag": "0002_fearless_shocker", "breakpoints": true + }, + { + "idx": 3, + "version": "6", + "when": 1718119090229, + "tag": "0003_perfect_diamondback", + "breakpoints": true } ] } \ No newline at end of file diff --git a/api/src/db/schema.ts b/api/src/db/schema.ts index 415b7eb6a..b02c3496a 100644 --- a/api/src/db/schema.ts +++ b/api/src/db/schema.ts @@ -11,6 +11,19 @@ type OctokitResponseGithubIssues = type OctokitGithubIssue = OctokitResponseGithubIssues["data"][number]; +export const appRoutes = sqliteTable("app_routes", { + id: integer("id", { mode: "number" }).primaryKey(), + method: text("method", { mode: "text" }), + path: text("path", { mode: "text" }), + handler: text("handler", { mode: "text" }), +}); + +export const appRoutesSelectSchema = createSelectSchema(appRoutes); +export const appRoutesInsertSchema = createInsertSchema(appRoutes); + +export type AppRoute = z.infer; +export type NewAppRoute = z.infer; + // HELPFUL: https://orm.drizzle.team/docs/column-types/sqlite export const mizuLogs = sqliteTable("mizu_logs", { id: integer("id", { mode: "number" }).primaryKey({ autoIncrement: true }), diff --git a/api/src/routes/logs.ts b/api/src/routes/logs.ts index 04004b1e2..eb8f16bc6 100644 --- a/api/src/routes/logs.ts +++ b/api/src/routes/logs.ts @@ -4,6 +4,7 @@ import { Hono } from "hono"; import { cors } from "hono/cors"; import { z } from "zod"; import * as schema from "../db/schema.js"; +import { appRoutes } from "../db/schema.js"; import type { Bindings, Variables } from "../lib/types.js"; import { tryParseJsonObjectMessage } from "../lib/utils.js"; @@ -29,9 +30,32 @@ const schemaPostLogs = z.object({ }) .nullable(), timestamp: z.string(), + routes: z.array( + z.object({ method: z.string(), path: z.string(), handler: z.string() }), + ), }); app.post("/v0/logs", zValidator("json", schemaPostLogs), async (ctx) => { + const routeInspectorHeader = ctx.req.header("X-Fpx-Route-Inspector"); + if (routeInspectorHeader) { + // parse routes and insert them into the database + const { routes } = ctx.req.valid("json"); + + if (routes.length > 0) { + const db = ctx.get("db"); + const dbErrors = ctx.get("dbErrors"); + try { + await db.insert(appRoutes).values(routes); + } catch (error) { + if (error instanceof Error) { + console.log("DB ERROR FOR:", { routes }, error); + dbErrors.push(error); + } + } + } + + return ctx.text("OK"); + } const { level, service, message, args, traceId, callerLocation, timestamp } = ctx.req.valid("json");