@qontinui/ui-bridge 0.9.1 → 0.10.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.
@@ -1616,6 +1616,29 @@ interface UseCommandRelayOptions {
1616
1616
  * build-time defaults baked into a static config).
1617
1617
  */
1618
1618
  version?: string;
1619
+ /**
1620
+ * Optional hook that returns the current session token (the raw token
1621
+ * value, WITHOUT a `Bearer ` prefix). When supplied and returns a
1622
+ * non-empty string, the SDK:
1623
+ *
1624
+ * - attaches `Authorization: Bearer <value>` to outbound
1625
+ * `POST {basePath}/commands` and `POST {basePath}/heartbeat`;
1626
+ * - appends a `_auth=<value>` query parameter to the SSE URL
1627
+ * `GET {basePath}/commands/stream` (EventSource cannot set custom
1628
+ * headers per the WhatWG spec).
1629
+ *
1630
+ * Called fresh on every outbound request — implementations should read
1631
+ * the token from a live source (e.g. `sessionStorage`) so a token
1632
+ * rotation is picked up without remounting the listener. Returning
1633
+ * `null` / `undefined` / empty string means "no auth this call" and
1634
+ * the transport falls back to legacy unauth'd / cookie-based behavior
1635
+ * (matching the SDK's pre-`authHeader` shape).
1636
+ *
1637
+ * Required to authenticate against any relay endpoint that enforces a
1638
+ * session-bound auth gate (e.g. qontinui-web's
1639
+ * `UI_BRIDGE_REQUIRE_AUTH=1` mode).
1640
+ */
1641
+ authHeader?: () => string | null | undefined;
1619
1642
  }
1620
1643
  /**
1621
1644
  * Hook that connects the browser to the server's command relay.
@@ -1660,6 +1683,14 @@ interface CommandRelayListenerProps {
1660
1683
  * defaults baked into the static config.
1661
1684
  */
1662
1685
  version?: string;
1686
+ /**
1687
+ * Optional hook returning the current session token (raw value, no
1688
+ * `Bearer ` prefix). When supplied, the SDK attaches
1689
+ * `Authorization: Bearer <value>` to outbound `POST /commands` and
1690
+ * `POST /heartbeat` and appends `_auth=<value>` to the SSE URL.
1691
+ * See `UseCommandRelayOptions.authHeader` for the full contract.
1692
+ */
1693
+ authHeader?: () => string | null | undefined;
1663
1694
  }
1664
1695
  declare function CommandRelayListener(props: CommandRelayListenerProps): null;
1665
1696
 
@@ -1616,6 +1616,29 @@ interface UseCommandRelayOptions {
1616
1616
  * build-time defaults baked into a static config).
1617
1617
  */
1618
1618
  version?: string;
1619
+ /**
1620
+ * Optional hook that returns the current session token (the raw token
1621
+ * value, WITHOUT a `Bearer ` prefix). When supplied and returns a
1622
+ * non-empty string, the SDK:
1623
+ *
1624
+ * - attaches `Authorization: Bearer <value>` to outbound
1625
+ * `POST {basePath}/commands` and `POST {basePath}/heartbeat`;
1626
+ * - appends a `_auth=<value>` query parameter to the SSE URL
1627
+ * `GET {basePath}/commands/stream` (EventSource cannot set custom
1628
+ * headers per the WhatWG spec).
1629
+ *
1630
+ * Called fresh on every outbound request — implementations should read
1631
+ * the token from a live source (e.g. `sessionStorage`) so a token
1632
+ * rotation is picked up without remounting the listener. Returning
1633
+ * `null` / `undefined` / empty string means "no auth this call" and
1634
+ * the transport falls back to legacy unauth'd / cookie-based behavior
1635
+ * (matching the SDK's pre-`authHeader` shape).
1636
+ *
1637
+ * Required to authenticate against any relay endpoint that enforces a
1638
+ * session-bound auth gate (e.g. qontinui-web's
1639
+ * `UI_BRIDGE_REQUIRE_AUTH=1` mode).
1640
+ */
1641
+ authHeader?: () => string | null | undefined;
1619
1642
  }
1620
1643
  /**
1621
1644
  * Hook that connects the browser to the server's command relay.
@@ -1660,6 +1683,14 @@ interface CommandRelayListenerProps {
1660
1683
  * defaults baked into the static config.
1661
1684
  */
1662
1685
  version?: string;
1686
+ /**
1687
+ * Optional hook returning the current session token (raw value, no
1688
+ * `Bearer ` prefix). When supplied, the SDK attaches
1689
+ * `Authorization: Bearer <value>` to outbound `POST /commands` and
1690
+ * `POST /heartbeat` and appends `_auth=<value>` to the SSE URL.
1691
+ * See `UseCommandRelayOptions.authHeader` for the full contract.
1692
+ */
1693
+ authHeader?: () => string | null | undefined;
1663
1694
  }
1664
1695
  declare function CommandRelayListener(props: CommandRelayListenerProps): null;
1665
1696
 
@@ -24948,7 +24948,7 @@ function exposeProviderOnWindow(internals) {
24948
24948
  if (typeof window === "undefined") return;
24949
24949
  const w = window;
24950
24950
  const root = w.__UI_BRIDGE__ ?? (w.__UI_BRIDGE__ = {});
24951
- root.version = "0.9.1";
24951
+ root.version = "0.10.0";
24952
24952
  root.specs = { getGlobalSpecStore };
24953
24953
  root.registry = internals.registry;
24954
24954
  root.browserCapture = internals.browserCapture;
@@ -32911,10 +32911,39 @@ function safeJsonStringify(value) {
32911
32911
  });
32912
32912
  }
32913
32913
  var HEARTBEAT_INTERVAL_MS = 1e4;
32914
+ function resolveAuthToken(authHeader) {
32915
+ if (!authHeader) return null;
32916
+ try {
32917
+ const value = authHeader();
32918
+ if (typeof value !== "string") return null;
32919
+ const trimmed = value.trim();
32920
+ return trimmed.length > 0 ? trimmed : null;
32921
+ } catch {
32922
+ return null;
32923
+ }
32924
+ }
32925
+ function transportHeaders(authHeader) {
32926
+ const headers = {
32927
+ "Content-Type": "application/json"
32928
+ };
32929
+ const token = resolveAuthToken(authHeader);
32930
+ if (token) {
32931
+ headers.Authorization = `Bearer ${token}`;
32932
+ }
32933
+ return headers;
32934
+ }
32935
+ function appendAuthQuery(url, authHeader) {
32936
+ const token = resolveAuthToken(authHeader);
32937
+ if (!token) return url;
32938
+ const sep = url.includes("?") ? "&" : "?";
32939
+ return `${url}${sep}_auth=${encodeURIComponent(token)}`;
32940
+ }
32914
32941
  function useCommandRelay(options) {
32915
32942
  const enabled = options?.enabled ?? true;
32916
32943
  const basePath = options?.basePath ?? "/api/ui-bridge";
32917
32944
  const heartbeatIntervalMs = options?.heartbeatInterval ?? HEARTBEAT_INTERVAL_MS;
32945
+ const authHeaderRef = react.useRef(void 0);
32946
+ authHeaderRef.current = options?.authHeader;
32918
32947
  const uiBridge = useUIBridge();
32919
32948
  const context = useUIBridgeOptional();
32920
32949
  const bridge2 = react.useMemo(
@@ -32970,7 +32999,7 @@ function useCommandRelay(options) {
32970
32999
  try {
32971
33000
  await fetch(`${basePath}/commands`, {
32972
33001
  method: "POST",
32973
- headers: { "Content-Type": "application/json" },
33002
+ headers: transportHeaders(authHeaderRef.current),
32974
33003
  body: safeJsonStringify({
32975
33004
  commandId,
32976
33005
  success: ok,
@@ -33036,9 +33065,8 @@ function useCommandRelay(options) {
33036
33065
  let isMounted = true;
33037
33066
  const connect = () => {
33038
33067
  if (!isMounted) return;
33039
- const es = new EventSource(
33040
- `${basePath}/commands/stream${tabId ? `?tabId=${encodeURIComponent(tabId)}` : ""}`
33041
- );
33068
+ const baseUrl = `${basePath}/commands/stream${tabId ? `?tabId=${encodeURIComponent(tabId)}` : ""}`;
33069
+ const es = new EventSource(appendAuthQuery(baseUrl, authHeaderRef.current));
33042
33070
  eventSourceRef.current = es;
33043
33071
  es.onmessage = (event) => {
33044
33072
  try {
@@ -33125,7 +33153,7 @@ function useCommandRelay(options) {
33125
33153
  if (heartbeatVersion !== void 0) body.version = heartbeatVersion;
33126
33154
  const resp = await fetch(`${basePath}/heartbeat`, {
33127
33155
  method: "POST",
33128
- headers: { "Content-Type": "application/json" },
33156
+ headers: transportHeaders(authHeaderRef.current),
33129
33157
  body: JSON.stringify(body)
33130
33158
  });
33131
33159
  if (resp.ok) {
@@ -33256,7 +33284,8 @@ function CommandRelayListener(props) {
33256
33284
  appType: props.appType,
33257
33285
  framework: props.framework,
33258
33286
  capabilities: props.capabilities,
33259
- version: props.version
33287
+ version: props.version,
33288
+ authHeader: props.authHeader
33260
33289
  };
33261
33290
  useCommandRelay(options);
33262
33291
  return null;