interface HeadscaleUser { id: string; name: string; } interface HeadscalePreAuthKey { key: string; expiration: string; aclTags: string[]; } export async function getHeadscaleUserId( baseUrl: string, apiKey: string, userName: string ): Promise { const res = await fetch( `${baseUrl}/api/v1/user?name=${encodeURIComponent(userName)}`, { headers: { Authorization: `Bearer ${apiKey}` }, } ); if (!res.ok) { throw new Error( `Headscale list users failed: ${res.status} ${await res.text()}` ); } const data = (await res.json()) as { users: HeadscaleUser[] }; const user = data.users.find((u) => u.name === userName); if (!user) { throw new Error(`Headscale user not found: ${userName}`); } return user.id; } export async function createEphemeralPreAuthKey( baseUrl: string, apiKey: string, userId: string, options: { expirationMinutes?: number; aclTags?: string[]; } = {} ): Promise { const expirationMinutes = options.expirationMinutes ?? 15; const aclTags = options.aclTags ?? []; const expiration = new Date( Date.now() + expirationMinutes * 60 * 1000 ).toISOString(); const res = await fetch(`${baseUrl}/api/v1/preauthkey`, { method: "POST", headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", }, body: JSON.stringify({ user: userId, reusable: false, ephemeral: false, expiration, aclTags, }), }); if (!res.ok) { throw new Error( `Headscale create preauthkey failed: ${res.status} ${await res.text()}` ); } const data = (await res.json()) as { preAuthKey: HeadscalePreAuthKey }; return data.preAuthKey.key; }