@meistrari/chat-nuxt 4.1.0-rc.2 → 4.1.0-rc.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.
package/README.md CHANGED
@@ -45,6 +45,8 @@ bunx --bun typedoc --entryPoints typedoc.ts --out /tmp/chat-nuxt-api --skipError
45
45
 
46
46
  The table below is a quick index for reading in-repo. **When you change a prop, update its JSDoc and this row together.**
47
47
 
48
+ The embed automatically sets the browser tab title to the active conversation title and synchronizes its ID to `?conversationId=` using router replacement, preserving other query parameters and the URL fragment. Starting a new conversation removes the conversation parameter. Opening or reloading that URL restores the conversation; existing `?conversation=` links are also accepted and converted to `?conversationId=`. Explicit `conversationId` and `initialConversationId` props take precedence over the URL on mount. Without a conversation title, the host application controls the tab title.
49
+
48
50
  ### `<MeistrariChatEmbed>` props
49
51
 
50
52
  Declared in `src/runtime/embed/types.ts`; prop, feature-flag, and event payload types are importable from the package root or `@meistrari/chat-nuxt/types/embed`.
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
3
  "configKey": "chatNuxt",
4
- "version": "4.1.0-rc.2",
4
+ "version": "4.1.0-rc.3",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
@@ -13,7 +13,8 @@ import ChatMessageInput from "../../messages/components/chat-message-input.vue";
13
13
  import { normalizeConversationId } from "../../conversations/scope";
14
14
  import { resolveChatFeatures } from "../feature-config";
15
15
  import { resolveConversationCreator } from "../../conversations/creator";
16
- import { buildConversationShareUrl } from "../conversation-share-url";
16
+ import { buildConversationShareUrl, getSharedConversationId } from "../conversation-share-url";
17
+ import { useConversationBrowserState } from "../composables/conversation-browser-state";
17
18
  import {
18
19
  resolveTelaAgentInputs,
19
20
  useChat
@@ -133,7 +134,7 @@ const {
133
134
  closePreview
134
135
  } = useFilePreviewPanel();
135
136
  const { isOpen: isCitationPanelOpen } = useCitationPanel();
136
- const sharedConversationId = typeof route.query.conversation === "string" ? route.query.conversation : null;
137
+ const sharedConversationId = getSharedConversationId(route.query);
137
138
  const activeConversationId = ref(
138
139
  normalizeConversationId(props.conversationId) ?? normalizeConversationId(props.initialConversationId) ?? normalizeConversationId(sharedConversationId)
139
140
  );
@@ -492,6 +493,11 @@ function dismissOutdatedBanner() {
492
493
  }
493
494
  }
494
495
  const optimisticTitle = ref(null);
496
+ useConversationBrowserState(activeConversationId, computed(() => {
497
+ if (currentConversation.value?.id !== activeConversationId.value)
498
+ return null;
499
+ return optimisticTitle.value ?? currentConversation.value?.title ?? null;
500
+ }));
495
501
  const displayTitle = computed(() => {
496
502
  if (optimisticTitle.value !== null)
497
503
  return optimisticTitle.value;
@@ -0,0 +1,2 @@
1
+ import type { Ref } from 'vue';
2
+ export declare function useConversationBrowserState(conversationId: Ref<string | null>, title: Ref<string | null>): void;
@@ -0,0 +1,18 @@
1
+ export function useConversationBrowserState(conversationId, title) {
2
+ const route = useRoute();
3
+ const router = useRouter();
4
+ useHead(computed(() => title.value ? { title: title.value } : {}));
5
+ onMounted(() => {
6
+ watch(conversationId, async (id) => {
7
+ if (route.query.conversationId === (id ?? void 0) && route.query.conversation === void 0)
8
+ return;
9
+ const query = { ...route.query };
10
+ delete query.conversation;
11
+ if (id)
12
+ query.conversationId = id;
13
+ else
14
+ delete query.conversationId;
15
+ await router.replace({ path: route.path, query, hash: route.hash });
16
+ }, { immediate: true });
17
+ });
18
+ }
@@ -1 +1,2 @@
1
+ export declare function getSharedConversationId(query: Record<string, unknown>): string | null;
1
2
  export declare function buildConversationShareUrl(currentHref: string, conversationId: string): string;
@@ -1,5 +1,10 @@
1
+ import { normalizeConversationId } from "../conversations/scope.js";
2
+ export function getSharedConversationId(query) {
3
+ return normalizeConversationId(typeof query.conversationId === "string" ? query.conversationId : null) ?? normalizeConversationId(typeof query.conversation === "string" ? query.conversation : null);
4
+ }
1
5
  export function buildConversationShareUrl(currentHref, conversationId) {
2
6
  const shareUrl = new URL(currentHref);
3
- shareUrl.searchParams.set("conversation", conversationId);
7
+ shareUrl.searchParams.delete("conversation");
8
+ shareUrl.searchParams.set("conversationId", conversationId);
4
9
  return shareUrl.href;
5
10
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
- "version": "4.1.0-rc.2",
3
+ "version": "4.1.0-rc.3",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {