@meistrari/chat-nuxt 3.12.1 → 3.13.0-rc.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.
package/dist/module.d.mts CHANGED
@@ -13,6 +13,20 @@ interface ChatNuxtModuleOptions {
13
13
  * required runtime config keys are unset.
14
14
  */
15
15
  validateConfig?: ChatNuxtConfigValidationMode;
16
+ /**
17
+ * Path, relative to `srcDir`, of a module default-exporting the host app's
18
+ * auth bridge built with `defineChatAuth()` (from `@meistrari/chat-nuxt/auth`).
19
+ * Setting it switches `#chat-auth` to the host implementation and lifts the
20
+ * `@meistrari/auth-nuxt` module requirement.
21
+ */
22
+ authComposable?: string;
23
+ /**
24
+ * Name of the cookie holding the bearer token the server proxy routes
25
+ * forward to the chat-api. Only read when `authComposable` is set; without
26
+ * it the proxies keep relying on `event.context.auth` populated by
27
+ * `@meistrari/auth-nuxt`.
28
+ */
29
+ authTokenCookie?: string;
16
30
  }
17
31
  declare const _default: any;
18
32
 
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
3
  "configKey": "chatNuxt",
4
- "version": "3.12.1-rc.0",
4
+ "version": "3.13.0-rc.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
package/dist/module.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { existsSync, readFileSync, mkdirSync, symlinkSync } from 'node:fs';
2
2
  import { createRequire } from 'node:module';
3
- import { join, dirname } from 'node:path';
3
+ import { join, dirname, isAbsolute } from 'node:path';
4
4
  import { defineNuxtModule, createResolver, addTemplate, addTypeTemplate, addPlugin, addImportsDir, addComponent, addComponentsDir } from 'nuxt/kit';
5
5
  import { TOOL_ICON_SAFELIST } from '../dist/runtime/messages/tool-registry.js';
6
6
  export { ChatMessageStatus } from '../dist/runtime/messages/composables/chat-message-terminal.js';
@@ -193,7 +193,33 @@ function resolveChatAuthMode(runtimeConfig) {
193
193
  const telaAuth = publicConfig?.telaAuth;
194
194
  return telaAuth?.application?.enabled ? "application" : "first-party";
195
195
  }
196
- function buildChatAuthTemplate(mode) {
196
+ const HOST_AUTH_COMPOSABLE_EXTENSIONS = ["", ".ts", ".mts", ".js", ".mjs"];
197
+ function resolveHostAuthComposable(srcDir, authComposable) {
198
+ const base = isAbsolute(authComposable) ? authComposable : join(srcDir, authComposable);
199
+ for (const extension of HOST_AUTH_COMPOSABLE_EXTENSIONS) {
200
+ const candidate = `${base}${extension}`;
201
+ if (existsSync(candidate)) {
202
+ return candidate;
203
+ }
204
+ }
205
+ throw new Error(
206
+ `[@meistrari/chat-nuxt] authComposable not found: ${base}
207
+ Create it with:
208
+
209
+ import { defineChatAuth } from '@meistrari/chat-nuxt/auth'
210
+
211
+ export default defineChatAuth(() => ({
212
+ user, activeOrganization, logout, getToken, getAvailableOrganizations, switchOrganization,
213
+ }))
214
+
215
+ See docs/guides/host-auth.md in @meistrari/chat-nuxt.`
216
+ );
217
+ }
218
+ function buildChatAuthTemplate(mode, hostAuthComposablePath) {
219
+ if (mode === "host") {
220
+ return `export { default as useChatAuth } from ${JSON.stringify((hostAuthComposablePath ?? "").replace(/\\/g, "/"))}
221
+ `;
222
+ }
197
223
  if (mode === "application") {
198
224
  return `
199
225
  import { useTelaApplicationAuth } from '#imports'
@@ -333,10 +359,11 @@ const module$1 = defineNuxtModule({
333
359
  validateConfig: false
334
360
  },
335
361
  setup(options, nuxt) {
362
+ const hostAuthComposablePath = options.authComposable ? resolveHostAuthComposable(nuxt.options.srcDir, options.authComposable) : void 0;
336
363
  const hasAuthModule = (nuxt.options.modules ?? []).some(isAuthModuleEntry);
337
- if (!hasAuthModule) {
364
+ if (!hasAuthModule && !hostAuthComposablePath) {
338
365
  throw new Error(
339
- '[@meistrari/chat-nuxt] Missing required module "@meistrari/auth-nuxt". Install and enable it so chat auth composables and event.context.auth are available.'
366
+ `[@meistrari/chat-nuxt] Missing required module "@meistrari/auth-nuxt". Install and enable it so chat auth composables and event.context.auth are available, or set chatNuxt.authComposable to provide the host app's own auth bridge.`
340
367
  );
341
368
  }
342
369
  ensureIconifyPackages(nuxt.options.rootDir);
@@ -356,10 +383,14 @@ const module$1 = defineNuxtModule({
356
383
  );
357
384
  const telaBuildPath = resolveTelaBuildLayer();
358
385
  const runtimeAliases = resolveRuntimeAliases(telaBuildPath);
359
- const chatAuthMode = resolveChatAuthMode(nuxt.options.runtimeConfig);
386
+ const chatAuthMode = hostAuthComposablePath ? "host" : resolveChatAuthMode(nuxt.options.runtimeConfig);
387
+ console.info(
388
+ { mode: chatAuthMode, ...options.authComposable ? { authComposable: options.authComposable } : {} },
389
+ "[@meistrari/chat-nuxt] auth bridge resolved"
390
+ );
360
391
  const chatAuthTemplate = addTemplate({
361
392
  filename: "chat-nuxt/auth.mjs",
362
- getContents: () => buildChatAuthTemplate(chatAuthMode)
393
+ getContents: () => buildChatAuthTemplate(chatAuthMode, hostAuthComposablePath)
363
394
  });
364
395
  const chatAuthTypeTemplate = addTypeTemplate({
365
396
  filename: "chat-nuxt/chat-auth.d.ts",
@@ -412,8 +443,14 @@ const module$1 = defineNuxtModule({
412
443
  rc.chatNuxt = {
413
444
  chatApiUrl: existingChatNuxtRuntimeConfig?.chatApiUrl || rc.chatApiUrl,
414
445
  source: options.source || existingChatNuxtRuntimeConfig?.source,
415
- clientVersion: _chatNuxtPackageVersion
446
+ clientVersion: _chatNuxtPackageVersion,
447
+ authTokenCookie: hostAuthComposablePath ? options.authTokenCookie || existingChatNuxtRuntimeConfig?.authTokenCookie : void 0
416
448
  };
449
+ if (hostAuthComposablePath && !rc.chatNuxt.authTokenCookie) {
450
+ console.warn(
451
+ "[@meistrari/chat-nuxt] authComposable is set but authTokenCookie is not. Server proxy routes will only authenticate if the host populates event.context.auth.token through its own server middleware."
452
+ );
453
+ }
417
454
  validateRuntimeConfig(rc, options.validateConfig ?? false);
418
455
  nuxt.options.css = nuxt.options.css || [];
419
456
  for (const css of [
@@ -427,6 +464,14 @@ const module$1 = defineNuxtModule({
427
464
  }
428
465
  addPlugin(join(runtimeDir, "plugins/markstream"));
429
466
  addImportsDir(FEATURE_DIRS.map((feature) => join(runtimeDir, feature, "composables")));
467
+ const importsExtendNuxt = nuxt;
468
+ importsExtendNuxt.hook("imports:extend", (imports) => {
469
+ for (const entry of imports) {
470
+ if (entry.from?.startsWith(runtimeDir)) {
471
+ entry.priority ||= -100;
472
+ }
473
+ }
474
+ });
430
475
  addComponent({
431
476
  name: "MeistrariChatEmbed",
432
477
  filePath: join(runtimeDir, "embed/components/meistrari-chat-embed.vue"),
@@ -0,0 +1,37 @@
1
+ import type { Ref } from 'vue';
2
+ export type ChatAuthUser = {
3
+ id: string;
4
+ email?: string | null;
5
+ name?: string | null;
6
+ image?: string | null;
7
+ };
8
+ export type ChatAuthMemberUser = {
9
+ name: string;
10
+ email: string;
11
+ image?: string;
12
+ };
13
+ export type ChatAuthMember = {
14
+ id: string;
15
+ userId: string;
16
+ user: ChatAuthMemberUser;
17
+ };
18
+ export type ChatAuthOrganization = {
19
+ id: string;
20
+ name?: string;
21
+ logo?: string | null;
22
+ members?: ChatAuthMember[];
23
+ };
24
+ export type ChatAuthBridge = {
25
+ user: Ref<ChatAuthUser | null>;
26
+ activeOrganization: Ref<ChatAuthOrganization | null>;
27
+ logout: () => Promise<void>;
28
+ getToken: () => Promise<string | null | undefined>;
29
+ getAvailableOrganizations: () => Promise<ChatAuthOrganization[]>;
30
+ switchOrganization: (organizationId: string) => Promise<void>;
31
+ };
32
+ /**
33
+ * Identity helper that types a host app's auth bridge against the `#chat-auth`
34
+ * contract at the definition site. Default-export the result from the file
35
+ * referenced by the `chatNuxt.authComposable` module option.
36
+ */
37
+ export declare function defineChatAuth(bridge: () => ChatAuthBridge): () => ChatAuthBridge;
@@ -0,0 +1,3 @@
1
+ export function defineChatAuth(bridge) {
2
+ return bridge;
3
+ }
@@ -1,6 +1,7 @@
1
1
  <script setup>
2
2
  import { useChatAuth } from "#chat-auth";
3
3
  import { useBreakpoints } from "@vueuse/core";
4
+ import { useCitationPanel } from "../../citations/composables/citation-panel";
4
5
  import { exportConversationToMarkdown } from "../../conversations/export";
5
6
  import { CHAT_MOBILE_BREAKPOINT } from "../../shared/breakpoints";
6
7
  import ChatMobileFilePreview from "./mobile/chat-mobile-file-preview.vue";
@@ -1,15 +1,40 @@
1
1
  import { getCookie } from "h3";
2
2
  import { useRuntimeConfig } from "nitropack/runtime";
3
+ import { parseAllowedEmailDomains } from "./domain-allow.js";
4
+ import { logger } from "./logger.js";
3
5
  const DEFAULT_FIRST_PARTY_JWT_COOKIE_NAME = "tela-jwt";
4
6
  function resolveFirstPartyJwtCookieName(event) {
5
7
  const config = useRuntimeConfig(event);
6
8
  return config.public?.telaAuth?.jwtCookieName || DEFAULT_FIRST_PARTY_JWT_COOKIE_NAME;
7
9
  }
10
+ function resolveHostAuthTokenCookieName(event) {
11
+ const config = useRuntimeConfig(event);
12
+ return config.chatNuxt?.authTokenCookie || void 0;
13
+ }
14
+ function hasEmailDomainRestrictions(event) {
15
+ const config = useRuntimeConfig(event);
16
+ return parseAllowedEmailDomains(config.auth?.allowedEmailDomains).length > 0;
17
+ }
8
18
  export function resolveAuthToken(event) {
9
19
  const auth = event.context.auth;
10
20
  if (auth?.token) {
11
21
  return auth.token;
12
22
  }
23
+ const hostCookieName = resolveHostAuthTokenCookieName(event);
24
+ if (hostCookieName) {
25
+ if (hasEmailDomainRestrictions(event)) {
26
+ logger.warn(
27
+ { cookie: hostCookieName },
28
+ "authTokenCookie ignored: auth.allowedEmailDomains is set and the host cookie carries no user context for domain validation"
29
+ );
30
+ return void 0;
31
+ }
32
+ const token2 = getCookie(event, hostCookieName);
33
+ if (token2 && auth) {
34
+ auth.token = token2;
35
+ }
36
+ return token2 || void 0;
37
+ }
13
38
  if (!auth?.user || !auth.workspace) {
14
39
  return void 0;
15
40
  }
@@ -1,3 +1,5 @@
1
+ // Keep these types in sync with ../auth/define.ts — the exported ChatAuthBridge
2
+ // there is the same contract host apps implement via defineChatAuth().
1
3
  declare module '#chat-auth' {
2
4
  type ChatAuthUser = {
3
5
  id: string
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
- "version": "3.12.1",
3
+ "version": "3.13.0-rc.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
7
7
  "types": "./dist/types.d.mts",
8
8
  "import": "./dist/module.mjs"
9
9
  },
10
+ "./auth": {
11
+ "types": "./dist/runtime/auth/define.d.ts",
12
+ "import": "./dist/runtime/auth/define.js"
13
+ },
10
14
  "./components/MeistrariChatEmbed": {
11
15
  "types": "./dist/runtime/embed/components/meistrari-chat-embed.vue.d.ts",
12
16
  "import": "./dist/runtime/embed/components/meistrari-chat-embed.vue"