uidex 0.4.0 → 0.5.1

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 (42) hide show
  1. package/dist/cli/cli.cjs +1111 -87
  2. package/dist/cli/cli.cjs.map +1 -1
  3. package/dist/cloud/index.cjs +375 -72
  4. package/dist/cloud/index.cjs.map +1 -1
  5. package/dist/cloud/index.d.cts +82 -0
  6. package/dist/cloud/index.d.ts +82 -0
  7. package/dist/cloud/index.js +376 -71
  8. package/dist/cloud/index.js.map +1 -1
  9. package/dist/headless/index.cjs +623 -469
  10. package/dist/headless/index.cjs.map +1 -1
  11. package/dist/headless/index.d.cts +77 -75
  12. package/dist/headless/index.d.ts +77 -75
  13. package/dist/headless/index.js +627 -469
  14. package/dist/headless/index.js.map +1 -1
  15. package/dist/index.cjs +4258 -2884
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +275 -234
  18. package/dist/index.d.ts +275 -234
  19. package/dist/index.js +4280 -2890
  20. package/dist/index.js.map +1 -1
  21. package/dist/playwright/index.cjs +4 -4
  22. package/dist/playwright/index.cjs.map +1 -1
  23. package/dist/playwright/index.js +3 -3
  24. package/dist/playwright/index.js.map +1 -1
  25. package/dist/playwright/reporter.cjs +3 -3
  26. package/dist/playwright/reporter.cjs.map +1 -1
  27. package/dist/playwright/reporter.js +3 -3
  28. package/dist/playwright/reporter.js.map +1 -1
  29. package/dist/react/index.cjs +4299 -2906
  30. package/dist/react/index.cjs.map +1 -1
  31. package/dist/react/index.d.cts +206 -200
  32. package/dist/react/index.d.ts +206 -200
  33. package/dist/react/index.js +4339 -2926
  34. package/dist/react/index.js.map +1 -1
  35. package/dist/scan/index.cjs +201 -49
  36. package/dist/scan/index.cjs.map +1 -1
  37. package/dist/scan/index.d.cts +27 -1
  38. package/dist/scan/index.d.ts +27 -1
  39. package/dist/scan/index.js +200 -48
  40. package/dist/scan/index.js.map +1 -1
  41. package/package.json +8 -14
  42. package/templates/claude/api.md +110 -0
@@ -1,6 +1,8 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode, ComponentType, ReactElement } from 'react';
3
3
  import { StoreApi } from 'zustand/vanilla';
4
+ import { ReportPayload, ReportResult, IngestConfig, ReportListResponse, PinRecord, ArchiveReason } from '@uidex/api-client';
5
+ import { TemplateResult } from 'lit-html';
4
6
 
5
7
  declare const ENTITY_KINDS: readonly ["route", "page", "feature", "widget", "region", "element", "primitive", "flow"];
6
8
  type EntityKind = (typeof ENTITY_KINDS)[number];
@@ -69,6 +71,26 @@ type EntityByKind<K extends EntityKind> = Extract<Entity, {
69
71
  kind: K;
70
72
  }>;
71
73
 
74
+ interface ReportRecord {
75
+ id: string;
76
+ entity?: string;
77
+ reporter?: {
78
+ id?: string;
79
+ email?: string;
80
+ name?: string;
81
+ };
82
+ title?: string;
83
+ body: string;
84
+ type: string;
85
+ severity: string;
86
+ status: string;
87
+ labels?: string[];
88
+ url: string;
89
+ route?: string;
90
+ pageTitle?: string;
91
+ screenshot?: string;
92
+ createdAt: string;
93
+ }
72
94
  interface Registry {
73
95
  add(entity: Entity): void;
74
96
  get<K extends EntityKind>(kind: K, id: string): EntityByKind<K> | undefined;
@@ -76,6 +98,17 @@ interface Registry {
76
98
  query(predicate: (entity: Entity) => boolean): Entity[];
77
99
  byScope(scope: Scope): Entity[];
78
100
  touchedBy(flowId: string): Entity[];
101
+ setReports(kind: EntityKind, id: string, reports: readonly ReportRecord[]): void;
102
+ getReports(kind: EntityKind, id: string): readonly ReportRecord[];
103
+ listReportKeys(): readonly string[];
104
+ archiveReport?: (reportId: string, reason?: string) => void | Promise<void>;
105
+ onReportsChange(cb: () => void): () => void;
106
+ }
107
+
108
+ interface UserIdentity {
109
+ id: string;
110
+ name?: string;
111
+ avatar?: string;
79
112
  }
80
113
 
81
114
  type ThemePreference = "light" | "dark" | "auto";
@@ -94,89 +127,60 @@ interface SessionSnapshot {
94
127
  theme: ThemePreference;
95
128
  resolvedTheme: ResolvedTheme;
96
129
  ingestActive: boolean;
97
- }
98
- interface SessionActions {
99
- hover(ref: EntityRef | null): void;
100
- select(ref: EntityRef | null): void;
101
- /**
102
- * Append a view onto the view stack. Pure: never resolves defaults.
103
- */
104
- pushStack(entry: ViewStackEntry): void;
105
- /**
106
- * Remove the top entry from the view stack. No-op when the stack is empty.
107
- */
108
- popStack(): void;
109
130
  /**
110
- * Empty the view stack.
131
+ * Identity for the local user. Set once at session creation; gates realtime
132
+ * features (cursor labels, presence) and auto-populates report attribution.
111
133
  */
112
- clearStack(): void;
113
- /**
114
- * Open a view by id. If `ref` is omitted, the current `selection` is captured;
115
- * pass `null` explicitly to open the view with no ref context. Thin wrapper
116
- * around `pushStack`.
117
- */
118
- openView(id: string, ref?: EntityRef | null): void;
119
- /**
120
- * Clear the entire view stack. Thin wrapper around `clearStack`.
121
- */
122
- closeView(): void;
123
- setInspectorActive(active: boolean): void;
124
- toggleInspector(): void;
125
- /** Pin the overlay to `ref` until `clearPinnedHighlight` is called. */
126
- pinHighlight(ref: EntityRef): void;
127
- clearPinnedHighlight(): void;
128
- setTheme(theme: ThemePreference, resolved?: ResolvedTheme): void;
129
- setIngest(active: boolean): void;
134
+ user: UserIdentity | null;
135
+ }
136
+ type SessionState = SessionSnapshot;
137
+
138
+ interface NavigationState {
139
+ stack: ViewStackEntry[];
130
140
  }
131
- interface SessionState extends SessionSnapshot {
132
- actions: SessionActions;
141
+ interface NavigationActions {
142
+ push(entry: ViewStackEntry): void;
143
+ pop(): void;
144
+ replace(entry: ViewStackEntry): void;
145
+ clear(): void;
146
+ reset(stack: ViewStackEntry[]): void;
133
147
  }
148
+ type NavigationStore = StoreApi<NavigationState> & {
149
+ nav: NavigationActions;
150
+ };
134
151
 
135
- type SurfaceEvent = {
136
- type: "TOGGLE_INSPECTOR";
137
- } | {
138
- type: "OPEN_PALETTE";
139
- } | {
140
- type: "PUSH_VIEW";
141
- entry: ViewStackEntry;
142
- } | {
143
- type: "POP_VIEW";
144
- } | {
145
- type: "CLOSE";
146
- } | {
147
- type: "ESC";
148
- } | {
149
- type: "CMD_K";
150
- } | {
151
- type: "SELECT";
152
- ref: EntityRef | null;
153
- entry: ViewStackEntry;
154
- } | {
155
- type: "SET_SELECTION";
156
- ref: EntityRef | null;
157
- } | {
158
- type: "HOVER";
159
- ref: EntityRef;
160
- element: HTMLElement | null;
161
- color?: string | null;
162
- } | {
163
- type: "UNHOVER";
164
- } | {
165
- type: "PIN";
166
- ref?: EntityRef;
167
- } | {
168
- type: "UNPIN";
169
- } | {
170
- type: "SET_THEME";
171
- theme: ThemePreference;
172
- resolvedTheme: ResolvedTheme;
173
- } | {
174
- type: "SET_INGEST";
175
- active: boolean;
152
+ type SurfaceMode = "idle" | "inspecting" | "palette" | "viewing";
153
+ interface ModeSnapshot {
154
+ mode: SurfaceMode;
155
+ inspectorActive: boolean;
156
+ }
157
+ interface ModeTransitions {
158
+ openPalette(): void;
159
+ openInspector(): void;
160
+ closeInspector(): void;
161
+ toggleInspector(): void;
162
+ enterViewing(initialStack: ViewStackEntry[]): void;
163
+ dismiss(): void;
164
+ popOrTransition(): void;
165
+ pushView(entry: ViewStackEntry): void;
166
+ }
167
+ type ModeStore = StoreApi<ModeSnapshot> & {
168
+ transition: ModeTransitions;
176
169
  };
177
170
 
171
+ interface HighlightActions {
172
+ hover(ref: EntityRef, element?: HTMLElement | null, color?: string | null): void;
173
+ unhover(): void;
174
+ pin(ref?: EntityRef): void;
175
+ unpin(): void;
176
+ }
178
177
  type SessionStore = StoreApi<SessionState> & {
179
- send(event: SurfaceEvent): void;
178
+ readonly nav: NavigationStore;
179
+ readonly mode: ModeStore;
180
+ readonly highlight: HighlightActions;
181
+ select(ref: EntityRef | null): void;
182
+ setTheme(theme: ThemePreference, resolved?: ResolvedTheme): void;
183
+ setIngest(active: boolean): void;
180
184
  };
181
185
 
182
186
  type ConsoleLevel = "warn" | "error";
@@ -220,99 +224,46 @@ interface NetworkCapture {
220
224
  clear(): void;
221
225
  }
222
226
 
223
- interface ConsoleLogEntry {
224
- level: "log" | "warn" | "error" | "info";
225
- message: string;
226
- timestamp: string;
227
- }
228
- interface NetworkErrorEntry {
229
- url: string;
230
- method: string;
231
- status: number | null;
232
- statusText: string | null;
233
- timestamp: string;
234
- }
235
- interface Viewport {
236
- width: number;
237
- height: number;
238
- }
239
- interface SourceRef {
240
- filePath: string;
241
- line: number;
242
- }
243
- interface FeedbackSuggestedTarget {
244
- integrationId: string;
245
- targetConfig: Record<string, unknown>;
246
- }
247
- interface FeedbackPayload {
248
- type: "bug" | "feature" | "improvement" | "question";
249
- severity: "low" | "medium" | "high" | "critical";
250
- title?: string;
251
- description: string;
252
- componentId: string;
253
- element?: string | null;
254
- sources?: SourceRef[];
255
- url: string;
256
- path: string;
257
- route?: string | null;
258
- pageTitle?: string;
259
- sessionId?: string;
260
- reporterEmail?: string;
261
- reporterName?: string;
262
- timestamp: string;
263
- viewport: Viewport;
264
- screen: Viewport;
265
- userAgent: string;
266
- locale?: string;
267
- environment?: string;
268
- appVersion?: string;
269
- consoleLogs?: ConsoleLogEntry[];
270
- networkErrors?: NetworkErrorEntry[];
271
- metadata?: Record<string, string>;
272
- screenshot?: string;
273
- suggestedTarget?: FeedbackSuggestedTarget;
274
- }
275
- interface FeedbackExternalLink {
276
- ok: boolean;
277
- url?: string;
278
- key?: string;
279
- error?: string;
280
- }
281
- interface FeedbackResult {
282
- id: string;
283
- sequenceNumber: number;
284
- externalLink?: FeedbackExternalLink;
285
- }
286
- interface IngestConfigIssue {
287
- id: string;
288
- key: string;
289
- summary: string;
290
- issueType: string;
291
- }
292
- interface IngestConfig {
293
- hasJira: boolean;
294
- integrationId?: string;
295
- parentIssues?: IngestConfigIssue[];
296
- }
297
- /**
298
- * Generic so third-party adapters (e.g. `uidex-cloud`) can plug in their own
299
- * payload/result/integration shapes. SDK-bundled `cloud()` returns the
300
- * defaulted form. `ViewContext.cloud` uses the fully-open variant; consumers
301
- * that need the SDK shape narrow with `as CloudAdapter`.
302
- */
303
- interface CloudAdapter<TPayload = FeedbackPayload, TResult = FeedbackResult, TIntegrations = {
227
+ type RealtimePresenceUser = {
228
+ userId: string;
229
+ name: string;
230
+ avatar: string | null;
231
+ };
232
+ type RealtimeChannelState = "connecting" | "connected" | "disconnected";
233
+ interface RealtimeConnectOpts {
234
+ user: UserIdentity;
235
+ route: string;
236
+ }
237
+ interface RealtimeChannel {
238
+ readonly state: RealtimeChannelState;
239
+ connect(): void;
240
+ disconnect(): void;
241
+ joinRoute(route: string): void;
242
+ onPresence(cb: (users: RealtimePresenceUser[]) => void): () => void;
243
+ onPin(cb: (pin: PinRecord) => void): () => void;
244
+ }
245
+ interface CloudAdapter<TPayload = ReportPayload, TResult = ReportResult, TIntegrations = {
304
246
  getConfig(): Promise<IngestConfig>;
305
- /**
306
- * Synchronous read of the eagerly-fetched config. Returns `null` until the
307
- * initial fetch resolves; views that need a sync answer (e.g. detail
308
- * actions deciding whether to surface a Jira button) read this.
309
- */
310
247
  getCachedConfig(): IngestConfig | null;
311
248
  }> {
312
- readonly feedback: {
249
+ readonly reports: {
313
250
  submit(payload: TPayload): Promise<TResult>;
251
+ list?(opts?: {
252
+ page?: number;
253
+ limit?: number;
254
+ }): Promise<ReportListResponse>;
314
255
  };
315
256
  readonly integrations: TIntegrations;
257
+ readonly realtime: {
258
+ connect(opts: RealtimeConnectOpts): RealtimeChannel;
259
+ };
260
+ readonly pins: {
261
+ list(params: {
262
+ route?: string;
263
+ entities?: string;
264
+ }): Promise<PinRecord[]>;
265
+ archive(reportId: string, reason?: ArchiveReason): Promise<void>;
266
+ };
316
267
  }
317
268
 
318
269
  interface IngestOptions {
@@ -344,7 +295,25 @@ interface OverlayShowOptions {
344
295
 
345
296
  type Corner = "top-left" | "top-right" | "bottom-left" | "bottom-right";
346
297
 
347
- type ViewSurface = ListSurface | DetailSurface | FormSurface | CustomSurface;
298
+ interface RouteMatch {
299
+ view: View;
300
+ priority: number;
301
+ }
302
+ interface Router {
303
+ resolve(ref: EntityRef): RouteMatch | null;
304
+ add(view: View, priority?: number): void;
305
+ remove(id: string): void;
306
+ get(id: string): View | undefined;
307
+ list(): readonly View[];
308
+ buildStack(entry: ViewStackEntry): ViewStackEntry[];
309
+ navigate(ref: EntityRef): void;
310
+ recents(): readonly EntityRef[];
311
+ favorites(): readonly EntityRef[];
312
+ toggleFavorite(ref: EntityRef): void;
313
+ isFavorite(ref: EntityRef): boolean;
314
+ }
315
+
316
+ type ViewSurface = ListSurface | DetailSurface | FormSurface;
348
317
  interface ListSurface {
349
318
  kind: "list";
350
319
  id: string;
@@ -353,6 +322,12 @@ interface ListSurface {
353
322
  emptyLabel?: string;
354
323
  defaultHighlight?: string;
355
324
  filter?(item: ListItem, query: string): boolean;
325
+ /**
326
+ * When false, the search input is hidden and the content element receives
327
+ * focus directly for keyboard navigation.
328
+ * @default true
329
+ */
330
+ searchable?: boolean;
356
331
  }
357
332
  interface ListItem {
358
333
  value: string;
@@ -372,12 +347,13 @@ interface ListItem {
372
347
  };
373
348
  /**
374
349
  * Optional leading-icon factory used for non-entity rows (e.g. a palette
375
- * "Feedback" command). Called per-render so the returned Node is fresh.
350
+ * "Report" command). Called per-render so the returned Node is fresh.
376
351
  * The shell wraps whatever is returned in a rounded-square tile.
377
352
  */
378
353
  leading?: () => Node;
379
354
  /** Raw data attribute tag appended to the row (for test/e2e hooks). */
380
355
  tag?: string;
356
+ trailing?: TemplateResult;
381
357
  /** Contextual actions surfaced in the footer popup when this row is highlighted. */
382
358
  actions?: readonly ShellAction[];
383
359
  }
@@ -403,6 +379,7 @@ interface DetailActionBase {
403
379
  ariaLabel?: string;
404
380
  hint?: string;
405
381
  intent?: ShellActionIntent;
382
+ group?: string;
406
383
  }
407
384
  type DetailAction = (DetailActionBase & {
408
385
  copy: string;
@@ -420,7 +397,7 @@ type DetailAction = (DetailActionBase & {
420
397
  }) | (DetailActionBase & {
421
398
  run: (ctx: DetailActionRunContext) => void | Promise<void>;
422
399
  });
423
- type DetailActionIcon = "copy" | "camera" | "message-circle-warning" | "chevron-down" | "highlighter" | "ticket-plus" | "view";
400
+ type DetailActionIcon = "archive-x" | "copy" | "camera" | "inbox" | "message-circle-warning" | "chevron-down" | "highlighter" | "sticky-note" | "ticket-plus" | "view";
424
401
  interface DetailActionRunContext {
425
402
  setLabel(next: string, durationMs?: number): void;
426
403
  }
@@ -461,7 +438,17 @@ type DetailSection = {
461
438
  id: "routes";
462
439
  paths: readonly string[];
463
440
  filterable?: boolean;
441
+ } | {
442
+ id: "screenshot";
443
+ url: string;
444
+ } | {
445
+ id: "metadata";
446
+ entries: readonly MetadataEntry[];
464
447
  };
448
+ interface MetadataEntry {
449
+ label: string;
450
+ value: string;
451
+ }
465
452
  interface FormSurface {
466
453
  kind: "form";
467
454
  id: string;
@@ -558,10 +545,6 @@ type FormField = (FormFieldBase & {
558
545
  kind: "checkbox";
559
546
  value?: boolean;
560
547
  });
561
- interface CustomSurface {
562
- kind: "custom";
563
- render: (ctx: ViewContext, root: HTMLElement) => Cleanup | void;
564
- }
565
548
 
566
549
  interface ViewPalette {
567
550
  label: string;
@@ -572,11 +555,7 @@ interface ViewPalette {
572
555
  */
573
556
  icon?: () => Node;
574
557
  shortcut?: string;
575
- }
576
- interface ViewDirectory {
577
- list(): readonly View[];
578
- recents(): readonly EntityRef[];
579
- favorites(): readonly EntityRef[];
558
+ subtitle?: string | (() => string);
580
559
  }
581
560
  interface ViewPushTarget {
582
561
  id: string;
@@ -590,28 +569,32 @@ interface ViewContext {
590
569
  ref: EntityRef | null;
591
570
  registry: Registry;
592
571
  cloud: CloudAdapter<unknown, unknown, unknown> | null;
593
- sdkCloud: CloudAdapter;
594
- views: ViewDirectory;
572
+ /**
573
+ * Local user identity from `createUidex`'s `user` option, or `null` when
574
+ * unconfigured. Views that auto-populate attribution (e.g. report
575
+ * `reporterName`) read this here instead of touching the session store.
576
+ */
577
+ user: UserIdentity | null;
578
+ views: Router;
595
579
  /** Push a view onto the stack. Unregistered ids are a no-op. */
596
580
  push: (target: ViewPushTarget) => void;
597
581
  /** Pop the top view off the stack. No-op when the stack is empty. */
598
582
  pop: () => void;
599
583
  /** Clear the entire view stack. */
600
584
  close: () => void;
601
- /** Resolve the first view matching `ref` and push it onto the stack. */
602
- navigate: (ref: EntityRef) => void;
603
585
  /** Pin the overlay to `ref` until the user presses Esc. */
604
586
  pinHighlight: (ref: EntityRef) => void;
605
- /** Toggle favorite status for an entity ref. */
606
- toggleFavorite: (ref: EntityRef) => void;
607
- /** Check if an entity ref is favorited. */
608
- isFavorite: (ref: EntityRef) => boolean;
609
587
  /** Shell-owned search input. The shell dispatches its value into the active surface. */
610
588
  searchInput: HTMLInputElement;
611
589
  /** Drives the Surface's singleton overlay from inside a custom surface. */
612
590
  highlight: HighlightController;
613
591
  /** Snapshot of the current view stack (top-most last). */
614
592
  getStack: () => readonly ViewStackEntry[];
593
+ pushEscapeLayer(handler: EscapeHandler): Cleanup;
594
+ /** Called after a report submission succeeds, to refresh pins etc. */
595
+ onAfterSubmit?: () => void;
596
+ /** Return the current route pattern. Falls back to `location.pathname`. */
597
+ getRoute?: () => string;
615
598
  }
616
599
  interface ShellHint {
617
600
  key: string;
@@ -657,6 +640,9 @@ interface View {
657
640
  */
658
641
  focusTarget?: (root: HTMLElement, ctx: ViewContext) => HTMLElement | null;
659
642
  surface: (ctx: ViewContext) => ViewSurface;
643
+ /** Direct render for integration adapters (React, etc.). Mutually exclusive with surface renderers. */
644
+ render?: (ctx: ViewContext, root: HTMLElement) => Cleanup | void;
645
+ parent?: (ref: EntityRef | null) => ViewStackEntry | null;
660
646
  }
661
647
 
662
648
  interface PaletteShortcut {
@@ -667,19 +653,7 @@ interface PaletteShortcut {
667
653
  /** Require Shift. Default: false. */
668
654
  shift?: boolean;
669
655
  }
670
-
671
- interface ViewRegistrar {
672
- register(view: View): void;
673
- unregister(id: string): void;
674
- list(): readonly View[];
675
- get(id: string): View | undefined;
676
- findMatch(ref: EntityRef): View | null;
677
- navigate(ref: EntityRef): void;
678
- recents(): readonly EntityRef[];
679
- favorites(): readonly EntityRef[];
680
- toggleFavorite(ref: EntityRef): void;
681
- isFavorite(ref: EntityRef): boolean;
682
- }
656
+ type EscapeHandler = () => boolean;
683
657
 
684
658
  interface CreateUidexOptions {
685
659
  theme?: ThemePreference;
@@ -702,13 +676,31 @@ interface CreateUidexOptions {
702
676
  ingest?: IngestOptions | null;
703
677
  /** Keyboard shortcut for the command palette. Defaults to Cmd+K / Ctrl+K. */
704
678
  shortcut?: PaletteShortcut;
679
+ /**
680
+ * Identity for the local user. Required to opt into realtime collaborative
681
+ * features (peer cursors, presence). When omitted, realtime stays
682
+ * disconnected and report attribution falls back to whatever the user
683
+ * types in the report form.
684
+ */
685
+ user?: UserIdentity;
686
+ /** Git context for pin filtering. Typically mirrors `cloud({ git })`. */
687
+ git?: {
688
+ branch?: string;
689
+ commit?: string;
690
+ };
691
+ /**
692
+ * Return the current route pattern (e.g. `/users/:id`). Used for
693
+ * route-based pin matching and report attribution. When omitted, the SDK
694
+ * falls back to `location.pathname`.
695
+ */
696
+ getRoute?: () => string;
705
697
  }
706
698
  interface Uidex {
707
699
  mount(target?: Element): void;
708
700
  unmount(): void;
709
701
  readonly registry: Registry;
710
702
  readonly session: SessionStore;
711
- readonly views: ViewRegistrar;
703
+ readonly views: Router;
712
704
  readonly cloud: CloudAdapter | null;
713
705
  readonly ingest: Ingest | null;
714
706
  readonly shadowRoot: ShadowRoot | null;
@@ -717,15 +709,16 @@ interface Uidex {
717
709
  interface UidexProviderProps {
718
710
  /**
719
711
  * Pre-built uidex instance (e.g. the `uidex` export from `uidex.gen.ts`).
720
- * When provided, `projectKey`, `cloud`, and `config` are ignored.
712
+ * When provided, `projectKey`, `cloud`, `user`, and `config` are ignored.
721
713
  */
722
714
  instance?: Uidex;
723
715
  projectKey?: string;
724
716
  cloud?: CloudAdapter | null;
725
- config?: Omit<CreateUidexOptions, "cloud">;
717
+ user?: UserIdentity;
718
+ config?: Omit<CreateUidexOptions, "cloud" | "user">;
726
719
  children?: ReactNode;
727
720
  }
728
- declare function UidexProvider({ instance: externalInstance, projectKey, cloud, config, children, }: UidexProviderProps): react_jsx_runtime.JSX.Element;
721
+ declare function UidexProvider({ instance: externalInstance, projectKey, cloud, user, config, children, }: UidexProviderProps): react_jsx_runtime.JSX.Element;
729
722
 
730
723
  declare class UidexContextError extends Error {
731
724
  constructor(hookName: string);
@@ -755,4 +748,17 @@ interface KindChipProps {
755
748
  }
756
749
  declare function KindChip({ kind, label, withKindName, className, }: KindChipProps): ReactElement;
757
750
 
758
- export { KindChip, type KindChipProps, type ReactViewDef, UidexContextError, UidexMount, type UidexMountProps, UidexProvider, type UidexProviderProps, createReactView, useUidex };
751
+ interface UidexDevtoolsProps {
752
+ loadRegistry: (target: Registry) => Registry;
753
+ projectKey?: string;
754
+ endpoint?: string;
755
+ user?: UserIdentity;
756
+ git?: {
757
+ branch?: string;
758
+ commit?: string;
759
+ };
760
+ config?: Omit<CreateUidexOptions, "cloud" | "user" | "git">;
761
+ }
762
+ declare function UidexDevtools({ loadRegistry, projectKey, endpoint, user, git, config, }: UidexDevtoolsProps): react_jsx_runtime.JSX.Element | null;
763
+
764
+ export { KindChip, type KindChipProps, type ReactViewDef, UidexContextError, UidexDevtools, type UidexDevtoolsProps, UidexMount, type UidexMountProps, UidexProvider, type UidexProviderProps, createReactView, useUidex };