Something went wrong. Try again.
The IoT platform Cloudflare didn't build. Telemetry, realtime dashboards, and automations on Workers + D1 + R2 + Durable Objects — in your… nodrix.live
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657// Service-layer kernel: the transport-agnostic vocabulary (Actor, ServiceError)// plus its HTTP binding. Services throw ServiceError and take an Actor; HTTP// routes and MCP tools translate to their own wire format.
import type { Context } from 'hono';import type { ContentfulStatusCode } from 'hono/utils/http-status';import type { SessionUser } from '../middleware/require-session';
// Who is performing a call, independent of how they authenticated. HTTP builds// this from the Better Auth session; MCP builds it from the token's creator.export type ActorRole = 'owner' | 'admin' | 'member';export type Actor = { userId: string; role: ActorRole; source: 'http' | 'mcp' };
export function isInstanceAdmin(actor: Actor): boolean { return actor.role === 'owner' || actor.role === 'admin';}
export type ServiceErrorCode = 'bad_request' | 'unauthorized' | 'forbidden' | 'not_found' | 'conflict';
const STATUS: Record<ServiceErrorCode, number> = { bad_request: 400, unauthorized: 401, forbidden: 403, not_found: 404, conflict: 409,};
export class ServiceError extends Error { constructor(public code: ServiceErrorCode, message?: string, public reason?: string) { super(message ?? code); this.name = 'ServiceError'; } get status(): number { return STATUS[this.code]; }}
export function isServiceError(e: unknown): e is ServiceError { return e instanceof ServiceError;}
export function actorFromSession(user: SessionUser): Actor { return { userId: user.id, role: user.role, source: 'http' };}
// Maps a ServiceError to the JSON error shape the web client expects; re-throws// anything else so genuine bugs still surface as 500s.export function serviceErrorResponse(c: Context, e: unknown): Response { if (isServiceError(e)) { return c.json( e.reason ? { error: e.code, reason: e.reason } : { error: e.code }, e.status as ContentfulStatusCode ); } throw e;}