@kelnishi/satmouse-client 0.18.1 → 0.18.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -348,8 +348,8 @@ var SatMouseConnection = class extends chunkI5MEZZOT_cjs.TypedEmitter {
348
348
  if (!wtUrl && !wsUrl) {
349
349
  const tdUrl = this.options.tdUrl;
350
350
  const tdUrls = tdUrl ? [tdUrl] : [
351
- "https://127.0.0.1:18947/td.json",
352
- "http://127.0.0.1:18945/td.json"
351
+ "http://127.0.0.1:18945/td.json",
352
+ "https://127.0.0.1:18947/td.json"
353
353
  ];
354
354
  let resolved = false;
355
355
  for (const url of tdUrls) {
@@ -367,8 +367,7 @@ var SatMouseConnection = class extends chunkI5MEZZOT_cjs.TypedEmitter {
367
367
  }
368
368
  if (!resolved) {
369
369
  this.emit("error", new Error("Failed to fetch Thing Description"));
370
- const isSecurePage = typeof globalThis.location !== "undefined" && globalThis.location.protocol === "https:";
371
- wsUrl = isSecurePage ? "wss://127.0.0.1:18947/spatial" : "ws://127.0.0.1:18945/spatial";
370
+ wsUrl = "ws://127.0.0.1:18945/spatial";
372
371
  }
373
372
  }
374
373
  for (const proto of this.options.transports) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/discovery.ts","../../src/core/decode.ts","../../src/core/transports/webtransport.ts","../../src/core/transports/websocket.ts","../../src/core/transports/extension.ts","../../src/core/connection.ts","../../src/core/launch.ts"],"names":["TypedEmitter"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ThingDescription } from \"./types.js\";\n\nexport interface ResolvedEndpoints {\n webtransport?: { url: string; certHash?: string };\n websocket?: { url: string };\n deviceInfoUrl?: string;\n}\n\n/** Fetch the WoT Thing Description from the bridge */\nexport async function fetchThingDescription(tdUrl: string): Promise<ThingDescription> {\n const res = await globalThis.fetch(tdUrl);\n if (!res.ok) throw new Error(`Failed to fetch TD: HTTP ${res.status}`);\n return res.json() as Promise<ThingDescription>;\n}\n\n/** Extract WebTransport, WebSocket, and device info endpoints from a Thing Description */\nexport function resolveEndpoints(td: ThingDescription): ResolvedEndpoints {\n const result: ResolvedEndpoints = {};\n\n const spatialForms = td.events?.spatialData?.forms ?? [];\n\n const wtForm = spatialForms.find((f) => f.subprotocol === \"webtransport\");\n if (wtForm) {\n result.webtransport = {\n url: wtForm.href,\n certHash: td[\"satmouse:certHash\"],\n };\n }\n\n const wsForm = spatialForms.find((f) => f.subprotocol === \"websocket\");\n if (wsForm) {\n result.websocket = { url: wsForm.href };\n }\n\n const deviceForm = td.properties?.deviceInfo?.forms?.[0];\n if (deviceForm) {\n result.deviceInfoUrl = deviceForm.href;\n }\n\n return result;\n}\n","import type { SpatialData, ButtonEvent } from \"./types.js\";\n\n/** Decode 24-byte binary spatial data datagram (WebTransport or raw binary) */\nexport function decodeBinaryFrame(buffer: ArrayBuffer | Uint8Array): SpatialData {\n const len = buffer instanceof ArrayBuffer ? buffer.byteLength : buffer.byteLength;\n if (len < 20) {\n throw new RangeError(`Spatial frame too short: expected ≥20 bytes, got ${len}`);\n }\n const ab = buffer instanceof ArrayBuffer ? buffer : buffer.buffer;\n const offset = buffer instanceof Uint8Array ? buffer.byteOffset : 0;\n const view = new DataView(ab, offset);\n return {\n translation: {\n x: view.getInt16(8, true),\n y: view.getInt16(10, true),\n z: view.getInt16(12, true),\n },\n rotation: {\n x: view.getInt16(14, true),\n y: view.getInt16(16, true),\n z: view.getInt16(18, true),\n },\n timestamp: view.getFloat64(0, true),\n };\n}\n\n/** Decode WebSocket binary frame (1-byte type prefix + 24-byte payload) */\nexport function decodeWsBinaryFrame(\n buffer: ArrayBuffer | Uint8Array,\n): { type: \"spatialData\"; data: SpatialData } | { type: \"buttonEvent\"; data: ButtonEvent } | null {\n const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);\n if (bytes.length < 1) return null;\n\n const typePrefix = bytes[0];\n if (typePrefix === 0x01 && bytes.length >= 25) {\n return { type: \"spatialData\", data: decodeBinaryFrame(bytes.subarray(1, 25)) };\n }\n if (typePrefix === 0x02) {\n const json = new TextDecoder().decode(bytes.subarray(1));\n return { type: \"buttonEvent\", data: JSON.parse(json) as ButtonEvent };\n }\n return null;\n}\n\n/** Decode length-prefixed JSON button events from a WebTransport stream chunk */\nexport function decodeButtonStream(\n buffer: Uint8Array<ArrayBufferLike>,\n): { events: ButtonEvent[]; remainder: Uint8Array<ArrayBufferLike> } {\n const events: ButtonEvent[] = [];\n let pos = 0;\n\n while (pos + 4 <= buffer.length) {\n const view = new DataView(buffer.buffer, buffer.byteOffset + pos);\n const len = view.getUint32(0, true);\n // Guard against absurd lengths\n if (len > 65536 || pos + 4 + len > buffer.length) break;\n const json = new TextDecoder().decode(buffer.subarray(pos + 4, pos + 4 + len));\n try {\n const event = JSON.parse(json);\n if (typeof event.button === \"number\" && typeof event.pressed === \"boolean\") {\n events.push(event as ButtonEvent);\n }\n } catch {\n // Skip malformed JSON frames\n }\n pos += 4 + len;\n }\n\n return { events, remainder: buffer.subarray(pos) };\n}\n","import type { Transport } from \"./transport.js\";\nimport type { SpatialData, ButtonEvent } from \"../types.js\";\nimport { decodeBinaryFrame, decodeButtonStream } from \"../decode.js\";\n\nexport class WebTransportAdapter implements Transport {\n readonly protocol = \"webtransport\" as const;\n\n onSpatialData: ((data: SpatialData) => void) | null = null;\n onButtonEvent: ((data: ButtonEvent) => void) | null = null;\n onClose: (() => void) | null = null;\n onError: ((error: Error) => void) | null = null;\n\n private transport: any = null;\n private url: string;\n private certHash?: string;\n\n constructor(url: string, certHash?: string) {\n this.url = url;\n this.certHash = certHash;\n }\n\n async connect(): Promise<void> {\n if (typeof globalThis.WebTransport === \"undefined\") {\n throw new Error(\"WebTransport is not available in this environment\");\n }\n\n const options: any = {};\n if (this.certHash) {\n options.serverCertificateHashes = [\n {\n algorithm: \"sha-256\",\n value: Uint8Array.from(atob(this.certHash), (c) => c.charCodeAt(0)),\n },\n ];\n }\n\n this.transport = new (globalThis as any).WebTransport(this.url, options);\n await this.transport.ready;\n\n this.readDatagrams();\n this.readStreams();\n\n this.transport.closed\n .then(() => this.onClose?.())\n .catch(() => this.onClose?.());\n }\n\n close(): void {\n try {\n this.transport?.close();\n } catch {}\n this.transport = null;\n }\n\n private async readDatagrams(): Promise<void> {\n const reader = this.transport.datagrams.readable.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n this.onSpatialData?.(decodeBinaryFrame(value));\n }\n } catch {\n // Transport closed\n }\n }\n\n private async readStreams(): Promise<void> {\n const reader = this.transport.incomingUnidirectionalStreams.getReader();\n try {\n while (true) {\n const { value: stream, done } = await reader.read();\n if (done) break;\n this.readButtonStream(stream);\n }\n } catch {\n // Transport closed\n }\n }\n\n private async readButtonStream(stream: any): Promise<void> {\n const reader = stream.getReader();\n let buffer: Uint8Array<ArrayBufferLike> = new Uint8Array(0);\n\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n\n const newBuf = new Uint8Array(buffer.length + value.length);\n newBuf.set(buffer);\n newBuf.set(value, buffer.length);\n\n const { events, remainder } = decodeButtonStream(newBuf);\n for (const event of events) {\n this.onButtonEvent?.(event);\n }\n buffer = remainder;\n }\n } catch {\n // Stream closed\n }\n }\n}\n","import type { Transport } from \"./transport.js\";\nimport type { SpatialData, ButtonEvent, DeviceInfo } from \"../types.js\";\nimport { decodeWsBinaryFrame } from \"../decode.js\";\n\nexport class WebSocketAdapter implements Transport {\n readonly protocol = \"websocket\" as const;\n\n onSpatialData: ((data: SpatialData) => void) | null = null;\n onButtonEvent: ((data: ButtonEvent) => void) | null = null;\n onDeviceStatus: ((event: \"connected\" | \"disconnected\", device: DeviceInfo) => void) | null = null;\n onClose: (() => void) | null = null;\n onError: ((error: Error) => void) | null = null;\n\n private ws: WebSocket | null = null;\n private url: string;\n private subprotocol: string;\n\n constructor(url: string, subprotocol: string = \"satmouse-json\") {\n this.url = url;\n this.subprotocol = subprotocol;\n }\n\n async connect(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n this.ws = new globalThis.WebSocket(this.url, this.subprotocol);\n if (this.subprotocol === \"satmouse-binary\") {\n this.ws.binaryType = \"arraybuffer\";\n }\n\n this.ws.onopen = () => resolve();\n\n this.ws.onerror = () => {\n reject(new Error(`WebSocket connection failed: ${this.url}`));\n };\n\n this.ws.onmessage = (event: MessageEvent) => {\n if (this.subprotocol === \"satmouse-binary\" && event.data instanceof ArrayBuffer) {\n const decoded = decodeWsBinaryFrame(event.data);\n if (decoded?.type === \"spatialData\") this.onSpatialData?.(decoded.data);\n else if (decoded?.type === \"buttonEvent\") this.onButtonEvent?.(decoded.data);\n } else if (typeof event.data === \"string\") {\n try {\n const msg = JSON.parse(event.data);\n if (msg.type === \"spatialData\") this.onSpatialData?.(msg.data);\n else if (msg.type === \"buttonEvent\") this.onButtonEvent?.(msg.data);\n else if (msg.type === \"deviceStatus\") {\n this.onDeviceStatus?.(msg.data.event, msg.data.device);\n }\n } catch {\n // Ignore malformed messages\n }\n }\n };\n\n this.ws.onclose = () => this.onClose?.();\n });\n }\n\n close(): void {\n try {\n this.ws?.close();\n } catch {}\n this.ws = null;\n }\n}\n","import type { Transport } from \"./transport.js\";\nimport type { SpatialData, ButtonEvent, DeviceInfo } from \"../types.js\";\n\n/**\n * Safari Web Extension transport adapter.\n *\n * The SatMouse extension's content script sets window.__satmouseExtensionAvailable\n * and bridges postMessage ↔ background script ↔ WebSocket to the bridge.\n *\n * This transport is transparent to the SDK — it just works when the extension\n * is installed, bypassing Safari's mixed-content restrictions entirely.\n */\nexport class ExtensionAdapter implements Transport {\n readonly protocol = \"extension\" as const;\n\n onSpatialData: ((data: SpatialData) => void) | null = null;\n onButtonEvent: ((data: ButtonEvent) => void) | null = null;\n onDeviceStatus: ((event: \"connected\" | \"disconnected\", device: DeviceInfo) => void) | null = null;\n onClose: (() => void) | null = null;\n onError: ((error: Error) => void) | null = null;\n\n private messageHandler: ((event: MessageEvent) => void) | null = null;\n private pendingDeviceFetch: ((devices: DeviceInfo[]) => void) | null = null;\n\n static isAvailable(): boolean {\n return !!(globalThis as any).__satmouseExtensionAvailable;\n }\n\n async connect(): Promise<void> {\n if (typeof globalThis.postMessage !== \"function\") {\n throw new Error(\"postMessage not available\");\n }\n\n return new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.close();\n reject(new Error(\"Extension connection timeout\"));\n }, 5000);\n\n this.messageHandler = (event: MessageEvent) => {\n if (event.data?.source !== \"satmouse-extension\") return;\n const msg = event.data;\n\n if ((msg.type === \"connected\" || msg.type === \"bridgeConnected\") && timeout) {\n clearTimeout(timeout);\n resolve();\n }\n\n if (msg.type === \"disconnected\") {\n this.onClose?.();\n }\n\n if (msg.type === \"spatialData\" && msg.data) {\n this.onSpatialData?.(msg.data as SpatialData);\n }\n\n if (msg.type === \"buttonEvent\" && msg.data) {\n this.onButtonEvent?.(msg.data as ButtonEvent);\n }\n\n if (msg.type === \"deviceStatus\" && msg.data) {\n this.onDeviceStatus?.(msg.data.event, msg.data.device);\n }\n\n if (msg.type === \"deviceList\" && this.pendingDeviceFetch) {\n this.pendingDeviceFetch(Array.isArray(msg.data) ? msg.data : []);\n this.pendingDeviceFetch = null;\n }\n };\n\n globalThis.addEventListener(\"message\", this.messageHandler);\n globalThis.postMessage({ target: \"satmouse-extension\", action: \"connect\" }, \"*\");\n });\n }\n\n fetchDeviceInfo(): Promise<DeviceInfo[]> {\n return new Promise((resolve) => {\n this.pendingDeviceFetch = resolve;\n globalThis.postMessage({ target: \"satmouse-extension\", action: \"fetchDevices\" }, \"*\");\n setTimeout(() => {\n if (this.pendingDeviceFetch) {\n this.pendingDeviceFetch = null;\n resolve([]);\n }\n }, 3000);\n });\n }\n\n close(): void {\n if (this.messageHandler) {\n globalThis.removeEventListener(\"message\", this.messageHandler);\n this.messageHandler = null;\n }\n globalThis.postMessage({ target: \"satmouse-extension\", action: \"disconnect\" }, \"*\");\n }\n}\n","import { TypedEmitter } from \"./emitter.js\";\nimport { fetchThingDescription, resolveEndpoints } from \"./discovery.js\";\nimport { WebTransportAdapter } from \"./transports/webtransport.js\";\nimport { WebSocketAdapter } from \"./transports/websocket.js\";\nimport { ExtensionAdapter } from \"./transports/extension.js\";\nimport type { Transport } from \"./transports/transport.js\";\nimport type {\n ConnectOptions,\n ConnectionState,\n DeviceInfo,\n SatMouseEvents,\n TransportProtocol,\n} from \"./types.js\";\n\n/**\n * Build a satmouse:// connect URI from connection parameters.\n */\nexport function buildSatMouseUri(host = \"localhost\", wsPort = 18945, wtPort = 18946): string {\n return `satmouse://connect?host=${encodeURIComponent(host)}&wsPort=${wsPort}&wtPort=${wtPort}`;\n}\n\n/**\n * Parse a satmouse:// URI into connection parameters.\n *\n * Format: satmouse://connect?host=<ip>&wsPort=<port>&wtPort=<port>\n * All query params are optional. Defaults: host=localhost, wsPort=4444, wtPort=4443.\n */\nexport function parseSatMouseUri(uri: string): { tdUrl: string; wsUrl: string; wtUrl: string } {\n const url = new URL(uri);\n const host = url.searchParams.get(\"host\") ?? \"localhost\";\n const wsPort = url.searchParams.get(\"wsPort\") ?? \"18945\";\n const wtPort = url.searchParams.get(\"wtPort\") ?? \"18946\";\n return {\n tdUrl: `http://${host}:${wsPort}/td.json`,\n wsUrl: `ws://${host}:${wsPort}/spatial`,\n wtUrl: `https://${host}:${wtPort}`,\n };\n}\n\nconst DEFAULT_OPTIONS: Required<\n Pick<ConnectOptions, \"transports\" | \"reconnectDelay\" | \"maxRetries\" | \"wsSubprotocol\">\n> = {\n transports: [\"webtransport\", \"extension\", \"websocket\"],\n reconnectDelay: 2000,\n maxRetries: 3,\n wsSubprotocol: \"satmouse-json\",\n};\n\n/**\n * Core connection to a SatMouse bridge.\n *\n * Handles discovery (via WoT Thing Description), transport negotiation\n * (WebTransport with WebSocket fallback), event dispatch, and auto-reconnect.\n */\nexport class SatMouseConnection extends TypedEmitter<SatMouseEvents> {\n private options: ConnectOptions & typeof DEFAULT_OPTIONS;\n private transport: Transport | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private intentionalClose = false;\n private deviceInfoUrl: string | null = null;\n private retryCount = 0;\n\n private _state: ConnectionState = \"disconnected\";\n private _protocol: TransportProtocol = \"none\";\n\n get state(): ConnectionState {\n return this._state;\n }\n get protocol(): TransportProtocol {\n return this._protocol;\n }\n\n constructor(options?: ConnectOptions) {\n super();\n this.options = { ...DEFAULT_OPTIONS, ...options };\n }\n\n async connect(): Promise<void> {\n this.intentionalClose = false;\n this.setState(\"connecting\", \"none\");\n\n // Resolve endpoints — satmouse:// URI takes priority\n let wtUrl = this.options.wtUrl;\n let wsUrl = this.options.wsUrl;\n let certHash = this.options.certHash;\n\n if (this.options.uri) {\n const parsed = parseSatMouseUri(this.options.uri);\n wtUrl = wtUrl ?? parsed.wtUrl;\n wsUrl = wsUrl ?? parsed.wsUrl;\n this.options.tdUrl = this.options.tdUrl ?? parsed.tdUrl;\n }\n\n if (!wtUrl && !wsUrl) {\n const tdUrl = this.options.tdUrl;\n // Use 127.0.0.1 (not localhost) — Safari treats the loopback IP as a\n // \"Potentially Trustworthy Origin\" more reliably than the hostname.\n // Try HTTPS first (works from HTTPS pages), fall back to HTTP.\n const tdUrls = tdUrl\n ? [tdUrl]\n : [\n \"https://127.0.0.1:18947/td.json\",\n \"http://127.0.0.1:18945/td.json\",\n ];\n\n let resolved = false;\n for (const url of tdUrls) {\n try {\n const td = await fetchThingDescription(url);\n const endpoints = resolveEndpoints(td);\n wtUrl = endpoints.webtransport?.url;\n wsUrl = endpoints.websocket?.url;\n certHash = certHash ?? endpoints.webtransport?.certHash;\n this.deviceInfoUrl = endpoints.deviceInfoUrl ?? null;\n resolved = true;\n break;\n } catch {\n // Try next URL\n }\n }\n if (!resolved) {\n this.emit(\"error\", new Error(\"Failed to fetch Thing Description\"));\n // On HTTPS pages, ws:// is blocked as mixed content.\n // Try wss:// on the HTTPS port; fall back to ws:// for HTTP pages.\n const isSecurePage = typeof globalThis.location !== \"undefined\" && globalThis.location.protocol === \"https:\";\n wsUrl = isSecurePage\n ? \"wss://127.0.0.1:18947/spatial\"\n : \"ws://127.0.0.1:18945/spatial\";\n }\n }\n\n // Try transports in preference order\n for (const proto of this.options.transports) {\n if (proto === \"webtransport\" && wtUrl) {\n try {\n if (typeof globalThis.WebTransport === \"undefined\") continue;\n const adapter = new WebTransportAdapter(wtUrl, certHash);\n if (await this.tryTransport(adapter)) return;\n } catch {\n continue;\n }\n }\n if (proto === \"extension\") {\n try {\n if (!ExtensionAdapter.isAvailable()) continue;\n const adapter = new ExtensionAdapter();\n if (await this.tryTransport(adapter)) return;\n } catch {\n continue;\n }\n }\n if (proto === \"websocket\" && wsUrl) {\n try {\n const adapter = new WebSocketAdapter(wsUrl, this.options.wsSubprotocol);\n if (await this.tryTransport(adapter)) return;\n } catch {\n continue;\n }\n }\n }\n\n this.setState(\"disconnected\", \"none\");\n this.scheduleReconnect();\n }\n\n /** Reset retry count and reconnect. Use after \"failed\" state. */\n retry(): void {\n this.retryCount = 0;\n this.intentionalClose = false;\n this.connect();\n }\n\n disconnect(): void {\n this.intentionalClose = true;\n this.clearReconnect();\n this.transport?.close();\n this.transport = null;\n this.setState(\"disconnected\", \"none\");\n }\n\n async fetchDeviceInfo(): Promise<DeviceInfo[]> {\n // Try HTTP endpoint first\n if (this.deviceInfoUrl) {\n try {\n const res = await globalThis.fetch(this.deviceInfoUrl);\n if (res.ok) {\n const data = await res.json();\n return data.devices ?? [];\n }\n } catch {\n // HTTP blocked (Safari HTTPS → localhost) — fall through to extension\n }\n }\n\n // Fall back to extension transport if connected via extension\n if (this.transport && \"fetchDeviceInfo\" in this.transport) {\n return (this.transport as ExtensionAdapter).fetchDeviceInfo();\n }\n\n return [];\n }\n\n private async tryTransport(adapter: Transport): Promise<boolean> {\n adapter.onSpatialData = (data) => this.emit(\"spatialData\", data);\n adapter.onButtonEvent = (data) => this.emit(\"buttonEvent\", data);\n adapter.onError = (err) => this.emit(\"error\", err);\n\n if (\"onDeviceStatus\" in adapter) {\n (adapter as any).onDeviceStatus = (event: \"connected\" | \"disconnected\", device: DeviceInfo) => {\n this.emit(\"deviceStatus\", event, device);\n };\n }\n\n adapter.onClose = () => {\n this.transport = null;\n this.setState(\"disconnected\", \"none\");\n if (!this.intentionalClose) this.scheduleReconnect();\n };\n\n try {\n // Timeout transport connection attempts to prevent hanging the fallback chain\n await Promise.race([\n adapter.connect(),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(`${adapter.protocol} connection timeout`)), 5000)\n ),\n ]);\n this.transport = adapter;\n this.retryCount = 0;\n this.setState(\"connected\", adapter.protocol);\n return true;\n } catch (err) {\n adapter.close();\n this.emit(\"error\", err instanceof Error ? err : new Error(String(err)));\n return false;\n }\n }\n\n private setState(state: ConnectionState, protocol: TransportProtocol): void {\n if (this._state === state && this._protocol === protocol) return;\n this._state = state;\n this._protocol = protocol;\n this.emit(\"stateChange\", state, protocol);\n }\n\n private scheduleReconnect(): void {\n if (this.options.reconnectDelay <= 0 || this.intentionalClose) return;\n\n this.retryCount++;\n console.log(`[SatMouse] Reconnect attempt ${this.retryCount}/${this.options.maxRetries}`);\n if (this.retryCount > this.options.maxRetries) {\n console.log(\"[SatMouse] Max retries exceeded, giving up\");\n this.setState(\"failed\", \"none\");\n return;\n }\n\n this.clearReconnect();\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, this.options.reconnectDelay);\n }\n\n private clearReconnect(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n}\n","const SCHEME_URL = \"satmouse://launch\";\nconst PROJECT_URL = \"https://github.com/kelnishi/SatMouse/releases/latest\";\n\n/** Result of a URI scheme negotiation */\nexport interface NegotiateResult {\n ip: string;\n wsPort: number;\n wtPort: number;\n httpsPort: number;\n certHash?: string;\n challenge?: string;\n}\n\n/**\n * Trigger the satmouse://negotiate URI scheme for discovery when direct\n * HTTP/HTTPS fetch is blocked (Safari LNA).\n *\n * The bridge intercepts the URI, then redirects back to your origin with\n * connection details as query parameters. Your app handles the callback\n * route and passes the result to SatMouseConnection.\n *\n * @param origin - Your app's origin (e.g., \"https://kelcite.app\")\n * @param callbackPath - Path the bridge redirects to (default: \"/satmouse-handshake\")\n * @param challenge - Optional challenge token for verification\n */\nexport function negotiateViaSatMouse(origin: string, callbackPath = \"/satmouse-handshake\", challenge?: string): void {\n const params = new URLSearchParams({ origin, callback: callbackPath });\n if (challenge) params.set(\"challenge\", challenge);\n globalThis.location.href = `satmouse://negotiate?${params}`;\n}\n\n/**\n * Parse the negotiate callback URL parameters (called on your callback route).\n * Returns connection details or null if the params are missing.\n */\nexport function parseNegotiateCallback(searchParams: URLSearchParams): NegotiateResult | null {\n const ip = searchParams.get(\"ip\");\n const wsPort = searchParams.get(\"wsPort\");\n if (!ip || !wsPort) return null;\n return {\n ip,\n wsPort: parseInt(wsPort, 10),\n wtPort: parseInt(searchParams.get(\"wtPort\") ?? \"18946\", 10),\n httpsPort: parseInt(searchParams.get(\"httpsPort\") ?? \"18947\", 10),\n certHash: searchParams.get(\"certHash\") ?? undefined,\n challenge: searchParams.get(\"challenge\") ?? undefined,\n };\n}\n\nexport interface LaunchOptions {\n /** URL scheme to open. Default: \"satmouse://launch\" */\n schemeUrl?: string;\n /** Fallback URL if the app is not installed. Default: GitHub releases page */\n fallbackUrl?: string;\n /** Timeout in ms before assuming the app is not installed. Default: 2500 */\n timeout?: number;\n}\n\n/**\n * Attempt to launch SatMouse via the `satmouse://` URL scheme.\n *\n * If the app is installed and registered, the OS opens it. If not,\n * navigates to the fallback URL (project releases page) after a timeout.\n *\n * Returns true if the scheme likely opened, false if it fell back.\n */\nexport function launchSatMouse(options?: LaunchOptions): Promise<boolean> {\n const schemeUrl = options?.schemeUrl ?? SCHEME_URL;\n const timeout = options?.timeout ?? 2500;\n\n // Validate fallback URL — only allow http/https to prevent javascript: or data: injection\n let fallbackUrl = PROJECT_URL;\n if (options?.fallbackUrl) {\n try {\n const parsed = new URL(options.fallbackUrl);\n if (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") {\n fallbackUrl = options.fallbackUrl;\n }\n } catch {}\n }\n\n return new Promise((resolve) => {\n // Track if we leave the page (scheme handler opened the app)\n let launched = false;\n\n const onBlur = () => {\n launched = true;\n };\n globalThis.addEventListener(\"blur\", onBlur);\n\n // Use a hidden iframe to trigger the scheme without navigating away\n const iframe = document.createElement(\"iframe\");\n iframe.style.display = \"none\";\n iframe.src = schemeUrl;\n document.body.appendChild(iframe);\n\n setTimeout(() => {\n globalThis.removeEventListener(\"blur\", onBlur);\n document.body.removeChild(iframe);\n\n if (launched || document.hidden) {\n resolve(true);\n } else {\n // App not installed — redirect to project page\n globalThis.location.href = fallbackUrl;\n resolve(false);\n }\n }, timeout);\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/core/discovery.ts","../../src/core/decode.ts","../../src/core/transports/webtransport.ts","../../src/core/transports/websocket.ts","../../src/core/transports/extension.ts","../../src/core/connection.ts","../../src/core/launch.ts"],"names":["TypedEmitter"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ThingDescription } from \"./types.js\";\n\nexport interface ResolvedEndpoints {\n webtransport?: { url: string; certHash?: string };\n websocket?: { url: string };\n deviceInfoUrl?: string;\n}\n\n/** Fetch the WoT Thing Description from the bridge */\nexport async function fetchThingDescription(tdUrl: string): Promise<ThingDescription> {\n const res = await globalThis.fetch(tdUrl);\n if (!res.ok) throw new Error(`Failed to fetch TD: HTTP ${res.status}`);\n return res.json() as Promise<ThingDescription>;\n}\n\n/** Extract WebTransport, WebSocket, and device info endpoints from a Thing Description */\nexport function resolveEndpoints(td: ThingDescription): ResolvedEndpoints {\n const result: ResolvedEndpoints = {};\n\n const spatialForms = td.events?.spatialData?.forms ?? [];\n\n const wtForm = spatialForms.find((f) => f.subprotocol === \"webtransport\");\n if (wtForm) {\n result.webtransport = {\n url: wtForm.href,\n certHash: td[\"satmouse:certHash\"],\n };\n }\n\n const wsForm = spatialForms.find((f) => f.subprotocol === \"websocket\");\n if (wsForm) {\n result.websocket = { url: wsForm.href };\n }\n\n const deviceForm = td.properties?.deviceInfo?.forms?.[0];\n if (deviceForm) {\n result.deviceInfoUrl = deviceForm.href;\n }\n\n return result;\n}\n","import type { SpatialData, ButtonEvent } from \"./types.js\";\n\n/** Decode 24-byte binary spatial data datagram (WebTransport or raw binary) */\nexport function decodeBinaryFrame(buffer: ArrayBuffer | Uint8Array): SpatialData {\n const len = buffer instanceof ArrayBuffer ? buffer.byteLength : buffer.byteLength;\n if (len < 20) {\n throw new RangeError(`Spatial frame too short: expected ≥20 bytes, got ${len}`);\n }\n const ab = buffer instanceof ArrayBuffer ? buffer : buffer.buffer;\n const offset = buffer instanceof Uint8Array ? buffer.byteOffset : 0;\n const view = new DataView(ab, offset);\n return {\n translation: {\n x: view.getInt16(8, true),\n y: view.getInt16(10, true),\n z: view.getInt16(12, true),\n },\n rotation: {\n x: view.getInt16(14, true),\n y: view.getInt16(16, true),\n z: view.getInt16(18, true),\n },\n timestamp: view.getFloat64(0, true),\n };\n}\n\n/** Decode WebSocket binary frame (1-byte type prefix + 24-byte payload) */\nexport function decodeWsBinaryFrame(\n buffer: ArrayBuffer | Uint8Array,\n): { type: \"spatialData\"; data: SpatialData } | { type: \"buttonEvent\"; data: ButtonEvent } | null {\n const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);\n if (bytes.length < 1) return null;\n\n const typePrefix = bytes[0];\n if (typePrefix === 0x01 && bytes.length >= 25) {\n return { type: \"spatialData\", data: decodeBinaryFrame(bytes.subarray(1, 25)) };\n }\n if (typePrefix === 0x02) {\n const json = new TextDecoder().decode(bytes.subarray(1));\n return { type: \"buttonEvent\", data: JSON.parse(json) as ButtonEvent };\n }\n return null;\n}\n\n/** Decode length-prefixed JSON button events from a WebTransport stream chunk */\nexport function decodeButtonStream(\n buffer: Uint8Array<ArrayBufferLike>,\n): { events: ButtonEvent[]; remainder: Uint8Array<ArrayBufferLike> } {\n const events: ButtonEvent[] = [];\n let pos = 0;\n\n while (pos + 4 <= buffer.length) {\n const view = new DataView(buffer.buffer, buffer.byteOffset + pos);\n const len = view.getUint32(0, true);\n // Guard against absurd lengths\n if (len > 65536 || pos + 4 + len > buffer.length) break;\n const json = new TextDecoder().decode(buffer.subarray(pos + 4, pos + 4 + len));\n try {\n const event = JSON.parse(json);\n if (typeof event.button === \"number\" && typeof event.pressed === \"boolean\") {\n events.push(event as ButtonEvent);\n }\n } catch {\n // Skip malformed JSON frames\n }\n pos += 4 + len;\n }\n\n return { events, remainder: buffer.subarray(pos) };\n}\n","import type { Transport } from \"./transport.js\";\nimport type { SpatialData, ButtonEvent } from \"../types.js\";\nimport { decodeBinaryFrame, decodeButtonStream } from \"../decode.js\";\n\nexport class WebTransportAdapter implements Transport {\n readonly protocol = \"webtransport\" as const;\n\n onSpatialData: ((data: SpatialData) => void) | null = null;\n onButtonEvent: ((data: ButtonEvent) => void) | null = null;\n onClose: (() => void) | null = null;\n onError: ((error: Error) => void) | null = null;\n\n private transport: any = null;\n private url: string;\n private certHash?: string;\n\n constructor(url: string, certHash?: string) {\n this.url = url;\n this.certHash = certHash;\n }\n\n async connect(): Promise<void> {\n if (typeof globalThis.WebTransport === \"undefined\") {\n throw new Error(\"WebTransport is not available in this environment\");\n }\n\n const options: any = {};\n if (this.certHash) {\n options.serverCertificateHashes = [\n {\n algorithm: \"sha-256\",\n value: Uint8Array.from(atob(this.certHash), (c) => c.charCodeAt(0)),\n },\n ];\n }\n\n this.transport = new (globalThis as any).WebTransport(this.url, options);\n await this.transport.ready;\n\n this.readDatagrams();\n this.readStreams();\n\n this.transport.closed\n .then(() => this.onClose?.())\n .catch(() => this.onClose?.());\n }\n\n close(): void {\n try {\n this.transport?.close();\n } catch {}\n this.transport = null;\n }\n\n private async readDatagrams(): Promise<void> {\n const reader = this.transport.datagrams.readable.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n this.onSpatialData?.(decodeBinaryFrame(value));\n }\n } catch {\n // Transport closed\n }\n }\n\n private async readStreams(): Promise<void> {\n const reader = this.transport.incomingUnidirectionalStreams.getReader();\n try {\n while (true) {\n const { value: stream, done } = await reader.read();\n if (done) break;\n this.readButtonStream(stream);\n }\n } catch {\n // Transport closed\n }\n }\n\n private async readButtonStream(stream: any): Promise<void> {\n const reader = stream.getReader();\n let buffer: Uint8Array<ArrayBufferLike> = new Uint8Array(0);\n\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n\n const newBuf = new Uint8Array(buffer.length + value.length);\n newBuf.set(buffer);\n newBuf.set(value, buffer.length);\n\n const { events, remainder } = decodeButtonStream(newBuf);\n for (const event of events) {\n this.onButtonEvent?.(event);\n }\n buffer = remainder;\n }\n } catch {\n // Stream closed\n }\n }\n}\n","import type { Transport } from \"./transport.js\";\nimport type { SpatialData, ButtonEvent, DeviceInfo } from \"../types.js\";\nimport { decodeWsBinaryFrame } from \"../decode.js\";\n\nexport class WebSocketAdapter implements Transport {\n readonly protocol = \"websocket\" as const;\n\n onSpatialData: ((data: SpatialData) => void) | null = null;\n onButtonEvent: ((data: ButtonEvent) => void) | null = null;\n onDeviceStatus: ((event: \"connected\" | \"disconnected\", device: DeviceInfo) => void) | null = null;\n onClose: (() => void) | null = null;\n onError: ((error: Error) => void) | null = null;\n\n private ws: WebSocket | null = null;\n private url: string;\n private subprotocol: string;\n\n constructor(url: string, subprotocol: string = \"satmouse-json\") {\n this.url = url;\n this.subprotocol = subprotocol;\n }\n\n async connect(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n this.ws = new globalThis.WebSocket(this.url, this.subprotocol);\n if (this.subprotocol === \"satmouse-binary\") {\n this.ws.binaryType = \"arraybuffer\";\n }\n\n this.ws.onopen = () => resolve();\n\n this.ws.onerror = () => {\n reject(new Error(`WebSocket connection failed: ${this.url}`));\n };\n\n this.ws.onmessage = (event: MessageEvent) => {\n if (this.subprotocol === \"satmouse-binary\" && event.data instanceof ArrayBuffer) {\n const decoded = decodeWsBinaryFrame(event.data);\n if (decoded?.type === \"spatialData\") this.onSpatialData?.(decoded.data);\n else if (decoded?.type === \"buttonEvent\") this.onButtonEvent?.(decoded.data);\n } else if (typeof event.data === \"string\") {\n try {\n const msg = JSON.parse(event.data);\n if (msg.type === \"spatialData\") this.onSpatialData?.(msg.data);\n else if (msg.type === \"buttonEvent\") this.onButtonEvent?.(msg.data);\n else if (msg.type === \"deviceStatus\") {\n this.onDeviceStatus?.(msg.data.event, msg.data.device);\n }\n } catch {\n // Ignore malformed messages\n }\n }\n };\n\n this.ws.onclose = () => this.onClose?.();\n });\n }\n\n close(): void {\n try {\n this.ws?.close();\n } catch {}\n this.ws = null;\n }\n}\n","import type { Transport } from \"./transport.js\";\nimport type { SpatialData, ButtonEvent, DeviceInfo } from \"../types.js\";\n\n/**\n * Safari Web Extension transport adapter.\n *\n * The SatMouse extension's content script sets window.__satmouseExtensionAvailable\n * and bridges postMessage ↔ background script ↔ WebSocket to the bridge.\n *\n * This transport is transparent to the SDK — it just works when the extension\n * is installed, bypassing Safari's mixed-content restrictions entirely.\n */\nexport class ExtensionAdapter implements Transport {\n readonly protocol = \"extension\" as const;\n\n onSpatialData: ((data: SpatialData) => void) | null = null;\n onButtonEvent: ((data: ButtonEvent) => void) | null = null;\n onDeviceStatus: ((event: \"connected\" | \"disconnected\", device: DeviceInfo) => void) | null = null;\n onClose: (() => void) | null = null;\n onError: ((error: Error) => void) | null = null;\n\n private messageHandler: ((event: MessageEvent) => void) | null = null;\n private pendingDeviceFetch: ((devices: DeviceInfo[]) => void) | null = null;\n\n static isAvailable(): boolean {\n return !!(globalThis as any).__satmouseExtensionAvailable;\n }\n\n async connect(): Promise<void> {\n if (typeof globalThis.postMessage !== \"function\") {\n throw new Error(\"postMessage not available\");\n }\n\n return new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.close();\n reject(new Error(\"Extension connection timeout\"));\n }, 5000);\n\n this.messageHandler = (event: MessageEvent) => {\n if (event.data?.source !== \"satmouse-extension\") return;\n const msg = event.data;\n\n if ((msg.type === \"connected\" || msg.type === \"bridgeConnected\") && timeout) {\n clearTimeout(timeout);\n resolve();\n }\n\n if (msg.type === \"disconnected\") {\n this.onClose?.();\n }\n\n if (msg.type === \"spatialData\" && msg.data) {\n this.onSpatialData?.(msg.data as SpatialData);\n }\n\n if (msg.type === \"buttonEvent\" && msg.data) {\n this.onButtonEvent?.(msg.data as ButtonEvent);\n }\n\n if (msg.type === \"deviceStatus\" && msg.data) {\n this.onDeviceStatus?.(msg.data.event, msg.data.device);\n }\n\n if (msg.type === \"deviceList\" && this.pendingDeviceFetch) {\n this.pendingDeviceFetch(Array.isArray(msg.data) ? msg.data : []);\n this.pendingDeviceFetch = null;\n }\n };\n\n globalThis.addEventListener(\"message\", this.messageHandler);\n globalThis.postMessage({ target: \"satmouse-extension\", action: \"connect\" }, \"*\");\n });\n }\n\n fetchDeviceInfo(): Promise<DeviceInfo[]> {\n return new Promise((resolve) => {\n this.pendingDeviceFetch = resolve;\n globalThis.postMessage({ target: \"satmouse-extension\", action: \"fetchDevices\" }, \"*\");\n setTimeout(() => {\n if (this.pendingDeviceFetch) {\n this.pendingDeviceFetch = null;\n resolve([]);\n }\n }, 3000);\n });\n }\n\n close(): void {\n if (this.messageHandler) {\n globalThis.removeEventListener(\"message\", this.messageHandler);\n this.messageHandler = null;\n }\n globalThis.postMessage({ target: \"satmouse-extension\", action: \"disconnect\" }, \"*\");\n }\n}\n","import { TypedEmitter } from \"./emitter.js\";\nimport { fetchThingDescription, resolveEndpoints } from \"./discovery.js\";\nimport { WebTransportAdapter } from \"./transports/webtransport.js\";\nimport { WebSocketAdapter } from \"./transports/websocket.js\";\nimport { ExtensionAdapter } from \"./transports/extension.js\";\nimport type { Transport } from \"./transports/transport.js\";\nimport type {\n ConnectOptions,\n ConnectionState,\n DeviceInfo,\n SatMouseEvents,\n TransportProtocol,\n} from \"./types.js\";\n\n/**\n * Build a satmouse:// connect URI from connection parameters.\n */\nexport function buildSatMouseUri(host = \"localhost\", wsPort = 18945, wtPort = 18946): string {\n return `satmouse://connect?host=${encodeURIComponent(host)}&wsPort=${wsPort}&wtPort=${wtPort}`;\n}\n\n/**\n * Parse a satmouse:// URI into connection parameters.\n *\n * Format: satmouse://connect?host=<ip>&wsPort=<port>&wtPort=<port>\n * All query params are optional. Defaults: host=localhost, wsPort=4444, wtPort=4443.\n */\nexport function parseSatMouseUri(uri: string): { tdUrl: string; wsUrl: string; wtUrl: string } {\n const url = new URL(uri);\n const host = url.searchParams.get(\"host\") ?? \"localhost\";\n const wsPort = url.searchParams.get(\"wsPort\") ?? \"18945\";\n const wtPort = url.searchParams.get(\"wtPort\") ?? \"18946\";\n return {\n tdUrl: `http://${host}:${wsPort}/td.json`,\n wsUrl: `ws://${host}:${wsPort}/spatial`,\n wtUrl: `https://${host}:${wtPort}`,\n };\n}\n\nconst DEFAULT_OPTIONS: Required<\n Pick<ConnectOptions, \"transports\" | \"reconnectDelay\" | \"maxRetries\" | \"wsSubprotocol\">\n> = {\n transports: [\"webtransport\", \"extension\", \"websocket\"],\n reconnectDelay: 2000,\n maxRetries: 3,\n wsSubprotocol: \"satmouse-json\",\n};\n\n/**\n * Core connection to a SatMouse bridge.\n *\n * Handles discovery (via WoT Thing Description), transport negotiation\n * (WebTransport with WebSocket fallback), event dispatch, and auto-reconnect.\n */\nexport class SatMouseConnection extends TypedEmitter<SatMouseEvents> {\n private options: ConnectOptions & typeof DEFAULT_OPTIONS;\n private transport: Transport | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private intentionalClose = false;\n private deviceInfoUrl: string | null = null;\n private retryCount = 0;\n\n private _state: ConnectionState = \"disconnected\";\n private _protocol: TransportProtocol = \"none\";\n\n get state(): ConnectionState {\n return this._state;\n }\n get protocol(): TransportProtocol {\n return this._protocol;\n }\n\n constructor(options?: ConnectOptions) {\n super();\n this.options = { ...DEFAULT_OPTIONS, ...options };\n }\n\n async connect(): Promise<void> {\n this.intentionalClose = false;\n this.setState(\"connecting\", \"none\");\n\n // Resolve endpoints — satmouse:// URI takes priority\n let wtUrl = this.options.wtUrl;\n let wsUrl = this.options.wsUrl;\n let certHash = this.options.certHash;\n\n if (this.options.uri) {\n const parsed = parseSatMouseUri(this.options.uri);\n wtUrl = wtUrl ?? parsed.wtUrl;\n wsUrl = wsUrl ?? parsed.wsUrl;\n this.options.tdUrl = this.options.tdUrl ?? parsed.tdUrl;\n }\n\n if (!wtUrl && !wsUrl) {\n const tdUrl = this.options.tdUrl;\n // Use 127.0.0.1 (not localhost) — browsers treat the loopback IP as a\n // \"Potentially Trustworthy Origin\" more reliably than the hostname.\n // Try HTTP first (Chrome allows PNA preflight to localhost),\n // then HTTPS (self-signed cert, may fail).\n const tdUrls = tdUrl\n ? [tdUrl]\n : [\n \"http://127.0.0.1:18945/td.json\",\n \"https://127.0.0.1:18947/td.json\",\n ];\n\n let resolved = false;\n for (const url of tdUrls) {\n try {\n const td = await fetchThingDescription(url);\n const endpoints = resolveEndpoints(td);\n wtUrl = endpoints.webtransport?.url;\n wsUrl = endpoints.websocket?.url;\n certHash = certHash ?? endpoints.webtransport?.certHash;\n this.deviceInfoUrl = endpoints.deviceInfoUrl ?? null;\n resolved = true;\n break;\n } catch {\n // Try next URL\n }\n }\n if (!resolved) {\n this.emit(\"error\", new Error(\"Failed to fetch Thing Description\"));\n // Last-resort WebSocket URL. Chrome allows ws://127.0.0.1 from HTTPS\n // pages via PNA preflight. Safari blocks it (extension handles that).\n wsUrl = \"ws://127.0.0.1:18945/spatial\";\n }\n }\n\n // Try transports in preference order\n for (const proto of this.options.transports) {\n if (proto === \"webtransport\" && wtUrl) {\n try {\n if (typeof globalThis.WebTransport === \"undefined\") continue;\n const adapter = new WebTransportAdapter(wtUrl, certHash);\n if (await this.tryTransport(adapter)) return;\n } catch {\n continue;\n }\n }\n if (proto === \"extension\") {\n try {\n if (!ExtensionAdapter.isAvailable()) continue;\n const adapter = new ExtensionAdapter();\n if (await this.tryTransport(adapter)) return;\n } catch {\n continue;\n }\n }\n if (proto === \"websocket\" && wsUrl) {\n try {\n const adapter = new WebSocketAdapter(wsUrl, this.options.wsSubprotocol);\n if (await this.tryTransport(adapter)) return;\n } catch {\n continue;\n }\n }\n }\n\n this.setState(\"disconnected\", \"none\");\n this.scheduleReconnect();\n }\n\n /** Reset retry count and reconnect. Use after \"failed\" state. */\n retry(): void {\n this.retryCount = 0;\n this.intentionalClose = false;\n this.connect();\n }\n\n disconnect(): void {\n this.intentionalClose = true;\n this.clearReconnect();\n this.transport?.close();\n this.transport = null;\n this.setState(\"disconnected\", \"none\");\n }\n\n async fetchDeviceInfo(): Promise<DeviceInfo[]> {\n // Try HTTP endpoint first\n if (this.deviceInfoUrl) {\n try {\n const res = await globalThis.fetch(this.deviceInfoUrl);\n if (res.ok) {\n const data = await res.json();\n return data.devices ?? [];\n }\n } catch {\n // HTTP blocked (Safari HTTPS → localhost) — fall through to extension\n }\n }\n\n // Fall back to extension transport if connected via extension\n if (this.transport && \"fetchDeviceInfo\" in this.transport) {\n return (this.transport as ExtensionAdapter).fetchDeviceInfo();\n }\n\n return [];\n }\n\n private async tryTransport(adapter: Transport): Promise<boolean> {\n adapter.onSpatialData = (data) => this.emit(\"spatialData\", data);\n adapter.onButtonEvent = (data) => this.emit(\"buttonEvent\", data);\n adapter.onError = (err) => this.emit(\"error\", err);\n\n if (\"onDeviceStatus\" in adapter) {\n (adapter as any).onDeviceStatus = (event: \"connected\" | \"disconnected\", device: DeviceInfo) => {\n this.emit(\"deviceStatus\", event, device);\n };\n }\n\n adapter.onClose = () => {\n this.transport = null;\n this.setState(\"disconnected\", \"none\");\n if (!this.intentionalClose) this.scheduleReconnect();\n };\n\n try {\n // Timeout transport connection attempts to prevent hanging the fallback chain\n await Promise.race([\n adapter.connect(),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(`${adapter.protocol} connection timeout`)), 5000)\n ),\n ]);\n this.transport = adapter;\n this.retryCount = 0;\n this.setState(\"connected\", adapter.protocol);\n return true;\n } catch (err) {\n adapter.close();\n this.emit(\"error\", err instanceof Error ? err : new Error(String(err)));\n return false;\n }\n }\n\n private setState(state: ConnectionState, protocol: TransportProtocol): void {\n if (this._state === state && this._protocol === protocol) return;\n this._state = state;\n this._protocol = protocol;\n this.emit(\"stateChange\", state, protocol);\n }\n\n private scheduleReconnect(): void {\n if (this.options.reconnectDelay <= 0 || this.intentionalClose) return;\n\n this.retryCount++;\n console.log(`[SatMouse] Reconnect attempt ${this.retryCount}/${this.options.maxRetries}`);\n if (this.retryCount > this.options.maxRetries) {\n console.log(\"[SatMouse] Max retries exceeded, giving up\");\n this.setState(\"failed\", \"none\");\n return;\n }\n\n this.clearReconnect();\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, this.options.reconnectDelay);\n }\n\n private clearReconnect(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n}\n","const SCHEME_URL = \"satmouse://launch\";\nconst PROJECT_URL = \"https://github.com/kelnishi/SatMouse/releases/latest\";\n\n/** Result of a URI scheme negotiation */\nexport interface NegotiateResult {\n ip: string;\n wsPort: number;\n wtPort: number;\n httpsPort: number;\n certHash?: string;\n challenge?: string;\n}\n\n/**\n * Trigger the satmouse://negotiate URI scheme for discovery when direct\n * HTTP/HTTPS fetch is blocked (Safari LNA).\n *\n * The bridge intercepts the URI, then redirects back to your origin with\n * connection details as query parameters. Your app handles the callback\n * route and passes the result to SatMouseConnection.\n *\n * @param origin - Your app's origin (e.g., \"https://kelcite.app\")\n * @param callbackPath - Path the bridge redirects to (default: \"/satmouse-handshake\")\n * @param challenge - Optional challenge token for verification\n */\nexport function negotiateViaSatMouse(origin: string, callbackPath = \"/satmouse-handshake\", challenge?: string): void {\n const params = new URLSearchParams({ origin, callback: callbackPath });\n if (challenge) params.set(\"challenge\", challenge);\n globalThis.location.href = `satmouse://negotiate?${params}`;\n}\n\n/**\n * Parse the negotiate callback URL parameters (called on your callback route).\n * Returns connection details or null if the params are missing.\n */\nexport function parseNegotiateCallback(searchParams: URLSearchParams): NegotiateResult | null {\n const ip = searchParams.get(\"ip\");\n const wsPort = searchParams.get(\"wsPort\");\n if (!ip || !wsPort) return null;\n return {\n ip,\n wsPort: parseInt(wsPort, 10),\n wtPort: parseInt(searchParams.get(\"wtPort\") ?? \"18946\", 10),\n httpsPort: parseInt(searchParams.get(\"httpsPort\") ?? \"18947\", 10),\n certHash: searchParams.get(\"certHash\") ?? undefined,\n challenge: searchParams.get(\"challenge\") ?? undefined,\n };\n}\n\nexport interface LaunchOptions {\n /** URL scheme to open. Default: \"satmouse://launch\" */\n schemeUrl?: string;\n /** Fallback URL if the app is not installed. Default: GitHub releases page */\n fallbackUrl?: string;\n /** Timeout in ms before assuming the app is not installed. Default: 2500 */\n timeout?: number;\n}\n\n/**\n * Attempt to launch SatMouse via the `satmouse://` URL scheme.\n *\n * If the app is installed and registered, the OS opens it. If not,\n * navigates to the fallback URL (project releases page) after a timeout.\n *\n * Returns true if the scheme likely opened, false if it fell back.\n */\nexport function launchSatMouse(options?: LaunchOptions): Promise<boolean> {\n const schemeUrl = options?.schemeUrl ?? SCHEME_URL;\n const timeout = options?.timeout ?? 2500;\n\n // Validate fallback URL — only allow http/https to prevent javascript: or data: injection\n let fallbackUrl = PROJECT_URL;\n if (options?.fallbackUrl) {\n try {\n const parsed = new URL(options.fallbackUrl);\n if (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") {\n fallbackUrl = options.fallbackUrl;\n }\n } catch {}\n }\n\n return new Promise((resolve) => {\n // Track if we leave the page (scheme handler opened the app)\n let launched = false;\n\n const onBlur = () => {\n launched = true;\n };\n globalThis.addEventListener(\"blur\", onBlur);\n\n // Use a hidden iframe to trigger the scheme without navigating away\n const iframe = document.createElement(\"iframe\");\n iframe.style.display = \"none\";\n iframe.src = schemeUrl;\n document.body.appendChild(iframe);\n\n setTimeout(() => {\n globalThis.removeEventListener(\"blur\", onBlur);\n document.body.removeChild(iframe);\n\n if (launched || document.hidden) {\n resolve(true);\n } else {\n // App not installed — redirect to project page\n globalThis.location.href = fallbackUrl;\n resolve(false);\n }\n }, timeout);\n });\n}\n"]}
@@ -347,8 +347,8 @@ var SatMouseConnection = class extends TypedEmitter {
347
347
  if (!wtUrl && !wsUrl) {
348
348
  const tdUrl = this.options.tdUrl;
349
349
  const tdUrls = tdUrl ? [tdUrl] : [
350
- "https://127.0.0.1:18947/td.json",
351
- "http://127.0.0.1:18945/td.json"
350
+ "http://127.0.0.1:18945/td.json",
351
+ "https://127.0.0.1:18947/td.json"
352
352
  ];
353
353
  let resolved = false;
354
354
  for (const url of tdUrls) {
@@ -366,8 +366,7 @@ var SatMouseConnection = class extends TypedEmitter {
366
366
  }
367
367
  if (!resolved) {
368
368
  this.emit("error", new Error("Failed to fetch Thing Description"));
369
- const isSecurePage = typeof globalThis.location !== "undefined" && globalThis.location.protocol === "https:";
370
- wsUrl = isSecurePage ? "wss://127.0.0.1:18947/spatial" : "ws://127.0.0.1:18945/spatial";
369
+ wsUrl = "ws://127.0.0.1:18945/spatial";
371
370
  }
372
371
  }
373
372
  for (const proto of this.options.transports) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/discovery.ts","../../src/core/decode.ts","../../src/core/transports/webtransport.ts","../../src/core/transports/websocket.ts","../../src/core/transports/extension.ts","../../src/core/connection.ts","../../src/core/launch.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { ThingDescription } from \"./types.js\";\n\nexport interface ResolvedEndpoints {\n webtransport?: { url: string; certHash?: string };\n websocket?: { url: string };\n deviceInfoUrl?: string;\n}\n\n/** Fetch the WoT Thing Description from the bridge */\nexport async function fetchThingDescription(tdUrl: string): Promise<ThingDescription> {\n const res = await globalThis.fetch(tdUrl);\n if (!res.ok) throw new Error(`Failed to fetch TD: HTTP ${res.status}`);\n return res.json() as Promise<ThingDescription>;\n}\n\n/** Extract WebTransport, WebSocket, and device info endpoints from a Thing Description */\nexport function resolveEndpoints(td: ThingDescription): ResolvedEndpoints {\n const result: ResolvedEndpoints = {};\n\n const spatialForms = td.events?.spatialData?.forms ?? [];\n\n const wtForm = spatialForms.find((f) => f.subprotocol === \"webtransport\");\n if (wtForm) {\n result.webtransport = {\n url: wtForm.href,\n certHash: td[\"satmouse:certHash\"],\n };\n }\n\n const wsForm = spatialForms.find((f) => f.subprotocol === \"websocket\");\n if (wsForm) {\n result.websocket = { url: wsForm.href };\n }\n\n const deviceForm = td.properties?.deviceInfo?.forms?.[0];\n if (deviceForm) {\n result.deviceInfoUrl = deviceForm.href;\n }\n\n return result;\n}\n","import type { SpatialData, ButtonEvent } from \"./types.js\";\n\n/** Decode 24-byte binary spatial data datagram (WebTransport or raw binary) */\nexport function decodeBinaryFrame(buffer: ArrayBuffer | Uint8Array): SpatialData {\n const len = buffer instanceof ArrayBuffer ? buffer.byteLength : buffer.byteLength;\n if (len < 20) {\n throw new RangeError(`Spatial frame too short: expected ≥20 bytes, got ${len}`);\n }\n const ab = buffer instanceof ArrayBuffer ? buffer : buffer.buffer;\n const offset = buffer instanceof Uint8Array ? buffer.byteOffset : 0;\n const view = new DataView(ab, offset);\n return {\n translation: {\n x: view.getInt16(8, true),\n y: view.getInt16(10, true),\n z: view.getInt16(12, true),\n },\n rotation: {\n x: view.getInt16(14, true),\n y: view.getInt16(16, true),\n z: view.getInt16(18, true),\n },\n timestamp: view.getFloat64(0, true),\n };\n}\n\n/** Decode WebSocket binary frame (1-byte type prefix + 24-byte payload) */\nexport function decodeWsBinaryFrame(\n buffer: ArrayBuffer | Uint8Array,\n): { type: \"spatialData\"; data: SpatialData } | { type: \"buttonEvent\"; data: ButtonEvent } | null {\n const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);\n if (bytes.length < 1) return null;\n\n const typePrefix = bytes[0];\n if (typePrefix === 0x01 && bytes.length >= 25) {\n return { type: \"spatialData\", data: decodeBinaryFrame(bytes.subarray(1, 25)) };\n }\n if (typePrefix === 0x02) {\n const json = new TextDecoder().decode(bytes.subarray(1));\n return { type: \"buttonEvent\", data: JSON.parse(json) as ButtonEvent };\n }\n return null;\n}\n\n/** Decode length-prefixed JSON button events from a WebTransport stream chunk */\nexport function decodeButtonStream(\n buffer: Uint8Array<ArrayBufferLike>,\n): { events: ButtonEvent[]; remainder: Uint8Array<ArrayBufferLike> } {\n const events: ButtonEvent[] = [];\n let pos = 0;\n\n while (pos + 4 <= buffer.length) {\n const view = new DataView(buffer.buffer, buffer.byteOffset + pos);\n const len = view.getUint32(0, true);\n // Guard against absurd lengths\n if (len > 65536 || pos + 4 + len > buffer.length) break;\n const json = new TextDecoder().decode(buffer.subarray(pos + 4, pos + 4 + len));\n try {\n const event = JSON.parse(json);\n if (typeof event.button === \"number\" && typeof event.pressed === \"boolean\") {\n events.push(event as ButtonEvent);\n }\n } catch {\n // Skip malformed JSON frames\n }\n pos += 4 + len;\n }\n\n return { events, remainder: buffer.subarray(pos) };\n}\n","import type { Transport } from \"./transport.js\";\nimport type { SpatialData, ButtonEvent } from \"../types.js\";\nimport { decodeBinaryFrame, decodeButtonStream } from \"../decode.js\";\n\nexport class WebTransportAdapter implements Transport {\n readonly protocol = \"webtransport\" as const;\n\n onSpatialData: ((data: SpatialData) => void) | null = null;\n onButtonEvent: ((data: ButtonEvent) => void) | null = null;\n onClose: (() => void) | null = null;\n onError: ((error: Error) => void) | null = null;\n\n private transport: any = null;\n private url: string;\n private certHash?: string;\n\n constructor(url: string, certHash?: string) {\n this.url = url;\n this.certHash = certHash;\n }\n\n async connect(): Promise<void> {\n if (typeof globalThis.WebTransport === \"undefined\") {\n throw new Error(\"WebTransport is not available in this environment\");\n }\n\n const options: any = {};\n if (this.certHash) {\n options.serverCertificateHashes = [\n {\n algorithm: \"sha-256\",\n value: Uint8Array.from(atob(this.certHash), (c) => c.charCodeAt(0)),\n },\n ];\n }\n\n this.transport = new (globalThis as any).WebTransport(this.url, options);\n await this.transport.ready;\n\n this.readDatagrams();\n this.readStreams();\n\n this.transport.closed\n .then(() => this.onClose?.())\n .catch(() => this.onClose?.());\n }\n\n close(): void {\n try {\n this.transport?.close();\n } catch {}\n this.transport = null;\n }\n\n private async readDatagrams(): Promise<void> {\n const reader = this.transport.datagrams.readable.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n this.onSpatialData?.(decodeBinaryFrame(value));\n }\n } catch {\n // Transport closed\n }\n }\n\n private async readStreams(): Promise<void> {\n const reader = this.transport.incomingUnidirectionalStreams.getReader();\n try {\n while (true) {\n const { value: stream, done } = await reader.read();\n if (done) break;\n this.readButtonStream(stream);\n }\n } catch {\n // Transport closed\n }\n }\n\n private async readButtonStream(stream: any): Promise<void> {\n const reader = stream.getReader();\n let buffer: Uint8Array<ArrayBufferLike> = new Uint8Array(0);\n\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n\n const newBuf = new Uint8Array(buffer.length + value.length);\n newBuf.set(buffer);\n newBuf.set(value, buffer.length);\n\n const { events, remainder } = decodeButtonStream(newBuf);\n for (const event of events) {\n this.onButtonEvent?.(event);\n }\n buffer = remainder;\n }\n } catch {\n // Stream closed\n }\n }\n}\n","import type { Transport } from \"./transport.js\";\nimport type { SpatialData, ButtonEvent, DeviceInfo } from \"../types.js\";\nimport { decodeWsBinaryFrame } from \"../decode.js\";\n\nexport class WebSocketAdapter implements Transport {\n readonly protocol = \"websocket\" as const;\n\n onSpatialData: ((data: SpatialData) => void) | null = null;\n onButtonEvent: ((data: ButtonEvent) => void) | null = null;\n onDeviceStatus: ((event: \"connected\" | \"disconnected\", device: DeviceInfo) => void) | null = null;\n onClose: (() => void) | null = null;\n onError: ((error: Error) => void) | null = null;\n\n private ws: WebSocket | null = null;\n private url: string;\n private subprotocol: string;\n\n constructor(url: string, subprotocol: string = \"satmouse-json\") {\n this.url = url;\n this.subprotocol = subprotocol;\n }\n\n async connect(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n this.ws = new globalThis.WebSocket(this.url, this.subprotocol);\n if (this.subprotocol === \"satmouse-binary\") {\n this.ws.binaryType = \"arraybuffer\";\n }\n\n this.ws.onopen = () => resolve();\n\n this.ws.onerror = () => {\n reject(new Error(`WebSocket connection failed: ${this.url}`));\n };\n\n this.ws.onmessage = (event: MessageEvent) => {\n if (this.subprotocol === \"satmouse-binary\" && event.data instanceof ArrayBuffer) {\n const decoded = decodeWsBinaryFrame(event.data);\n if (decoded?.type === \"spatialData\") this.onSpatialData?.(decoded.data);\n else if (decoded?.type === \"buttonEvent\") this.onButtonEvent?.(decoded.data);\n } else if (typeof event.data === \"string\") {\n try {\n const msg = JSON.parse(event.data);\n if (msg.type === \"spatialData\") this.onSpatialData?.(msg.data);\n else if (msg.type === \"buttonEvent\") this.onButtonEvent?.(msg.data);\n else if (msg.type === \"deviceStatus\") {\n this.onDeviceStatus?.(msg.data.event, msg.data.device);\n }\n } catch {\n // Ignore malformed messages\n }\n }\n };\n\n this.ws.onclose = () => this.onClose?.();\n });\n }\n\n close(): void {\n try {\n this.ws?.close();\n } catch {}\n this.ws = null;\n }\n}\n","import type { Transport } from \"./transport.js\";\nimport type { SpatialData, ButtonEvent, DeviceInfo } from \"../types.js\";\n\n/**\n * Safari Web Extension transport adapter.\n *\n * The SatMouse extension's content script sets window.__satmouseExtensionAvailable\n * and bridges postMessage ↔ background script ↔ WebSocket to the bridge.\n *\n * This transport is transparent to the SDK — it just works when the extension\n * is installed, bypassing Safari's mixed-content restrictions entirely.\n */\nexport class ExtensionAdapter implements Transport {\n readonly protocol = \"extension\" as const;\n\n onSpatialData: ((data: SpatialData) => void) | null = null;\n onButtonEvent: ((data: ButtonEvent) => void) | null = null;\n onDeviceStatus: ((event: \"connected\" | \"disconnected\", device: DeviceInfo) => void) | null = null;\n onClose: (() => void) | null = null;\n onError: ((error: Error) => void) | null = null;\n\n private messageHandler: ((event: MessageEvent) => void) | null = null;\n private pendingDeviceFetch: ((devices: DeviceInfo[]) => void) | null = null;\n\n static isAvailable(): boolean {\n return !!(globalThis as any).__satmouseExtensionAvailable;\n }\n\n async connect(): Promise<void> {\n if (typeof globalThis.postMessage !== \"function\") {\n throw new Error(\"postMessage not available\");\n }\n\n return new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.close();\n reject(new Error(\"Extension connection timeout\"));\n }, 5000);\n\n this.messageHandler = (event: MessageEvent) => {\n if (event.data?.source !== \"satmouse-extension\") return;\n const msg = event.data;\n\n if ((msg.type === \"connected\" || msg.type === \"bridgeConnected\") && timeout) {\n clearTimeout(timeout);\n resolve();\n }\n\n if (msg.type === \"disconnected\") {\n this.onClose?.();\n }\n\n if (msg.type === \"spatialData\" && msg.data) {\n this.onSpatialData?.(msg.data as SpatialData);\n }\n\n if (msg.type === \"buttonEvent\" && msg.data) {\n this.onButtonEvent?.(msg.data as ButtonEvent);\n }\n\n if (msg.type === \"deviceStatus\" && msg.data) {\n this.onDeviceStatus?.(msg.data.event, msg.data.device);\n }\n\n if (msg.type === \"deviceList\" && this.pendingDeviceFetch) {\n this.pendingDeviceFetch(Array.isArray(msg.data) ? msg.data : []);\n this.pendingDeviceFetch = null;\n }\n };\n\n globalThis.addEventListener(\"message\", this.messageHandler);\n globalThis.postMessage({ target: \"satmouse-extension\", action: \"connect\" }, \"*\");\n });\n }\n\n fetchDeviceInfo(): Promise<DeviceInfo[]> {\n return new Promise((resolve) => {\n this.pendingDeviceFetch = resolve;\n globalThis.postMessage({ target: \"satmouse-extension\", action: \"fetchDevices\" }, \"*\");\n setTimeout(() => {\n if (this.pendingDeviceFetch) {\n this.pendingDeviceFetch = null;\n resolve([]);\n }\n }, 3000);\n });\n }\n\n close(): void {\n if (this.messageHandler) {\n globalThis.removeEventListener(\"message\", this.messageHandler);\n this.messageHandler = null;\n }\n globalThis.postMessage({ target: \"satmouse-extension\", action: \"disconnect\" }, \"*\");\n }\n}\n","import { TypedEmitter } from \"./emitter.js\";\nimport { fetchThingDescription, resolveEndpoints } from \"./discovery.js\";\nimport { WebTransportAdapter } from \"./transports/webtransport.js\";\nimport { WebSocketAdapter } from \"./transports/websocket.js\";\nimport { ExtensionAdapter } from \"./transports/extension.js\";\nimport type { Transport } from \"./transports/transport.js\";\nimport type {\n ConnectOptions,\n ConnectionState,\n DeviceInfo,\n SatMouseEvents,\n TransportProtocol,\n} from \"./types.js\";\n\n/**\n * Build a satmouse:// connect URI from connection parameters.\n */\nexport function buildSatMouseUri(host = \"localhost\", wsPort = 18945, wtPort = 18946): string {\n return `satmouse://connect?host=${encodeURIComponent(host)}&wsPort=${wsPort}&wtPort=${wtPort}`;\n}\n\n/**\n * Parse a satmouse:// URI into connection parameters.\n *\n * Format: satmouse://connect?host=<ip>&wsPort=<port>&wtPort=<port>\n * All query params are optional. Defaults: host=localhost, wsPort=4444, wtPort=4443.\n */\nexport function parseSatMouseUri(uri: string): { tdUrl: string; wsUrl: string; wtUrl: string } {\n const url = new URL(uri);\n const host = url.searchParams.get(\"host\") ?? \"localhost\";\n const wsPort = url.searchParams.get(\"wsPort\") ?? \"18945\";\n const wtPort = url.searchParams.get(\"wtPort\") ?? \"18946\";\n return {\n tdUrl: `http://${host}:${wsPort}/td.json`,\n wsUrl: `ws://${host}:${wsPort}/spatial`,\n wtUrl: `https://${host}:${wtPort}`,\n };\n}\n\nconst DEFAULT_OPTIONS: Required<\n Pick<ConnectOptions, \"transports\" | \"reconnectDelay\" | \"maxRetries\" | \"wsSubprotocol\">\n> = {\n transports: [\"webtransport\", \"extension\", \"websocket\"],\n reconnectDelay: 2000,\n maxRetries: 3,\n wsSubprotocol: \"satmouse-json\",\n};\n\n/**\n * Core connection to a SatMouse bridge.\n *\n * Handles discovery (via WoT Thing Description), transport negotiation\n * (WebTransport with WebSocket fallback), event dispatch, and auto-reconnect.\n */\nexport class SatMouseConnection extends TypedEmitter<SatMouseEvents> {\n private options: ConnectOptions & typeof DEFAULT_OPTIONS;\n private transport: Transport | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private intentionalClose = false;\n private deviceInfoUrl: string | null = null;\n private retryCount = 0;\n\n private _state: ConnectionState = \"disconnected\";\n private _protocol: TransportProtocol = \"none\";\n\n get state(): ConnectionState {\n return this._state;\n }\n get protocol(): TransportProtocol {\n return this._protocol;\n }\n\n constructor(options?: ConnectOptions) {\n super();\n this.options = { ...DEFAULT_OPTIONS, ...options };\n }\n\n async connect(): Promise<void> {\n this.intentionalClose = false;\n this.setState(\"connecting\", \"none\");\n\n // Resolve endpoints — satmouse:// URI takes priority\n let wtUrl = this.options.wtUrl;\n let wsUrl = this.options.wsUrl;\n let certHash = this.options.certHash;\n\n if (this.options.uri) {\n const parsed = parseSatMouseUri(this.options.uri);\n wtUrl = wtUrl ?? parsed.wtUrl;\n wsUrl = wsUrl ?? parsed.wsUrl;\n this.options.tdUrl = this.options.tdUrl ?? parsed.tdUrl;\n }\n\n if (!wtUrl && !wsUrl) {\n const tdUrl = this.options.tdUrl;\n // Use 127.0.0.1 (not localhost) — Safari treats the loopback IP as a\n // \"Potentially Trustworthy Origin\" more reliably than the hostname.\n // Try HTTPS first (works from HTTPS pages), fall back to HTTP.\n const tdUrls = tdUrl\n ? [tdUrl]\n : [\n \"https://127.0.0.1:18947/td.json\",\n \"http://127.0.0.1:18945/td.json\",\n ];\n\n let resolved = false;\n for (const url of tdUrls) {\n try {\n const td = await fetchThingDescription(url);\n const endpoints = resolveEndpoints(td);\n wtUrl = endpoints.webtransport?.url;\n wsUrl = endpoints.websocket?.url;\n certHash = certHash ?? endpoints.webtransport?.certHash;\n this.deviceInfoUrl = endpoints.deviceInfoUrl ?? null;\n resolved = true;\n break;\n } catch {\n // Try next URL\n }\n }\n if (!resolved) {\n this.emit(\"error\", new Error(\"Failed to fetch Thing Description\"));\n // On HTTPS pages, ws:// is blocked as mixed content.\n // Try wss:// on the HTTPS port; fall back to ws:// for HTTP pages.\n const isSecurePage = typeof globalThis.location !== \"undefined\" && globalThis.location.protocol === \"https:\";\n wsUrl = isSecurePage\n ? \"wss://127.0.0.1:18947/spatial\"\n : \"ws://127.0.0.1:18945/spatial\";\n }\n }\n\n // Try transports in preference order\n for (const proto of this.options.transports) {\n if (proto === \"webtransport\" && wtUrl) {\n try {\n if (typeof globalThis.WebTransport === \"undefined\") continue;\n const adapter = new WebTransportAdapter(wtUrl, certHash);\n if (await this.tryTransport(adapter)) return;\n } catch {\n continue;\n }\n }\n if (proto === \"extension\") {\n try {\n if (!ExtensionAdapter.isAvailable()) continue;\n const adapter = new ExtensionAdapter();\n if (await this.tryTransport(adapter)) return;\n } catch {\n continue;\n }\n }\n if (proto === \"websocket\" && wsUrl) {\n try {\n const adapter = new WebSocketAdapter(wsUrl, this.options.wsSubprotocol);\n if (await this.tryTransport(adapter)) return;\n } catch {\n continue;\n }\n }\n }\n\n this.setState(\"disconnected\", \"none\");\n this.scheduleReconnect();\n }\n\n /** Reset retry count and reconnect. Use after \"failed\" state. */\n retry(): void {\n this.retryCount = 0;\n this.intentionalClose = false;\n this.connect();\n }\n\n disconnect(): void {\n this.intentionalClose = true;\n this.clearReconnect();\n this.transport?.close();\n this.transport = null;\n this.setState(\"disconnected\", \"none\");\n }\n\n async fetchDeviceInfo(): Promise<DeviceInfo[]> {\n // Try HTTP endpoint first\n if (this.deviceInfoUrl) {\n try {\n const res = await globalThis.fetch(this.deviceInfoUrl);\n if (res.ok) {\n const data = await res.json();\n return data.devices ?? [];\n }\n } catch {\n // HTTP blocked (Safari HTTPS → localhost) — fall through to extension\n }\n }\n\n // Fall back to extension transport if connected via extension\n if (this.transport && \"fetchDeviceInfo\" in this.transport) {\n return (this.transport as ExtensionAdapter).fetchDeviceInfo();\n }\n\n return [];\n }\n\n private async tryTransport(adapter: Transport): Promise<boolean> {\n adapter.onSpatialData = (data) => this.emit(\"spatialData\", data);\n adapter.onButtonEvent = (data) => this.emit(\"buttonEvent\", data);\n adapter.onError = (err) => this.emit(\"error\", err);\n\n if (\"onDeviceStatus\" in adapter) {\n (adapter as any).onDeviceStatus = (event: \"connected\" | \"disconnected\", device: DeviceInfo) => {\n this.emit(\"deviceStatus\", event, device);\n };\n }\n\n adapter.onClose = () => {\n this.transport = null;\n this.setState(\"disconnected\", \"none\");\n if (!this.intentionalClose) this.scheduleReconnect();\n };\n\n try {\n // Timeout transport connection attempts to prevent hanging the fallback chain\n await Promise.race([\n adapter.connect(),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(`${adapter.protocol} connection timeout`)), 5000)\n ),\n ]);\n this.transport = adapter;\n this.retryCount = 0;\n this.setState(\"connected\", adapter.protocol);\n return true;\n } catch (err) {\n adapter.close();\n this.emit(\"error\", err instanceof Error ? err : new Error(String(err)));\n return false;\n }\n }\n\n private setState(state: ConnectionState, protocol: TransportProtocol): void {\n if (this._state === state && this._protocol === protocol) return;\n this._state = state;\n this._protocol = protocol;\n this.emit(\"stateChange\", state, protocol);\n }\n\n private scheduleReconnect(): void {\n if (this.options.reconnectDelay <= 0 || this.intentionalClose) return;\n\n this.retryCount++;\n console.log(`[SatMouse] Reconnect attempt ${this.retryCount}/${this.options.maxRetries}`);\n if (this.retryCount > this.options.maxRetries) {\n console.log(\"[SatMouse] Max retries exceeded, giving up\");\n this.setState(\"failed\", \"none\");\n return;\n }\n\n this.clearReconnect();\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, this.options.reconnectDelay);\n }\n\n private clearReconnect(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n}\n","const SCHEME_URL = \"satmouse://launch\";\nconst PROJECT_URL = \"https://github.com/kelnishi/SatMouse/releases/latest\";\n\n/** Result of a URI scheme negotiation */\nexport interface NegotiateResult {\n ip: string;\n wsPort: number;\n wtPort: number;\n httpsPort: number;\n certHash?: string;\n challenge?: string;\n}\n\n/**\n * Trigger the satmouse://negotiate URI scheme for discovery when direct\n * HTTP/HTTPS fetch is blocked (Safari LNA).\n *\n * The bridge intercepts the URI, then redirects back to your origin with\n * connection details as query parameters. Your app handles the callback\n * route and passes the result to SatMouseConnection.\n *\n * @param origin - Your app's origin (e.g., \"https://kelcite.app\")\n * @param callbackPath - Path the bridge redirects to (default: \"/satmouse-handshake\")\n * @param challenge - Optional challenge token for verification\n */\nexport function negotiateViaSatMouse(origin: string, callbackPath = \"/satmouse-handshake\", challenge?: string): void {\n const params = new URLSearchParams({ origin, callback: callbackPath });\n if (challenge) params.set(\"challenge\", challenge);\n globalThis.location.href = `satmouse://negotiate?${params}`;\n}\n\n/**\n * Parse the negotiate callback URL parameters (called on your callback route).\n * Returns connection details or null if the params are missing.\n */\nexport function parseNegotiateCallback(searchParams: URLSearchParams): NegotiateResult | null {\n const ip = searchParams.get(\"ip\");\n const wsPort = searchParams.get(\"wsPort\");\n if (!ip || !wsPort) return null;\n return {\n ip,\n wsPort: parseInt(wsPort, 10),\n wtPort: parseInt(searchParams.get(\"wtPort\") ?? \"18946\", 10),\n httpsPort: parseInt(searchParams.get(\"httpsPort\") ?? \"18947\", 10),\n certHash: searchParams.get(\"certHash\") ?? undefined,\n challenge: searchParams.get(\"challenge\") ?? undefined,\n };\n}\n\nexport interface LaunchOptions {\n /** URL scheme to open. Default: \"satmouse://launch\" */\n schemeUrl?: string;\n /** Fallback URL if the app is not installed. Default: GitHub releases page */\n fallbackUrl?: string;\n /** Timeout in ms before assuming the app is not installed. Default: 2500 */\n timeout?: number;\n}\n\n/**\n * Attempt to launch SatMouse via the `satmouse://` URL scheme.\n *\n * If the app is installed and registered, the OS opens it. If not,\n * navigates to the fallback URL (project releases page) after a timeout.\n *\n * Returns true if the scheme likely opened, false if it fell back.\n */\nexport function launchSatMouse(options?: LaunchOptions): Promise<boolean> {\n const schemeUrl = options?.schemeUrl ?? SCHEME_URL;\n const timeout = options?.timeout ?? 2500;\n\n // Validate fallback URL — only allow http/https to prevent javascript: or data: injection\n let fallbackUrl = PROJECT_URL;\n if (options?.fallbackUrl) {\n try {\n const parsed = new URL(options.fallbackUrl);\n if (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") {\n fallbackUrl = options.fallbackUrl;\n }\n } catch {}\n }\n\n return new Promise((resolve) => {\n // Track if we leave the page (scheme handler opened the app)\n let launched = false;\n\n const onBlur = () => {\n launched = true;\n };\n globalThis.addEventListener(\"blur\", onBlur);\n\n // Use a hidden iframe to trigger the scheme without navigating away\n const iframe = document.createElement(\"iframe\");\n iframe.style.display = \"none\";\n iframe.src = schemeUrl;\n document.body.appendChild(iframe);\n\n setTimeout(() => {\n globalThis.removeEventListener(\"blur\", onBlur);\n document.body.removeChild(iframe);\n\n if (launched || document.hidden) {\n resolve(true);\n } else {\n // App not installed — redirect to project page\n globalThis.location.href = fallbackUrl;\n resolve(false);\n }\n }, timeout);\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/core/discovery.ts","../../src/core/decode.ts","../../src/core/transports/webtransport.ts","../../src/core/transports/websocket.ts","../../src/core/transports/extension.ts","../../src/core/connection.ts","../../src/core/launch.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { ThingDescription } from \"./types.js\";\n\nexport interface ResolvedEndpoints {\n webtransport?: { url: string; certHash?: string };\n websocket?: { url: string };\n deviceInfoUrl?: string;\n}\n\n/** Fetch the WoT Thing Description from the bridge */\nexport async function fetchThingDescription(tdUrl: string): Promise<ThingDescription> {\n const res = await globalThis.fetch(tdUrl);\n if (!res.ok) throw new Error(`Failed to fetch TD: HTTP ${res.status}`);\n return res.json() as Promise<ThingDescription>;\n}\n\n/** Extract WebTransport, WebSocket, and device info endpoints from a Thing Description */\nexport function resolveEndpoints(td: ThingDescription): ResolvedEndpoints {\n const result: ResolvedEndpoints = {};\n\n const spatialForms = td.events?.spatialData?.forms ?? [];\n\n const wtForm = spatialForms.find((f) => f.subprotocol === \"webtransport\");\n if (wtForm) {\n result.webtransport = {\n url: wtForm.href,\n certHash: td[\"satmouse:certHash\"],\n };\n }\n\n const wsForm = spatialForms.find((f) => f.subprotocol === \"websocket\");\n if (wsForm) {\n result.websocket = { url: wsForm.href };\n }\n\n const deviceForm = td.properties?.deviceInfo?.forms?.[0];\n if (deviceForm) {\n result.deviceInfoUrl = deviceForm.href;\n }\n\n return result;\n}\n","import type { SpatialData, ButtonEvent } from \"./types.js\";\n\n/** Decode 24-byte binary spatial data datagram (WebTransport or raw binary) */\nexport function decodeBinaryFrame(buffer: ArrayBuffer | Uint8Array): SpatialData {\n const len = buffer instanceof ArrayBuffer ? buffer.byteLength : buffer.byteLength;\n if (len < 20) {\n throw new RangeError(`Spatial frame too short: expected ≥20 bytes, got ${len}`);\n }\n const ab = buffer instanceof ArrayBuffer ? buffer : buffer.buffer;\n const offset = buffer instanceof Uint8Array ? buffer.byteOffset : 0;\n const view = new DataView(ab, offset);\n return {\n translation: {\n x: view.getInt16(8, true),\n y: view.getInt16(10, true),\n z: view.getInt16(12, true),\n },\n rotation: {\n x: view.getInt16(14, true),\n y: view.getInt16(16, true),\n z: view.getInt16(18, true),\n },\n timestamp: view.getFloat64(0, true),\n };\n}\n\n/** Decode WebSocket binary frame (1-byte type prefix + 24-byte payload) */\nexport function decodeWsBinaryFrame(\n buffer: ArrayBuffer | Uint8Array,\n): { type: \"spatialData\"; data: SpatialData } | { type: \"buttonEvent\"; data: ButtonEvent } | null {\n const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);\n if (bytes.length < 1) return null;\n\n const typePrefix = bytes[0];\n if (typePrefix === 0x01 && bytes.length >= 25) {\n return { type: \"spatialData\", data: decodeBinaryFrame(bytes.subarray(1, 25)) };\n }\n if (typePrefix === 0x02) {\n const json = new TextDecoder().decode(bytes.subarray(1));\n return { type: \"buttonEvent\", data: JSON.parse(json) as ButtonEvent };\n }\n return null;\n}\n\n/** Decode length-prefixed JSON button events from a WebTransport stream chunk */\nexport function decodeButtonStream(\n buffer: Uint8Array<ArrayBufferLike>,\n): { events: ButtonEvent[]; remainder: Uint8Array<ArrayBufferLike> } {\n const events: ButtonEvent[] = [];\n let pos = 0;\n\n while (pos + 4 <= buffer.length) {\n const view = new DataView(buffer.buffer, buffer.byteOffset + pos);\n const len = view.getUint32(0, true);\n // Guard against absurd lengths\n if (len > 65536 || pos + 4 + len > buffer.length) break;\n const json = new TextDecoder().decode(buffer.subarray(pos + 4, pos + 4 + len));\n try {\n const event = JSON.parse(json);\n if (typeof event.button === \"number\" && typeof event.pressed === \"boolean\") {\n events.push(event as ButtonEvent);\n }\n } catch {\n // Skip malformed JSON frames\n }\n pos += 4 + len;\n }\n\n return { events, remainder: buffer.subarray(pos) };\n}\n","import type { Transport } from \"./transport.js\";\nimport type { SpatialData, ButtonEvent } from \"../types.js\";\nimport { decodeBinaryFrame, decodeButtonStream } from \"../decode.js\";\n\nexport class WebTransportAdapter implements Transport {\n readonly protocol = \"webtransport\" as const;\n\n onSpatialData: ((data: SpatialData) => void) | null = null;\n onButtonEvent: ((data: ButtonEvent) => void) | null = null;\n onClose: (() => void) | null = null;\n onError: ((error: Error) => void) | null = null;\n\n private transport: any = null;\n private url: string;\n private certHash?: string;\n\n constructor(url: string, certHash?: string) {\n this.url = url;\n this.certHash = certHash;\n }\n\n async connect(): Promise<void> {\n if (typeof globalThis.WebTransport === \"undefined\") {\n throw new Error(\"WebTransport is not available in this environment\");\n }\n\n const options: any = {};\n if (this.certHash) {\n options.serverCertificateHashes = [\n {\n algorithm: \"sha-256\",\n value: Uint8Array.from(atob(this.certHash), (c) => c.charCodeAt(0)),\n },\n ];\n }\n\n this.transport = new (globalThis as any).WebTransport(this.url, options);\n await this.transport.ready;\n\n this.readDatagrams();\n this.readStreams();\n\n this.transport.closed\n .then(() => this.onClose?.())\n .catch(() => this.onClose?.());\n }\n\n close(): void {\n try {\n this.transport?.close();\n } catch {}\n this.transport = null;\n }\n\n private async readDatagrams(): Promise<void> {\n const reader = this.transport.datagrams.readable.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n this.onSpatialData?.(decodeBinaryFrame(value));\n }\n } catch {\n // Transport closed\n }\n }\n\n private async readStreams(): Promise<void> {\n const reader = this.transport.incomingUnidirectionalStreams.getReader();\n try {\n while (true) {\n const { value: stream, done } = await reader.read();\n if (done) break;\n this.readButtonStream(stream);\n }\n } catch {\n // Transport closed\n }\n }\n\n private async readButtonStream(stream: any): Promise<void> {\n const reader = stream.getReader();\n let buffer: Uint8Array<ArrayBufferLike> = new Uint8Array(0);\n\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n\n const newBuf = new Uint8Array(buffer.length + value.length);\n newBuf.set(buffer);\n newBuf.set(value, buffer.length);\n\n const { events, remainder } = decodeButtonStream(newBuf);\n for (const event of events) {\n this.onButtonEvent?.(event);\n }\n buffer = remainder;\n }\n } catch {\n // Stream closed\n }\n }\n}\n","import type { Transport } from \"./transport.js\";\nimport type { SpatialData, ButtonEvent, DeviceInfo } from \"../types.js\";\nimport { decodeWsBinaryFrame } from \"../decode.js\";\n\nexport class WebSocketAdapter implements Transport {\n readonly protocol = \"websocket\" as const;\n\n onSpatialData: ((data: SpatialData) => void) | null = null;\n onButtonEvent: ((data: ButtonEvent) => void) | null = null;\n onDeviceStatus: ((event: \"connected\" | \"disconnected\", device: DeviceInfo) => void) | null = null;\n onClose: (() => void) | null = null;\n onError: ((error: Error) => void) | null = null;\n\n private ws: WebSocket | null = null;\n private url: string;\n private subprotocol: string;\n\n constructor(url: string, subprotocol: string = \"satmouse-json\") {\n this.url = url;\n this.subprotocol = subprotocol;\n }\n\n async connect(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n this.ws = new globalThis.WebSocket(this.url, this.subprotocol);\n if (this.subprotocol === \"satmouse-binary\") {\n this.ws.binaryType = \"arraybuffer\";\n }\n\n this.ws.onopen = () => resolve();\n\n this.ws.onerror = () => {\n reject(new Error(`WebSocket connection failed: ${this.url}`));\n };\n\n this.ws.onmessage = (event: MessageEvent) => {\n if (this.subprotocol === \"satmouse-binary\" && event.data instanceof ArrayBuffer) {\n const decoded = decodeWsBinaryFrame(event.data);\n if (decoded?.type === \"spatialData\") this.onSpatialData?.(decoded.data);\n else if (decoded?.type === \"buttonEvent\") this.onButtonEvent?.(decoded.data);\n } else if (typeof event.data === \"string\") {\n try {\n const msg = JSON.parse(event.data);\n if (msg.type === \"spatialData\") this.onSpatialData?.(msg.data);\n else if (msg.type === \"buttonEvent\") this.onButtonEvent?.(msg.data);\n else if (msg.type === \"deviceStatus\") {\n this.onDeviceStatus?.(msg.data.event, msg.data.device);\n }\n } catch {\n // Ignore malformed messages\n }\n }\n };\n\n this.ws.onclose = () => this.onClose?.();\n });\n }\n\n close(): void {\n try {\n this.ws?.close();\n } catch {}\n this.ws = null;\n }\n}\n","import type { Transport } from \"./transport.js\";\nimport type { SpatialData, ButtonEvent, DeviceInfo } from \"../types.js\";\n\n/**\n * Safari Web Extension transport adapter.\n *\n * The SatMouse extension's content script sets window.__satmouseExtensionAvailable\n * and bridges postMessage ↔ background script ↔ WebSocket to the bridge.\n *\n * This transport is transparent to the SDK — it just works when the extension\n * is installed, bypassing Safari's mixed-content restrictions entirely.\n */\nexport class ExtensionAdapter implements Transport {\n readonly protocol = \"extension\" as const;\n\n onSpatialData: ((data: SpatialData) => void) | null = null;\n onButtonEvent: ((data: ButtonEvent) => void) | null = null;\n onDeviceStatus: ((event: \"connected\" | \"disconnected\", device: DeviceInfo) => void) | null = null;\n onClose: (() => void) | null = null;\n onError: ((error: Error) => void) | null = null;\n\n private messageHandler: ((event: MessageEvent) => void) | null = null;\n private pendingDeviceFetch: ((devices: DeviceInfo[]) => void) | null = null;\n\n static isAvailable(): boolean {\n return !!(globalThis as any).__satmouseExtensionAvailable;\n }\n\n async connect(): Promise<void> {\n if (typeof globalThis.postMessage !== \"function\") {\n throw new Error(\"postMessage not available\");\n }\n\n return new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.close();\n reject(new Error(\"Extension connection timeout\"));\n }, 5000);\n\n this.messageHandler = (event: MessageEvent) => {\n if (event.data?.source !== \"satmouse-extension\") return;\n const msg = event.data;\n\n if ((msg.type === \"connected\" || msg.type === \"bridgeConnected\") && timeout) {\n clearTimeout(timeout);\n resolve();\n }\n\n if (msg.type === \"disconnected\") {\n this.onClose?.();\n }\n\n if (msg.type === \"spatialData\" && msg.data) {\n this.onSpatialData?.(msg.data as SpatialData);\n }\n\n if (msg.type === \"buttonEvent\" && msg.data) {\n this.onButtonEvent?.(msg.data as ButtonEvent);\n }\n\n if (msg.type === \"deviceStatus\" && msg.data) {\n this.onDeviceStatus?.(msg.data.event, msg.data.device);\n }\n\n if (msg.type === \"deviceList\" && this.pendingDeviceFetch) {\n this.pendingDeviceFetch(Array.isArray(msg.data) ? msg.data : []);\n this.pendingDeviceFetch = null;\n }\n };\n\n globalThis.addEventListener(\"message\", this.messageHandler);\n globalThis.postMessage({ target: \"satmouse-extension\", action: \"connect\" }, \"*\");\n });\n }\n\n fetchDeviceInfo(): Promise<DeviceInfo[]> {\n return new Promise((resolve) => {\n this.pendingDeviceFetch = resolve;\n globalThis.postMessage({ target: \"satmouse-extension\", action: \"fetchDevices\" }, \"*\");\n setTimeout(() => {\n if (this.pendingDeviceFetch) {\n this.pendingDeviceFetch = null;\n resolve([]);\n }\n }, 3000);\n });\n }\n\n close(): void {\n if (this.messageHandler) {\n globalThis.removeEventListener(\"message\", this.messageHandler);\n this.messageHandler = null;\n }\n globalThis.postMessage({ target: \"satmouse-extension\", action: \"disconnect\" }, \"*\");\n }\n}\n","import { TypedEmitter } from \"./emitter.js\";\nimport { fetchThingDescription, resolveEndpoints } from \"./discovery.js\";\nimport { WebTransportAdapter } from \"./transports/webtransport.js\";\nimport { WebSocketAdapter } from \"./transports/websocket.js\";\nimport { ExtensionAdapter } from \"./transports/extension.js\";\nimport type { Transport } from \"./transports/transport.js\";\nimport type {\n ConnectOptions,\n ConnectionState,\n DeviceInfo,\n SatMouseEvents,\n TransportProtocol,\n} from \"./types.js\";\n\n/**\n * Build a satmouse:// connect URI from connection parameters.\n */\nexport function buildSatMouseUri(host = \"localhost\", wsPort = 18945, wtPort = 18946): string {\n return `satmouse://connect?host=${encodeURIComponent(host)}&wsPort=${wsPort}&wtPort=${wtPort}`;\n}\n\n/**\n * Parse a satmouse:// URI into connection parameters.\n *\n * Format: satmouse://connect?host=<ip>&wsPort=<port>&wtPort=<port>\n * All query params are optional. Defaults: host=localhost, wsPort=4444, wtPort=4443.\n */\nexport function parseSatMouseUri(uri: string): { tdUrl: string; wsUrl: string; wtUrl: string } {\n const url = new URL(uri);\n const host = url.searchParams.get(\"host\") ?? \"localhost\";\n const wsPort = url.searchParams.get(\"wsPort\") ?? \"18945\";\n const wtPort = url.searchParams.get(\"wtPort\") ?? \"18946\";\n return {\n tdUrl: `http://${host}:${wsPort}/td.json`,\n wsUrl: `ws://${host}:${wsPort}/spatial`,\n wtUrl: `https://${host}:${wtPort}`,\n };\n}\n\nconst DEFAULT_OPTIONS: Required<\n Pick<ConnectOptions, \"transports\" | \"reconnectDelay\" | \"maxRetries\" | \"wsSubprotocol\">\n> = {\n transports: [\"webtransport\", \"extension\", \"websocket\"],\n reconnectDelay: 2000,\n maxRetries: 3,\n wsSubprotocol: \"satmouse-json\",\n};\n\n/**\n * Core connection to a SatMouse bridge.\n *\n * Handles discovery (via WoT Thing Description), transport negotiation\n * (WebTransport with WebSocket fallback), event dispatch, and auto-reconnect.\n */\nexport class SatMouseConnection extends TypedEmitter<SatMouseEvents> {\n private options: ConnectOptions & typeof DEFAULT_OPTIONS;\n private transport: Transport | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private intentionalClose = false;\n private deviceInfoUrl: string | null = null;\n private retryCount = 0;\n\n private _state: ConnectionState = \"disconnected\";\n private _protocol: TransportProtocol = \"none\";\n\n get state(): ConnectionState {\n return this._state;\n }\n get protocol(): TransportProtocol {\n return this._protocol;\n }\n\n constructor(options?: ConnectOptions) {\n super();\n this.options = { ...DEFAULT_OPTIONS, ...options };\n }\n\n async connect(): Promise<void> {\n this.intentionalClose = false;\n this.setState(\"connecting\", \"none\");\n\n // Resolve endpoints — satmouse:// URI takes priority\n let wtUrl = this.options.wtUrl;\n let wsUrl = this.options.wsUrl;\n let certHash = this.options.certHash;\n\n if (this.options.uri) {\n const parsed = parseSatMouseUri(this.options.uri);\n wtUrl = wtUrl ?? parsed.wtUrl;\n wsUrl = wsUrl ?? parsed.wsUrl;\n this.options.tdUrl = this.options.tdUrl ?? parsed.tdUrl;\n }\n\n if (!wtUrl && !wsUrl) {\n const tdUrl = this.options.tdUrl;\n // Use 127.0.0.1 (not localhost) — browsers treat the loopback IP as a\n // \"Potentially Trustworthy Origin\" more reliably than the hostname.\n // Try HTTP first (Chrome allows PNA preflight to localhost),\n // then HTTPS (self-signed cert, may fail).\n const tdUrls = tdUrl\n ? [tdUrl]\n : [\n \"http://127.0.0.1:18945/td.json\",\n \"https://127.0.0.1:18947/td.json\",\n ];\n\n let resolved = false;\n for (const url of tdUrls) {\n try {\n const td = await fetchThingDescription(url);\n const endpoints = resolveEndpoints(td);\n wtUrl = endpoints.webtransport?.url;\n wsUrl = endpoints.websocket?.url;\n certHash = certHash ?? endpoints.webtransport?.certHash;\n this.deviceInfoUrl = endpoints.deviceInfoUrl ?? null;\n resolved = true;\n break;\n } catch {\n // Try next URL\n }\n }\n if (!resolved) {\n this.emit(\"error\", new Error(\"Failed to fetch Thing Description\"));\n // Last-resort WebSocket URL. Chrome allows ws://127.0.0.1 from HTTPS\n // pages via PNA preflight. Safari blocks it (extension handles that).\n wsUrl = \"ws://127.0.0.1:18945/spatial\";\n }\n }\n\n // Try transports in preference order\n for (const proto of this.options.transports) {\n if (proto === \"webtransport\" && wtUrl) {\n try {\n if (typeof globalThis.WebTransport === \"undefined\") continue;\n const adapter = new WebTransportAdapter(wtUrl, certHash);\n if (await this.tryTransport(adapter)) return;\n } catch {\n continue;\n }\n }\n if (proto === \"extension\") {\n try {\n if (!ExtensionAdapter.isAvailable()) continue;\n const adapter = new ExtensionAdapter();\n if (await this.tryTransport(adapter)) return;\n } catch {\n continue;\n }\n }\n if (proto === \"websocket\" && wsUrl) {\n try {\n const adapter = new WebSocketAdapter(wsUrl, this.options.wsSubprotocol);\n if (await this.tryTransport(adapter)) return;\n } catch {\n continue;\n }\n }\n }\n\n this.setState(\"disconnected\", \"none\");\n this.scheduleReconnect();\n }\n\n /** Reset retry count and reconnect. Use after \"failed\" state. */\n retry(): void {\n this.retryCount = 0;\n this.intentionalClose = false;\n this.connect();\n }\n\n disconnect(): void {\n this.intentionalClose = true;\n this.clearReconnect();\n this.transport?.close();\n this.transport = null;\n this.setState(\"disconnected\", \"none\");\n }\n\n async fetchDeviceInfo(): Promise<DeviceInfo[]> {\n // Try HTTP endpoint first\n if (this.deviceInfoUrl) {\n try {\n const res = await globalThis.fetch(this.deviceInfoUrl);\n if (res.ok) {\n const data = await res.json();\n return data.devices ?? [];\n }\n } catch {\n // HTTP blocked (Safari HTTPS → localhost) — fall through to extension\n }\n }\n\n // Fall back to extension transport if connected via extension\n if (this.transport && \"fetchDeviceInfo\" in this.transport) {\n return (this.transport as ExtensionAdapter).fetchDeviceInfo();\n }\n\n return [];\n }\n\n private async tryTransport(adapter: Transport): Promise<boolean> {\n adapter.onSpatialData = (data) => this.emit(\"spatialData\", data);\n adapter.onButtonEvent = (data) => this.emit(\"buttonEvent\", data);\n adapter.onError = (err) => this.emit(\"error\", err);\n\n if (\"onDeviceStatus\" in adapter) {\n (adapter as any).onDeviceStatus = (event: \"connected\" | \"disconnected\", device: DeviceInfo) => {\n this.emit(\"deviceStatus\", event, device);\n };\n }\n\n adapter.onClose = () => {\n this.transport = null;\n this.setState(\"disconnected\", \"none\");\n if (!this.intentionalClose) this.scheduleReconnect();\n };\n\n try {\n // Timeout transport connection attempts to prevent hanging the fallback chain\n await Promise.race([\n adapter.connect(),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(`${adapter.protocol} connection timeout`)), 5000)\n ),\n ]);\n this.transport = adapter;\n this.retryCount = 0;\n this.setState(\"connected\", adapter.protocol);\n return true;\n } catch (err) {\n adapter.close();\n this.emit(\"error\", err instanceof Error ? err : new Error(String(err)));\n return false;\n }\n }\n\n private setState(state: ConnectionState, protocol: TransportProtocol): void {\n if (this._state === state && this._protocol === protocol) return;\n this._state = state;\n this._protocol = protocol;\n this.emit(\"stateChange\", state, protocol);\n }\n\n private scheduleReconnect(): void {\n if (this.options.reconnectDelay <= 0 || this.intentionalClose) return;\n\n this.retryCount++;\n console.log(`[SatMouse] Reconnect attempt ${this.retryCount}/${this.options.maxRetries}`);\n if (this.retryCount > this.options.maxRetries) {\n console.log(\"[SatMouse] Max retries exceeded, giving up\");\n this.setState(\"failed\", \"none\");\n return;\n }\n\n this.clearReconnect();\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, this.options.reconnectDelay);\n }\n\n private clearReconnect(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n}\n","const SCHEME_URL = \"satmouse://launch\";\nconst PROJECT_URL = \"https://github.com/kelnishi/SatMouse/releases/latest\";\n\n/** Result of a URI scheme negotiation */\nexport interface NegotiateResult {\n ip: string;\n wsPort: number;\n wtPort: number;\n httpsPort: number;\n certHash?: string;\n challenge?: string;\n}\n\n/**\n * Trigger the satmouse://negotiate URI scheme for discovery when direct\n * HTTP/HTTPS fetch is blocked (Safari LNA).\n *\n * The bridge intercepts the URI, then redirects back to your origin with\n * connection details as query parameters. Your app handles the callback\n * route and passes the result to SatMouseConnection.\n *\n * @param origin - Your app's origin (e.g., \"https://kelcite.app\")\n * @param callbackPath - Path the bridge redirects to (default: \"/satmouse-handshake\")\n * @param challenge - Optional challenge token for verification\n */\nexport function negotiateViaSatMouse(origin: string, callbackPath = \"/satmouse-handshake\", challenge?: string): void {\n const params = new URLSearchParams({ origin, callback: callbackPath });\n if (challenge) params.set(\"challenge\", challenge);\n globalThis.location.href = `satmouse://negotiate?${params}`;\n}\n\n/**\n * Parse the negotiate callback URL parameters (called on your callback route).\n * Returns connection details or null if the params are missing.\n */\nexport function parseNegotiateCallback(searchParams: URLSearchParams): NegotiateResult | null {\n const ip = searchParams.get(\"ip\");\n const wsPort = searchParams.get(\"wsPort\");\n if (!ip || !wsPort) return null;\n return {\n ip,\n wsPort: parseInt(wsPort, 10),\n wtPort: parseInt(searchParams.get(\"wtPort\") ?? \"18946\", 10),\n httpsPort: parseInt(searchParams.get(\"httpsPort\") ?? \"18947\", 10),\n certHash: searchParams.get(\"certHash\") ?? undefined,\n challenge: searchParams.get(\"challenge\") ?? undefined,\n };\n}\n\nexport interface LaunchOptions {\n /** URL scheme to open. Default: \"satmouse://launch\" */\n schemeUrl?: string;\n /** Fallback URL if the app is not installed. Default: GitHub releases page */\n fallbackUrl?: string;\n /** Timeout in ms before assuming the app is not installed. Default: 2500 */\n timeout?: number;\n}\n\n/**\n * Attempt to launch SatMouse via the `satmouse://` URL scheme.\n *\n * If the app is installed and registered, the OS opens it. If not,\n * navigates to the fallback URL (project releases page) after a timeout.\n *\n * Returns true if the scheme likely opened, false if it fell back.\n */\nexport function launchSatMouse(options?: LaunchOptions): Promise<boolean> {\n const schemeUrl = options?.schemeUrl ?? SCHEME_URL;\n const timeout = options?.timeout ?? 2500;\n\n // Validate fallback URL — only allow http/https to prevent javascript: or data: injection\n let fallbackUrl = PROJECT_URL;\n if (options?.fallbackUrl) {\n try {\n const parsed = new URL(options.fallbackUrl);\n if (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") {\n fallbackUrl = options.fallbackUrl;\n }\n } catch {}\n }\n\n return new Promise((resolve) => {\n // Track if we leave the page (scheme handler opened the app)\n let launched = false;\n\n const onBlur = () => {\n launched = true;\n };\n globalThis.addEventListener(\"blur\", onBlur);\n\n // Use a hidden iframe to trigger the scheme without navigating away\n const iframe = document.createElement(\"iframe\");\n iframe.style.display = \"none\";\n iframe.src = schemeUrl;\n document.body.appendChild(iframe);\n\n setTimeout(() => {\n globalThis.removeEventListener(\"blur\", onBlur);\n document.body.removeChild(iframe);\n\n if (launched || document.hidden) {\n resolve(true);\n } else {\n // App not installed — redirect to project page\n globalThis.location.href = fallbackUrl;\n resolve(false);\n }\n }, timeout);\n });\n}\n"]}
@@ -377,8 +377,8 @@ var SatMouseConnection = class extends TypedEmitter {
377
377
  if (!wtUrl && !wsUrl) {
378
378
  const tdUrl = this.options.tdUrl;
379
379
  const tdUrls = tdUrl ? [tdUrl] : [
380
- "https://127.0.0.1:18947/td.json",
381
- "http://127.0.0.1:18945/td.json"
380
+ "http://127.0.0.1:18945/td.json",
381
+ "https://127.0.0.1:18947/td.json"
382
382
  ];
383
383
  let resolved = false;
384
384
  for (const url of tdUrls) {
@@ -396,8 +396,7 @@ var SatMouseConnection = class extends TypedEmitter {
396
396
  }
397
397
  if (!resolved) {
398
398
  this.emit("error", new Error("Failed to fetch Thing Description"));
399
- const isSecurePage = typeof globalThis.location !== "undefined" && globalThis.location.protocol === "https:";
400
- wsUrl = isSecurePage ? "wss://127.0.0.1:18947/spatial" : "ws://127.0.0.1:18945/spatial";
399
+ wsUrl = "ws://127.0.0.1:18945/spatial";
401
400
  }
402
401
  }
403
402
  for (const proto of this.options.transports) {