922a57fe34
Self-hosted 開源:WASM 零件 + recipe + cypher-executor,跑在你自己的 Cloudflare。 此為重建的乾淨歷史起點(移除曾誤 commit 的 GCP SA 金鑰,舊歷史保留在 richblack/arcrun 與本地 backup 分支)。含: - acr init --self-hosted installer(建 KV/R2 + codeload 拉預編譯 wasm + wrangler deploy + seed recipe) - recipe push 把關(資料外流提醒 + 打通檢查) - 19 個正當零件預編譯 wasm(claude_api/km_writer/kbdb_upsert_block 排除:違反 DECISIONS §1) - CLI / cypher-executor / registry / 完整 SDD Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
101 lines
3.5 KiB
TypeScript
101 lines
3.5 KiB
TypeScript
'use client';
|
||
|
||
import { useEffect, useRef } from 'react';
|
||
import Link from 'next/link';
|
||
import SiteNav from '../components/SiteNav';
|
||
|
||
const API_BASE = process.env.NEXT_PUBLIC_API_BASE ?? 'https://cypher.arcrun.dev';
|
||
|
||
export default function ApiDocsPage() {
|
||
const containerRef = useRef<HTMLDivElement>(null);
|
||
const initialized = useRef(false);
|
||
|
||
useEffect(() => {
|
||
if (initialized.current || !containerRef.current) return;
|
||
initialized.current = true;
|
||
|
||
// Dynamically load Swagger UI from CDN
|
||
const link = document.createElement('link');
|
||
link.rel = 'stylesheet';
|
||
link.href = 'https://unpkg.com/swagger-ui-dist@5/swagger-ui.css';
|
||
document.head.appendChild(link);
|
||
|
||
const script = document.createElement('script');
|
||
script.src = 'https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js';
|
||
script.onload = () => {
|
||
const SwaggerUIBundle = (window as unknown as { SwaggerUIBundle: (opts: unknown) => void }).SwaggerUIBundle;
|
||
if (!SwaggerUIBundle || !containerRef.current) return;
|
||
SwaggerUIBundle({
|
||
url: `${API_BASE}/openapi.json`,
|
||
dom_id: '#swagger-ui',
|
||
presets: [(window as unknown as { SwaggerUIBundle: { presets: { apis: unknown } } }).SwaggerUIBundle.presets.apis],
|
||
layout: 'BaseLayout',
|
||
defaultModelsExpandDepth: -1,
|
||
docExpansion: 'list',
|
||
filter: true,
|
||
tryItOutEnabled: true,
|
||
supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch'],
|
||
requestInterceptor: (request: { headers: Record<string, string> }) => {
|
||
// Inject API key from localStorage if present
|
||
const key = localStorage.getItem('arcrun_api_key');
|
||
if (key) request.headers['X-Arcrun-API-Key'] = key;
|
||
return request;
|
||
},
|
||
});
|
||
};
|
||
document.head.appendChild(script);
|
||
|
||
return () => {
|
||
// cleanup not strictly needed for page navigation
|
||
};
|
||
}, []);
|
||
|
||
return (
|
||
<div className="min-h-screen bg-[#0a0a0a] text-[#ededed]">
|
||
<SiteNav currentPath="/api-docs" />
|
||
|
||
{/* Header */}
|
||
<div className="max-w-5xl mx-auto px-6 py-8">
|
||
<h1 className="text-2xl font-bold text-white mb-2">API Reference</h1>
|
||
<p className="text-[#555] text-sm mb-2">
|
||
這是 arcrun 的原始 API。Python / JS lib 是它的包裝,任何能發 HTTP request 的工具都能直接用。
|
||
</p>
|
||
<p className="text-[#444] text-xs mb-6">
|
||
Endpoint: <span className="font-mono text-[#666]">{API_BASE}</span>
|
||
</p>
|
||
|
||
{/* API Key hint */}
|
||
<div className="bg-[#111] border border-[#222] rounded-lg p-4 mb-8 text-sm">
|
||
<p className="text-[#666] mb-2">
|
||
若要在此頁面試打 API,請先設定 API Key:
|
||
</p>
|
||
<ApiKeyInput />
|
||
</div>
|
||
|
||
{/* Swagger UI */}
|
||
<div className="bg-white rounded-xl overflow-hidden" ref={containerRef}>
|
||
<div id="swagger-ui" className="min-h-96"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
function ApiKeyInput() {
|
||
return (
|
||
<div className="flex gap-2">
|
||
<input
|
||
type="text"
|
||
placeholder="ak_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||
className="flex-1 bg-[#0a0a0a] border border-[#2a2a2a] rounded px-3 py-1.5 text-xs font-mono text-[#cdd6f4] focus:outline-none focus:border-indigo-700"
|
||
onChange={(e) => {
|
||
if (e.target.value.startsWith('ak_')) {
|
||
localStorage.setItem('arcrun_api_key', e.target.value);
|
||
}
|
||
}}
|
||
/>
|
||
<span className="text-[#444] text-xs self-center">自動注入到 requests</span>
|
||
</div>
|
||
);
|
||
}
|