Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 59 additions & 17 deletions apps/dws/api/observability/routes.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { type WalletSignatureConfig, validateWalletSignatureFromHeaders } from '@jejunetwork/api'
import { getCurrentNetwork } from '@jejunetwork/config'
import { Elysia, t } from 'elysia'
import type { Address } from 'viem'
import {
Expand All @@ -17,6 +19,39 @@ export function createObservabilityRoutes(serviceName = 'dws') {
const tracer = getTracer(serviceName)
const alertManager = getAlertManager()
const healthChecker = getHealthChecker()
const walletSignatureConfig: WalletSignatureConfig = {
validityWindowMs: 5 * 60 * 1000,
}

async function requireWalletOwner(
headers: Record<string, string | undefined>,
): Promise<Address> {
const owner = (headers['x-jeju-address'] ??
headers['x-wallet-address']) as Address | undefined

if (!owner) {
throw new Error('Authentication required: x-jeju-address header missing')
}

if (getCurrentNetwork() === 'localnet') {
return owner
}

const result = await validateWalletSignatureFromHeaders(
{
'x-jeju-address': owner,
'x-jeju-timestamp': headers['x-jeju-timestamp'],
'x-jeju-signature': headers['x-jeju-signature'],
},
walletSignatureConfig,
)

if (!result.valid || !result.user?.address) {
throw new Error(result.error ?? 'Authentication required')
}

return result.user.address
}

// Register default health checks
healthChecker.register('database', async () => {
Expand Down Expand Up @@ -82,7 +117,8 @@ export function createObservabilityRoutes(serviceName = 'dws') {
// Write log entry (for external services)
.post(
'/',
({ body }) => {
async ({ body, headers }) => {
await requireWalletOwner(headers)
const level = body.level as LogLevel
const message = body.message as string
const attributes = (body.attributes ?? {}) as Record<
Expand Down Expand Up @@ -145,7 +181,8 @@ export function createObservabilityRoutes(serviceName = 'dws') {
// Record counter
.post(
'/counter',
({ body }) => {
async ({ body, headers }) => {
await requireWalletOwner(headers)
metrics.incCounter(body.name, body.labels ?? {}, body.value ?? 1)
return { success: true }
},
Expand All @@ -161,7 +198,8 @@ export function createObservabilityRoutes(serviceName = 'dws') {
// Record gauge
.post(
'/gauge',
({ body }) => {
async ({ body, headers }) => {
await requireWalletOwner(headers)
if (body.action === 'set') {
metrics.setGauge(body.name, body.labels ?? {}, body.value)
} else if (body.action === 'inc') {
Expand All @@ -188,7 +226,8 @@ export function createObservabilityRoutes(serviceName = 'dws') {
// Record histogram observation
.post(
'/histogram',
({ body }) => {
async ({ body, headers }) => {
await requireWalletOwner(headers)
metrics.observeHistogram(body.name, body.labels ?? {}, body.value)
return { success: true }
},
Expand Down Expand Up @@ -261,7 +300,8 @@ export function createObservabilityRoutes(serviceName = 'dws') {
// Start a new span
.post(
'/spans',
({ body }) => {
async ({ body, headers }) => {
await requireWalletOwner(headers)
const span = tracer.startSpan(body.name, {
kind: body.kind,
parentSpanId: body.parentSpanId,
Expand Down Expand Up @@ -298,7 +338,8 @@ export function createObservabilityRoutes(serviceName = 'dws') {
// End a span
.post(
'/spans/:spanId/end',
({ params, body }) => {
async ({ params, body, headers }) => {
await requireWalletOwner(headers)
tracer.endSpan(params.spanId, body.status)

const span = tracer.getSpan(params.spanId)
Expand All @@ -320,7 +361,8 @@ export function createObservabilityRoutes(serviceName = 'dws') {
// Add event to span
.post(
'/spans/:spanId/events',
({ params, body }) => {
async ({ params, body, headers }) => {
await requireWalletOwner(headers)
tracer.addEvent(params.spanId, body.name, body.attributes ?? {})
return { success: true }
},
Expand All @@ -340,7 +382,8 @@ export function createObservabilityRoutes(serviceName = 'dws') {
// Set span attribute
.post(
'/spans/:spanId/attributes',
({ params, body }) => {
async ({ params, body, headers }) => {
await requireWalletOwner(headers)
tracer.setAttribute(params.spanId, body.key, body.value)
return { success: true }
},
Expand All @@ -366,7 +409,8 @@ export function createObservabilityRoutes(serviceName = 'dws') {
// Create alert rule
.post(
'/rules',
({ body }) => {
async ({ body, headers }) => {
await requireWalletOwner(headers)
const rule = alertManager.addRule({
name: body.name,
expression: body.expression,
Expand Down Expand Up @@ -403,15 +447,17 @@ export function createObservabilityRoutes(serviceName = 'dws') {
)

// Delete alert rule
.delete('/rules/:ruleId', ({ params }) => {
.delete('/rules/:ruleId', async ({ params, headers }) => {
await requireWalletOwner(headers)
alertManager.removeRule(params.ruleId)
return { success: true }
})

// Enable/disable alert rule
.post(
'/rules/:ruleId/toggle',
({ params, body }) => {
async ({ params, body, headers }) => {
await requireWalletOwner(headers)
if (body.enabled) {
alertManager.enableRule(params.ruleId)
} else {
Expand Down Expand Up @@ -443,12 +489,8 @@ export function createObservabilityRoutes(serviceName = 'dws') {
})

// Acknowledge alert
.post('/:alertId/ack', ({ params, headers }) => {
const address = headers['x-wallet-address'] as Address
if (!address) {
return { error: 'Unauthorized' }
}

.post('/:alertId/ack', async ({ params, headers }) => {
const address = await requireWalletOwner(headers)
alertManager.acknowledgeAlert(params.alertId, address)
return { success: true }
}),
Expand Down