multica/packages/store/src/connection.ts
Naiyuan Qing 1fe27a59d0 chore(store): remove unused Zustand stores and slim down package
After the chat refactoring moved state management to @multica/hooks,
the Zustand stores (useConnectionStore, useMessagesStore, useAutoConnect)
are no longer imported by any application code. This removes them along
with their unused dependencies (zustand, uuid, react).

- Delete connection-store.ts, messages.ts, use-auto-connect.ts
- Extract Message/ToolStatus types into types.ts (preserves UI imports)
- Remove saveConnection/loadConnection/clearConnection from connection.ts
- Drop zustand, uuid, react deps from package.json

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 18:41:31 +08:00

88 lines
2.3 KiB
TypeScript

export interface ConnectionInfo {
type: "multica-connect"
gateway: string
hubId: string
agentId: string
token: string
expires: number
}
function isConnectionInfo(obj: unknown): obj is ConnectionInfo {
if (typeof obj !== "object" || obj === null) return false
const o = obj as Record<string, unknown>
return (
o.type === "multica-connect" &&
typeof o.gateway === "string" &&
typeof o.hubId === "string" &&
typeof o.agentId === "string" &&
typeof o.token === "string" &&
typeof o.expires === "number"
)
}
// Parse multica://connect?gateway=...&hub=...&agent=...&token=...&exp=... URL format
// Uses string prefix + URLSearchParams to avoid cross-engine URL hostname differences
function parseConnectionUrl(input: string): ConnectionInfo | null {
const prefix = "multica://connect?"
if (!input.startsWith(prefix)) return null
try {
const params = new URLSearchParams(input.slice(prefix.length))
const gateway = params.get("gateway")
const hubId = params.get("hub")
const agentId = params.get("agent")
const token = params.get("token")
const exp = params.get("exp")
if (!gateway || !hubId || !agentId || !token || !exp) return null
return {
type: "multica-connect",
gateway,
hubId,
agentId,
token,
expires: Number(exp),
}
} catch {
return null
}
}
function isExpired(expires: number): boolean {
// Desktop generates expires as millisecond timestamp (Date.now() + seconds * 1000)
return Date.now() > expires
}
export function parseConnectionCode(input: string): ConnectionInfo {
const trimmed = input.trim()
// Try multica:// URL format first (desktop "Copy Link" output)
const fromUrl = parseConnectionUrl(trimmed)
if (fromUrl) {
if (isExpired(fromUrl.expires)) {
throw new Error("Connection code has expired")
}
return fromUrl
}
// Try JSON (QR code scan output)
let parsed: unknown
try {
parsed = JSON.parse(trimmed)
} catch {
// Try base64 decode then JSON
try {
parsed = JSON.parse(atob(trimmed))
} catch {
throw new Error("Invalid connection code")
}
}
if (!isConnectionInfo(parsed)) {
throw new Error("Invalid connection code format")
}
if (isExpired(parsed.expires)) {
throw new Error("Connection code has expired")
}
return parsed
}