fix: finish 2.9.0 plugin moves and get every check green

This commit is contained in:
LukeGus committed 2026-09-24 23:35:18 -05:00
1 parent 8c1e02af89
commit 6489b62ece
335 files changed
+29878 -17749

No files matched your search

+1 -1
View File
@@ -6,7 +6,7 @@
"scripts": {
"build": "termix-plugin build",
"test": "termix-plugin test",
"typecheck": "tsc -p tsconfig.json",
"typecheck": "tsc -b ../../tsconfig.plugins.json ../../tsconfig.plugins.frontend.json",
"validate": "termix-plugin validate"
},
"devDependencies": {
@@ -12,6 +12,7 @@ import {
WifiOff,
} from "lucide-react";
import {
logActivity,
useHost,
useToast,
useTranslation,
@@ -253,6 +254,14 @@ export function TunnelTab({ host: given }: { host?: PluginHostRecord }) {
useEffect(() => subscribeTunnelStatuses(setStatuses), []);
// One recent-activity entry per host opened here.
const hostId = host?.id;
const hostLabel = host ? tunnelHostLabel(host) : "";
useEffect(() => {
if (typeof hostId !== "number") return;
logActivity("tunnel", hostId, hostLabel).catch(() => {});
}, [hostId]); // eslint-disable-line react-hooks/exhaustive-deps
if (!host) {
return (
<div className="flex flex-col items-center justify-center flex-1 gap-3 p-6 text-center">
+32 -17
View File
@@ -9,10 +9,24 @@ import type {
export type TunnelStatusMap = Record<string, TunnelStatus>;
let client: PluginApiClient | null = null;
let remoteClient: PluginApiClient | null = null;
let openStream: ((init: RequestInit) => Promise<Response>) | null = null;
export interface TunnelsTransport {
/** app.fetch for the status stream, which carries core's auth. */
stream?: (init: RequestInit) => Promise<Response>;
/** The connected remote server's client, on the desktop app. */
remote?: PluginApiClient | null;
}
/** Set from activate with app.api, cleared on deactivate. */
export function setTunnelsApi(api: PluginApiClient | null): void {
export function setTunnelsApi(
api: PluginApiClient | null,
transport: TunnelsTransport = {},
): void {
client = api;
remoteClient = api ? (transport.remote ?? null) : null;
openStream = api ? (transport.stream ?? null) : null;
}
function api(): PluginApiClient {
@@ -121,11 +135,23 @@ export function subscribeTunnelStatuses(
timers.add(timer);
});
const url = streamUrl();
// A test hands in fetchImpl and a base URL; the app hands in app.fetch.
const url = options.fetchImpl ? streamUrl() : null;
const connect: ((init: RequestInit) => Promise<Response>) | null = url
? (init) => fetchImpl(url, { credentials: "include", ...init })
: openStream;
const fetchRemote =
options.fetchRemote ??
(remoteClient
? async () => {
const response = await remoteClient!.get<TunnelStatusMap>("/status");
return response.data || {};
}
: undefined);
void (async () => {
while (!controller.signal.aborted) {
if (!url) {
if (!connect) {
try {
latestLocal = await getTunnelStatuses();
emit();
@@ -136,19 +162,9 @@ export function subscribeTunnelStatuses(
continue;
}
const headers: Record<string, string> = {
Accept: "text/event-stream",
};
if (typeof window !== "undefined" && window.electronAPI?.isElectron) {
headers["X-Electron-App"] = "true";
const jwt = localStorage.getItem("jwt");
if (jwt) headers.Authorization = `Bearer ${jwt}`;
}
try {
const response = await fetchImpl(url, {
credentials: "include",
headers,
const response = await connect({
headers: { Accept: "text/event-stream" },
signal: controller.signal,
});
if (!response.ok || !response.body) throw new Error("stream failed");
@@ -179,8 +195,7 @@ export function subscribeTunnelStatuses(
}
})();
if (options.fetchRemote) {
const fetchRemote = options.fetchRemote;
if (fetchRemote) {
void (async () => {
while (!controller.signal.aborted) {
try {
+6 -1
View File
@@ -24,7 +24,12 @@ function TunnelTabView({ host }: TabProps) {
}
export function activate(app: TermixApp): void {
setTunnelsApi(app.api);
// apiFor("remote") hands back app.api itself outside the desktop app.
const remote = app.apiFor("remote");
setTunnelsApi(app.api, {
stream: (init) => app.fetch("/status/stream", init),
remote: remote === app.api ? null : remote,
});
app.onDispose(() => setTunnelsApi(null));
// Keeps the "tunnel" tab type and ?view=tunnel links from before the
@@ -53,7 +53,9 @@ describe("tunnels activate", () => {
for (const method of ["forward", "start", "stop", "status", "list"]) {
expect(typeof service[method]).toBe("function");
}
expect(server.mock.wsRoutes).toEqual([{ path: "/c2s/stream", raw: false }]);
expect(server.mock.wsRoutes).toMatchObject([
{ path: "/c2s/stream", raw: false },
]);
});
for (const capability of ["db:own", "network:serve"]) {