chore(oss): audit the server package and resync the SDK mirrors

Split the 657-line operation service into eor, submit, and verify
modules, add the AGENT_REVOKED and KEY_RETIRED codes the Backend already
emits, and condense every multi-line comment. Mirror Node, Python, and
Go at 2.1.0 with the deep-health 503, non-idempotent retry, rotation
grace, and path-encoding fixes. Document which routes and response
fields the self-hosted server does not provide.

Claude-Session: https://claude.ai/code/session_01Agoc9bRVE9KL7mmWtey9Vq
This commit is contained in:
雷电芽衣 committed 2026-09-03 20:48:20 -04:00
1 parent 2010175a82
commit bc6983a62e
364 files changed
+10180 -23349

No files matched your search

+1 -8
View File
@@ -1,11 +1,4 @@
/**
* Authentication middleware for opaque API tokens and Better Auth sessions.
*
* A bearer value is resolved as a hashed API token first; anything else is
* validated as a Better Auth session (cookie or bearer session token).
* On success the org_id, role, actor, and credential kind are stored in the
* Hono context variables for downstream handlers.
*/
/** Authentication middleware for opaque API tokens and Better Auth sessions. */
import type { MiddlewareHandler } from 'hono';
import type { RbacRole } from '../shared/index.js';
+10 -52
View File
@@ -1,15 +1,4 @@
/**
* Global error handler middleware.
*
* Catches all uncaught exceptions and formats them as a standardized
* ErrorResponse with the appropriate HTTP status code, error code,
* and the request's unique identifier for tracing.
*
* When an AppError carries a `messageKey`, the handler resolves it to
* the correct language using the `lang` context variable set by the
* i18n middleware. This allows services to throw errors with i18n keys
* without needing direct access to the Hono context.
*/
/** Global error handler middleware. */
import type { ErrorHandler } from 'hono';
import type { ErrorCode, ErrorResponse } from '../shared/index.js';
@@ -18,18 +7,14 @@ import type { Env, AppVariables } from '../types.js';
import { getMessage } from '../i18n/messages.js';
import type { Lang } from '../i18n/messages.js';
/**
* Maps each ErrorCode to its corresponding i18n message key.
*
* This is used when an AppError is thrown with only an error code
* (no explicit message or i18n key), so the global error handler
* can still resolve a translated default message.
*/
/** Maps each ErrorCode to its corresponding i18n message key. */
const ERROR_CODE_TO_I18N_KEY: Record<ErrorCode, string> = {
INVALID_SIGNATURE: 'error.invalidSignature',
UNKNOWN_AGENT: 'error.unknownAgent',
KEY_REVOKED: 'error.keyRevoked',
KEY_RETIRED: 'error.keyRetired',
AGENT_FROZEN: 'error.agentFrozen',
AGENT_REVOKED: 'error.agentRevoked',
TTL_EXPIRED: 'error.ttlExpired',
REPLAY_DETECTED: 'error.replayDetected',
PREV_HASH_MISMATCH: 'error.prevHashMismatch',
@@ -42,16 +27,7 @@ const ERROR_CODE_TO_I18N_KEY: Record<ErrorCode, string> = {
VALIDATION_ERROR: 'error.validationError',
};
/**
* Custom error class that carries an HTTP status and Elydora error code.
*
* Supports three modes:
* 1. Code-only: `new AppError(status, code)` — uses ErrorCode default message
* 2. i18n key: `new AppError(status, code, { key: 'msg.key', params: {...} })` —
* the message is resolved at response time from the translation map
* 3. Raw string: `new AppError(status, code, 'raw message')` — message is used as-is
* (should be avoided in new code; prefer mode 2)
*/
/** Custom error class that carries an HTTP status and Elydora error code. */
export class AppError extends Error {
public readonly statusCode: number;
public readonly errorCode: ErrorCode;
@@ -68,13 +44,13 @@ export class AppError extends Error {
details?: Record<string, unknown>,
) {
if (typeof messageOrOpts === 'object' && messageOrOpts !== null) {
// i18n mode — store the key; resolve later in the error handler
// i18n mode: store the key; resolve later in the error handler
super(getMessage(messageOrOpts.key, 'en', messageOrOpts.params));
this.messageKey = messageOrOpts.key;
this.messageParams = messageOrOpts.params;
this.usesDefaultMessage = false;
} else if (messageOrOpts === undefined) {
// Code-only mode — will be resolved via ERROR_CODE_TO_I18N_KEY
// Code-only mode: will be resolved via ERROR_CODE_TO_I18N_KEY
super(ERROR_CODES[errorCode]);
this.usesDefaultMessage = true;
} else {
@@ -88,15 +64,7 @@ export class AppError extends Error {
this.details = details;
}
/**
* Resolve the user-facing message for a given language.
*
* Resolution order:
* 1. If a messageKey was provided, use that with the translation map.
* 2. If the error used the default ErrorCode message, translate via
* the ERROR_CODE_TO_I18N_KEY mapping.
* 3. Otherwise return the raw message string.
*/
/** Resolve the user-facing message for a given language. */
resolveMessage(lang: Lang): string {
if (this.messageKey) {
return getMessage(this.messageKey, lang, this.messageParams);
@@ -111,12 +79,7 @@ export class AppError extends Error {
}
}
/**
* Build a standardised error response body.
*
* When `lang` is provided and no explicit `message` is given, the
* ErrorCode default message is resolved from the translation map.
*/
/** Build a standardised error response body. */
export function buildErrorResponse(
code: ErrorCode,
requestId: string,
@@ -139,12 +102,7 @@ export function buildErrorResponse(
};
}
/**
* Hono error handler that converts all errors into the ErrorResponse format.
*
* Resolves i18n message keys using the `lang` context variable set by
* the i18n middleware.
*/
/** Hono error handler that converts all errors into the ErrorResponse format. */
export const globalErrorHandler: ErrorHandler<{
Bindings: Env;
Variables: AppVariables;
+1 -8
View File
@@ -1,11 +1,4 @@
/**
* i18n middleware — language detection from Accept-Language header.
*
* Reads the Accept-Language request header, detects the preferred
* language (English or Chinese), and stores it in the Hono context
* so that all downstream handlers and services can access it via
* `c.get('lang')`.
*/
/** i18n middleware: language detection from Accept-Language header. */
import type { MiddlewareHandler } from 'hono';
import type { Env, AppVariables } from '../types.js';
+4 -27
View File
@@ -1,25 +1,11 @@
/**
* Role-based access control (RBAC) middleware.
*
* The Elydora console defines five roles with a clear privilege hierarchy:
*
* org_owner > security_admin > compliance_auditor > readonly_investigator
* integration_engineer (parallel to compliance_auditor, agent-management focused)
*
* This middleware checks whether the role extracted by the auth middleware
* satisfies the minimum required role for a given route.
*/
/** Role-based access control (RBAC) middleware. */
import type { MiddlewareHandler } from 'hono';
import type { RbacRole } from '../shared/index.js';
import type { Env, AppVariables } from '../types.js';
import { AppError } from './error-handler.js';
/**
* Privilege level map. Higher number = more privilege.
* integration_engineer is a special role with limited admin capabilities
* for agent management only.
*/
/** Privilege level map. */
const ROLE_LEVEL: Record<RbacRole, number> = {
readonly_investigator: 10,
integration_engineer: 20,
@@ -28,21 +14,12 @@ const ROLE_LEVEL: Record<RbacRole, number> = {
org_owner: 50,
};
/**
* Check if a role has at least the given privilege level.
*/
/** Check if a role has at least the given privilege level. */
function hasMinimumRole(userRole: RbacRole, requiredRole: RbacRole): boolean {
return ROLE_LEVEL[userRole] >= ROLE_LEVEL[requiredRole];
}
/**
* Create an RBAC middleware that requires a minimum role.
*
* Usage:
* app.post('/v1/agents/:id/freeze', requireRole('security_admin'), handler);
*
* @param minimumRole - The minimum RBAC role required to access the endpoint
*/
/** Create an RBAC middleware that requires a minimum role. */
export function requireRole(minimumRole: RbacRole): MiddlewareHandler<{
Bindings: Env;
Variables: AppVariables;
+1 -7
View File
@@ -1,10 +1,4 @@
/**
* Request ID middleware.
*
* Generates a UUIDv7 for every incoming request and stores it in the
* Hono context variables. The ID is also set as the X-Request-Id
* response header so clients can reference it when reporting issues.
*/
/** Request ID middleware. */
import type { MiddlewareHandler } from 'hono';
import type { Env, AppVariables } from '../types.js';