feat: add native fnOS gateway socket and base path support
CI / verify (push) Canceled after 0s

This commit is contained in:
2026-10-02 14:59:57 +08:00
parent c5502b0f95
commit 419c205103
7 changed files with 69 additions and 9 deletions
+6
View File
@@ -0,0 +1,6 @@
export const APP_BASE = import.meta.env.BASE_URL.replace(/\/$/, '')
export function withBase(path: string): string {
if (!path.startsWith('/')) return path
return `${APP_BASE}${path}`
}
+7 -6
View File
@@ -51,6 +51,7 @@ import type {
CfPreflightResult,
CfRouteTestResult,
} from './types'
import { withBase } from './base'
export function asList<T>(value: T[] | null | undefined): T[] {
return Array.isArray(value) ? value : []
@@ -79,7 +80,7 @@ async function request<T>(path: string, init?: RequestInit, timeoutMs = REQUEST_
}
async function requestWithSignal<T>(path: string, init?: RequestInit, signal?: AbortSignal): Promise<T> {
const response = await fetch(path, {
const response = await fetch(withBase(path), {
credentials: 'include',
signal,
headers: {
@@ -179,7 +180,7 @@ export const api = {
email: payload.email ?? '',
}),
}),
certificateApplyStreamURL: (jobId: string) => `/api/certificates/jobs/${encodeURIComponent(jobId)}/stream`,
certificateApplyStreamURL: (jobId: string) => withBase(`/api/certificates/jobs/${encodeURIComponent(jobId)}/stream`),
importCertificate: (payload: {
certificate?: string
private_key?: string
@@ -192,7 +193,7 @@ export const api = {
}),
async downloadCertificate(domain: string, part: 'zip' | 'cert' | 'key' = 'zip') {
const response = await fetch(
`/api/certificates/${encodeURIComponent(domain)}/download?part=${part}`,
withBase(`/api/certificates/${encodeURIComponent(domain)}/download?part=${part}`),
{ credentials: 'include' },
)
if (!response.ok) {
@@ -432,7 +433,7 @@ export const api = {
},
async exportBackup() {
const response = await fetch('/api/backup/export', { credentials: 'include' })
const response = await fetch(withBase('/api/backup/export'), { credentials: 'include' })
if (!response.ok) {
throw new Error('导出备份失败')
}
@@ -454,7 +455,7 @@ export const api = {
deleteBackupArchive: (name: string) =>
request<{ ok: boolean }>(`/api/backup/archives/${encodeURIComponent(name)}`, { method: 'DELETE' }),
async downloadBackupArchive(name: string) {
const response = await fetch(`/api/backup/archives/${encodeURIComponent(name)}`, { credentials: 'include' })
const response = await fetch(withBase(`/api/backup/archives/${encodeURIComponent(name)}`), { credentials: 'include' })
if (!response.ok) {
throw new Error('下载备份失败')
}
@@ -470,7 +471,7 @@ export const api = {
async restoreBackup(file: File) {
const form = new FormData()
form.append('file', file)
const response = await fetch('/api/backup/restore', {
const response = await fetch(withBase('/api/backup/restore'), {
method: 'POST',
credentials: 'include',
body: form,
+1 -1
View File
@@ -17,7 +17,7 @@ import StatusPageView from '../views/StatusPageView.vue'
import AboutView from '../views/AboutView.vue'
const router = createRouter({
history: createWebHistory(),
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{ path: '/setup', redirect: '/login' },
{ path: '/login', name: 'login', component: LoginView, meta: { public: true } },
+2 -1
View File
@@ -912,6 +912,7 @@ import {
WarningOutline,
} from '@vicons/ionicons5'
import { api, asList } from '../api/client'
import { withBase } from '../api/base'
import type { CfTunnel, DiscoveredService, ProxyClientConn, ProxyRule, ProxySavePayload, ProxyTraffic } from '../api/types'
import { useVisibilityPolling } from '../composables/useVisibilityPolling'
import EmptyState from '../components/EmptyState.vue'
@@ -1835,7 +1836,7 @@ function stopLogStream() {
function startLogStream() {
const rule = selectedRule.value
if (!rule || logEventSource) return
logEventSource = new EventSource(`/api/proxies/${rule.id}/logs/stream?tail=100`, {
logEventSource = new EventSource(withBase(`/api/proxies/${rule.id}/logs/stream?tail=100`), {
withCredentials: true,
})
logEventSource.addEventListener('log', (event) => {