uidex 0.7.0 → 0.8.0
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.
- package/dist/cli/cli.cjs +1024 -1041
- package/dist/cli/cli.cjs.map +1 -1
- package/dist/headless/index.cjs +4 -448
- package/dist/headless/index.cjs.map +1 -1
- package/dist/headless/index.d.cts +41 -11
- package/dist/headless/index.d.ts +41 -11
- package/dist/headless/index.js +4 -450
- package/dist/headless/index.js.map +1 -1
- package/dist/index.cjs +147 -3252
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +43 -316
- package/dist/index.d.ts +43 -316
- package/dist/index.js +133 -3254
- package/dist/index.js.map +1 -1
- package/dist/playwright/index.cjs +175 -0
- package/dist/playwright/index.cjs.map +1 -1
- package/dist/playwright/index.d.cts +2 -0
- package/dist/playwright/index.d.ts +2 -0
- package/dist/playwright/index.js +167 -0
- package/dist/playwright/index.js.map +1 -1
- package/dist/playwright/states-reporter.cjs +123 -0
- package/dist/playwright/states-reporter.cjs.map +1 -0
- package/dist/playwright/states-reporter.d.cts +46 -0
- package/dist/playwright/states-reporter.d.ts +46 -0
- package/dist/playwright/states-reporter.js +88 -0
- package/dist/playwright/states-reporter.js.map +1 -0
- package/dist/playwright/states.cjs +118 -0
- package/dist/playwright/states.cjs.map +1 -0
- package/dist/playwright/states.d.cts +120 -0
- package/dist/playwright/states.d.ts +120 -0
- package/dist/playwright/states.js +88 -0
- package/dist/playwright/states.js.map +1 -0
- package/dist/react/index.cjs +163 -3255
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +62 -275
- package/dist/react/index.d.ts +62 -275
- package/dist/react/index.js +151 -3268
- package/dist/react/index.js.map +1 -1
- package/dist/scan/index.cjs +1194 -322
- package/dist/scan/index.cjs.map +1 -1
- package/dist/scan/index.d.cts +274 -8
- package/dist/scan/index.d.ts +274 -8
- package/dist/scan/index.js +1185 -322
- package/dist/scan/index.js.map +1 -1
- package/package.json +27 -31
- package/dist/cloud/index.cjs +0 -682
- package/dist/cloud/index.cjs.map +0 -1
- package/dist/cloud/index.d.cts +0 -270
- package/dist/cloud/index.d.ts +0 -270
- package/dist/cloud/index.js +0 -645
- package/dist/cloud/index.js.map +0 -1
package/dist/cloud/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cloud/index.ts","../../src/cloud/protocol.ts","../../src/cloud/realtime.ts","../../src/cloud/types.ts","../../src/cloud/rpc.ts","../../src/cloud/client.ts"],"sourcesContent":["export { cloud } from \"./client\"\nexport { createRealtimeChannel, type InternalRealtimeChannel } from \"./realtime\"\nexport { createRpcClient, DEFAULT_RPC_TIMEOUT_MS, type RpcClient } from \"./rpc\"\nexport {\n RPC_METHODS,\n SCREENSHOT_CHUNK_BYTES,\n SCREENSHOT_INLINE_MAX_BYTES,\n isRpcMethod,\n parseRpcResponseFrame,\n type IdentifyFrame,\n type LeaveFrame,\n type PinArchivedFrame,\n type ReportSubmitParams,\n type RpcErrFrame,\n type RpcMethod,\n type RpcOkFrame,\n type RpcParamsMap,\n type RpcRequestFrame,\n type RpcResponseFrame,\n type RpcResultMap,\n type ScreenshotChunkParams,\n} from \"./protocol\"\nexport {\n CloudError,\n DEFAULT_CLOUD_ENDPOINT,\n type CloudAdapter,\n type CloudOptions,\n type RealtimeChannel,\n type RealtimeChannelState,\n type RealtimeConnectOpts,\n type RealtimePresenceUser,\n} from \"./types\"\nexport type {\n ArchiveReason,\n ReportListRecord,\n ReportListResponse,\n ReportPayload,\n ReportResult,\n IngestConfig,\n PinRecord,\n} from \"@uidex/api-client\"\n","import type {\n ArchiveReason,\n IngestConfig,\n PinRecord,\n ReportListResponse,\n ReportPayload,\n ReportResult,\n} from \"@uidex/api-client\"\n\n/**\n * WS RPC protocol shared by the SDK (`packages/sdk/src/cloud`) and the relay\n * server (`apps/app/src/lib/relay-handler.ts`, type-only import from\n * \"uidex/cloud\"). These frames ride the same socket as the existing\n * fire-and-forget messages (`cursor`, `join`, `presence`, `pin`); peers that\n * predate a frame type silently drop it.\n */\n\nexport const RPC_METHODS = [\n \"reports.submit\",\n \"reports.list\",\n \"config.get\",\n \"pins.list\",\n \"pins.screenshot\",\n \"pins.archive\",\n \"screenshot.chunk\",\n] as const\n\nexport type RpcMethod = (typeof RPC_METHODS)[number]\n\n/**\n * Screenshots whose base64 data-URL length is at or below this ride inline in\n * the `reports.submit` frame (the common case). Larger ones are streamed via\n * `screenshot.chunk` so no single frame approaches the relay's 25 MiB WS\n * `maxPayload` — an oversized frame is dropped server-side (close 1009), which\n * the SDK surfaces as \"Connection lost\".\n */\nexport const SCREENSHOT_INLINE_MAX_BYTES = 20 * 1024 * 1024\n/** Per-chunk size when a screenshot is streamed. Each `screenshot.chunk` frame stays well under `maxPayload`. */\nexport const SCREENSHOT_CHUNK_BYTES = 8 * 1024 * 1024\n\n/** One streamed screenshot fragment. Parts are keyed by `seq` and reassembled in order server-side. */\nexport type ScreenshotChunkParams = {\n /** Client-generated id grouping a screenshot's chunks; referenced by `reports.submit` as `screenshotUploadId`. */\n uploadId: string\n /** 0-based index of this part. */\n seq: number\n /** Total number of parts in this upload. */\n total: number\n /** A slice of the screenshot data URL. */\n data: string\n}\n\n/**\n * `reports.submit` params. Either the screenshot rides inline (`screenshot`) or,\n * for large captures, it is streamed via `screenshot.chunk` and referenced here\n * by `screenshotUploadId` — the server reassembles it before persisting.\n */\nexport type ReportSubmitParams = ReportPayload & {\n screenshotUploadId?: string\n}\n\nexport interface RpcParamsMap {\n \"reports.submit\": ReportSubmitParams\n \"reports.list\": { page?: number; limit?: number }\n \"config.get\": undefined\n \"pins.list\": { route?: string; entities?: string[] }\n \"pins.screenshot\": { reportId: string }\n \"pins.archive\": { reportId: string; reason?: ArchiveReason }\n \"screenshot.chunk\": ScreenshotChunkParams\n}\n\nexport interface RpcResultMap {\n \"reports.submit\": ReportResult\n \"reports.list\": ReportListResponse\n \"config.get\": IngestConfig\n // Pins travel without their screenshot (a multi-MB base64 frame would\n // head-of-line-block cursor/presence on the shared socket); the detail\n // view lazy-fetches it per pin via `pins.screenshot`.\n \"pins.list\": { pins: PinRecord[] }\n \"pins.screenshot\": { screenshot: string | null }\n \"pins.archive\": { ok: true }\n /** Acks a stored chunk; `received` is how many distinct parts have arrived. */\n \"screenshot.chunk\": { received: number }\n}\n\nexport type RpcRequestFrame = {\n type: \"rpc\"\n id: string\n method: RpcMethod\n params?: unknown\n}\n\nexport type RpcOkFrame = {\n type: \"rpc:res\"\n id: string\n ok: true\n data: unknown\n}\n\nexport type RpcErrFrame = {\n type: \"rpc:res\"\n id: string\n ok: false\n /** HTTP-equivalent status so CloudError semantics survive the transport. */\n status: number\n error: string\n /** Seconds, present on 429 responses (mirrors the Retry-After header). */\n retryAfter?: number\n details?: unknown\n}\n\nexport type RpcResponseFrame = RpcOkFrame | RpcErrFrame\n\n/**\n * Sent by the SDK after `realtime.connect(opts)` to attach a user identity to\n * an initially anonymous connection. The server marks the connection visible\n * in presence from this point on. Connections that never identify stay\n * RPC-only: excluded from presence, no room auto-join.\n */\nexport type IdentifyFrame = {\n type: \"identify\"\n userId: string\n name?: string\n avatar?: string\n}\n\n/**\n * Reverse of `IdentifyFrame`: sent when a realtime consumer disconnects\n * (e.g. the uidex surface unmounts) while the adapter keeps using the socket\n * for RPC. The server drops the connection from presence and its room but\n * keeps the socket open.\n */\nexport type LeaveFrame = {\n type: \"leave\"\n}\n\n/**\n * Server→client broadcast when a pin's report leaves the open statuses\n * (closed via the SDK, the dashboard, or the REST route). Sent to the room of\n * the report's route so live overlays drop the pin without a refresh.\n */\nexport type PinArchivedFrame = {\n type: \"pin:archived\"\n reportId: string\n}\n\nexport function isRpcMethod(value: unknown): value is RpcMethod {\n return (\n typeof value === \"string\" &&\n (RPC_METHODS as readonly string[]).includes(value)\n )\n}\n\n/** Client-side guard for inbound `rpc:res` frames (server validates inbound `rpc` frames itself). */\nexport function parseRpcResponseFrame(msg: unknown): RpcResponseFrame | null {\n if (!msg || typeof msg !== \"object\") return null\n const m = msg as Record<string, unknown>\n if (m.type !== \"rpc:res\" || typeof m.id !== \"string\") return null\n if (m.ok === true) {\n return { type: \"rpc:res\", id: m.id, ok: true, data: m.data }\n }\n if (m.ok === false) {\n if (typeof m.status !== \"number\" || typeof m.error !== \"string\") return null\n return {\n type: \"rpc:res\",\n id: m.id,\n ok: false,\n status: m.status,\n error: m.error,\n retryAfter: typeof m.retryAfter === \"number\" ? m.retryAfter : undefined,\n details: m.details,\n }\n }\n return null\n}\n","import type { PinRecord } from \"@uidex/api-client\"\nimport { parseRpcResponseFrame, type RpcResponseFrame } from \"./protocol\"\nimport type { UserIdentity } from \"../shared/user\"\nimport type {\n RealtimeChannel,\n RealtimeChannelState,\n RealtimePresenceUser,\n} from \"./types\"\n\nconst RECONNECT_INITIAL_MS = 1000\nconst RECONNECT_MAX_MS = 30_000\n/**\n * Give up after ~3 minutes of consecutive failures (1+2+4+8+16+5×30s) instead\n * of retrying forever: an unreachable endpoint (server down, adblocker,\n * corporate proxy) must not make every host-app tab churn connections for its\n * whole lifetime. Any later `connect()` — every RPC call issues one on a\n * closed socket — resets the budget and revives the channel.\n */\nconst MAX_RECONNECT_ATTEMPTS = 10\nexport const CLOSE_CODE_AUTH_FAILED = 4001\n/** Reported to `onClose` when the socket never produced a real close code (failed constructor, failed `buildUrl`, local disconnect). */\nexport const CLOSE_CODE_SYNTHETIC = 1006\n\nexport type RealtimeChannelOptions = {\n /** Builds the WebSocket URL on each (re)connect attempt. Only needs the project key — identity and route ride dedicated frames. */\n buildUrl: () => string\n /** Optional WebSocket constructor override (testing). Defaults to `globalThis.WebSocket`. */\n WebSocketImpl?: typeof WebSocket\n}\n\n/**\n * Superset of the public `RealtimeChannel` used internally by the cloud\n * adapter: the RPC client (`./rpc`) shares the same socket and needs raw\n * frame access plus open/close notifications.\n */\nexport interface InternalRealtimeChannel extends RealtimeChannel {\n /** Required here (optional on the public interface only for channel stubs). */\n onPinArchived(cb: (reportId: string) => void): () => void\n /** Stores the identity and (re)sends the `identify` frame on every open. */\n identify(user: UserIdentity): void\n /** Drops the stored identity/route without touching the socket (soft leave). */\n clearSession(): void\n /** Sends a JSON frame if the socket is OPEN. Returns false otherwise. */\n sendFrame(frame: object): boolean\n /** Fires after the channel finished its identify/join replay on (re)open. */\n onOpen(cb: () => void): () => void\n /**\n * Fires with the close code (or `CLOSE_CODE_SYNTHETIC`) whenever the socket\n * goes away. `willReconnect` is false for terminal closes (`disconnect()`,\n * auth failure, no WebSocket implementation): queued work must reject\n * instead of riding a reconnect that will never come.\n */\n onClose(cb: (code: number, willReconnect: boolean) => void): () => void\n onRpcResponse(cb: (frame: RpcResponseFrame) => void): () => void\n}\n\ntype Listener<T> = (value: T) => void\n\nfunction emit<T>(listeners: Set<Listener<T>>, value: T): void {\n for (const cb of listeners) {\n try {\n cb(value)\n } catch {\n // listener errors must not break the channel\n }\n }\n}\n\nfunction resolveWebSocket(override?: typeof WebSocket): typeof WebSocket {\n if (override) return override\n if (\n typeof globalThis !== \"undefined\" &&\n typeof (globalThis as { WebSocket?: typeof WebSocket }).WebSocket ===\n \"function\"\n ) {\n return (globalThis as { WebSocket: typeof WebSocket }).WebSocket\n }\n throw new Error(\n \"uidex/cloud: global WebSocket is not available; pass a `WebSocketImpl` override\"\n )\n}\n\nexport function createRealtimeChannel(\n options: RealtimeChannelOptions\n): InternalRealtimeChannel {\n // Resolved lazily on the first connect attempt so channel construction\n // never throws on runtimes without a WebSocket global (SSR, old Node).\n let WS: typeof WebSocket | null = options.WebSocketImpl ?? null\n\n const presenceListeners = new Set<Listener<RealtimePresenceUser[]>>()\n const pinListeners = new Set<Listener<PinRecord>>()\n const pinArchivedListeners = new Set<Listener<string>>()\n const openListeners = new Set<Listener<void>>()\n const closeListeners = new Set<\n (code: number, willReconnect: boolean) => void\n >()\n const rpcListeners = new Set<Listener<RpcResponseFrame>>()\n\n let ws: WebSocket | null = null\n let state: RealtimeChannelState = \"disconnected\"\n let disposed = false\n let reconnectAttempts = 0\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null\n let identity: UserIdentity | null = null\n let route: string | null = null\n\n function emitClose(code: number, willReconnect: boolean): void {\n for (const cb of closeListeners) {\n try {\n cb(code, willReconnect)\n } catch {\n // listener errors must not break the channel\n }\n }\n }\n\n function clearReconnectTimer(): void {\n if (reconnectTimer !== null) {\n clearTimeout(reconnectTimer)\n reconnectTimer = null\n }\n }\n\n function scheduleReconnect(): void {\n if (disposed) return\n const delay = Math.min(\n RECONNECT_INITIAL_MS * 2 ** reconnectAttempts,\n RECONNECT_MAX_MS\n )\n reconnectAttempts += 1\n state = \"connecting\"\n clearReconnectTimer()\n reconnectTimer = setTimeout(() => {\n reconnectTimer = null\n openSocket()\n }, delay)\n }\n\n function handleMessage(event: MessageEvent): void {\n if (typeof event.data !== \"string\") return\n let parsed: unknown\n try {\n parsed = JSON.parse(event.data)\n } catch {\n return\n }\n if (!parsed || typeof parsed !== \"object\") return\n const msg = parsed as { type?: unknown }\n\n if (msg.type === \"rpc:res\") {\n const frame = parseRpcResponseFrame(parsed)\n if (frame) emit(rpcListeners, frame)\n return\n }\n\n if (msg.type === \"presence\") {\n const p = msg as { users?: unknown }\n if (!Array.isArray(p.users)) return\n const users: RealtimePresenceUser[] = []\n for (const raw of p.users) {\n if (!raw || typeof raw !== \"object\") continue\n const u = raw as Partial<RealtimePresenceUser>\n if (typeof u.userId !== \"string\" || typeof u.name !== \"string\") continue\n users.push({\n userId: u.userId,\n name: u.name,\n avatar: typeof u.avatar === \"string\" ? u.avatar : null,\n })\n }\n emit(presenceListeners, users)\n return\n }\n\n if (msg.type === \"pin:archived\") {\n const p = msg as { reportId?: unknown }\n if (typeof p.reportId !== \"string\") return\n emit(pinArchivedListeners, p.reportId)\n return\n }\n\n if (msg.type === \"pin\") {\n // Wire format is the relay's PinPayload (apps/app/src/lib/relay.ts):\n // `reportId` + legacy field names; map to the API PinRecord shape.\n const p = msg as Record<string, unknown>\n if (\n typeof p.reportId !== \"string\" ||\n !p.elementRef ||\n typeof p.elementRef !== \"object\" ||\n typeof (p.elementRef as { kind?: unknown }).kind !== \"string\" ||\n typeof (p.elementRef as { id?: unknown }).id !== \"string\" ||\n !p.author ||\n typeof p.author !== \"object\" ||\n typeof p.body !== \"string\" ||\n typeof p.reportType !== \"string\" ||\n typeof p.reportSeverity !== \"string\" ||\n typeof p.createdAt !== \"string\"\n ) {\n return\n }\n const author = p.author as Record<string, unknown>\n const elRef = p.elementRef as { kind: string; id: string }\n const pin: PinRecord = {\n id: p.reportId,\n entity: `${elRef.kind}:${elRef.id}`,\n reporter: {\n name: typeof author.name === \"string\" ? author.name : undefined,\n email: typeof author.email === \"string\" ? author.email : undefined,\n },\n body: p.body,\n type: p.reportType as PinRecord[\"type\"],\n severity: p.reportSeverity as PinRecord[\"severity\"],\n status: \"open\" as PinRecord[\"status\"],\n createdAt: p.createdAt,\n url: \"\",\n }\n emit(pinListeners, pin)\n return\n }\n }\n\n function sendRaw(frame: object): boolean {\n if (!ws || !WS || ws.readyState !== WS.OPEN) return false\n try {\n ws.send(JSON.stringify(frame))\n return true\n } catch {\n // socket may have closed mid-call\n return false\n }\n }\n\n function openSocket(): void {\n if (disposed) return\n state = \"connecting\"\n if (!WS) {\n try {\n WS = resolveWebSocket(options.WebSocketImpl)\n } catch {\n // No implementation will ever appear; reconnecting is pointless.\n state = \"disconnected\"\n emitClose(CLOSE_CODE_SYNTHETIC, false)\n return\n }\n }\n let url: string\n try {\n url = options.buildUrl()\n } catch {\n state = \"disconnected\"\n emitClose(CLOSE_CODE_SYNTHETIC, false)\n return\n }\n let socket: WebSocket\n try {\n socket = new WS(url)\n } catch {\n if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {\n state = \"disconnected\"\n emitClose(CLOSE_CODE_SYNTHETIC, false)\n return\n }\n emitClose(CLOSE_CODE_SYNTHETIC, true)\n scheduleReconnect()\n return\n }\n ws = socket\n\n socket.addEventListener(\"open\", () => {\n if (ws !== socket) return\n state = \"connected\"\n reconnectAttempts = 0\n // Replay session frames before notifying open listeners so RPC frames\n // queued in `./rpc` are always flushed after identify/join.\n if (identity) {\n sendRaw({\n type: \"identify\",\n userId: identity.id,\n ...(identity.name ? { name: identity.name } : {}),\n ...(identity.avatar ? { avatar: identity.avatar } : {}),\n })\n }\n if (route !== null) {\n sendRaw({ type: \"join\", route })\n }\n emit(openListeners, undefined)\n })\n\n socket.addEventListener(\"message\", (event) => {\n if (ws !== socket) return\n handleMessage(event as MessageEvent)\n })\n\n socket.addEventListener(\"close\", (event) => {\n if (ws !== socket) return\n ws = null\n const code = (event as CloseEvent).code\n if (\n disposed ||\n code === CLOSE_CODE_AUTH_FAILED ||\n reconnectAttempts >= MAX_RECONNECT_ATTEMPTS\n ) {\n // Terminal: queued RPCs must reject now instead of waiting on a\n // reconnect that will never come.\n state = \"disconnected\"\n emitClose(code, false)\n return\n }\n emitClose(code, true)\n scheduleReconnect()\n })\n\n socket.addEventListener(\"error\", () => {\n // close fires after error; reconnect handled there\n })\n }\n\n function connect(): void {\n if (disposed) {\n disposed = false\n }\n if (ws) return\n if (state === \"connecting\") return\n reconnectAttempts = 0\n openSocket()\n }\n\n function disconnect(): void {\n disposed = true\n clearReconnectTimer()\n state = \"disconnected\"\n // Forget the session so a later revival (any RPC call re-connects the\n // socket) is anonymous instead of replaying identify/join for a user who\n // explicitly disconnected.\n identity = null\n route = null\n if (ws) {\n const socket = ws\n // Null first so the socket's own close event is ignored; we emit one\n // synthetic close instead.\n ws = null\n try {\n socket.close(1000)\n } catch {\n // ignore\n }\n }\n // Notify even when no socket was open (e.g. reconnect backoff armed):\n // the RPC client must reject queued requests rather than strand them.\n emitClose(CLOSE_CODE_SYNTHETIC, false)\n }\n\n function clearSession(): void {\n identity = null\n route = null\n }\n\n function identify(user: UserIdentity): void {\n identity = user\n sendRaw({\n type: \"identify\",\n userId: user.id,\n ...(user.name ? { name: user.name } : {}),\n ...(user.avatar ? { avatar: user.avatar } : {}),\n })\n }\n\n function joinRoute(nextRoute: string): void {\n route = nextRoute\n emit(presenceListeners, [])\n sendRaw({ type: \"join\", route: nextRoute })\n }\n\n function onPresence(cb: Listener<RealtimePresenceUser[]>): () => void {\n presenceListeners.add(cb)\n return () => {\n presenceListeners.delete(cb)\n }\n }\n\n function onPin(cb: Listener<PinRecord>): () => void {\n pinListeners.add(cb)\n return () => {\n pinListeners.delete(cb)\n }\n }\n\n function onPinArchived(cb: Listener<string>): () => void {\n pinArchivedListeners.add(cb)\n return () => {\n pinArchivedListeners.delete(cb)\n }\n }\n\n function onOpen(cb: Listener<void>): () => void {\n openListeners.add(cb)\n return () => {\n openListeners.delete(cb)\n }\n }\n\n function onClose(\n cb: (code: number, willReconnect: boolean) => void\n ): () => void {\n closeListeners.add(cb)\n return () => {\n closeListeners.delete(cb)\n }\n }\n\n function onRpcResponse(cb: Listener<RpcResponseFrame>): () => void {\n rpcListeners.add(cb)\n return () => {\n rpcListeners.delete(cb)\n }\n }\n\n return {\n get state() {\n return state\n },\n connect,\n disconnect,\n identify,\n clearSession,\n joinRoute,\n sendFrame: sendRaw,\n onPresence,\n onPin,\n onPinArchived,\n onOpen,\n onClose,\n onRpcResponse,\n }\n}\n","import type {\n ArchiveReason,\n ReportListResponse,\n ReportPayload,\n ReportResult,\n IngestConfig,\n PinRecord,\n} from \"@uidex/api-client\"\nimport type { UserIdentity } from \"../shared/user\"\n\nexport type {\n ArchiveReason,\n ReportListResponse,\n ReportPayload,\n ReportResult,\n IngestConfig,\n PinRecord,\n} from \"@uidex/api-client\"\n\nexport const DEFAULT_CLOUD_ENDPOINT = \"https://app.uidex.dev\"\n\nexport interface CloudOptions {\n projectKey: string\n endpoint?: string\n /** @deprecated Unused — the adapter talks RPC over WebSocket. Kept for API compatibility. */\n fetch?: typeof fetch\n /** Optional WebSocket constructor override (tests, Node). Defaults to `globalThis.WebSocket`. */\n WebSocketImpl?: typeof WebSocket\n git?: { branch?: string; commit?: string }\n}\n\nexport class CloudError extends Error {\n readonly status: number\n readonly retryAfter?: number\n readonly details?: unknown\n\n constructor(\n message: string,\n options: { status: number; retryAfter?: number; details?: unknown }\n ) {\n super(message)\n this.name = \"CloudError\"\n this.status = options.status\n this.retryAfter = options.retryAfter\n this.details = options.details\n }\n}\n\nexport type RealtimePresenceUser = {\n userId: string\n name: string\n avatar: string | null\n}\n\nexport type RealtimeChannelState = \"connecting\" | \"connected\" | \"disconnected\"\n\nexport interface RealtimeConnectOpts {\n user: UserIdentity\n route: string\n}\n\nexport interface RealtimeChannel {\n readonly state: RealtimeChannelState\n connect(): void\n disconnect(): void\n joinRoute(route: string): void\n onPresence(cb: (users: RealtimePresenceUser[]) => void): () => void\n onPin(cb: (pin: PinRecord) => void): () => void\n /** Optional so pre-existing channel stubs keep satisfying the interface. */\n onPinArchived?(cb: (reportId: string) => void): () => void\n}\n\nexport interface CloudAdapter<\n TPayload = ReportPayload,\n TResult = ReportResult,\n TIntegrations = {\n getConfig(): Promise<IngestConfig>\n getCachedConfig(): IngestConfig | null\n },\n> {\n readonly reports: {\n submit(payload: TPayload): Promise<TResult>\n list?(opts?: { page?: number; limit?: number }): Promise<ReportListResponse>\n }\n readonly integrations: TIntegrations\n readonly realtime: {\n connect(opts: RealtimeConnectOpts): RealtimeChannel\n }\n readonly pins: {\n list(params: { route?: string; entities?: string }): Promise<PinRecord[]>\n /**\n * Pin records travel without their screenshot (kept out of `pins.list`\n * so multi-MB frames don't stall the shared socket); the report detail\n * view fetches it lazily through here. Optional for host-provided\n * adapters that inline screenshots on the record instead.\n */\n screenshot?(reportId: string): Promise<string | null>\n close(reportId: string, reason?: ArchiveReason): Promise<void>\n }\n /** Closes the adapter's shared socket. Any later RPC call revives it. */\n dispose?(): void\n}\n","import type {\n RpcMethod,\n RpcParamsMap,\n RpcRequestFrame,\n RpcResultMap,\n} from \"./protocol\"\nimport {\n CLOSE_CODE_AUTH_FAILED,\n type InternalRealtimeChannel,\n} from \"./realtime\"\nimport { CloudError } from \"./types\"\n\nexport const DEFAULT_RPC_TIMEOUT_MS = 30_000\n/**\n * `reports.submit` frames embed an inline base64 screenshot (multi-MB is\n * routine) and the server persists the report even when the client stops\n * waiting — a timeout there means a duplicate on retry, so give slow uplinks\n * far more headroom than a quick list/config call.\n */\nexport const SUBMIT_RPC_TIMEOUT_MS = 120_000\n\ntype PendingEntry = {\n resolve: (data: unknown) => void\n reject: (err: unknown) => void\n timer: ReturnType<typeof setTimeout>\n}\n\ntype QueuedRequest = {\n frame: RpcRequestFrame\n entry: PendingEntry\n}\n\nexport interface RpcClient {\n call<M extends RpcMethod>(\n method: M,\n params: RpcParamsMap[M],\n opts?: { timeoutMs?: number }\n ): Promise<RpcResultMap[M]>\n}\n\nfunction authFailedError(): CloudError {\n return new CloudError(\"WebSocket authentication failed\", { status: 401 })\n}\n\n/**\n * Request/response RPC over the realtime channel's socket. Requests made\n * while the socket is closed are queued and flushed on (re)open — after the\n * channel's identify/join replay, because the channel emits `onOpen` last.\n */\nexport function createRpcClient(\n channel: InternalRealtimeChannel,\n options?: { timeoutMs?: number }\n): RpcClient {\n const timeoutMs = options?.timeoutMs ?? DEFAULT_RPC_TIMEOUT_MS\n const idSuffix = Math.random().toString(36).slice(2, 8)\n let idCounter = 0\n\n /** Sent, awaiting an `rpc:res` frame. */\n const pending = new Map<string, PendingEntry>()\n /** Not yet sent; rides the next (re)open. */\n const queue: QueuedRequest[] = []\n /** Set after a 4001 close — the channel will not reconnect, so fail fast. */\n let terminalError: CloudError | null = null\n\n function settlePending(err: CloudError): void {\n for (const entry of pending.values()) {\n clearTimeout(entry.timer)\n entry.reject(err)\n }\n pending.clear()\n }\n\n channel.onOpen(() => {\n while (queue.length > 0) {\n const next = queue[0]\n if (!channel.sendFrame(next.frame)) return\n queue.shift()\n pending.set(next.frame.id, next.entry)\n }\n })\n\n function rejectQueue(err: CloudError): void {\n for (const queued of queue) {\n clearTimeout(queued.entry.timer)\n queued.entry.reject(err)\n }\n queue.length = 0\n }\n\n channel.onClose((code, willReconnect) => {\n if (code === CLOSE_CODE_AUTH_FAILED) {\n const err = authFailedError()\n terminalError = err\n settlePending(err)\n rejectQueue(err)\n return\n }\n // In-flight requests are lost with the socket; queued ones ride the\n // reconnect — unless the close is terminal (disconnect()/dispose(), no\n // WebSocket implementation), where waiting would only strand them until\n // the timeout.\n settlePending(new CloudError(\"Connection lost\", { status: 0 }))\n if (!willReconnect) {\n rejectQueue(new CloudError(\"Connection lost\", { status: 0 }))\n }\n })\n\n channel.onRpcResponse((frame) => {\n const entry = pending.get(frame.id)\n if (!entry) return // late response after timeout/close — ignore\n pending.delete(frame.id)\n clearTimeout(entry.timer)\n if (frame.ok) {\n entry.resolve(frame.data)\n } else {\n entry.reject(\n new CloudError(frame.error, {\n status: frame.status,\n retryAfter: frame.retryAfter,\n details: frame.details,\n })\n )\n }\n })\n\n function call<M extends RpcMethod>(\n method: M,\n params: RpcParamsMap[M],\n opts?: { timeoutMs?: number }\n ): Promise<RpcResultMap[M]> {\n if (terminalError) return Promise.reject(terminalError)\n const callTimeoutMs = opts?.timeoutMs ?? timeoutMs\n return new Promise<RpcResultMap[M]>((resolve, reject) => {\n idCounter += 1\n const id = `${idCounter.toString(36)}-${idSuffix}`\n const frame: RpcRequestFrame = {\n type: \"rpc\",\n id,\n method,\n ...(params !== undefined ? { params } : {}),\n }\n const timer = setTimeout(() => {\n pending.delete(id)\n const queuedIndex = queue.findIndex((q) => q.frame.id === id)\n if (queuedIndex !== -1) queue.splice(queuedIndex, 1)\n reject(new CloudError(\"Request timed out\", { status: 0 }))\n }, callTimeoutMs)\n const entry: PendingEntry = {\n resolve: resolve as (data: unknown) => void,\n reject,\n timer,\n }\n if (channel.sendFrame(frame)) {\n pending.set(id, entry)\n } else {\n queue.push({ frame, entry })\n channel.connect()\n }\n })\n }\n\n return { call }\n}\n","import { createRealtimeChannel } from \"./realtime\"\nimport { SCREENSHOT_CHUNK_BYTES, SCREENSHOT_INLINE_MAX_BYTES } from \"./protocol\"\nimport { createRpcClient, SUBMIT_RPC_TIMEOUT_MS } from \"./rpc\"\nimport {\n DEFAULT_CLOUD_ENDPOINT,\n type ArchiveReason,\n type CloudAdapter,\n type CloudOptions,\n type ReportListResponse,\n type ReportPayload,\n type ReportResult,\n type IngestConfig,\n type PinRecord,\n type RealtimeChannel,\n type RealtimeConnectOpts,\n} from \"./types\"\n\nfunction trimEndpoint(endpoint: string): string {\n return endpoint.endsWith(\"/\") ? endpoint.slice(0, -1) : endpoint\n}\n\n/** Unique id grouping a streamed screenshot's chunks (server also scopes it by project). */\nfunction nextUploadId(): string {\n return `up-${crypto.randomUUID()}`\n}\n\nexport function cloud(options: CloudOptions): CloudAdapter {\n let cachedConfig: Promise<IngestConfig> | null = null\n let resolvedConfig: IngestConfig | null = null\n\n const projectKey = options.projectKey\n if (!projectKey) {\n throw new Error(\"uidex/cloud: `projectKey` is required\")\n }\n const endpoint = trimEndpoint(options.endpoint ?? DEFAULT_CLOUD_ENDPOINT)\n const git = options.git\n\n function buildWsUrl(): string {\n const httpToWs = endpoint\n .replace(/^http:/, \"ws:\")\n .replace(/^https:/, \"wss:\")\n const params = new URLSearchParams()\n params.set(\"key\", projectKey)\n return `${httpToWs}/ws?${params.toString()}`\n }\n\n // One socket per adapter: realtime events and RPC share this channel.\n const channel = createRealtimeChannel({\n buildUrl: buildWsUrl,\n ...(options.WebSocketImpl ? { WebSocketImpl: options.WebSocketImpl } : {}),\n })\n const rpc = createRpcClient(channel)\n // Eager presence-invisible connect + config prefetch happen in the browser\n // only (or with an explicit WebSocketImpl): `use client` components still\n // construct adapters during SSR renders, which must stay side-effect free.\n // RPC calls connect on demand, so server-side usage still works.\n const eagerConnect =\n options.WebSocketImpl !== undefined ||\n (typeof window !== \"undefined\" && typeof WebSocket === \"function\")\n\n async function submit(payload: ReportPayload): Promise<ReportResult> {\n const enriched =\n git?.branch || git?.commit\n ? {\n ...payload,\n context: {\n ...payload.context,\n git: payload.context?.git ?? {\n branch: git.branch,\n commit: git.commit,\n },\n },\n }\n : payload\n\n const screenshot = enriched.screenshot\n if (\n typeof screenshot === \"string\" &&\n screenshot.length > SCREENSHOT_INLINE_MAX_BYTES\n ) {\n // A screenshot this large would blow the relay's WS `maxPayload` as a\n // single frame (the server drops it → close 1009 → \"Connection lost\").\n // Stream it as a sequence of sub-cap `screenshot.chunk` frames, then\n // submit the report referencing the upload; the server reassembles it.\n //\n // Send sequentially (await each ack) rather than all at once: this bounds\n // the WS send buffer and live substring memory to ~one chunk, and starts\n // each chunk's timeout when it is actually sent (a parallel burst would\n // start every timer at once, so a slow uplink times out the tail).\n const uploadId = nextUploadId()\n const total = Math.ceil(screenshot.length / SCREENSHOT_CHUNK_BYTES)\n for (let seq = 0; seq < total; seq++) {\n const data = screenshot.slice(\n seq * SCREENSHOT_CHUNK_BYTES,\n (seq + 1) * SCREENSHOT_CHUNK_BYTES\n )\n await rpc.call(\n \"screenshot.chunk\",\n { uploadId, seq, total, data },\n { timeoutMs: SUBMIT_RPC_TIMEOUT_MS }\n )\n }\n return rpc.call(\n \"reports.submit\",\n { ...enriched, screenshot: undefined, screenshotUploadId: uploadId },\n { timeoutMs: SUBMIT_RPC_TIMEOUT_MS }\n )\n }\n\n return rpc.call(\"reports.submit\", enriched, {\n timeoutMs: SUBMIT_RPC_TIMEOUT_MS,\n })\n }\n\n function startFetch(): Promise<IngestConfig> {\n const promise = rpc.call(\"config.get\", undefined)\n cachedConfig = promise\n promise.then(\n (config) => {\n resolvedConfig = config\n },\n () => {\n // Drop the rejected promise so the next getConfig() retries.\n if (cachedConfig === promise) cachedConfig = null\n }\n )\n return promise\n }\n\n if (eagerConnect) {\n channel.connect()\n startFetch()\n }\n\n function getConfig(): Promise<IngestConfig> {\n return cachedConfig ?? startFetch()\n }\n\n function getCachedConfig(): IngestConfig | null {\n return resolvedConfig\n }\n\n function connectRealtime(opts: RealtimeConnectOpts): RealtimeChannel {\n if (!opts || !opts.user || typeof opts.user.id !== \"string\") {\n throw new TypeError(\"uidex/cloud: realtime.connect requires `user.id`\")\n }\n let currentRoute = opts.route\n // Facade-level disconnected flag: the adapter's shared socket outlives a\n // facade disconnect(), so `state` must not mirror the channel's.\n let detached = false\n // Listeners registered through this facade. disconnect() detaches them\n // from the shared channel (an unmounted surface stops receiving\n // presence/pin events) but keeps the registrations, so a later connect()\n // re-attaches them — matching the REST-era channel semantics.\n type Registration = {\n attach: () => () => void\n detach: (() => void) | null\n }\n const registrations = new Set<Registration>()\n function register(attach: () => () => void): () => void {\n const reg: Registration = { attach, detach: detached ? null : attach() }\n registrations.add(reg)\n return () => {\n registrations.delete(reg)\n reg.detach?.()\n reg.detach = null\n }\n }\n function arm(): void {\n channel.identify(opts.user)\n channel.joinRoute(currentRoute)\n channel.connect()\n }\n arm()\n return {\n get state() {\n return detached ? \"disconnected\" : channel.state\n },\n // Re-arms identity/route and re-attaches this facade's listeners so an\n // explicit disconnect() -> connect() restores presence and pin events.\n connect: () => {\n if (detached) {\n detached = false\n for (const reg of registrations) reg.detach ??= reg.attach()\n }\n arm()\n },\n // Soft leave: drop presence and the stored identity (so a later\n // reopen/revival stays anonymous) but keep the adapter's shared socket\n // alive — in-flight and future RPCs (reports.submit, pins.*) must\n // survive a surface unmount. Socket teardown is reserved for\n // CloudAdapter.dispose().\n disconnect: () => {\n detached = true\n channel.sendFrame({ type: \"leave\" })\n channel.clearSession()\n for (const reg of registrations) {\n reg.detach?.()\n reg.detach = null\n }\n },\n joinRoute: (route: string) => {\n currentRoute = route\n channel.joinRoute(route)\n },\n onPresence: (cb) => register(() => channel.onPresence(cb)),\n onPin: (cb) => register(() => channel.onPin(cb)),\n onPinArchived: (cb) => register(() => channel.onPinArchived(cb)),\n }\n }\n\n async function listPins(params: {\n route?: string\n entities?: string\n }): Promise<PinRecord[]> {\n // Mirror the REST route's split exactly (no trim, send present-but-empty\n // arrays): tokens travel verbatim and `entities: \",\"` still resolves to\n // an empty pin list instead of a 400.\n const entities = params.entities\n ? params.entities.split(\",\").filter(Boolean)\n : undefined\n const result = await rpc.call(\"pins.list\", {\n ...(params.route !== undefined ? { route: params.route } : {}),\n ...(entities ? { entities } : {}),\n })\n return result.pins\n }\n\n async function getPinScreenshot(reportId: string): Promise<string | null> {\n const result = await rpc.call(\"pins.screenshot\", { reportId })\n return result.screenshot\n }\n\n async function closePin(\n reportId: string,\n reason?: ArchiveReason\n ): Promise<void> {\n await rpc.call(\"pins.archive\", { reportId, ...(reason ? { reason } : {}) })\n }\n\n function listReports(opts?: {\n page?: number\n limit?: number\n }): Promise<ReportListResponse> {\n return rpc.call(\"reports.list\", opts ?? {})\n }\n\n function dispose(): void {\n // Pending and queued RPCs reject through the channel's close notification.\n channel.disconnect()\n }\n\n return {\n reports: { submit, list: listReports },\n integrations: { getConfig, getCachedConfig },\n realtime: { connect: connectRealtime },\n pins: { list: listPins, screenshot: getPinScreenshot, close: closePin },\n dispose,\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/cloud/index.d.cts
DELETED
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
import { ReportPayload, ReportResult, IngestConfig, ReportListResponse, PinRecord, ArchiveReason } from '@uidex/api-client';
|
|
2
|
-
export { ArchiveReason, IngestConfig, PinRecord, ReportListRecord, ReportListResponse, ReportPayload, ReportResult } from '@uidex/api-client';
|
|
3
|
-
|
|
4
|
-
interface UserIdentity {
|
|
5
|
-
id: string;
|
|
6
|
-
name?: string;
|
|
7
|
-
avatar?: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
declare const DEFAULT_CLOUD_ENDPOINT = "https://app.uidex.dev";
|
|
11
|
-
interface CloudOptions {
|
|
12
|
-
projectKey: string;
|
|
13
|
-
endpoint?: string;
|
|
14
|
-
/** @deprecated Unused — the adapter talks RPC over WebSocket. Kept for API compatibility. */
|
|
15
|
-
fetch?: typeof fetch;
|
|
16
|
-
/** Optional WebSocket constructor override (tests, Node). Defaults to `globalThis.WebSocket`. */
|
|
17
|
-
WebSocketImpl?: typeof WebSocket;
|
|
18
|
-
git?: {
|
|
19
|
-
branch?: string;
|
|
20
|
-
commit?: string;
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
declare class CloudError extends Error {
|
|
24
|
-
readonly status: number;
|
|
25
|
-
readonly retryAfter?: number;
|
|
26
|
-
readonly details?: unknown;
|
|
27
|
-
constructor(message: string, options: {
|
|
28
|
-
status: number;
|
|
29
|
-
retryAfter?: number;
|
|
30
|
-
details?: unknown;
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
type RealtimePresenceUser = {
|
|
34
|
-
userId: string;
|
|
35
|
-
name: string;
|
|
36
|
-
avatar: string | null;
|
|
37
|
-
};
|
|
38
|
-
type RealtimeChannelState = "connecting" | "connected" | "disconnected";
|
|
39
|
-
interface RealtimeConnectOpts {
|
|
40
|
-
user: UserIdentity;
|
|
41
|
-
route: string;
|
|
42
|
-
}
|
|
43
|
-
interface RealtimeChannel {
|
|
44
|
-
readonly state: RealtimeChannelState;
|
|
45
|
-
connect(): void;
|
|
46
|
-
disconnect(): void;
|
|
47
|
-
joinRoute(route: string): void;
|
|
48
|
-
onPresence(cb: (users: RealtimePresenceUser[]) => void): () => void;
|
|
49
|
-
onPin(cb: (pin: PinRecord) => void): () => void;
|
|
50
|
-
/** Optional so pre-existing channel stubs keep satisfying the interface. */
|
|
51
|
-
onPinArchived?(cb: (reportId: string) => void): () => void;
|
|
52
|
-
}
|
|
53
|
-
interface CloudAdapter<TPayload = ReportPayload, TResult = ReportResult, TIntegrations = {
|
|
54
|
-
getConfig(): Promise<IngestConfig>;
|
|
55
|
-
getCachedConfig(): IngestConfig | null;
|
|
56
|
-
}> {
|
|
57
|
-
readonly reports: {
|
|
58
|
-
submit(payload: TPayload): Promise<TResult>;
|
|
59
|
-
list?(opts?: {
|
|
60
|
-
page?: number;
|
|
61
|
-
limit?: number;
|
|
62
|
-
}): Promise<ReportListResponse>;
|
|
63
|
-
};
|
|
64
|
-
readonly integrations: TIntegrations;
|
|
65
|
-
readonly realtime: {
|
|
66
|
-
connect(opts: RealtimeConnectOpts): RealtimeChannel;
|
|
67
|
-
};
|
|
68
|
-
readonly pins: {
|
|
69
|
-
list(params: {
|
|
70
|
-
route?: string;
|
|
71
|
-
entities?: string;
|
|
72
|
-
}): Promise<PinRecord[]>;
|
|
73
|
-
/**
|
|
74
|
-
* Pin records travel without their screenshot (kept out of `pins.list`
|
|
75
|
-
* so multi-MB frames don't stall the shared socket); the report detail
|
|
76
|
-
* view fetches it lazily through here. Optional for host-provided
|
|
77
|
-
* adapters that inline screenshots on the record instead.
|
|
78
|
-
*/
|
|
79
|
-
screenshot?(reportId: string): Promise<string | null>;
|
|
80
|
-
close(reportId: string, reason?: ArchiveReason): Promise<void>;
|
|
81
|
-
};
|
|
82
|
-
/** Closes the adapter's shared socket. Any later RPC call revives it. */
|
|
83
|
-
dispose?(): void;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
declare function cloud(options: CloudOptions): CloudAdapter;
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* WS RPC protocol shared by the SDK (`packages/sdk/src/cloud`) and the relay
|
|
90
|
-
* server (`apps/app/src/lib/relay-handler.ts`, type-only import from
|
|
91
|
-
* "uidex/cloud"). These frames ride the same socket as the existing
|
|
92
|
-
* fire-and-forget messages (`cursor`, `join`, `presence`, `pin`); peers that
|
|
93
|
-
* predate a frame type silently drop it.
|
|
94
|
-
*/
|
|
95
|
-
declare const RPC_METHODS: readonly ["reports.submit", "reports.list", "config.get", "pins.list", "pins.screenshot", "pins.archive", "screenshot.chunk"];
|
|
96
|
-
type RpcMethod = (typeof RPC_METHODS)[number];
|
|
97
|
-
/**
|
|
98
|
-
* Screenshots whose base64 data-URL length is at or below this ride inline in
|
|
99
|
-
* the `reports.submit` frame (the common case). Larger ones are streamed via
|
|
100
|
-
* `screenshot.chunk` so no single frame approaches the relay's 25 MiB WS
|
|
101
|
-
* `maxPayload` — an oversized frame is dropped server-side (close 1009), which
|
|
102
|
-
* the SDK surfaces as "Connection lost".
|
|
103
|
-
*/
|
|
104
|
-
declare const SCREENSHOT_INLINE_MAX_BYTES: number;
|
|
105
|
-
/** Per-chunk size when a screenshot is streamed. Each `screenshot.chunk` frame stays well under `maxPayload`. */
|
|
106
|
-
declare const SCREENSHOT_CHUNK_BYTES: number;
|
|
107
|
-
/** One streamed screenshot fragment. Parts are keyed by `seq` and reassembled in order server-side. */
|
|
108
|
-
type ScreenshotChunkParams = {
|
|
109
|
-
/** Client-generated id grouping a screenshot's chunks; referenced by `reports.submit` as `screenshotUploadId`. */
|
|
110
|
-
uploadId: string;
|
|
111
|
-
/** 0-based index of this part. */
|
|
112
|
-
seq: number;
|
|
113
|
-
/** Total number of parts in this upload. */
|
|
114
|
-
total: number;
|
|
115
|
-
/** A slice of the screenshot data URL. */
|
|
116
|
-
data: string;
|
|
117
|
-
};
|
|
118
|
-
/**
|
|
119
|
-
* `reports.submit` params. Either the screenshot rides inline (`screenshot`) or,
|
|
120
|
-
* for large captures, it is streamed via `screenshot.chunk` and referenced here
|
|
121
|
-
* by `screenshotUploadId` — the server reassembles it before persisting.
|
|
122
|
-
*/
|
|
123
|
-
type ReportSubmitParams = ReportPayload & {
|
|
124
|
-
screenshotUploadId?: string;
|
|
125
|
-
};
|
|
126
|
-
interface RpcParamsMap {
|
|
127
|
-
"reports.submit": ReportSubmitParams;
|
|
128
|
-
"reports.list": {
|
|
129
|
-
page?: number;
|
|
130
|
-
limit?: number;
|
|
131
|
-
};
|
|
132
|
-
"config.get": undefined;
|
|
133
|
-
"pins.list": {
|
|
134
|
-
route?: string;
|
|
135
|
-
entities?: string[];
|
|
136
|
-
};
|
|
137
|
-
"pins.screenshot": {
|
|
138
|
-
reportId: string;
|
|
139
|
-
};
|
|
140
|
-
"pins.archive": {
|
|
141
|
-
reportId: string;
|
|
142
|
-
reason?: ArchiveReason;
|
|
143
|
-
};
|
|
144
|
-
"screenshot.chunk": ScreenshotChunkParams;
|
|
145
|
-
}
|
|
146
|
-
interface RpcResultMap {
|
|
147
|
-
"reports.submit": ReportResult;
|
|
148
|
-
"reports.list": ReportListResponse;
|
|
149
|
-
"config.get": IngestConfig;
|
|
150
|
-
"pins.list": {
|
|
151
|
-
pins: PinRecord[];
|
|
152
|
-
};
|
|
153
|
-
"pins.screenshot": {
|
|
154
|
-
screenshot: string | null;
|
|
155
|
-
};
|
|
156
|
-
"pins.archive": {
|
|
157
|
-
ok: true;
|
|
158
|
-
};
|
|
159
|
-
/** Acks a stored chunk; `received` is how many distinct parts have arrived. */
|
|
160
|
-
"screenshot.chunk": {
|
|
161
|
-
received: number;
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
type RpcRequestFrame = {
|
|
165
|
-
type: "rpc";
|
|
166
|
-
id: string;
|
|
167
|
-
method: RpcMethod;
|
|
168
|
-
params?: unknown;
|
|
169
|
-
};
|
|
170
|
-
type RpcOkFrame = {
|
|
171
|
-
type: "rpc:res";
|
|
172
|
-
id: string;
|
|
173
|
-
ok: true;
|
|
174
|
-
data: unknown;
|
|
175
|
-
};
|
|
176
|
-
type RpcErrFrame = {
|
|
177
|
-
type: "rpc:res";
|
|
178
|
-
id: string;
|
|
179
|
-
ok: false;
|
|
180
|
-
/** HTTP-equivalent status so CloudError semantics survive the transport. */
|
|
181
|
-
status: number;
|
|
182
|
-
error: string;
|
|
183
|
-
/** Seconds, present on 429 responses (mirrors the Retry-After header). */
|
|
184
|
-
retryAfter?: number;
|
|
185
|
-
details?: unknown;
|
|
186
|
-
};
|
|
187
|
-
type RpcResponseFrame = RpcOkFrame | RpcErrFrame;
|
|
188
|
-
/**
|
|
189
|
-
* Sent by the SDK after `realtime.connect(opts)` to attach a user identity to
|
|
190
|
-
* an initially anonymous connection. The server marks the connection visible
|
|
191
|
-
* in presence from this point on. Connections that never identify stay
|
|
192
|
-
* RPC-only: excluded from presence, no room auto-join.
|
|
193
|
-
*/
|
|
194
|
-
type IdentifyFrame = {
|
|
195
|
-
type: "identify";
|
|
196
|
-
userId: string;
|
|
197
|
-
name?: string;
|
|
198
|
-
avatar?: string;
|
|
199
|
-
};
|
|
200
|
-
/**
|
|
201
|
-
* Reverse of `IdentifyFrame`: sent when a realtime consumer disconnects
|
|
202
|
-
* (e.g. the uidex surface unmounts) while the adapter keeps using the socket
|
|
203
|
-
* for RPC. The server drops the connection from presence and its room but
|
|
204
|
-
* keeps the socket open.
|
|
205
|
-
*/
|
|
206
|
-
type LeaveFrame = {
|
|
207
|
-
type: "leave";
|
|
208
|
-
};
|
|
209
|
-
/**
|
|
210
|
-
* Server→client broadcast when a pin's report leaves the open statuses
|
|
211
|
-
* (closed via the SDK, the dashboard, or the REST route). Sent to the room of
|
|
212
|
-
* the report's route so live overlays drop the pin without a refresh.
|
|
213
|
-
*/
|
|
214
|
-
type PinArchivedFrame = {
|
|
215
|
-
type: "pin:archived";
|
|
216
|
-
reportId: string;
|
|
217
|
-
};
|
|
218
|
-
declare function isRpcMethod(value: unknown): value is RpcMethod;
|
|
219
|
-
/** Client-side guard for inbound `rpc:res` frames (server validates inbound `rpc` frames itself). */
|
|
220
|
-
declare function parseRpcResponseFrame(msg: unknown): RpcResponseFrame | null;
|
|
221
|
-
|
|
222
|
-
type RealtimeChannelOptions = {
|
|
223
|
-
/** Builds the WebSocket URL on each (re)connect attempt. Only needs the project key — identity and route ride dedicated frames. */
|
|
224
|
-
buildUrl: () => string;
|
|
225
|
-
/** Optional WebSocket constructor override (testing). Defaults to `globalThis.WebSocket`. */
|
|
226
|
-
WebSocketImpl?: typeof WebSocket;
|
|
227
|
-
};
|
|
228
|
-
/**
|
|
229
|
-
* Superset of the public `RealtimeChannel` used internally by the cloud
|
|
230
|
-
* adapter: the RPC client (`./rpc`) shares the same socket and needs raw
|
|
231
|
-
* frame access plus open/close notifications.
|
|
232
|
-
*/
|
|
233
|
-
interface InternalRealtimeChannel extends RealtimeChannel {
|
|
234
|
-
/** Required here (optional on the public interface only for channel stubs). */
|
|
235
|
-
onPinArchived(cb: (reportId: string) => void): () => void;
|
|
236
|
-
/** Stores the identity and (re)sends the `identify` frame on every open. */
|
|
237
|
-
identify(user: UserIdentity): void;
|
|
238
|
-
/** Drops the stored identity/route without touching the socket (soft leave). */
|
|
239
|
-
clearSession(): void;
|
|
240
|
-
/** Sends a JSON frame if the socket is OPEN. Returns false otherwise. */
|
|
241
|
-
sendFrame(frame: object): boolean;
|
|
242
|
-
/** Fires after the channel finished its identify/join replay on (re)open. */
|
|
243
|
-
onOpen(cb: () => void): () => void;
|
|
244
|
-
/**
|
|
245
|
-
* Fires with the close code (or `CLOSE_CODE_SYNTHETIC`) whenever the socket
|
|
246
|
-
* goes away. `willReconnect` is false for terminal closes (`disconnect()`,
|
|
247
|
-
* auth failure, no WebSocket implementation): queued work must reject
|
|
248
|
-
* instead of riding a reconnect that will never come.
|
|
249
|
-
*/
|
|
250
|
-
onClose(cb: (code: number, willReconnect: boolean) => void): () => void;
|
|
251
|
-
onRpcResponse(cb: (frame: RpcResponseFrame) => void): () => void;
|
|
252
|
-
}
|
|
253
|
-
declare function createRealtimeChannel(options: RealtimeChannelOptions): InternalRealtimeChannel;
|
|
254
|
-
|
|
255
|
-
declare const DEFAULT_RPC_TIMEOUT_MS = 30000;
|
|
256
|
-
interface RpcClient {
|
|
257
|
-
call<M extends RpcMethod>(method: M, params: RpcParamsMap[M], opts?: {
|
|
258
|
-
timeoutMs?: number;
|
|
259
|
-
}): Promise<RpcResultMap[M]>;
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* Request/response RPC over the realtime channel's socket. Requests made
|
|
263
|
-
* while the socket is closed are queued and flushed on (re)open — after the
|
|
264
|
-
* channel's identify/join replay, because the channel emits `onOpen` last.
|
|
265
|
-
*/
|
|
266
|
-
declare function createRpcClient(channel: InternalRealtimeChannel, options?: {
|
|
267
|
-
timeoutMs?: number;
|
|
268
|
-
}): RpcClient;
|
|
269
|
-
|
|
270
|
-
export { type CloudAdapter, CloudError, type CloudOptions, DEFAULT_CLOUD_ENDPOINT, DEFAULT_RPC_TIMEOUT_MS, type IdentifyFrame, type InternalRealtimeChannel, type LeaveFrame, type PinArchivedFrame, RPC_METHODS, type RealtimeChannel, type RealtimeChannelState, type RealtimeConnectOpts, type RealtimePresenceUser, type ReportSubmitParams, type RpcClient, type RpcErrFrame, type RpcMethod, type RpcOkFrame, type RpcParamsMap, type RpcRequestFrame, type RpcResponseFrame, type RpcResultMap, SCREENSHOT_CHUNK_BYTES, SCREENSHOT_INLINE_MAX_BYTES, type ScreenshotChunkParams, cloud, createRealtimeChannel, createRpcClient, isRpcMethod, parseRpcResponseFrame };
|
package/dist/cloud/index.d.ts
DELETED
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
import { ReportPayload, ReportResult, IngestConfig, ReportListResponse, PinRecord, ArchiveReason } from '@uidex/api-client';
|
|
2
|
-
export { ArchiveReason, IngestConfig, PinRecord, ReportListRecord, ReportListResponse, ReportPayload, ReportResult } from '@uidex/api-client';
|
|
3
|
-
|
|
4
|
-
interface UserIdentity {
|
|
5
|
-
id: string;
|
|
6
|
-
name?: string;
|
|
7
|
-
avatar?: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
declare const DEFAULT_CLOUD_ENDPOINT = "https://app.uidex.dev";
|
|
11
|
-
interface CloudOptions {
|
|
12
|
-
projectKey: string;
|
|
13
|
-
endpoint?: string;
|
|
14
|
-
/** @deprecated Unused — the adapter talks RPC over WebSocket. Kept for API compatibility. */
|
|
15
|
-
fetch?: typeof fetch;
|
|
16
|
-
/** Optional WebSocket constructor override (tests, Node). Defaults to `globalThis.WebSocket`. */
|
|
17
|
-
WebSocketImpl?: typeof WebSocket;
|
|
18
|
-
git?: {
|
|
19
|
-
branch?: string;
|
|
20
|
-
commit?: string;
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
declare class CloudError extends Error {
|
|
24
|
-
readonly status: number;
|
|
25
|
-
readonly retryAfter?: number;
|
|
26
|
-
readonly details?: unknown;
|
|
27
|
-
constructor(message: string, options: {
|
|
28
|
-
status: number;
|
|
29
|
-
retryAfter?: number;
|
|
30
|
-
details?: unknown;
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
type RealtimePresenceUser = {
|
|
34
|
-
userId: string;
|
|
35
|
-
name: string;
|
|
36
|
-
avatar: string | null;
|
|
37
|
-
};
|
|
38
|
-
type RealtimeChannelState = "connecting" | "connected" | "disconnected";
|
|
39
|
-
interface RealtimeConnectOpts {
|
|
40
|
-
user: UserIdentity;
|
|
41
|
-
route: string;
|
|
42
|
-
}
|
|
43
|
-
interface RealtimeChannel {
|
|
44
|
-
readonly state: RealtimeChannelState;
|
|
45
|
-
connect(): void;
|
|
46
|
-
disconnect(): void;
|
|
47
|
-
joinRoute(route: string): void;
|
|
48
|
-
onPresence(cb: (users: RealtimePresenceUser[]) => void): () => void;
|
|
49
|
-
onPin(cb: (pin: PinRecord) => void): () => void;
|
|
50
|
-
/** Optional so pre-existing channel stubs keep satisfying the interface. */
|
|
51
|
-
onPinArchived?(cb: (reportId: string) => void): () => void;
|
|
52
|
-
}
|
|
53
|
-
interface CloudAdapter<TPayload = ReportPayload, TResult = ReportResult, TIntegrations = {
|
|
54
|
-
getConfig(): Promise<IngestConfig>;
|
|
55
|
-
getCachedConfig(): IngestConfig | null;
|
|
56
|
-
}> {
|
|
57
|
-
readonly reports: {
|
|
58
|
-
submit(payload: TPayload): Promise<TResult>;
|
|
59
|
-
list?(opts?: {
|
|
60
|
-
page?: number;
|
|
61
|
-
limit?: number;
|
|
62
|
-
}): Promise<ReportListResponse>;
|
|
63
|
-
};
|
|
64
|
-
readonly integrations: TIntegrations;
|
|
65
|
-
readonly realtime: {
|
|
66
|
-
connect(opts: RealtimeConnectOpts): RealtimeChannel;
|
|
67
|
-
};
|
|
68
|
-
readonly pins: {
|
|
69
|
-
list(params: {
|
|
70
|
-
route?: string;
|
|
71
|
-
entities?: string;
|
|
72
|
-
}): Promise<PinRecord[]>;
|
|
73
|
-
/**
|
|
74
|
-
* Pin records travel without their screenshot (kept out of `pins.list`
|
|
75
|
-
* so multi-MB frames don't stall the shared socket); the report detail
|
|
76
|
-
* view fetches it lazily through here. Optional for host-provided
|
|
77
|
-
* adapters that inline screenshots on the record instead.
|
|
78
|
-
*/
|
|
79
|
-
screenshot?(reportId: string): Promise<string | null>;
|
|
80
|
-
close(reportId: string, reason?: ArchiveReason): Promise<void>;
|
|
81
|
-
};
|
|
82
|
-
/** Closes the adapter's shared socket. Any later RPC call revives it. */
|
|
83
|
-
dispose?(): void;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
declare function cloud(options: CloudOptions): CloudAdapter;
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* WS RPC protocol shared by the SDK (`packages/sdk/src/cloud`) and the relay
|
|
90
|
-
* server (`apps/app/src/lib/relay-handler.ts`, type-only import from
|
|
91
|
-
* "uidex/cloud"). These frames ride the same socket as the existing
|
|
92
|
-
* fire-and-forget messages (`cursor`, `join`, `presence`, `pin`); peers that
|
|
93
|
-
* predate a frame type silently drop it.
|
|
94
|
-
*/
|
|
95
|
-
declare const RPC_METHODS: readonly ["reports.submit", "reports.list", "config.get", "pins.list", "pins.screenshot", "pins.archive", "screenshot.chunk"];
|
|
96
|
-
type RpcMethod = (typeof RPC_METHODS)[number];
|
|
97
|
-
/**
|
|
98
|
-
* Screenshots whose base64 data-URL length is at or below this ride inline in
|
|
99
|
-
* the `reports.submit` frame (the common case). Larger ones are streamed via
|
|
100
|
-
* `screenshot.chunk` so no single frame approaches the relay's 25 MiB WS
|
|
101
|
-
* `maxPayload` — an oversized frame is dropped server-side (close 1009), which
|
|
102
|
-
* the SDK surfaces as "Connection lost".
|
|
103
|
-
*/
|
|
104
|
-
declare const SCREENSHOT_INLINE_MAX_BYTES: number;
|
|
105
|
-
/** Per-chunk size when a screenshot is streamed. Each `screenshot.chunk` frame stays well under `maxPayload`. */
|
|
106
|
-
declare const SCREENSHOT_CHUNK_BYTES: number;
|
|
107
|
-
/** One streamed screenshot fragment. Parts are keyed by `seq` and reassembled in order server-side. */
|
|
108
|
-
type ScreenshotChunkParams = {
|
|
109
|
-
/** Client-generated id grouping a screenshot's chunks; referenced by `reports.submit` as `screenshotUploadId`. */
|
|
110
|
-
uploadId: string;
|
|
111
|
-
/** 0-based index of this part. */
|
|
112
|
-
seq: number;
|
|
113
|
-
/** Total number of parts in this upload. */
|
|
114
|
-
total: number;
|
|
115
|
-
/** A slice of the screenshot data URL. */
|
|
116
|
-
data: string;
|
|
117
|
-
};
|
|
118
|
-
/**
|
|
119
|
-
* `reports.submit` params. Either the screenshot rides inline (`screenshot`) or,
|
|
120
|
-
* for large captures, it is streamed via `screenshot.chunk` and referenced here
|
|
121
|
-
* by `screenshotUploadId` — the server reassembles it before persisting.
|
|
122
|
-
*/
|
|
123
|
-
type ReportSubmitParams = ReportPayload & {
|
|
124
|
-
screenshotUploadId?: string;
|
|
125
|
-
};
|
|
126
|
-
interface RpcParamsMap {
|
|
127
|
-
"reports.submit": ReportSubmitParams;
|
|
128
|
-
"reports.list": {
|
|
129
|
-
page?: number;
|
|
130
|
-
limit?: number;
|
|
131
|
-
};
|
|
132
|
-
"config.get": undefined;
|
|
133
|
-
"pins.list": {
|
|
134
|
-
route?: string;
|
|
135
|
-
entities?: string[];
|
|
136
|
-
};
|
|
137
|
-
"pins.screenshot": {
|
|
138
|
-
reportId: string;
|
|
139
|
-
};
|
|
140
|
-
"pins.archive": {
|
|
141
|
-
reportId: string;
|
|
142
|
-
reason?: ArchiveReason;
|
|
143
|
-
};
|
|
144
|
-
"screenshot.chunk": ScreenshotChunkParams;
|
|
145
|
-
}
|
|
146
|
-
interface RpcResultMap {
|
|
147
|
-
"reports.submit": ReportResult;
|
|
148
|
-
"reports.list": ReportListResponse;
|
|
149
|
-
"config.get": IngestConfig;
|
|
150
|
-
"pins.list": {
|
|
151
|
-
pins: PinRecord[];
|
|
152
|
-
};
|
|
153
|
-
"pins.screenshot": {
|
|
154
|
-
screenshot: string | null;
|
|
155
|
-
};
|
|
156
|
-
"pins.archive": {
|
|
157
|
-
ok: true;
|
|
158
|
-
};
|
|
159
|
-
/** Acks a stored chunk; `received` is how many distinct parts have arrived. */
|
|
160
|
-
"screenshot.chunk": {
|
|
161
|
-
received: number;
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
type RpcRequestFrame = {
|
|
165
|
-
type: "rpc";
|
|
166
|
-
id: string;
|
|
167
|
-
method: RpcMethod;
|
|
168
|
-
params?: unknown;
|
|
169
|
-
};
|
|
170
|
-
type RpcOkFrame = {
|
|
171
|
-
type: "rpc:res";
|
|
172
|
-
id: string;
|
|
173
|
-
ok: true;
|
|
174
|
-
data: unknown;
|
|
175
|
-
};
|
|
176
|
-
type RpcErrFrame = {
|
|
177
|
-
type: "rpc:res";
|
|
178
|
-
id: string;
|
|
179
|
-
ok: false;
|
|
180
|
-
/** HTTP-equivalent status so CloudError semantics survive the transport. */
|
|
181
|
-
status: number;
|
|
182
|
-
error: string;
|
|
183
|
-
/** Seconds, present on 429 responses (mirrors the Retry-After header). */
|
|
184
|
-
retryAfter?: number;
|
|
185
|
-
details?: unknown;
|
|
186
|
-
};
|
|
187
|
-
type RpcResponseFrame = RpcOkFrame | RpcErrFrame;
|
|
188
|
-
/**
|
|
189
|
-
* Sent by the SDK after `realtime.connect(opts)` to attach a user identity to
|
|
190
|
-
* an initially anonymous connection. The server marks the connection visible
|
|
191
|
-
* in presence from this point on. Connections that never identify stay
|
|
192
|
-
* RPC-only: excluded from presence, no room auto-join.
|
|
193
|
-
*/
|
|
194
|
-
type IdentifyFrame = {
|
|
195
|
-
type: "identify";
|
|
196
|
-
userId: string;
|
|
197
|
-
name?: string;
|
|
198
|
-
avatar?: string;
|
|
199
|
-
};
|
|
200
|
-
/**
|
|
201
|
-
* Reverse of `IdentifyFrame`: sent when a realtime consumer disconnects
|
|
202
|
-
* (e.g. the uidex surface unmounts) while the adapter keeps using the socket
|
|
203
|
-
* for RPC. The server drops the connection from presence and its room but
|
|
204
|
-
* keeps the socket open.
|
|
205
|
-
*/
|
|
206
|
-
type LeaveFrame = {
|
|
207
|
-
type: "leave";
|
|
208
|
-
};
|
|
209
|
-
/**
|
|
210
|
-
* Server→client broadcast when a pin's report leaves the open statuses
|
|
211
|
-
* (closed via the SDK, the dashboard, or the REST route). Sent to the room of
|
|
212
|
-
* the report's route so live overlays drop the pin without a refresh.
|
|
213
|
-
*/
|
|
214
|
-
type PinArchivedFrame = {
|
|
215
|
-
type: "pin:archived";
|
|
216
|
-
reportId: string;
|
|
217
|
-
};
|
|
218
|
-
declare function isRpcMethod(value: unknown): value is RpcMethod;
|
|
219
|
-
/** Client-side guard for inbound `rpc:res` frames (server validates inbound `rpc` frames itself). */
|
|
220
|
-
declare function parseRpcResponseFrame(msg: unknown): RpcResponseFrame | null;
|
|
221
|
-
|
|
222
|
-
type RealtimeChannelOptions = {
|
|
223
|
-
/** Builds the WebSocket URL on each (re)connect attempt. Only needs the project key — identity and route ride dedicated frames. */
|
|
224
|
-
buildUrl: () => string;
|
|
225
|
-
/** Optional WebSocket constructor override (testing). Defaults to `globalThis.WebSocket`. */
|
|
226
|
-
WebSocketImpl?: typeof WebSocket;
|
|
227
|
-
};
|
|
228
|
-
/**
|
|
229
|
-
* Superset of the public `RealtimeChannel` used internally by the cloud
|
|
230
|
-
* adapter: the RPC client (`./rpc`) shares the same socket and needs raw
|
|
231
|
-
* frame access plus open/close notifications.
|
|
232
|
-
*/
|
|
233
|
-
interface InternalRealtimeChannel extends RealtimeChannel {
|
|
234
|
-
/** Required here (optional on the public interface only for channel stubs). */
|
|
235
|
-
onPinArchived(cb: (reportId: string) => void): () => void;
|
|
236
|
-
/** Stores the identity and (re)sends the `identify` frame on every open. */
|
|
237
|
-
identify(user: UserIdentity): void;
|
|
238
|
-
/** Drops the stored identity/route without touching the socket (soft leave). */
|
|
239
|
-
clearSession(): void;
|
|
240
|
-
/** Sends a JSON frame if the socket is OPEN. Returns false otherwise. */
|
|
241
|
-
sendFrame(frame: object): boolean;
|
|
242
|
-
/** Fires after the channel finished its identify/join replay on (re)open. */
|
|
243
|
-
onOpen(cb: () => void): () => void;
|
|
244
|
-
/**
|
|
245
|
-
* Fires with the close code (or `CLOSE_CODE_SYNTHETIC`) whenever the socket
|
|
246
|
-
* goes away. `willReconnect` is false for terminal closes (`disconnect()`,
|
|
247
|
-
* auth failure, no WebSocket implementation): queued work must reject
|
|
248
|
-
* instead of riding a reconnect that will never come.
|
|
249
|
-
*/
|
|
250
|
-
onClose(cb: (code: number, willReconnect: boolean) => void): () => void;
|
|
251
|
-
onRpcResponse(cb: (frame: RpcResponseFrame) => void): () => void;
|
|
252
|
-
}
|
|
253
|
-
declare function createRealtimeChannel(options: RealtimeChannelOptions): InternalRealtimeChannel;
|
|
254
|
-
|
|
255
|
-
declare const DEFAULT_RPC_TIMEOUT_MS = 30000;
|
|
256
|
-
interface RpcClient {
|
|
257
|
-
call<M extends RpcMethod>(method: M, params: RpcParamsMap[M], opts?: {
|
|
258
|
-
timeoutMs?: number;
|
|
259
|
-
}): Promise<RpcResultMap[M]>;
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* Request/response RPC over the realtime channel's socket. Requests made
|
|
263
|
-
* while the socket is closed are queued and flushed on (re)open — after the
|
|
264
|
-
* channel's identify/join replay, because the channel emits `onOpen` last.
|
|
265
|
-
*/
|
|
266
|
-
declare function createRpcClient(channel: InternalRealtimeChannel, options?: {
|
|
267
|
-
timeoutMs?: number;
|
|
268
|
-
}): RpcClient;
|
|
269
|
-
|
|
270
|
-
export { type CloudAdapter, CloudError, type CloudOptions, DEFAULT_CLOUD_ENDPOINT, DEFAULT_RPC_TIMEOUT_MS, type IdentifyFrame, type InternalRealtimeChannel, type LeaveFrame, type PinArchivedFrame, RPC_METHODS, type RealtimeChannel, type RealtimeChannelState, type RealtimeConnectOpts, type RealtimePresenceUser, type ReportSubmitParams, type RpcClient, type RpcErrFrame, type RpcMethod, type RpcOkFrame, type RpcParamsMap, type RpcRequestFrame, type RpcResponseFrame, type RpcResultMap, SCREENSHOT_CHUNK_BYTES, SCREENSHOT_INLINE_MAX_BYTES, type ScreenshotChunkParams, cloud, createRealtimeChannel, createRpcClient, isRpcMethod, parseRpcResponseFrame };
|