uidex 0.6.0 → 0.7.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.
Files changed (39) hide show
  1. package/README.md +3 -3
  2. package/dist/cli/cli.cjs +1510 -1244
  3. package/dist/cli/cli.cjs.map +1 -1
  4. package/dist/cloud/index.cjs +385 -175
  5. package/dist/cloud/index.cjs.map +1 -1
  6. package/dist/cloud/index.d.cts +192 -4
  7. package/dist/cloud/index.d.ts +192 -4
  8. package/dist/cloud/index.js +377 -177
  9. package/dist/cloud/index.js.map +1 -1
  10. package/dist/headless/index.cjs +82 -255
  11. package/dist/headless/index.cjs.map +1 -1
  12. package/dist/headless/index.d.cts +5 -11
  13. package/dist/headless/index.d.ts +5 -11
  14. package/dist/headless/index.js +82 -257
  15. package/dist/headless/index.js.map +1 -1
  16. package/dist/index.cjs +721 -1053
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +149 -160
  19. package/dist/index.d.ts +149 -160
  20. package/dist/index.js +741 -1068
  21. package/dist/index.js.map +1 -1
  22. package/dist/react/index.cjs +729 -1000
  23. package/dist/react/index.cjs.map +1 -1
  24. package/dist/react/index.d.cts +99 -86
  25. package/dist/react/index.d.ts +99 -86
  26. package/dist/react/index.js +745 -1015
  27. package/dist/react/index.js.map +1 -1
  28. package/dist/scan/index.cjs +1518 -1237
  29. package/dist/scan/index.cjs.map +1 -1
  30. package/dist/scan/index.d.cts +209 -12
  31. package/dist/scan/index.d.ts +209 -12
  32. package/dist/scan/index.js +1515 -1236
  33. package/dist/scan/index.js.map +1 -1
  34. package/package.json +22 -21
  35. package/templates/claude/SKILL.md +71 -0
  36. package/templates/claude/references/audit.md +43 -0
  37. package/templates/claude/{rules.md → references/conventions.md} +25 -28
  38. package/templates/claude/audit.md +0 -43
  39. /package/templates/claude/{api.md → references/api.md} +0 -0
@@ -11,7 +11,10 @@ declare const DEFAULT_CLOUD_ENDPOINT = "https://app.uidex.dev";
11
11
  interface CloudOptions {
12
12
  projectKey: string;
13
13
  endpoint?: string;
14
+ /** @deprecated Unused — the adapter talks RPC over WebSocket. Kept for API compatibility. */
14
15
  fetch?: typeof fetch;
16
+ /** Optional WebSocket constructor override (tests, Node). Defaults to `globalThis.WebSocket`. */
17
+ WebSocketImpl?: typeof WebSocket;
15
18
  git?: {
16
19
  branch?: string;
17
20
  commit?: string;
@@ -44,6 +47,8 @@ interface RealtimeChannel {
44
47
  joinRoute(route: string): void;
45
48
  onPresence(cb: (users: RealtimePresenceUser[]) => void): () => void;
46
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;
47
52
  }
48
53
  interface CloudAdapter<TPayload = ReportPayload, TResult = ReportResult, TIntegrations = {
49
54
  getConfig(): Promise<IngestConfig>;
@@ -65,18 +70,201 @@ interface CloudAdapter<TPayload = ReportPayload, TResult = ReportResult, TIntegr
65
70
  route?: string;
66
71
  entities?: string;
67
72
  }): Promise<PinRecord[]>;
68
- archive(reportId: string, reason?: ArchiveReason): Promise<void>;
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>;
69
81
  };
82
+ /** Closes the adapter's shared socket. Any later RPC call revives it. */
83
+ dispose?(): void;
70
84
  }
71
85
 
72
86
  declare function cloud(options: CloudOptions): CloudAdapter;
73
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
+
74
222
  type RealtimeChannelOptions = {
75
- /** Builds the WebSocket URL on each (re)connect attempt. Allows the caller to refresh `route` query params. */
223
+ /** Builds the WebSocket URL on each (re)connect attempt. Only needs the project key identity and route ride dedicated frames. */
76
224
  buildUrl: () => string;
77
225
  /** Optional WebSocket constructor override (testing). Defaults to `globalThis.WebSocket`. */
78
226
  WebSocketImpl?: typeof WebSocket;
79
227
  };
80
- declare function createRealtimeChannel(options: RealtimeChannelOptions): RealtimeChannel;
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;
81
269
 
82
- export { type CloudAdapter, CloudError, type CloudOptions, DEFAULT_CLOUD_ENDPOINT, type RealtimeChannel, type RealtimeChannelState, type RealtimeConnectOpts, type RealtimePresenceUser, cloud, createRealtimeChannel };
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 };