Files
paseo/packages/server/src/server/connection-offer.ts
T
Mohamed Boudra 53c14d9855 Extract client SDK package (#1052)
* Extract client SDK package

* Polish SDK client identity defaults

* Build client before dependent CI jobs

* Restore daemon client server export

* Extract protocol and client SDK packages

* Fix provider override schema validation

* Fix app test daemon client imports

* Simplify workspace build targets

* Fix CLI test server build bootstrap

* Run SDK package tests in CI

* Fix rebase package split drift

* Restore lockfile registry metadata

* Update SDK config test for prompt default

* Move terminal stream router test to client package

* Fix rebase drift for protocol imports

* Fix SDK agent capability fixture

* Restore legacy server client exports

* Fix server export compatibility test

* Advertise custom mode icon client capability

* Remove server daemon-client exports

* Format rebased mode control import

* Fix rebase drift for protocol imports

Files added by upstream PRs (#893, #1147, #1154) referenced the pre-split
shared/ paths that this branch moves into @getpaseo/protocol. Redirect
those imports to the protocol package so typecheck stays green after the
rebase.
2026-05-28 01:58:18 +08:00

80 lines
2.1 KiB
TypeScript

import os from "node:os";
import { ConnectionOfferV2Schema, type ConnectionOffer } from "@getpaseo/protocol/connection-offer";
interface BuildOfferEndpointsArgs {
listenHost: string;
port: number;
}
export function buildOfferEndpoints({ listenHost, port }: BuildOfferEndpointsArgs): string[] {
const endpoints: string[] = [];
const isLoopbackHost = listenHost === "127.0.0.1" || listenHost === "localhost";
const isWildcardHost = listenHost === "0.0.0.0" || listenHost === "::" || listenHost === "[::]";
if (isWildcardHost) {
const lanIp = getPrimaryLanIp();
if (lanIp) {
endpoints.push(`${lanIp}:${port}`);
}
} else if (!isLoopbackHost) {
endpoints.push(`${listenHost}:${port}`);
}
endpoints.push(`localhost:${port}`);
return dedupePreserveOrder(endpoints);
}
export async function createConnectionOfferV2(args: {
serverId: string;
daemonPublicKeyB64: string;
relay: { endpoint: string; useTls?: boolean };
}): Promise<ConnectionOffer> {
return ConnectionOfferV2Schema.parse({
v: 2,
serverId: args.serverId,
daemonPublicKeyB64: args.daemonPublicKeyB64,
relay: args.relay,
});
}
export function encodeOfferToFragmentUrl(args: {
offer: ConnectionOffer;
appBaseUrl: string;
}): string {
const json = JSON.stringify(args.offer);
const encoded = Buffer.from(json, "utf8").toString("base64url");
return `${args.appBaseUrl.replace(/\/$/, "")}/#offer=${encoded}`;
}
function getPrimaryLanIp(): string | null {
const override = process.env.PASEO_PRIMARY_LAN_IP?.trim();
if (override) return override;
const nets = os.networkInterfaces();
const names = Object.keys(nets).sort();
for (const name of names) {
const addrs = nets[name] ?? [];
for (const addr of addrs) {
if (addr.family === "IPv4" && !addr.internal) {
return addr.address;
}
}
}
return null;
}
function dedupePreserveOrder(values: string[]): string[] {
const out: string[] = [];
const seen = new Set<string>();
for (const value of values) {
if (seen.has(value)) continue;
seen.add(value);
out.push(value);
}
return out;
}