@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 +14 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +52 -7
- package/dist/runtime/auth/define.d.ts +37 -0
- package/dist/runtime/auth/define.js +3 -0
- package/dist/runtime/embed/components/chat-embed-inner.vue +1 -0
- package/dist/runtime/server/utils/auth-token.js +25 -0
- package/dist/runtime/types/chat-auth.d.ts +2 -0
- package/package.json +5 -1
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
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
|
-
|
|
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
|
-
|
|
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;
|
|
@@ -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
|
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meistrari/chat-nuxt",
|
|
3
|
-
"version": "3.
|
|
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"
|