@sanity/sdk-react 3.4.0-next.20260921073349 → 3.4.0-next.20260921115438

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.
@@ -586,50 +586,69 @@ type TopicEmitter<K extends EventTopic$1> = (...args: PayloadOf$1<K> extends voi
586
586
  * @public
587
587
  */
588
588
  export declare function useEmit<K extends EventTopic$1>(topic: K): TopicEmitter<K>;
589
+ /**
590
+ * A navigation the Dashboard asks the app to perform, or that the app reports to the Dashboard.
591
+ * `path` is relative to the app's own route, with no leading slash (`'documents/abc'`), and may
592
+ * carry a query string and hash.
593
+ * @public
594
+ */
595
+ type DashboardNavigation = PathChangeMessage['data'];
596
+ /**
597
+ * Reports an in-app navigation to the Dashboard so the browser URL and the Dashboard's own
598
+ * router follow the app. `type` defaults to `'push'` and only applies in the federated runtime;
599
+ * see {@link useNavigate}.
600
+ * @public
601
+ */
602
+ type NavigateToDashboardPath = (options: {
603
+ path: string;
604
+ type?: 'push' | 'replace';
605
+ }) => void;
589
606
  /**
590
607
  * @public
591
608
  *
592
609
  * A helper hook designed to be injected into routing components for apps within the Dashboard.
593
- * While the Dashboard can usually handle navigation, there are special cases when you
594
- * are already within a target app, and need to navigate to another route inside of that app.
595
- *
596
- * For example, your user might "favorite" a document inside of your application.
597
- * If they click on the Dashboard favorites item in the sidebar, and are already within your application,
598
- * there needs to be some way for the dashboard to signal to your application to reroute to where that document was favorited.
599
- *
600
- * This hook is intended to receive those messages, and takes a function to route to the correct path.
610
+ * It keeps the app's router and the Dashboard in two-way sync: `navigateFn` receives the
611
+ * navigations the Dashboard asks the app to perform, and the returned function reports the app's
612
+ * own in-app navigations back to the Dashboard so the browser URL and the Dashboard's router
613
+ * follow along.
614
+ *
615
+ * A navigation the app reports is not echoed back through `navigateFn`. The returned function is
616
+ * referentially stable.
617
+ *
618
+ * The two Dashboard runtimes differ:
619
+ * - In an iframe (Comlink), inbound `type` may be `'push'`, `'replace'` or `'pop'`. Reporting is
620
+ * optional because the bridge already forwards the iframe's own `pushState`; a reported `type`
621
+ * is ignored and the host applies the URL as a `replace`.
622
+ * - In a federated app (message bus), inbound `type` is `'push'` or `'replace'`; `'pop'` is never
623
+ * sent. Reporting is required because the app's router does not reach the host, and `type` is
624
+ * honoured. Until the Dashboard publishes the app's base path, reports are dropped with a
625
+ * console warning.
601
626
  *
602
627
  * @param navigateFn - Function to handle navigation; should accept:
603
628
  * - `path`: a string, which will be a relative path (for example, 'my-route')
604
629
  * - `type`: 'push', 'replace', or 'pop', which will be the type of navigation to perform
630
+ * @returns A function the app calls to report its own in-app navigations to the Dashboard.
605
631
  *
606
632
  * @example
607
633
  * ```tsx
608
634
  * import {useNavigate} from '@sanity/sdk-react/dashboard'
609
- * import {BrowserRouter, useNavigate as useRouterNavigate} from 'react-router'
610
- * import {Suspense} from 'react'
611
- *
612
- * function DashboardNavigationHandler() {
613
- * const navigate = useRouterNavigate()
614
- * useNavigate(({path, type}) => {
615
- * navigate(path, {replace: type === 'replace'})
635
+ * import {useEffect} from 'react'
636
+ * import {useLocation, useNavigate as useRouterNavigate} from 'react-router'
637
+ *
638
+ * function DashboardNavigationSync() {
639
+ * const routerNavigate = useRouterNavigate()
640
+ * const {pathname, search, hash} = useLocation()
641
+ * const navigate = useNavigate(({path, type}) => {
642
+ * routerNavigate(path, {replace: type === 'replace'})
616
643
  * })
644
+ * useEffect(() => {
645
+ * navigate({path: `${pathname.slice(1)}${search}${hash}`})
646
+ * }, [navigate, pathname, search, hash])
617
647
  * return null
618
648
  * }
619
- *
620
- * // Wrap the component with Suspense since the hook may suspend
621
- * function MyApp() {
622
- * return (
623
- * <BrowserRouter>
624
- * <Suspense>
625
- * <DashboardNavigationHandler />
626
- * </Suspense>
627
- * </BrowserRouter>
628
- * )
629
- * }
630
649
  * ```
631
650
  */
632
- export declare function useNavigate(navigateFn: (options: PathChangeMessage['data']) => void): void;
651
+ export declare function useNavigate(navigateFn: (options: DashboardNavigation) => void): NavigateToDashboardPath;
633
652
  /**
634
653
  * @public
635
654
  * @category Types
@@ -645,6 +664,9 @@ interface NavigateToStudioResult {
645
664
  * Uses the `projectId` and `dataset` properties of the {@link DocumentHandle} you provide to resolve the correct Studio.
646
665
  * This will only work if you have deployed a studio with a workspace with this `projectId` / `dataset` combination.
647
666
  *
667
+ * Works in both Dashboard runtimes: it sends the navigation over the Comlink connection in the
668
+ * iframe runtime and over the message bus in the federated runtime.
669
+ *
648
670
  * @remarks If you write your own Document Handle to pass to this hook (as opposed to a Document Handle generated by another hook),
649
671
  * it must include values for `documentId`, `documentType`, `projectId`, and `dataset`.
650
672
  *
@@ -773,5 +795,5 @@ export declare const useTopic: <K extends StateTopic$1>(topic: K) => TopicData$1
773
795
  * @public
774
796
  */
775
797
  export declare function useWindowTitle(viewTitle?: string): void;
776
- export { type AgentResourceContextOptions, type ApplicationConfig, type ApplicationConfigAppType, type ApplicationConfigSelector, type CanvasUrl, type Capability, type CapabilityRecord, type ConnectMessageBusOptions, type CoreApplicationUrl, type CreateIntentParameters, type CreateRemoteInstanceOptions, type DashboardApplication, type DashboardTopics, type DashboardUrl, type DashboardView, type DashboardWebWorker, type EditIntentParameters, type EventTopic, type EventTopicDef, type FederationRemote, type MediaLibraryUrl, type MessageBus, type MessageBusAbortOptions, type MessageBusClient, type MessageBusConnection, type MessageBusEmitOptions, type MessageBusEmitResult, MessageBusError, type MessageBusErrorCode, type MessageBusHost, type MessageBusMessage, type MessageBusMeta, type MessageBusQueryOptions, type MessageBusStateSource, type NavigateToStudioResult, type NavigationLocation, type NavigationTarget, type PayloadOf, type ReleaseIntentParameters, type RemoteInstance, type RemoteModuleRef, type ReplyOf, type StateTopic, type StateTopicDef, type StudioIntentUrl, type StudioUrl, type StudioWorkspaceUrl, DashboardTokenRefreshProvider as TokenRefreshProvider, type TopicData, type TopicEmitter, TopicError, type TopicName, type TopicResult, type Topics, type Urls, type ValueOf, capabilities, connectMessageBus };
798
+ export { type AgentResourceContextOptions, type ApplicationConfig, type ApplicationConfigAppType, type ApplicationConfigSelector, type CanvasUrl, type Capability, type CapabilityRecord, type ConnectMessageBusOptions, type CoreApplicationUrl, type CreateIntentParameters, type CreateRemoteInstanceOptions, type DashboardApplication, type DashboardNavigation, type DashboardTopics, type DashboardUrl, type DashboardView, type DashboardWebWorker, type EditIntentParameters, type EventTopic, type EventTopicDef, type FederationRemote, type MediaLibraryUrl, type MessageBus, type MessageBusAbortOptions, type MessageBusClient, type MessageBusConnection, type MessageBusEmitOptions, type MessageBusEmitResult, MessageBusError, type MessageBusErrorCode, type MessageBusHost, type MessageBusMessage, type MessageBusMeta, type MessageBusQueryOptions, type MessageBusStateSource, type NavigateToDashboardPath, type NavigateToStudioResult, type NavigationLocation, type NavigationTarget, type PayloadOf, type ReleaseIntentParameters, type RemoteInstance, type RemoteModuleRef, type ReplyOf, type StateTopic, type StateTopicDef, type StudioIntentUrl, type StudioUrl, type StudioWorkspaceUrl, DashboardTokenRefreshProvider as TokenRefreshProvider, type TopicData, type TopicEmitter, TopicError, type TopicName, type TopicResult, type Topics, type Urls, type ValueOf, capabilities, connectMessageBus };
777
799
  //# sourceMappingURL=dashboard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.d.ts","names":[],"sources":["../../src/context/DashboardTokenRefresh.tsx","../../src/dashboard/createRemoteInstance.ts","../../src/dashboard/urlFor.ts","../../src/hooks/dashboard/useAgentResourceContext.ts","../../src/hooks/dashboard/useApplications.ts","../../src/hooks/dashboard/useApplication.ts","../../src/hooks/dashboard/useApplicationBasePath.ts","../../src/hooks/dashboard/useApplicationConfig.ts","../../src/hooks/dashboard/useApplicationConfigs.ts","../../src/hooks/dashboard/useApplicationForegroundId.ts","../../src/hooks/dashboard/useAuthToken.ts","../../src/hooks/dashboard/useCapabilities.ts","../../src/hooks/dashboard/useCurrentUser.ts","../../src/hooks/dashboard/useEmit.ts","../../src/hooks/dashboard/useNavigate.ts","../../src/hooks/dashboard/useNavigateToStudioDocument.ts","../../src/hooks/dashboard/useOrganizationId.tsx","../../src/hooks/dashboard/useRemoteClient.ts","../../src/hooks/dashboard/useTopic.ts","../../src/hooks/dashboard/useWindowTitle.ts"],"mappings":"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"}
1
+ {"version":3,"file":"dashboard.d.ts","names":[],"sources":["../../src/context/DashboardTokenRefresh.tsx","../../src/dashboard/createRemoteInstance.ts","../../src/dashboard/urlFor.ts","../../src/hooks/dashboard/useAgentResourceContext.ts","../../src/hooks/dashboard/useApplications.ts","../../src/hooks/dashboard/useApplication.ts","../../src/hooks/dashboard/useApplicationBasePath.ts","../../src/hooks/dashboard/useApplicationConfig.ts","../../src/hooks/dashboard/useApplicationConfigs.ts","../../src/hooks/dashboard/useApplicationForegroundId.ts","../../src/hooks/dashboard/useAuthToken.ts","../../src/hooks/dashboard/useCapabilities.ts","../../src/hooks/dashboard/useCurrentUser.ts","../../src/hooks/dashboard/useEmit.ts","../../src/hooks/dashboard/useNavigate.ts","../../src/hooks/dashboard/useNavigateToStudioDocument.ts","../../src/hooks/dashboard/useOrganizationId.tsx","../../src/hooks/dashboard/useRemoteClient.ts","../../src/hooks/dashboard/useTopic.ts","../../src/hooks/dashboard/useWindowTitle.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA+Fa,+BAA+B,MAAM,GAAG;KCxFhD,aAAa,GAAG,gBAAgB,KAAK,KAAK,GAAG,KAAK,QAAQ,KAAK,GAAG;;;;KAK3D;EACV;EACA;;;;;KAcU,8BAA8B,aACxC,KAAK;;;;UAOU;EACf,gBAAgB,SAAS;;EAEzB,WAAW,GAAG,aAAa,QAAQ;;EAEnC,cAAc,cAAc,qBAAqB;;;;;;wBAOnC,qBAAqB,SAAS,8BAA8B;;UC/C3D;EACf,IAAI;IAAW;;EACf,MAAM;IAAU;MAAkB;EAClC;;;UAOe;EACf;;EAEA;;EAEA,gDAAgD;;;UAIjC;EACf;EACA;;;UAIe;EACf;;;UAIe,2BAA2B;EAC1C,OAAO,gBAAgB,YAAY,uBAAuB;EAC1D,OAAO,kBAAkB,YAAY,yBAAyB;EAC9D,OAAO,mBAAmB,YAAY,0BAA0B;EAChE,QAAQ,iBAAiB;EACzB,KAAK,iBAAiB;;;UAIP,kBAAkB;EACjC,UAAU,oBAAoB;;;UAIf,wBAAwB;EACvC,YAAY,sBAAsB;EAClC,QAAQ,oBAAoB;EAC5B,KAAK,iBAAiB;;;UAIP,2BAA2B;EAC1C,QAAQ,iBAAiB;;;UAIV,wBAAwB;EACvC,MAAM,kBAAkB;EACxB,WAAW,uBAAuB;;;UAInB,kBAAkB;EACjC,SAAS,qBAAqB;;;;;;;qBA0EnB,sBAAsB;;;;;;;;;;;;;;EAerB,YAAA,KAAK;;;;;;;;;;;;;;;;;;;;YAuBP,UAAU;;;;;;;;;;;;;;;;;;;;;YAwBV,KAAK,SAAS,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;YA+BnB,aAAa,gBAAgB,YACrC,cAAc,KAAK,QAAQ,YACxB,qBACF;;;;;;;;;;;;;;;;;EAoBH,IAAI;IAAW;;;;;;;;;;;;;;;EAkBf,QAAO;IAAU;MAAkB;;;;;;;;;;;;;EAgBnC;;;UAuFe;EACf,WAAW;EACX,QAAQ,gBAAgB;EACxB,gBAAgB;EAChB,aAAa,gBAAgB;EAC7B,gBAAgB;EAChB,UAAU;EACV,QAAQ;EACR,aACQ,iBAAiB,SACrB;aAGa;SACJ,KAAK,MAAM;OAKtB,UAAU,WAAW,QAAQ,gDACV,cAAc,iBAAiB,aAAa,SAAS;;;qBAkE/D,QAAQ;;;;UCpcJ;;;;EAIf;;;;EAIA;;;;EAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAiCc,wBAAwB,SAAS;KC/C5C,4BAA4B,QAC/B,YAAY;EACX;;KAEE,gCAAgC,YACnC,YAAY;KAET,gBAAgB,QAAQ;EAAgC;;;;;;KAMjD,mBACT,QAAQ,wBAAwB,KAAK,QAAQ;EAAgB,MAAM;;WACzD,aAAa;WACb,QAAQ;WACR,SAAS,gCAAgC;KAEpD;;;;;KAMU,qBAAqB,QAAQ;EAAgC;;WAC9D,aAAa;WACb,QAAQ;;;;;;KAOP,uBAAuB;WACxB,OAAO;WACP,YAAY;;;;;;;;;;;;;;;;;;wBA8DP,mBAAmB;;;;;;;;;;;;;;;;wBCxFnB,eACd,eAAe,6BACd;;;;;;;;;;;;;;;;;wBCCa,0BAA0B;;;;;KCX9B;EACP,OAAO;EAAmB;;EAC1B;EAAe,SAAS;;;;;;;;;;;;;;;;;;;;;;wBAsBb,qBACd,UAAU,4BACT;;;;;;;;;;;;;;;;wBCZa,kCAAkC;;;;;;;;;;;;;;;;wBCJlC,8BAA8B;;;;;;;;;;;;;;;;wBCF9B;;;;;;;;;;;;;;;;;;;;;wBCOA,mBAAmB;;;;;;;;;;;;;;;;wBCLnB,kBAAkB;;;;;KCHtB,aAAa,UAAU,oBAC9B,MAAM,YAAU,mBACd,gBAAgB,UAAU,4BAC1B,SAAS,YAAU,IAAI,UAAU,6BACnC,uBAAqB,UAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAkDlB,QAAQ,UAAU,cAAY,OAAO,IAAI,aAAa;;;;;;;KC/C1D,sBAAsB;;;;;;;KAQtB,2BAA2B;EAAU;EAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA+C/C,YACd,aAAa,SAAS,+BACrB;;;;;UC9Dc;EACf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA0Gc,4BACd,gBAAgB,gBAChB,8BACC;;;;;;;;;;;;;;;;;;;;;;;wBClGa;;;;;;qBCrBH,uBAAuB;;;;;;;;;;;;;;;;;;qBCavB,WAMN,UAAU,cAAY,OAAO,MAAM,YAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBC4CpC,eAAe"}
@@ -2,11 +2,11 @@ import { a as useWindowConnection, c as useSanityInstance, i as DashboardTokenRe
2
2
  import { c } from "react-compiler-runtime";
3
3
  import "@sanity/sdk";
4
4
  import { createLogger, getApplicationOrigin, isDashboardEnvironment, requireDashboardMessageBus } from "@sanity/sdk/_internal";
5
- import { useEffect, useRef, useState } from "react";
5
+ import { useCallback, useEffect, useEffectEvent, useRef, useState } from "react";
6
6
  import { SDK_CHANNEL_NAME, SDK_NODE_NAME } from "@sanity/message-protocol";
7
7
  import "@sanity/sdk/comlink";
8
- import { of } from "rxjs";
9
- import { MessageBusError, TopicError, capabilities, connectMessageBus } from "@sanity/sdk/dashboard";
8
+ import { filter, map, of, pairwise } from "rxjs";
9
+ import { MessageBusError, TopicError, TopicError as TopicError$1, capabilities, connectMessageBus } from "@sanity/sdk/dashboard";
10
10
  import "@sanity/types";
11
11
  import { createInstance } from "@module-federation/runtime";
12
12
  import "@module-federation/runtime/types";
@@ -723,54 +723,140 @@ function useEmit(topic) {
723
723
  * @public
724
724
  *
725
725
  * A helper hook designed to be injected into routing components for apps within the Dashboard.
726
- * While the Dashboard can usually handle navigation, there are special cases when you
727
- * are already within a target app, and need to navigate to another route inside of that app.
728
- *
729
- * For example, your user might "favorite" a document inside of your application.
730
- * If they click on the Dashboard favorites item in the sidebar, and are already within your application,
731
- * there needs to be some way for the dashboard to signal to your application to reroute to where that document was favorited.
732
- *
733
- * This hook is intended to receive those messages, and takes a function to route to the correct path.
726
+ * It keeps the app's router and the Dashboard in two-way sync: `navigateFn` receives the
727
+ * navigations the Dashboard asks the app to perform, and the returned function reports the app's
728
+ * own in-app navigations back to the Dashboard so the browser URL and the Dashboard's router
729
+ * follow along.
730
+ *
731
+ * A navigation the app reports is not echoed back through `navigateFn`. The returned function is
732
+ * referentially stable.
733
+ *
734
+ * The two Dashboard runtimes differ:
735
+ * - In an iframe (Comlink), inbound `type` may be `'push'`, `'replace'` or `'pop'`. Reporting is
736
+ * optional because the bridge already forwards the iframe's own `pushState`; a reported `type`
737
+ * is ignored and the host applies the URL as a `replace`.
738
+ * - In a federated app (message bus), inbound `type` is `'push'` or `'replace'`; `'pop'` is never
739
+ * sent. Reporting is required because the app's router does not reach the host, and `type` is
740
+ * honoured. Until the Dashboard publishes the app's base path, reports are dropped with a
741
+ * console warning.
734
742
  *
735
743
  * @param navigateFn - Function to handle navigation; should accept:
736
744
  * - `path`: a string, which will be a relative path (for example, 'my-route')
737
745
  * - `type`: 'push', 'replace', or 'pop', which will be the type of navigation to perform
746
+ * @returns A function the app calls to report its own in-app navigations to the Dashboard.
738
747
  *
739
748
  * @example
740
749
  * ```tsx
741
750
  * import {useNavigate} from '@sanity/sdk-react/dashboard'
742
- * import {BrowserRouter, useNavigate as useRouterNavigate} from 'react-router'
743
- * import {Suspense} from 'react'
744
- *
745
- * function DashboardNavigationHandler() {
746
- * const navigate = useRouterNavigate()
747
- * useNavigate(({path, type}) => {
748
- * navigate(path, {replace: type === 'replace'})
751
+ * import {useEffect} from 'react'
752
+ * import {useLocation, useNavigate as useRouterNavigate} from 'react-router'
753
+ *
754
+ * function DashboardNavigationSync() {
755
+ * const routerNavigate = useRouterNavigate()
756
+ * const {pathname, search, hash} = useLocation()
757
+ * const navigate = useNavigate(({path, type}) => {
758
+ * routerNavigate(path, {replace: type === 'replace'})
749
759
  * })
760
+ * useEffect(() => {
761
+ * navigate({path: `${pathname.slice(1)}${search}${hash}`})
762
+ * }, [navigate, pathname, search, hash])
750
763
  * return null
751
764
  * }
752
- *
753
- * // Wrap the component with Suspense since the hook may suspend
754
- * function MyApp() {
755
- * return (
756
- * <BrowserRouter>
757
- * <Suspense>
758
- * <DashboardNavigationHandler />
759
- * </Suspense>
760
- * </BrowserRouter>
761
- * )
762
- * }
763
765
  * ```
764
766
  */
765
767
  function useNavigate(navigateFn) {
766
- let $ = c(2), t0;
768
+ return isDashboardEnvironment() ? useBusNavigate(navigateFn) : useComlinkNavigate(navigateFn);
769
+ }
770
+ function useComlinkNavigate(navigateFn) {
771
+ let $ = c(4), t0;
767
772
  $[0] === navigateFn ? t0 = $[1] : (t0 = {
768
773
  name: SDK_NODE_NAME,
769
774
  connectTo: SDK_CHANNEL_NAME,
770
775
  onMessage: { "dashboard/v1/history/change-path": (data) => {
771
776
  navigateFn(data);
772
777
  } }
773
- }, $[0] = navigateFn, $[1] = t0), useWindowConnection(t0);
778
+ }, $[0] = navigateFn, $[1] = t0);
779
+ let { sendMessage } = useWindowConnection(t0), t1;
780
+ return $[2] === sendMessage ? t1 = $[3] : (t1 = (t2) => {
781
+ let { path } = t2;
782
+ return sendMessage("dashboard/v1/bridge/listeners/history/update-url", { url: new URL(path, window.location.origin).href });
783
+ }, $[2] = sendMessage, $[3] = t1), t1;
784
+ }
785
+ function joinPath(base, path) {
786
+ let root = base.replace(/\/$/, "");
787
+ return path ? `${root}/${path}` : root;
788
+ }
789
+ function useBusNavigate(navigateFn) {
790
+ let $ = c(9), instance = useSanityInstance(), t0;
791
+ $[0] === instance ? t0 = $[1] : (t0 = requireDashboardMessageBus(instance, "navigate"), $[0] = instance, $[1] = t0);
792
+ let bus = t0, navigate = useEffectEvent(navigateFn), ownRequest = useRef(null), t1;
793
+ $[2] !== bus || $[3] !== navigate ? (t1 = () => {
794
+ let sub = bus.subscribe("navigation.location").pipe(pairwise(), filter((pair) => {
795
+ let [prev, curr] = pair;
796
+ return curr?.transition === null && curr.appId === bus.appId && prev?.transition?.to.appId === bus.appId && prev.transition.to.path === curr.path;
797
+ }), filter((t2) => {
798
+ let [, curr_0] = t2, suppress = curr_0.path === ownRequest.current;
799
+ return ownRequest.current = null, !suppress;
800
+ }), map(_temp$1)).subscribe((change) => navigate(change));
801
+ return () => sub.unsubscribe();
802
+ }, $[2] = bus, $[3] = navigate, $[4] = t1) : t1 = $[4];
803
+ let t2;
804
+ $[5] === bus ? t2 = $[6] : (t2 = [bus], $[5] = bus, $[6] = t2), useEffect(t1, t2);
805
+ let t3;
806
+ return $[7] === bus ? t3 = $[8] : (t3 = (t4) => {
807
+ let { path, type: t5 } = t4, type = t5 === void 0 ? "push" : t5, own = path.replace(/^\//, "");
808
+ ownRequest.current = own;
809
+ let clearIfStale = () => {
810
+ ownRequest.current === own && (ownRequest.current = null);
811
+ };
812
+ bus.query("applications.base-path").then((base) => {
813
+ if (!base.ok) throw new TopicError$1("applications.base-path");
814
+ return bus.emit("navigation.location.update", {
815
+ url: joinPath(base.value, own),
816
+ history: type
817
+ });
818
+ }).then((reply) => {
819
+ reply.ok || clearIfStale();
820
+ }, (error) => {
821
+ console.warn("Failed to report navigation to the Dashboard", error), clearIfStale();
822
+ });
823
+ }, $[7] = bus, $[8] = t3), t3;
824
+ }
825
+ function _temp$1(t0) {
826
+ let [prev_0, curr_1] = t0;
827
+ return {
828
+ path: curr_1.path,
829
+ type: prev_0.transition.navigationType
830
+ };
831
+ }
832
+ function useComlinkStudioNavigator(documentHandle) {
833
+ let $ = c(5), t0;
834
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = {
835
+ name: SDK_NODE_NAME,
836
+ connectTo: SDK_CHANNEL_NAME
837
+ }, $[0] = t0) : t0 = $[0];
838
+ let { sendMessage } = useWindowConnection(t0), t1;
839
+ return $[1] !== documentHandle.documentId || $[2] !== documentHandle.documentType || $[3] !== sendMessage ? (t1 = (workspace) => {
840
+ let message = {
841
+ type: "dashboard/v1/bridge/navigate-to-resource",
842
+ data: {
843
+ resourceId: workspace.id,
844
+ resourceType: "studio",
845
+ path: `/intent/edit/id=${documentHandle.documentId};type=${documentHandle.documentType}`
846
+ }
847
+ };
848
+ sendMessage(message.type, message.data);
849
+ }, $[1] = documentHandle.documentId, $[2] = documentHandle.documentType, $[3] = sendMessage, $[4] = t1) : t1 = $[4], t1;
850
+ }
851
+ function useBusStudioNavigator(documentHandle) {
852
+ let $ = c(4), navigate = useEmit("navigation.location.update"), t0;
853
+ return $[0] !== documentHandle.documentId || $[1] !== documentHandle.documentType || $[2] !== navigate ? (t0 = (workspace) => {
854
+ let url = urlFor.studios(workspace.userApplicationId).workspace(workspace.name).intent("edit", {
855
+ id: documentHandle.documentId,
856
+ type: documentHandle.documentType
857
+ }).url();
858
+ navigate({ url }).then(_temp, _temp2);
859
+ }, $[0] = documentHandle.documentId, $[1] = documentHandle.documentType, $[2] = navigate, $[3] = t0) : t0 = $[3], t0;
774
860
  }
775
861
  /**
776
862
  * @public
@@ -780,6 +866,9 @@ function useNavigate(navigateFn) {
780
866
  * Uses the `projectId` and `dataset` properties of the {@link DocumentHandle} you provide to resolve the correct Studio.
781
867
  * This will only work if you have deployed a studio with a workspace with this `projectId` / `dataset` combination.
782
868
  *
869
+ * Works in both Dashboard runtimes: it sends the navigation over the Comlink connection in the
870
+ * iframe runtime and over the message bus in the federated runtime.
871
+ *
783
872
  * @remarks If you write your own Document Handle to pass to this hook (as opposed to a Document Handle generated by another hook),
784
873
  * it must include values for `documentId`, `documentType`, `projectId`, and `dataset`.
785
874
  *
@@ -817,41 +906,38 @@ function useNavigate(navigateFn) {
817
906
  * }
818
907
  * ```
819
908
  */
909
+ function _temp2(error) {
910
+ console.warn("Failed to navigate to studio document", error);
911
+ }
912
+ function _temp(reply) {
913
+ reply.ok === !1 && console.warn("Failed to navigate to studio document", reply);
914
+ }
820
915
  function useNavigateToStudioDocument(documentHandle, preferredStudioUrl) {
821
- let $ = c(8), { workspacesByProjectIdAndDataset } = useStudioWorkspacesByProjectIdDataset(), t0;
822
- $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = {
823
- name: SDK_NODE_NAME,
824
- connectTo: SDK_CHANNEL_NAME
825
- }, $[0] = t0) : t0 = $[0];
826
- let { sendMessage } = useWindowConnection(t0), t1;
827
- $[1] !== documentHandle || $[2] !== preferredStudioUrl || $[3] !== sendMessage || $[4] !== workspacesByProjectIdAndDataset ? (t1 = () => {
916
+ let { workspacesByProjectIdAndDataset } = useStudioWorkspacesByProjectIdDataset(), sendToWorkspace = isDashboardEnvironment() ? useBusStudioNavigator(documentHandle) : useComlinkStudioNavigator(documentHandle);
917
+ return { navigateToStudioDocument: useCallback(() => {
828
918
  let { projectId, dataset } = documentHandle;
829
919
  if (!projectId || !dataset) {
830
920
  console.warn("Project ID and dataset are required to navigate to a studio document");
831
921
  return;
832
922
  }
833
- let workspace;
834
- if (preferredStudioUrl) workspace = [...workspacesByProjectIdAndDataset[`${projectId}:${dataset}`] || [], ...workspacesByProjectIdAndDataset["NO_PROJECT_ID:NO_DATASET"] || []].find((w) => w.url === preferredStudioUrl);
835
- else {
836
- let workspaces = workspacesByProjectIdAndDataset[`${projectId}:${dataset}`];
837
- workspaces?.length > 1 && (console.warn("Multiple workspaces found for document and no preferred studio url", documentHandle), console.warn("Using the first one", workspaces[0])), workspace = workspaces?.[0];
838
- }
923
+ let workspace = resolveWorkspace(documentHandle, workspacesByProjectIdAndDataset, preferredStudioUrl);
839
924
  if (!workspace) {
840
925
  console.warn(`No workspace found for document with projectId: ${projectId} and dataset: ${dataset}${preferredStudioUrl ? ` or with preferred studio url: ${preferredStudioUrl}` : ""}`);
841
926
  return;
842
927
  }
843
- let message = {
844
- type: "dashboard/v1/bridge/navigate-to-resource",
845
- data: {
846
- resourceId: workspace.id,
847
- resourceType: "studio",
848
- path: `/intent/edit/id=${documentHandle.documentId};type=${documentHandle.documentType}`
849
- }
850
- };
851
- sendMessage(message.type, message.data);
852
- }, $[1] = documentHandle, $[2] = preferredStudioUrl, $[3] = sendMessage, $[4] = workspacesByProjectIdAndDataset, $[5] = t1) : t1 = $[5];
853
- let navigateToStudioDocument = t1, t2;
854
- return $[6] === navigateToStudioDocument ? t2 = $[7] : (t2 = { navigateToStudioDocument }, $[6] = navigateToStudioDocument, $[7] = t2), t2;
928
+ sendToWorkspace(workspace);
929
+ }, [
930
+ documentHandle,
931
+ workspacesByProjectIdAndDataset,
932
+ preferredStudioUrl,
933
+ sendToWorkspace
934
+ ]) };
935
+ }
936
+ function resolveWorkspace(documentHandle, workspacesByProjectIdAndDataset, preferredStudioUrl) {
937
+ let { projectId, dataset } = documentHandle, key = `${projectId}:${dataset}`;
938
+ if (preferredStudioUrl) return [...workspacesByProjectIdAndDataset[key] || [], ...workspacesByProjectIdAndDataset["NO_PROJECT_ID:NO_DATASET"] || []].find((w) => w.url === preferredStudioUrl);
939
+ let workspaces = workspacesByProjectIdAndDataset[key];
940
+ return workspaces && workspaces.length > 1 && (console.warn("Multiple workspaces found for document and no preferred studio url", documentHandle), console.warn("Using the first one", workspaces[0])), workspaces?.[0];
855
941
  }
856
942
  const remoteClientStates = /* @__PURE__ */ new WeakMap();
857
943
  /** Returns the instance's remote client state, creating it on first use. @internal */