/**
* HTTPS tunnels on your own domain, reverse-tunneled to your device over
* SSH. Hourly billing while the tunnel exists. Mutations are subject to the
* client's domain gate on the tunnel's hostname.
*/
import type { Client } from './client.js';
import { checkGate } from './gate.js';
import * as http from './http.js';
import type { Body } from './types.js';
/** GET /tunnels — List your tunnels. */
export const list = (client: Client) => http.get(client, '/tunnels');
/** POST /tunnels — Create a tunnel. Gated on `hostname`. */
export const create = async (client: Client, body: Body<'/tunnels', 'post'>) => {
await checkGate(client, 'POST /tunnels', { domain: body.hostname });
return http.post(client, '/tunnels', { body });
};
/** GET /tunnels/{id} — Tunnel detail. */
export const get = (client: Client, id: string) => http.get(client, '/tunnels/{id}', { params: { id } });
/** Resolve the tunnel's hostname (only when gated) and run the gate. */
const checkTunnelGate = async (client: Client, op: string, id: string): Promise<void> => {
if (!client.gate) return;
const { tunnel } = await get(client, id);
await checkGate(client, op, { domain: tunnel?.hostname });
};
/** DELETE /tunnels/{id} — Delete a tunnel (billing stops). */
export const remove = async (client: Client, id: string, body?: Body<'/tunnels/{id}', 'delete'>) => {
await checkTunnelGate(client, 'DELETE /tunnels/{id}', id);
return http.del(client, '/tunnels/{id}', { params: { id }, body });
};
/** PATCH /tunnels/{id} — Update tunnel settings. */
export const update = async (client: Client, id: string, body: Body<'/tunnels/{id}', 'patch'>) => {
await checkTunnelGate(client, 'PATCH /tunnels/{id}', id);
return http.patch(client, '/tunnels/{id}', { params: { id }, body });
};
/** POST /tunnels/{id}/verify-dns — Re-check DNS. */
export const verifyDns = (client: Client, id: string) =>
http.post(client, '/tunnels/{id}/verify-dns', { params: { id } });