Răsfoiți Sursa

fix(pairing): shrink mobile QR payload

Ryan Vogel 5 zile în urmă
părinte
comite
a4d4a3f545

+ 1 - 0
packages/mobile-voice/notes.md

@@ -4,3 +4,4 @@
 - Need to figure out a good way to start new sessions.
 - When an agent returns a generation, we should be able to expand it into a reader mode view.
 - Work on the live activity widget.
+- In the OpenCode Control app, if a link is generated in Markdown, it should be tappable and open in the device's default browser.

+ 5 - 5
packages/mobile-voice/src/app/index.tsx

@@ -370,7 +370,6 @@ function formatWorkingDirectory(directory?: string): string {
 type DropdownMode = "none" | "server" | "session"
 
 type Pair = {
-  v: 1
   serverID?: string
   relayURL: string
   relaySecret: string
@@ -454,18 +453,19 @@ type Cam = {
 
 function parsePairShape(data: unknown): Pair | undefined {
   if (!data || typeof data !== "object") return
-  if ((data as { v?: unknown }).v !== 1) return
-  if (typeof (data as { relayURL?: unknown }).relayURL !== "string") return
+  const version = (data as { v?: unknown }).v
+  if (version !== undefined && version !== 1) return
   if (typeof (data as { relaySecret?: unknown }).relaySecret !== "string") return
   if (!Array.isArray((data as { hosts?: unknown }).hosts)) return
   const hosts = (data as { hosts: unknown[] }).hosts.filter((item): item is string => typeof item === "string")
   if (!hosts.length) return
+  const relayURLRaw = (data as { relayURL?: unknown }).relayURL
+  const relayURL = typeof relayURLRaw === "string" && relayURLRaw.length > 0 ? relayURLRaw : DEFAULT_RELAY_URL
   const serverIDRaw = (data as { serverID?: unknown }).serverID
   const serverID = typeof serverIDRaw === "string" && serverIDRaw.length > 0 ? serverIDRaw : undefined
   return {
-    v: 1,
     serverID,
-    relayURL: (data as { relayURL: string }).relayURL,
+    relayURL,
     relaySecret: (data as { relaySecret: string }).relaySecret,
     hosts,
   }

+ 11 - 11
packages/opencode/src/cli/cmd/serve.ts

@@ -15,13 +15,17 @@ import * as QRCode from "qrcode"
 const log = Log.create({ service: "serve" })
 
 type PairPayload = {
-  v: 1
   serverID?: string
   relayURL: string
   relaySecret: string
   hosts: string[]
 }
 
+type PairQRCodePayload = {
+  relaySecret: string
+  hosts: string[]
+}
+
 type TailscaleStatus = {
   Self?: {
     DNSName?: unknown
@@ -102,12 +106,12 @@ function hosts(hostname: string, port: number, advertised: string[] = [], includ
   return [...preferred, ...entries.map((item) => item.url)]
 }
 
-function pairLink(pair: unknown) {
-  return `mobilevoice:///?pair=${encodeURIComponent(JSON.stringify(pair))}`
-}
-
-function pairServerID(input: { relayURL: string; relaySecret: string }) {
-  return createHash("sha256").update(`${input.relayURL}|${input.relaySecret}`).digest("hex").slice(0, 16)
+function pairLink(pair: PairQRCodePayload) {
+  const payload: PairQRCodePayload = {
+    relaySecret: pair.relaySecret,
+    hosts: pair.hosts,
+  }
+  return `mobilevoice:///?pair=${encodeURIComponent(JSON.stringify(payload))}`
 }
 
 function secretHash(input: string) {
@@ -240,8 +244,6 @@ export const ServeCommand = cmd({
 
       console.log("printing connect qr without starting the server")
       await printPairQR({
-        v: 1,
-        serverID: pairServerID({ relayURL, relaySecret }),
         relayURL,
         relaySecret,
         hosts: pairHosts,
@@ -274,8 +276,6 @@ export const ServeCommand = cmd({
       })
       const pair = started ??
         PushRelay.pair() ?? {
-          v: 1 as const,
-          serverID: pairServerID({ relayURL, relaySecret }),
           relayURL,
           relaySecret,
           hosts: hosts(host, port, advertiseHosts),

+ 7 - 6
packages/opencode/src/server/routes/experimental.ts

@@ -21,9 +21,6 @@ import { Agent } from "@/agent/agent"
 
 const PushPairPayload = z
   .object({
-    v: z.literal(1),
-    serverID: z.string().optional(),
-    relayURL: z.string(),
     relaySecret: z.string(),
     hosts: z.array(z.string()),
   })
@@ -49,12 +46,16 @@ const pushPairQROptions = {
   width: 256,
 }
 
-function pushPairLink(payload: z.infer<typeof PushPairPayload>) {
+function pushPairLink(input: { relaySecret: string; hosts: string[] }) {
+  const payload: z.infer<typeof PushPairPayload> = {
+    relaySecret: input.relaySecret,
+    hosts: input.hosts,
+  }
   return `mobilevoice:///?pair=${encodeURIComponent(JSON.stringify(payload))}`
 }
 
-async function pushPairQRCode(payload: z.infer<typeof PushPairPayload>) {
-  return QRCode.toDataURL(pushPairLink(payload), pushPairQROptions)
+async function pushPairQRCode(input: { relaySecret: string; hosts: string[] }) {
+  return QRCode.toDataURL(pushPairLink(input), pushPairQROptions)
 }
 
 const ConsoleOrgOption = z.object({