refactor: adopt CorePHP lifecycle event patterns in all Mod modules
All 6 Mod modules now use $event->routes() and $event->views() instead
of raw Route:: and app('view')-> calls. Service singletons moved to
FrameworkBooted where appropriate. Website/Api module added for
api.lthn.io domain with proper DomainResolving.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f1b741da49
commit
646fb0602f
11 changed files with 217 additions and 40 deletions
|
|
@ -14,13 +14,12 @@ class Boot
|
|||
WebRoutesRegistering::class => 'onBoot',
|
||||
];
|
||||
|
||||
public function onBoot(): void
|
||||
public function onBoot(WebRoutesRegistering $event): void
|
||||
{
|
||||
app('config')->set('chain', require __DIR__ . '/config.php');
|
||||
app()->singleton(DaemonRpc::class);
|
||||
app()->singleton(WalletRpc::class);
|
||||
|
||||
// Register API auth middleware
|
||||
app('router')->aliasMiddleware('auth.api', \App\Http\Middleware\ApiTokenAuth::class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,12 @@ class Boot
|
|||
WebRoutesRegistering::class => 'onWebRoutes',
|
||||
];
|
||||
|
||||
public function onWebRoutes(): void
|
||||
public function onWebRoutes(WebRoutesRegistering $event): void
|
||||
{
|
||||
app('view')->addNamespace('explorer', __DIR__ . '/Views');
|
||||
Route::prefix('explorer')->group(__DIR__ . '/Routes/web.php');
|
||||
Route::prefix('v1/explorer')->group(__DIR__ . '/Routes/api.php');
|
||||
$event->views('explorer', __DIR__ . '/Views');
|
||||
$event->routes(function () {
|
||||
Route::prefix('explorer')->group(__DIR__ . '/Routes/web.php');
|
||||
Route::prefix('v1/explorer')->group(__DIR__ . '/Routes/api.php');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Mod\Gateway;
|
||||
|
||||
use Core\Events\FrameworkBooted;
|
||||
use Core\Events\WebRoutesRegistering;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Mod\Gateway\Services\GatewayRegistry;
|
||||
|
|
@ -12,11 +13,16 @@ class Boot
|
|||
{
|
||||
public static array $listens = [
|
||||
WebRoutesRegistering::class => 'onWebRoutes',
|
||||
FrameworkBooted::class => 'onFrameworkBooted',
|
||||
];
|
||||
|
||||
public function onWebRoutes(): void
|
||||
public function onWebRoutes(WebRoutesRegistering $event): void
|
||||
{
|
||||
$event->routes(fn () => Route::prefix('v1/gateway')->group(__DIR__ . '/Routes/api.php'));
|
||||
}
|
||||
|
||||
public function onFrameworkBooted(FrameworkBooted $event): void
|
||||
{
|
||||
app()->singleton(GatewayRegistry::class);
|
||||
Route::prefix('v1/gateway')->group(__DIR__ . '/Routes/api.php');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace Mod\Names;
|
||||
|
||||
use Core\Events\ApiRoutesRegistering;
|
||||
use Core\Events\ConsoleBooting;
|
||||
use Core\Events\WebRoutesRegistering;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
|
@ -17,20 +16,17 @@ class Boot
|
|||
ConsoleBooting::class => 'onConsole',
|
||||
];
|
||||
|
||||
public function onWebRoutes(): void
|
||||
public function onWebRoutes(WebRoutesRegistering $event): void
|
||||
{
|
||||
app('view')->addNamespace('names', __DIR__ . '/Views');
|
||||
Route::prefix('v1/names')->group(__DIR__ . '/Routes/api.php');
|
||||
Route::prefix('names')->group(__DIR__ . '/Routes/web.php');
|
||||
$event->views('names', __DIR__ . '/Views');
|
||||
$event->routes(function () {
|
||||
Route::prefix('names')->group(__DIR__ . '/Routes/web.php');
|
||||
Route::prefix('v1/names')->group(__DIR__ . '/Routes/api.php');
|
||||
});
|
||||
}
|
||||
|
||||
public function onConsole(ConsoleBooting $event): void
|
||||
{
|
||||
$event->command(RetryDnsTickets::class);
|
||||
}
|
||||
|
||||
public function onApiRoutes(): void
|
||||
{
|
||||
Route::prefix('v1/names')->group(__DIR__ . '/Routes/api.php');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Mod\Pool;
|
||||
|
||||
use Core\Events\ApiRoutesRegistering;
|
||||
use Core\Events\FrameworkBooted;
|
||||
use Core\Events\WebRoutesRegistering;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Mod\Pool\Services\PoolClient;
|
||||
|
|
@ -13,19 +13,20 @@ class Boot
|
|||
{
|
||||
public static array $listens = [
|
||||
WebRoutesRegistering::class => 'onWebRoutes',
|
||||
|
||||
FrameworkBooted::class => 'onFrameworkBooted',
|
||||
];
|
||||
|
||||
public function onWebRoutes(): void
|
||||
public function onWebRoutes(WebRoutesRegistering $event): void
|
||||
{
|
||||
$event->routes(function () {
|
||||
Route::prefix('pool')->group(__DIR__ . '/Routes/web.php');
|
||||
Route::prefix('v1/pool')->group(__DIR__ . '/Routes/api.php');
|
||||
});
|
||||
}
|
||||
|
||||
public function onFrameworkBooted(FrameworkBooted $event): void
|
||||
{
|
||||
app()->singleton(PoolClient::class);
|
||||
app('config')->set('pool', require __DIR__ . '/config.php');
|
||||
Route::prefix('v1/pool')->group(__DIR__ . '/Routes/api.php');
|
||||
Route::prefix('pool')->group(__DIR__ . '/Routes/web.php');
|
||||
}
|
||||
|
||||
public function onApiRoutes(): void
|
||||
{
|
||||
Route::prefix('v1/pool')->group(__DIR__ . '/Routes/api.php');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ class Boot
|
|||
WebRoutesRegistering::class => 'onWebRoutes',
|
||||
];
|
||||
|
||||
public function onWebRoutes(): void
|
||||
public function onWebRoutes(WebRoutesRegistering $event): void
|
||||
{
|
||||
Route::prefix('v1/proxy')->group(__DIR__ . '/Routes/api.php');
|
||||
$event->routes(fn () => Route::prefix('v1/proxy')->group(__DIR__ . '/Routes/api.php'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace Mod\Trade;
|
||||
|
||||
use Core\Events\ApiRoutesRegistering;
|
||||
use Core\Events\WebRoutesRegistering;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
|
|
@ -12,17 +11,13 @@ class Boot
|
|||
{
|
||||
public static array $listens = [
|
||||
WebRoutesRegistering::class => 'onWebRoutes',
|
||||
|
||||
];
|
||||
|
||||
public function onWebRoutes(): void
|
||||
public function onWebRoutes(WebRoutesRegistering $event): void
|
||||
{
|
||||
Route::prefix('v1/trade')->group(__DIR__ . '/Routes/api.php');
|
||||
Route::prefix('trade')->group(__DIR__ . '/Routes/web.php');
|
||||
}
|
||||
|
||||
public function onApiRoutes(): void
|
||||
{
|
||||
Route::prefix('v1/trade')->group(__DIR__ . '/Routes/api.php');
|
||||
$event->routes(function () {
|
||||
Route::prefix('trade')->group(__DIR__ . '/Routes/web.php');
|
||||
Route::prefix('v1/trade')->group(__DIR__ . '/Routes/api.php');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
65
app/Website/Api/Boot.php
Normal file
65
app/Website/Api/Boot.php
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Website\Api;
|
||||
|
||||
use Core\Events\DomainResolving;
|
||||
use Core\Events\WebRoutesRegistering;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
/**
|
||||
* api.lthn.io — REST API homepage.
|
||||
*
|
||||
* When api.lthn.io is the resolved domain, serves an API reference
|
||||
* landing page at /. API endpoints themselves are registered by Mod
|
||||
* modules via ApiRoutesRegistering.
|
||||
*/
|
||||
class Boot extends ServiceProvider
|
||||
{
|
||||
public static array $domains = [
|
||||
'/^api\.lthn\.io$/',
|
||||
'/^api\.lthn\.sh$/',
|
||||
'/^api\.(test|localhost)$/',
|
||||
];
|
||||
|
||||
public static array $listens = [
|
||||
DomainResolving::class => 'onDomain',
|
||||
WebRoutesRegistering::class => 'onWebRoutes',
|
||||
];
|
||||
|
||||
public function register(): void {}
|
||||
|
||||
public function boot(): void
|
||||
{
|
||||
$this->loadViewsFrom(__DIR__ . '/Views', 'api');
|
||||
|
||||
foreach (static::$listens as $event => $method) {
|
||||
Event::listen($event, [$this, $method]);
|
||||
}
|
||||
}
|
||||
|
||||
public function onDomain(DomainResolving $event): void
|
||||
{
|
||||
foreach (static::$domains as $pattern) {
|
||||
if (preg_match($pattern, $event->domain)) {
|
||||
$event->resolve($this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function onWebRoutes(WebRoutesRegistering $event): void
|
||||
{
|
||||
$host = $_SERVER['HTTP_HOST'] ?? '';
|
||||
|
||||
foreach (static::$domains as $pattern) {
|
||||
if (preg_match($pattern, $host)) {
|
||||
$event->routes(fn () => Route::group([], __DIR__ . '/Routes/web.php'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
20
app/Website/Api/Controllers/ApiDocsController.php
Normal file
20
app/Website/Api/Controllers/ApiDocsController.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Website\Api\Controllers;
|
||||
|
||||
use Illuminate\Routing\Controller;
|
||||
|
||||
/**
|
||||
* api.lthn.io landing page.
|
||||
*
|
||||
* GET / — API reference and endpoint index
|
||||
*/
|
||||
class ApiDocsController extends Controller
|
||||
{
|
||||
public function index(): \Illuminate\View\View
|
||||
{
|
||||
return view('api::index');
|
||||
}
|
||||
}
|
||||
9
app/Website/Api/Routes/web.php
Normal file
9
app/Website/Api/Routes/web.php
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Website\Api\Controllers\ApiDocsController;
|
||||
|
||||
// Homepage — API reference (only serves on api.lthn.io domain)
|
||||
Route::get('/', [ApiDocsController::class, 'index'])->name('api.index');
|
||||
84
app/Website/Api/Views/index.blade.php
Normal file
84
app/Website/Api/Views/index.blade.php
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>.lthn API</title>
|
||||
<meta name="description" content="REST API for the Lethean .lthn TLD registrar — names, DNS, proxy, gateway, and blockchain explorer.">
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0}
|
||||
body{font-family:'Inter',-apple-system,BlinkMacSystemFont,sans-serif;background:#0a0e17;color:#e5e7eb;padding:2rem}
|
||||
.container{max-width:900px;margin:0 auto}
|
||||
h1{font-size:1.5rem;font-weight:600;margin-bottom:0.5rem}
|
||||
h2{font-size:1.1rem;font-weight:600;margin:2rem 0 0.75rem;color:#e5e7eb}
|
||||
p{color:#9ca3af;line-height:1.6;margin-bottom:1rem}
|
||||
a{color:#818cf8;text-decoration:none}
|
||||
a:hover{text-decoration:underline}
|
||||
code{background:#111827;padding:0.15rem 0.4rem;border-radius:0.25rem;font-size:0.85rem}
|
||||
table{width:100%;border-collapse:collapse;margin-bottom:1.5rem}
|
||||
th{text-align:left;padding:0.5rem;color:#6b7280;font-size:0.75rem;text-transform:uppercase;letter-spacing:0.05em;border-bottom:1px solid #1f2937}
|
||||
td{padding:0.5rem;border-bottom:1px solid #1f2937;font-size:0.85rem}
|
||||
.get{background:#065f46;color:#34d399;padding:0.15rem 0.5rem;border-radius:0.2rem;font-size:0.7rem;font-weight:600}
|
||||
.post{background:#78350f;color:#fbbf24;padding:0.15rem 0.5rem;border-radius:0.2rem;font-size:0.7rem;font-weight:600}
|
||||
.muted{color:#6b7280}
|
||||
.card{background:#111827;border:1px solid #1f2937;border-radius:0.5rem;padding:1rem;margin-bottom:1rem}
|
||||
.header{display:flex;align-items:baseline;gap:1rem;margin-bottom:1.5rem}
|
||||
.header .badge{background:rgba(52,211,153,0.15);color:#34d399;padding:0.25rem 0.75rem;border-radius:1rem;font-size:0.75rem;font-weight:500}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>.lthn API</h1>
|
||||
<span class="badge">v1</span>
|
||||
</div>
|
||||
<p>REST API for the Lethean .lthn TLD registrar. All endpoints return JSON when called with <code>Accept: application/json</code>.</p>
|
||||
<p>Base URL: <code>https://api.lthn.io/v1</code> · Website: <a href="https://lthn.io">lthn.io</a> · Full docs: <a href="https://lthn.io/docs">lthn.io/docs</a></p>
|
||||
|
||||
<h2>Names</h2>
|
||||
<table>
|
||||
<tr><th>Method</th><th>Endpoint</th><th>Description</th></tr>
|
||||
<tr><td><span class="get">GET</span></td><td><a href="/v1/names/available/darbs">/v1/names/available/{name}</a></td><td class="muted">Check availability</td></tr>
|
||||
<tr><td><span class="get">GET</span></td><td><a href="/v1/names/lookup/charon">/v1/names/lookup/{name}</a></td><td class="muted">Look up registered name</td></tr>
|
||||
<tr><td><span class="get">GET</span></td><td><a href="/v1/names/directory">/v1/names/directory</a></td><td class="muted">All names by type</td></tr>
|
||||
<tr><td><span class="get">GET</span></td><td><a href="/v1/names/search?q=ch">/v1/names/search?q={query}</a></td><td class="muted">Search names</td></tr>
|
||||
<tr><td><span class="post">POST</span></td><td>/v1/names/register</td><td class="muted">Register a name</td></tr>
|
||||
<tr><td><span class="post">POST</span></td><td>/v1/names/claim</td><td class="muted">Pre-register a claim</td></tr>
|
||||
<tr><td><span class="get">GET</span></td><td><a href="/v1/names/records/charon">/v1/names/records/{name}</a></td><td class="muted">DNS records</td></tr>
|
||||
<tr><td><span class="post">POST</span></td><td>/v1/names/records/{name}</td><td class="muted">Update DNS records</td></tr>
|
||||
<tr><td><span class="get">GET</span></td><td><a href="/v1/names/health">/v1/names/health</a></td><td class="muted">Registrar health</td></tr>
|
||||
</table>
|
||||
|
||||
<h2>Explorer</h2>
|
||||
<table>
|
||||
<tr><th>Method</th><th>Endpoint</th><th>Description</th></tr>
|
||||
<tr><td><span class="get">GET</span></td><td><a href="/v1/explorer/info">/v1/explorer/info</a></td><td class="muted">Chain info</td></tr>
|
||||
<tr><td><span class="get">GET</span></td><td><a href="/v1/explorer/stats">/v1/explorer/stats</a></td><td class="muted">Chain statistics</td></tr>
|
||||
<tr><td><span class="get">GET</span></td><td><a href="/v1/explorer/block/100">/v1/explorer/block/{id}</a></td><td class="muted">Block by height or hash</td></tr>
|
||||
<tr><td><span class="get">GET</span></td><td><a href="/v1/explorer/aliases">/v1/explorer/aliases</a></td><td class="muted">All chain aliases</td></tr>
|
||||
<tr><td><span class="get">GET</span></td><td><a href="/v1/explorer/alias/charon">/v1/explorer/alias/{name}</a></td><td class="muted">Alias details</td></tr>
|
||||
</table>
|
||||
|
||||
<h2>Proxy</h2>
|
||||
<table>
|
||||
<tr><th>Method</th><th>Endpoint</th><th>Description</th></tr>
|
||||
<tr><td><span class="get">GET</span></td><td><a href="/v1/proxy/status">/v1/proxy/status</a></td><td class="muted">Network availability + pricing</td></tr>
|
||||
<tr><td><span class="get">GET</span></td><td><a href="/v1/proxy/nodes">/v1/proxy/nodes</a></td><td class="muted">List nodes by capability</td></tr>
|
||||
<tr><td><span class="post">POST</span></td><td>/v1/proxy/connect</td><td class="muted">Get gateway connection</td></tr>
|
||||
</table>
|
||||
|
||||
<h2>Gateway</h2>
|
||||
<table>
|
||||
<tr><th>Method</th><th>Endpoint</th><th>Description</th></tr>
|
||||
<tr><td><span class="post">POST</span></td><td>/v1/gateway/pair</td><td class="muted">Pair a gateway node</td></tr>
|
||||
<tr><td><span class="post">POST</span></td><td>/v1/gateway/heartbeat</td><td class="muted">Report alive + stats</td></tr>
|
||||
<tr><td><span class="get">GET</span></td><td><a href="/v1/gateway/live">/v1/gateway/live</a></td><td class="muted">Live paired gateways</td></tr>
|
||||
</table>
|
||||
|
||||
<div class="card">
|
||||
<strong>Authentication</strong>
|
||||
<p style="margin-top:0.5rem">Read endpoints (GET) are public. Write endpoints (POST) require <code>Authorization: Bearer {token}</code>. Get keys at <a href="https://order.lthn.ai">order.lthn.ai</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Reference in a new issue