@burdenoff/fe-libs 2026.1024.1 → 2026.1024.3

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 (132) hide show
  1. package/dist/chrome/FooterBar.d.ts +1 -1
  2. package/dist/chrome/NativePageTransition.d.ts +1 -1
  3. package/dist/chrome/ProductPickerSheet.js +42 -42
  4. package/dist/chrome/ProductSwitcher.d.ts +8 -0
  5. package/dist/chrome/ProductSwitcher.js +83 -72
  6. package/dist/chrome/index.d.ts +9 -9
  7. package/dist/chrome/swipe/swipeMath.d.ts +1 -1
  8. package/dist/shared/assistant/api.d.ts +3 -3
  9. package/dist/shared/assistant/appControls/grammar.d.ts +21 -21
  10. package/dist/shared/assistant/appControls/languageReply.d.ts +1 -1
  11. package/dist/shared/assistant/appControls/names.d.ts +3 -3
  12. package/dist/shared/assistant/appControls/pageAdapters.d.ts +5 -5
  13. package/dist/shared/assistant/appControls/plan.d.ts +38 -38
  14. package/dist/shared/assistant/appControls/types.d.ts +15 -15
  15. package/dist/shared/assistant/appControls/useAssistantControl.d.ts +1 -1
  16. package/dist/shared/assistant/attachmentSources.d.ts +2 -2
  17. package/dist/shared/assistant/attachments.d.ts +5 -5
  18. package/dist/shared/assistant/autoRouting.d.ts +6 -6
  19. package/dist/shared/assistant/avatar/live/LiveAvatarStage.js +5 -1
  20. package/dist/shared/assistant/avatar/live/LiveAvatarTabView.js +28 -25
  21. package/dist/shared/assistant/avatar/live/createLiveAvatarSeam.d.ts +1 -1
  22. package/dist/shared/assistant/avatar/live/createLiveAvatarSeam.js +61 -50
  23. package/dist/shared/assistant/avatar/live/liveAvatarController.d.ts +19 -4
  24. package/dist/shared/assistant/avatar/live/liveAvatarController.js +163 -155
  25. package/dist/shared/assistant/avatar/live/liveAvatarStatus.d.ts +5 -3
  26. package/dist/shared/assistant/avatar/live/liveAvatarStatus.js +2 -2
  27. package/dist/shared/assistant/conversation.d.ts +20 -20
  28. package/dist/shared/assistant/displayContent.d.ts +4 -4
  29. package/dist/shared/assistant/documentText.d.ts +3 -3
  30. package/dist/shared/assistant/exportConversation.d.ts +1 -1
  31. package/dist/shared/assistant/history/historyControls.d.ts +4 -4
  32. package/dist/shared/assistant/history/historyErrors.d.ts +3 -3
  33. package/dist/shared/assistant/history/historyList.d.ts +5 -5
  34. package/dist/shared/assistant/history/historyMerge.d.ts +4 -4
  35. package/dist/shared/assistant/history/historyOperations.d.ts +1 -1
  36. package/dist/shared/assistant/history/historySearch.d.ts +5 -5
  37. package/dist/shared/assistant/history/historyStatus.d.ts +1 -1
  38. package/dist/shared/assistant/history/historyTypes.d.ts +12 -12
  39. package/dist/shared/assistant/history/profileBoundStorage.d.ts +2 -2
  40. package/dist/shared/assistant/i18n.d.ts +1 -1
  41. package/dist/shared/assistant/i18nManifest.d.ts +534 -534
  42. package/dist/shared/assistant/liveDeltas.d.ts +1 -1
  43. package/dist/shared/assistant/liveOverlay.d.ts +1 -1
  44. package/dist/shared/assistant/localUiCommandCopy.d.ts +1 -1
  45. package/dist/shared/assistant/localUiCommands.d.ts +22 -22
  46. package/dist/shared/assistant/localeCommands/engine.d.ts +5 -5
  47. package/dist/shared/assistant/localeCommands/evaluate.d.ts +8 -8
  48. package/dist/shared/assistant/localeCommands/fold.d.ts +2 -2
  49. package/dist/shared/assistant/localeCommands/frames.d.ts +3 -3
  50. package/dist/shared/assistant/localeCommands/gate.d.ts +3 -3
  51. package/dist/shared/assistant/localeCommands/languageNames.d.ts +1 -1
  52. package/dist/shared/assistant/localeCommands/normalise.d.ts +1 -1
  53. package/dist/shared/assistant/localeCommands/types.d.ts +4 -4
  54. package/dist/shared/assistant/modeCapabilities.d.ts +1 -1
  55. package/dist/shared/assistant/modeCopy.d.ts +2 -2
  56. package/dist/shared/assistant/permissionError.d.ts +2 -2
  57. package/dist/shared/assistant/preview/surfaceState.d.ts +1 -1
  58. package/dist/shared/assistant/preview/types.d.ts +5 -5
  59. package/dist/shared/assistant/preview/writeActionResults.d.ts +1 -1
  60. package/dist/shared/assistant/prewarm.d.ts +5 -5
  61. package/dist/shared/assistant/quota.d.ts +2 -2
  62. package/dist/shared/assistant/sandboxReadiness.d.ts +2 -2
  63. package/dist/shared/assistant/speech/speechFeed.d.ts +3 -3
  64. package/dist/shared/assistant/turnOutcome.d.ts +2 -2
  65. package/dist/shared/assistant/turnProgress.d.ts +1 -1
  66. package/dist/shared/assistant/turnState.d.ts +1 -1
  67. package/dist/shared/assistant/turnStream.d.ts +3 -3
  68. package/dist/shared/assistant/turnTimeline.d.ts +13 -13
  69. package/dist/shared/assistant/turnTimingReport.d.ts +1 -1
  70. package/dist/shared/assistant/turnTimingReporter.d.ts +3 -3
  71. package/dist/shared/assistant/ui/AssistantAvatarTabs.d.ts +1 -1
  72. package/dist/shared/assistant/ui/AssistantHistoryNotices.d.ts +1 -1
  73. package/dist/shared/assistant/ui/AssistantToolActivity.d.ts +1 -1
  74. package/dist/shared/assistant/ui/AssistantUiOfferLink.d.ts +2 -2
  75. package/dist/shared/assistant/ui/AssistantWriteConfirmDialog.d.ts +3 -3
  76. package/dist/shared/assistant/ui/composer/AssistantAttachmentButton.d.ts +1 -1
  77. package/dist/shared/assistant/ui/composer/AssistantConnectSourceItem.d.ts +1 -1
  78. package/dist/shared/assistant/ui/leaveConfirmFocus.d.ts +1 -1
  79. package/dist/shared/assistant/ui/leaveConfirmNavigate.d.ts +3 -3
  80. package/dist/shared/assistant/ui/panelOverlays.d.ts +5 -5
  81. package/dist/shared/assistant/ui/useVoiceSession.d.ts +5 -5
  82. package/dist/shared/assistant/ui/useWriteProposalConfirm.d.ts +4 -4
  83. package/dist/shared/assistant/ui/useWriteProposals.d.ts +2 -2
  84. package/dist/shared/assistant/ui/voice/AssistantVoiceSession.d.ts +1 -1
  85. package/dist/shared/assistant/ui/voice/VoiceCaption.d.ts +1 -1
  86. package/dist/shared/assistant/ui/voice/VoiceWaveform.d.ts +1 -1
  87. package/dist/shared/assistant/ui/voice/voiceSessionEscape.d.ts +2 -2
  88. package/dist/shared/assistant/ui/voice/voiceStartGate.d.ts +6 -6
  89. package/dist/shared/assistant/ui/writeProposalPresentation.d.ts +1 -1
  90. package/dist/shared/assistant/uiActions/actOnResolve.d.ts +5 -5
  91. package/dist/shared/assistant/uiActions/assistantHref.d.ts +2 -2
  92. package/dist/shared/assistant/uiActions/backStack.d.ts +1 -1
  93. package/dist/shared/assistant/uiActions/deixis.d.ts +3 -3
  94. package/dist/shared/assistant/uiActions/entityRoutes.d.ts +1 -1
  95. package/dist/shared/assistant/uiActions/navigationOutcome.d.ts +8 -8
  96. package/dist/shared/assistant/uiActions/offerYesOnSurface.d.ts +1 -1
  97. package/dist/shared/assistant/uiActions/resolveTarget.d.ts +2 -2
  98. package/dist/shared/assistant/uiActions/uiOffers.d.ts +5 -5
  99. package/dist/shared/assistant/usageReporting.d.ts +2 -2
  100. package/dist/shared/assistant/useWorkspaceWriteAccess.d.ts +1 -1
  101. package/dist/shared/assistant/voice/affirmations.d.ts +1 -1
  102. package/dist/shared/assistant/voice/handsFree.d.ts +3 -3
  103. package/dist/shared/assistant/voice/handsfree/bargeIn.d.ts +5 -5
  104. package/dist/shared/assistant/voice/handsfree/echoGate.d.ts +6 -6
  105. package/dist/shared/assistant/voice/handsfree/handsFreeController.d.ts +7 -7
  106. package/dist/shared/assistant/voice/handsfree/handsFreeSetting.d.ts +2 -2
  107. package/dist/shared/assistant/voice/handsfree/micCapture.d.ts +1 -1
  108. package/dist/shared/assistant/voice/handsfree/playbackReference.d.ts +1 -1
  109. package/dist/shared/assistant/voice/handsfree/sttTransport.d.ts +3 -3
  110. package/dist/shared/assistant/voice/handsfree/useHandsFreeInterrupt.d.ts +4 -4
  111. package/dist/shared/assistant/voice/handsfree/vad.d.ts +1 -1
  112. package/dist/shared/assistant/voice/speechPlayback.d.ts +7 -7
  113. package/dist/shared/assistant/voice/useVoiceInput.d.ts +1 -1
  114. package/dist/shared/assistant/voice/voiceReopen.d.ts +8 -8
  115. package/dist/shared/assistant/writeConfirmSeam.d.ts +1 -1
  116. package/dist/shared/assistant/writeModeConsent.d.ts +7 -7
  117. package/dist/shared/assistant/writeProposalDiscovery.d.ts +3 -3
  118. package/dist/shared/assistant/writeProposalErrorCopy.d.ts +1 -1
  119. package/dist/shared/assistant/writeProposals.d.ts +23 -23
  120. package/dist/shared/assistant/writeReplyBinder.d.ts +11 -11
  121. package/dist/shared/assistant/writeReplySend.d.ts +7 -7
  122. package/dist/shared/components/LandingOrDashboardRedirect.d.ts +18 -3
  123. package/dist/shared/components/LandingOrDashboardRedirect.js +58 -28
  124. package/dist/shared/components/index.d.ts +2 -1
  125. package/dist/shared/hooks/shell/globalSearchError.d.ts +2 -2
  126. package/dist/shared/navigation/productSwitchHandoff.d.ts +45 -0
  127. package/dist/shared/navigation/productSwitchHandoff.js +27 -0
  128. package/dist/shared/navigation/unsavedChanges.d.ts +1 -1
  129. package/dist/shared/utils/index.d.ts +3 -3
  130. package/dist/shared-components.js +7 -6
  131. package/dist/shared.js +71 -70
  132. package/package.json +3 -2
@@ -1,18 +1,18 @@
1
1
  import { UiOfferYesState } from './uiActions/uiOffers';
2
2
  import { WriteExecutionState, WriteProposalDeclineReason } from './writeProposals';
3
3
  /** What a reply is, as far as a waiting change is concerned (contract §3.3). */
4
- export type WriteReplyClass = "affirm" | "affirm_with_change" | "decline" | "decline_redirect" | "other";
4
+ export type WriteReplyClass = 'affirm' | 'affirm_with_change' | 'decline' | 'decline_redirect' | 'other';
5
5
  /** Where a prompt came from. Mirrors the sandbox's `writeReply.origin`. */
6
- export type WriteReplyOrigin = "typed" | "spoken" | "chip" | "host_queued" | "retry" | "proposal_result";
6
+ export type WriteReplyOrigin = 'typed' | 'spoken' | 'chip' | 'host_queued' | 'retry' | 'proposal_result';
7
7
  /** The kinds the sandbox accepts in `writeReply.kind`. */
8
- export type WriteReplyKind = "affirm" | "decline" | "other";
8
+ export type WriteReplyKind = 'affirm' | 'decline' | 'other';
9
9
  /** The `writeReply` a forwarded prompt carries in its body. */
10
10
  export interface WriteReplyTag {
11
11
  kind: WriteReplyKind;
12
12
  origin: WriteReplyOrigin;
13
13
  }
14
14
  /** The reasons the binder declines with. A subset of the client's own. */
15
- export type WriteReplyDeclineReason = Extract<WriteProposalDeclineReason, "corrected" | "user_declined" | "redirected">;
15
+ export type WriteReplyDeclineReason = Extract<WriteProposalDeclineReason, 'corrected' | 'user_declined' | 'redirected'>;
16
16
  /** A line the panel shows (and, in voice, speaks) through `tr()`. */
17
17
  export interface WriteReplyLine {
18
18
  readonly key: string;
@@ -30,9 +30,9 @@ export interface WriteReplyAnalysis {
30
30
  }
31
31
  /** Which text an action applies to. */
32
32
  export type WriteReplyText = {
33
- from: "utterance";
33
+ from: 'utterance';
34
34
  } | {
35
- from: "remainder";
35
+ from: 'remainder';
36
36
  value: string;
37
37
  };
38
38
  export type WriteReplyDecision =
@@ -43,7 +43,7 @@ export type WriteReplyDecision =
43
43
  * as it would have gone.
44
44
  */
45
45
  {
46
- action: "forward";
46
+ action: 'forward';
47
47
  text: WriteReplyText;
48
48
  declineAll: WriteReplyDeclineReason | null;
49
49
  writeReply: WriteReplyTag | null;
@@ -52,12 +52,12 @@ export type WriteReplyDecision =
52
52
  }
53
53
  /** Nothing is waiting: the ordinary send path (local commands, then the model). */
54
54
  | {
55
- action: "normal";
55
+ action: 'normal';
56
56
  writeReply: WriteReplyTag;
57
57
  }
58
58
  /** Answer in the panel. Nothing is sent and nothing is declined. */
59
59
  | {
60
- action: "local_reply";
60
+ action: 'local_reply';
61
61
  line: WriteReplyLine;
62
62
  values: {
63
63
  count: number;
@@ -68,7 +68,7 @@ export type WriteReplyDecision =
68
68
  * `declineAll` is set, await it first; otherwise the proposals stay live.
69
69
  */
70
70
  | {
71
- action: "local";
71
+ action: 'local';
72
72
  text: WriteReplyText;
73
73
  declineAll: WriteReplyDeclineReason | null;
74
74
  }
@@ -80,7 +80,7 @@ export type WriteReplyDecision =
80
80
  * a confirmation of anything.
81
81
  */
82
82
  | {
83
- action: "accept_offer";
83
+ action: 'accept_offer';
84
84
  };
85
85
  export interface WriteReplyDecisionInput {
86
86
  cls: WriteReplyClass;
@@ -2,7 +2,7 @@ import { WriteReplyDeclineReason, WriteReplyLine, WriteReplyTag } from './writeR
2
2
  import { UiOfferYesState } from './uiActions/uiOffers';
3
3
  import { SandboxWriteCapabilities, WriteExecutionState } from './writeProposals';
4
4
  /** Where a person's own reply came from. */
5
- export type WriteReplyPersonOrigin = "typed" | "spoken";
5
+ export type WriteReplyPersonOrigin = 'typed' | 'spoken';
6
6
  /**
7
7
  * What a bound send carries on its way to the model, once the binder has run.
8
8
  * The send path re-enters with it and never binds the same send twice.
@@ -32,7 +32,7 @@ export interface WriteReplyLiveState {
32
32
  export type WriteReplyPlan =
33
33
  /** Answer in the panel. Nothing is sent, nothing is declined. */
34
34
  {
35
- kind: "local_reply";
35
+ kind: 'local_reply';
36
36
  line: WriteReplyLine;
37
37
  values: {
38
38
  count: number;
@@ -43,14 +43,14 @@ export type WriteReplyPlan =
43
43
  * `commandText`. When it cannot run here, `fallback` is sent instead.
44
44
  */
45
45
  | {
46
- kind: "local";
46
+ kind: 'local';
47
47
  commandText: string;
48
48
  declineAll: WriteReplyDeclineReason | null;
49
49
  fallback: WriteReplyBound;
50
50
  }
51
51
  /** Await `declineAll` when set, then send `bound`. */
52
52
  | {
53
- kind: "send";
53
+ kind: 'send';
54
54
  declineAll: WriteReplyDeclineReason | null;
55
55
  bound: WriteReplyBound;
56
56
  }
@@ -60,7 +60,7 @@ export type WriteReplyPlan =
60
60
  * nothing is declined; navigation only.
61
61
  */
62
62
  | {
63
- kind: "accept_offer";
63
+ kind: 'accept_offer';
64
64
  /**
65
65
  * ★ BOFF-8867: the acceptance came through the multilingual assent row
66
66
  * (the words are not an English affirm). If the offer then cannot run, the
@@ -129,11 +129,11 @@ export interface WriteReplyTimers {
129
129
  * Resolves `settled` once every promise has settled (fulfilled or rejected),
130
130
  * or `timed_out` after `ms`, whichever comes first. Never rejects.
131
131
  */
132
- export declare function settleWithin(work: readonly Promise<unknown>[], ms: number, timers?: WriteReplyTimers): Promise<"settled" | "timed_out">;
132
+ export declare function settleWithin(work: readonly Promise<unknown>[], ms: number, timers?: WriteReplyTimers): Promise<'settled' | 'timed_out'>;
133
133
  /**
134
134
  * The sandbox's write mode for a prompt, from its own `/health`. Proposal
135
135
  * instructions need the v1 protocol as well as the mode, the same test as
136
136
  * `writeProposalsEnabledFor`: a sandbox with only one of them keeps the legacy
137
137
  * card, so its prompt must stay legacy too.
138
138
  */
139
- export declare function promptWriteApproval(capabilities: SandboxWriteCapabilities | null | undefined): "legacy" | "proposal-v1";
139
+ export declare function promptWriteApproval(capabilities: SandboxWriteCapabilities | null | undefined): 'legacy' | 'proposal-v1';
@@ -1,6 +1,6 @@
1
1
  import { ReactNode } from 'react';
2
2
  /** What the `/` route renders. */
3
- export type LandingGateDecision = 'loading' | 'home' | 'native-welcome' | 'landing';
3
+ export type LandingGateDecision = 'loading' | 'home' | 'native-welcome' | 'landing' | 'switch-handoff';
4
4
  export interface LandingGateInput {
5
5
  /** The auth provider is still settling (bridge handshake, hydration). */
6
6
  isLoading: boolean;
@@ -10,12 +10,27 @@ export interface LandingGateInput {
10
10
  isInstalledApp: boolean;
11
11
  /** Whether the shell supplied a native welcome page. */
12
12
  hasNativeWelcome: boolean;
13
+ /**
14
+ * The visit carries the product switcher's `?bf-switch=1` marker: a user
15
+ * signed in on another product just switched here.
16
+ */
17
+ isProductSwitchHandoff?: boolean;
13
18
  }
14
19
  /**
15
- * Pure decision for the `/` route. There is intentionally no "sso" outcome:
16
- * the landing gate never relays an anonymous visitor to the auth bridge.
20
+ * Pure decision for the `/` route. An anonymous visitor is never relayed to
21
+ * the auth bridge; only an explicit product-switch handoff in a browser starts
22
+ * SSO discovery ('switch-handoff'). Installed apps keep their welcome: they
23
+ * have no cross-origin relay.
17
24
  */
18
25
  export declare function resolveLandingGate(input: LandingGateInput): LandingGateDecision;
26
+ /**
27
+ * Start SSO discovery for a product-switch handoff. Removes the marker from
28
+ * the address bar first and uses the marker-free path as the relay's return
29
+ * target, so neither a successful return nor `?sso_failed=1` can re-trigger
30
+ * it. Returns whether the relay navigation was started; on `false` the caller
31
+ * renders the landing. Never throws.
32
+ */
33
+ export declare function startProductSwitchHandoff(): boolean;
19
34
  /**
20
35
  * Whether the active profile has an unexpired access token persisted in
21
36
  * storage — the profile token slot first, then microfe-auth's per-profile
@@ -1,63 +1,93 @@
1
1
  import { getProfileTokens as e, resolveActiveProfileId as t } from "../providers/shell/ProfileStorageManager.js";
2
2
  import { BrandedSplash as n } from "../../ui/branded-splash.js";
3
- import { getJwtExpiry as r } from "../providers/shell/authProvider/jwt.js";
4
- import { useAuth as i } from "../providers/shell/AuthProvider.js";
5
- import { MicrofrontendErrorBoundary as a } from "./MicrofrontendErrorBoundary.js";
6
- import { shouldShowNativeWelcome as o } from "../native/entry.js";
7
- import { Fragment as s, jsx as c } from "react/jsx-runtime";
8
- import { Navigate as l } from "react-router";
3
+ import { redirectToSSO as r } from "./SSORedirectGuard.js";
4
+ import { getJwtExpiry as i } from "../providers/shell/authProvider/jwt.js";
5
+ import { useAuth as a } from "../providers/shell/AuthProvider.js";
6
+ import { MicrofrontendErrorBoundary as o } from "./MicrofrontendErrorBoundary.js";
7
+ import { shouldShowNativeWelcome as s } from "../native/entry.js";
8
+ import { hasProductSwitchHandoff as c, stripProductSwitchHandoff as l } from "../navigation/productSwitchHandoff.js";
9
+ import { useEffect as u, useState as d } from "react";
10
+ import { Fragment as f, jsx as p } from "react/jsx-runtime";
11
+ import { Navigate as m, useLocation as h } from "react-router";
9
12
  //#region src/shared/components/LandingOrDashboardRedirect.tsx
10
- function u(e) {
11
- return e.isLoading ? "loading" : e.hasSession ? "home" : e.isInstalledApp && e.hasNativeWelcome ? "native-welcome" : "landing";
13
+ function g(e) {
14
+ return e.isLoading ? "loading" : e.hasSession ? "home" : e.isInstalledApp && e.hasNativeWelcome ? "native-welcome" : e.isProductSwitchHandoff && !e.isInstalledApp ? "switch-handoff" : "landing";
12
15
  }
13
- function d(e, t) {
16
+ function _() {
17
+ if (typeof window > "u") return !1;
18
+ try {
19
+ let e = l(window.location);
20
+ try {
21
+ window.history?.replaceState(window.history.state, "", e);
22
+ } catch {}
23
+ return r(e);
24
+ } catch {
25
+ return !1;
26
+ }
27
+ }
28
+ function v({ landing: e, loadingFallback: t, loadingMessage: r }) {
29
+ let [i, a] = d(!1);
30
+ return u(() => {
31
+ _() || a(!0);
32
+ }, []), i ? /* @__PURE__ */ p(o, {
33
+ loadingMessage: r,
34
+ children: e
35
+ }) : /* @__PURE__ */ p(f, { children: t ?? /* @__PURE__ */ p(n, {}) });
36
+ }
37
+ function y(e, t) {
14
38
  if (!e) return !1;
15
- let n = r(e);
39
+ let n = i(e);
16
40
  return n !== null && n > t;
17
41
  }
18
- function f(e) {
42
+ function b(e) {
19
43
  let t = localStorage.getItem(e ? `bf-p-${e}-auth-storage` : "auth-storage");
20
44
  if (!t) return null;
21
45
  let n = JSON.parse(t)?.state?.accessToken;
22
46
  return typeof n == "string" && n ? n : null;
23
47
  }
24
- function p(n = Date.now()) {
48
+ function x(n = Date.now()) {
25
49
  if (typeof window > "u") return !1;
26
50
  try {
27
51
  let r = t();
28
- return d(r ? e(r)?.accessToken : null, n) ? !0 : d(f(r), n);
52
+ return y(r ? e(r)?.accessToken : null, n) ? !0 : y(b(r), n);
29
53
  } catch {
30
54
  return !1;
31
55
  }
32
56
  }
33
- function m({ decision: e, homePath: t, landing: r, nativeWelcome: i, loadingFallback: o, loadingMessage: u }) {
57
+ function S({ decision: e, homePath: t, landing: r, nativeWelcome: i, loadingFallback: a, loadingMessage: s }) {
34
58
  switch (e) {
35
- case "loading": return /* @__PURE__ */ c(s, { children: o ?? /* @__PURE__ */ c(n, {}) });
36
- case "home": return /* @__PURE__ */ c(l, {
59
+ case "loading": return /* @__PURE__ */ p(f, { children: a ?? /* @__PURE__ */ p(n, {}) });
60
+ case "home": return /* @__PURE__ */ p(m, {
37
61
  to: t,
38
62
  replace: !0
39
63
  });
40
- case "native-welcome": return /* @__PURE__ */ c(a, {
41
- loadingMessage: u,
64
+ case "native-welcome": return /* @__PURE__ */ p(o, {
65
+ loadingMessage: s,
42
66
  children: i
43
67
  });
44
- case "landing": return /* @__PURE__ */ c(a, {
45
- loadingMessage: u,
68
+ case "switch-handoff": return /* @__PURE__ */ p(v, {
69
+ landing: r,
70
+ loadingFallback: a,
71
+ loadingMessage: s
72
+ });
73
+ case "landing": return /* @__PURE__ */ p(o, {
74
+ loadingMessage: s,
46
75
  children: r
47
76
  });
48
77
  }
49
78
  }
50
- function h(e) {
51
- let t = i();
52
- return /* @__PURE__ */ c(m, {
53
- decision: u({
79
+ function C(e) {
80
+ let t = a(), n = h();
81
+ return /* @__PURE__ */ p(S, {
82
+ decision: g({
54
83
  isLoading: t.isLoading,
55
- hasSession: !t.isLoading && (!!t.tokens?.accessToken || p()),
56
- isInstalledApp: o(),
57
- hasNativeWelcome: e.nativeWelcome !== void 0
84
+ hasSession: !t.isLoading && (!!t.tokens?.accessToken || x()),
85
+ isInstalledApp: s(),
86
+ hasNativeWelcome: e.nativeWelcome !== void 0,
87
+ isProductSwitchHandoff: c(n.search)
58
88
  }),
59
89
  ...e
60
90
  });
61
91
  }
62
92
  //#endregion
63
- export { m as LandingGateView, h as LandingOrDashboardRedirect, p as hasStoredValidSession, u as resolveLandingGate };
93
+ export { S as LandingGateView, C as LandingOrDashboardRedirect, x as hasStoredValidSession, g as resolveLandingGate, _ as startProductSwitchHandoff };
@@ -32,7 +32,8 @@ export { MAIN_CONTENT_ID, MainLandmark, PublicLayout, SkipToContentLink, focusSk
32
32
  export type { MainLandmarkProps, PublicLayoutProps, SkipTarget, SkipToContentLinkProps, } from './SkipToContent';
33
33
  export { DocsLink, useProductDocsOrigin, useProductDocsUrl, fetchRegistryDocsUrl, readRegistryDocsUrl, PUBLIC_PRODUCT_DOCS_URL_QUERY, } from './DocsLink';
34
34
  export type { DocsLinkProps, DocsRegistryClient, UseProductDocsOptions } from './DocsLink';
35
- export { LandingOrDashboardRedirect, LandingGateView, resolveLandingGate, hasStoredValidSession, } from './LandingOrDashboardRedirect';
35
+ export { LandingOrDashboardRedirect, LandingGateView, resolveLandingGate, hasStoredValidSession, startProductSwitchHandoff, } from './LandingOrDashboardRedirect';
36
+ export { PRODUCT_SWITCH_HANDOFF_PARAM, withProductSwitchHandoff, hasProductSwitchHandoff, stripProductSwitchHandoff, } from '../navigation/productSwitchHandoff';
36
37
  export type { LandingOrDashboardRedirectProps, LandingGateViewProps, LandingGateDecision, LandingGateInput, } from './LandingOrDashboardRedirect';
37
38
  export { AssistantWidget, ASSISTANT_WIDGET_TOGGLE_EVENT } from './assistantWidget/AssistantWidget';
38
39
  export type { AssistantWidgetProps, AssistantModeOption } from './assistantWidget/AssistantWidget';
@@ -5,7 +5,7 @@
5
5
  * when the search request failed; `detail` keeps the backend message for logs.
6
6
  */
7
7
  export declare class GlobalSearchError extends Error {
8
- readonly reason: "NO_WORKSPACE_CONTEXT" | "UNAVAILABLE";
8
+ readonly reason: 'NO_WORKSPACE_CONTEXT' | 'UNAVAILABLE';
9
9
  readonly detail: string;
10
- constructor(reason: "NO_WORKSPACE_CONTEXT" | "UNAVAILABLE", detail: string);
10
+ constructor(reason: 'NO_WORKSPACE_CONTEXT' | 'UNAVAILABLE', detail: string);
11
11
  }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Product-switch SSO handoff marker.
3
+ *
4
+ * The cross-product switcher sends a signed-in user to another product's app
5
+ * shell. That shell's public `/` route (`LandingOrDashboardRedirect`) does no
6
+ * SSO discovery for anonymous visitors, on purpose: a first-time visitor must
7
+ * see the marketing landing instead of being bounced through the auth relay
8
+ * (BOFF-6457 / 6482 / 6494). The target origin has no local session yet (each
9
+ * product lives on its own eTLD+1), so without a signal the switched user
10
+ * landed on the target's landing page, signed out.
11
+ *
12
+ * The switcher therefore appends this marker to the target URL. It states an
13
+ * explicit intent, like a "Sign in" CTA: "this visit comes from a signed-in
14
+ * product switch". The landing gate honours it by starting SSO discovery once,
15
+ * after stripping the marker so a failed relay (`?sso_failed=1`) falls back to
16
+ * the normal landing and can never loop.
17
+ *
18
+ * The marker carries no identity and grants nothing: the relay still needs a
19
+ * session at the central auth bridge, exactly as for a protected route.
20
+ *
21
+ * @module @burdenoff/fe-libs/shared/navigation/productSwitchHandoff
22
+ */
23
+ /** Query parameter the switcher appends to a target product URL. */
24
+ export declare const PRODUCT_SWITCH_HANDOFF_PARAM = "bf-switch";
25
+ /** Value of the marker. Any other value is ignored. */
26
+ export declare const PRODUCT_SWITCH_HANDOFF_VALUE = "1";
27
+ /**
28
+ * Append the handoff marker to an absolute http(s) product URL. Placeholder
29
+ * URLs (`#`, empty) and anything that does not parse as http(s) are returned
30
+ * unchanged, so a product without a configured URL keeps its current
31
+ * behaviour.
32
+ */
33
+ export declare function withProductSwitchHandoff(url: string): string;
34
+ /** Whether a location's query string carries the handoff marker. */
35
+ export declare function hasProductSwitchHandoff(search: string): boolean;
36
+ /**
37
+ * The same-origin path (pathname + query + hash) of a location with the
38
+ * handoff marker removed. Used as the SSO return path, so the relay's return
39
+ * trip (success or `?sso_failed=1`) never carries the marker again.
40
+ */
41
+ export declare function stripProductSwitchHandoff(location: {
42
+ pathname: string;
43
+ search: string;
44
+ hash: string;
45
+ }): string;
@@ -0,0 +1,27 @@
1
+ //#region src/shared/navigation/productSwitchHandoff.ts
2
+ var e = "bf-switch";
3
+ function t(t) {
4
+ if (!t || t === "#") return t;
5
+ let n;
6
+ try {
7
+ n = new URL(t);
8
+ } catch {
9
+ return t;
10
+ }
11
+ return n.protocol !== "https:" && n.protocol !== "http:" ? t : (n.searchParams.set(e, "1"), n.toString());
12
+ }
13
+ function n(t) {
14
+ try {
15
+ return new URLSearchParams(t).get(e) === "1";
16
+ } catch {
17
+ return !1;
18
+ }
19
+ }
20
+ function r(t) {
21
+ let n = new URLSearchParams(t.search);
22
+ n.delete(e);
23
+ let r = n.toString();
24
+ return `${t.pathname}${r ? `?${r}` : ""}${t.hash}`;
25
+ }
26
+ //#endregion
27
+ export { e as PRODUCT_SWITCH_HANDOFF_PARAM, n as hasProductSwitchHandoff, r as stripProductSwitchHandoff, t as withProductSwitchHandoff };
@@ -74,7 +74,7 @@ export declare function listUnsavedChanges(): UnsavedChange[];
74
74
  */
75
75
  export declare function useUnsavedChanges({ id, label, dirty }: UseUnsavedChangesOptions): void;
76
76
  /** Who started a navigation: the person (a link, the sidebar) or the assistant. */
77
- export type NavigationInitiator = "person" | "assistant";
77
+ export type NavigationInitiator = 'person' | 'assistant';
78
78
  /**
79
79
  * Should a navigation be refused for unsaved changes? Only one the ASSISTANT
80
80
  * started, and only while something is unsaved. The person's own tap is never
@@ -18,9 +18,9 @@ export { clearAuthSessionStorage, hasAuthGraphQLErrors, isAuthGraphQLError, isAu
18
18
  export type { GraphQLErrorLike, TokenRefreshConfig } from './authErrorHandling';
19
19
  export { BACKEND_ERROR_EVENT, CONNECTION_STATUS_EVENT, dispatchBackendErrorEvent, extractBackendError, isAbortError, isBackendErrorDisplay, isTransportError, markConnectionHealthy, shouldToastBackendError, } from './backendErrors';
20
20
  export type { BackendErrorDisplay, BackendErrorExtensions, ConnectionStatusDetail, ExtractBackendErrorOptions, GraphQLBackendErrorLike, } from './backendErrors';
21
- export { AppInitializer, useShellNavigate, useRegistryHelpers, } from './appHelpers';
21
+ export { AppInitializer, useShellNavigate, useRegistryHelpers } from './appHelpers';
22
22
  export type { AppInitializerProps } from './appHelpers';
23
- export { initializeLogger, setUserContext, clearUserContext, } from './loggerInit';
23
+ export { initializeLogger, setUserContext, clearUserContext } from './loggerInit';
24
24
  export type { InitLoggerOptions } from './loggerInit';
25
25
  export { setSSoCookie, getSSoCookie, clearSSoCookie, setShellSsoCookies, readShellSsoCookie, clearShellSsoCookies, isSharedSsoCookieDomain, isTrustedSsoOrigin, } from './authCookie';
26
26
  export type { ShellSsoCookieData } from './authCookie';
@@ -28,7 +28,7 @@ export { isAllowedRedirectUrl, replaceLocationWithAllowlist, assignLocationWithA
28
28
  export type { RedirectAllowlistOptions } from './redirectAllowlist';
29
29
  export { SSO_DEPOSITED_PARAM, beginSsoNavigation, isSsoNavigationPending, clearSsoNavigation, readSsoDepositState, markSsoDepositPending, markSsoDepositDone, clearSsoDepositState, shouldAttemptSsoDeposit, mintSsoSessionTokens, buildSsoDepositUrl, consumeSsoDepositMarker, } from './ssoDeposit';
30
30
  export type { MintedSsoTokens, MintSsoSessionResult, SsoDepositPayload, SsoDepositState, } from './ssoDeposit';
31
- export { createProfileScopedStorage, getProfileScopedKey, } from './profileScopedStorage';
31
+ export { createProfileScopedStorage, getProfileScopedKey } from './profileScopedStorage';
32
32
  export { QUOTA_EXHAUSTED_CODE, RESOURCE_CAP_EXCEEDED_CODE, STORAGE_QUOTA_EXCEEDED_CODE, UPGRADE_ERROR_CODES, isQuotaExhaustedError, isUpgradeError, extractUpgradeErrorExtensions, extractQuotaExhaustedExtensions, buildQuotaExhaustedMessage, } from './quotaErrors';
33
33
  export type { QuotaExhaustedExtensions, UpgradeErrorCode, UpgradeErrorExtensions, } from './quotaErrors';
34
34
  export * from './imageDownscale';
@@ -17,9 +17,10 @@ import { UPGRADE_PROMPT_EVENT as j, UpgradePromptModal as M, dispatchUpgradeProm
17
17
  import { UpgradeInlineBanner as P } from "./shared/components/UpgradeInlineBanner.js";
18
18
  import { DEFAULT_QUOTA_UPGRADE_COPY as F, QuotaUpgradeBridge as I, captureQuotaDialogOwners as L, claimQuotaDialog as R, dispatchProductQuotaExhausted as z, quotaEventKind as B, resolveQuotaUpgradeCopy as V, useQuotaDialogOwnership as H, useQuotaUpgradeBridge as U, withQuotaDialogOwnership as W } from "./shared/components/QuotaUpgradeBridge.js";
19
19
  import { DocsLink as G, PUBLIC_PRODUCT_DOCS_URL_QUERY as K, fetchRegistryDocsUrl as q, readRegistryDocsUrl as J, useProductDocsOrigin as Y, useProductDocsUrl as X } from "./shared/components/DocsLink.js";
20
- import { LandingGateView as Z, LandingOrDashboardRedirect as Q, hasStoredValidSession as $, resolveLandingGate as ee } from "./shared/components/LandingOrDashboardRedirect.js";
21
- import { useVoiceInput as te } from "./shared/components/assistantWidget/useVoiceInput.js";
22
- import { ASSISTANT_WIDGET_TOGGLE_EVENT as ne, AssistantWidget as re } from "./shared/components/assistantWidget/AssistantWidget.js";
23
- import { Markdown as ie } from "./shared/components/Markdown.js";
24
- import { DesktopUpdateToast as ae } from "./shared/components/DesktopUpdateToast.js";
25
- export { ne as ASSISTANT_WIDGET_TOGGLE_EVENT, v as AccessDenied, D as AppErrorBoundary, re as AssistantWidget, T as ConditionalShell, O as ContextConversationWidget, F as DEFAULT_QUOTA_UPGRADE_COPY, ae as DesktopUpdateToast, G as DocsLink, f as ErrorBoundary, b as ErrorFallback, k as KeyboardHelpDialogWrapper, Z as LandingGateView, Q as LandingOrDashboardRedirect, x as LoadingFallback, o as MAIN_CONTENT_ID, s as MainLandmark, ie as Markdown, w as MicrofrontendErrorBoundary, K as PUBLIC_PRODUCT_DOCS_URL_QUERY, E as PWAInstallBanner, S as PageLoadingFallback, h as PermissionButton, y as PermissionDenied, g as PermissionGate, _ as PermissionLink, c as PublicLayout, A as QuotaMeter, I as QuotaUpgradeBridge, p as RequireAuth, m as RequireGuest, e as SSORedirectSpinner, C as SectionLoadingFallback, l as SkipToContentLink, j as UPGRADE_PROMPT_EVENT, P as UpgradeInlineBanner, M as UpgradePromptModal, L as captureQuotaDialogOwners, t as checkRemoteSLO, n as checkSLO, R as claimQuotaDialog, r as clearLocalAuthState, z as dispatchProductQuotaExhausted, N as dispatchUpgradePrompt, q as fetchRegistryDocsUrl, u as focusSkipTarget, i as getSSORedirectUrl, $ as hasStoredValidSession, B as quotaEventKind, J as readRegistryDocsUrl, a as redirectToSSO, ee as resolveLandingGate, V as resolveQuotaUpgradeCopy, d as useInsideMainLandmark, Y as useProductDocsOrigin, X as useProductDocsUrl, H as useQuotaDialogOwnership, U as useQuotaUpgradeBridge, te as useVoiceInput, W as withQuotaDialogOwnership };
20
+ import { PRODUCT_SWITCH_HANDOFF_PARAM as Z, hasProductSwitchHandoff as Q, stripProductSwitchHandoff as $, withProductSwitchHandoff as ee } from "./shared/navigation/productSwitchHandoff.js";
21
+ import { LandingGateView as te, LandingOrDashboardRedirect as ne, hasStoredValidSession as re, resolveLandingGate as ie, startProductSwitchHandoff as ae } from "./shared/components/LandingOrDashboardRedirect.js";
22
+ import { useVoiceInput as oe } from "./shared/components/assistantWidget/useVoiceInput.js";
23
+ import { ASSISTANT_WIDGET_TOGGLE_EVENT as se, AssistantWidget as ce } from "./shared/components/assistantWidget/AssistantWidget.js";
24
+ import { Markdown as le } from "./shared/components/Markdown.js";
25
+ import { DesktopUpdateToast as ue } from "./shared/components/DesktopUpdateToast.js";
26
+ export { se as ASSISTANT_WIDGET_TOGGLE_EVENT, v as AccessDenied, D as AppErrorBoundary, ce as AssistantWidget, T as ConditionalShell, O as ContextConversationWidget, F as DEFAULT_QUOTA_UPGRADE_COPY, ue as DesktopUpdateToast, G as DocsLink, f as ErrorBoundary, b as ErrorFallback, k as KeyboardHelpDialogWrapper, te as LandingGateView, ne as LandingOrDashboardRedirect, x as LoadingFallback, o as MAIN_CONTENT_ID, s as MainLandmark, le as Markdown, w as MicrofrontendErrorBoundary, Z as PRODUCT_SWITCH_HANDOFF_PARAM, K as PUBLIC_PRODUCT_DOCS_URL_QUERY, E as PWAInstallBanner, S as PageLoadingFallback, h as PermissionButton, y as PermissionDenied, g as PermissionGate, _ as PermissionLink, c as PublicLayout, A as QuotaMeter, I as QuotaUpgradeBridge, p as RequireAuth, m as RequireGuest, e as SSORedirectSpinner, C as SectionLoadingFallback, l as SkipToContentLink, j as UPGRADE_PROMPT_EVENT, P as UpgradeInlineBanner, M as UpgradePromptModal, L as captureQuotaDialogOwners, t as checkRemoteSLO, n as checkSLO, R as claimQuotaDialog, r as clearLocalAuthState, z as dispatchProductQuotaExhausted, N as dispatchUpgradePrompt, q as fetchRegistryDocsUrl, u as focusSkipTarget, i as getSSORedirectUrl, Q as hasProductSwitchHandoff, re as hasStoredValidSession, B as quotaEventKind, J as readRegistryDocsUrl, a as redirectToSSO, ie as resolveLandingGate, V as resolveQuotaUpgradeCopy, ae as startProductSwitchHandoff, $ as stripProductSwitchHandoff, d as useInsideMainLandmark, Y as useProductDocsOrigin, X as useProductDocsUrl, H as useQuotaDialogOwnership, U as useQuotaUpgradeBridge, oe as useVoiceInput, ee as withProductSwitchHandoff, W as withQuotaDialogOwnership };