Lets an unauthenticated viewer of a published share ask an AI scoped strictly to that share's page tree. The authenticated agent is untouched; the security boundary is the tool scope (no identity), and nothing is persisted. Server: - workspace toggle settings.ai.publicShareAssistant (default off) + optional settings.ai.provider.publicShareChatModel (cheap model id; reuses the chat driver/baseUrl/key). getChatModel(workspaceId, override) substitutes only the model id, falling back to chatModel. - POST /api/shares/ai/stream (@Public, SSE). Guardrail funnel, each failing before streaming: toggle off -> 404; share missing/wrong-workspace/sharing off -> 404; pageId not in share tree -> 404; provider unconfigured -> 503; per-IP (5/min) and per-workspace (300/h, IP-independent) rate limits -> 429. Uniform 404s never confirm a private page's existence. - forShare read-only in-process toolset: searchSharePages (existing shareId FTS branch, no spaceId/userId), getSharePage (getShareForPage gate + share.id check, content via the public sanitizer), listSharePages. No write/ comment/history/cross-space/external-MCP tools. - Locked share system prompt + immutable safety block; stepCountIs(5). - /shares/page-info exposes an aiAssistant flag (gated behind isSharingAllowed). Client: an ephemeral, text-only Ask-AI widget on the public shared page, shown only when the flag is set; useChat -> /api/shares/ai/stream, credentials omit. Admin toggle + model field in Settings -> AI. Also adds a jest moduleNameMapper for src/-rooted imports (fixes pre-existing unresolvable specs; additive). Implements docs/public-share-assistant-plan.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
18 lines
759 B
TypeScript
18 lines
759 B
TypeScript
import { Module } from '@nestjs/common';
|
|
import { ShareController } from './share.controller';
|
|
import { ShareService } from './share.service';
|
|
import { TokenModule } from '../auth/token.module';
|
|
import { ShareSeoController } from './share-seo.controller';
|
|
import { TransclusionModule } from '../page/transclusion/transclusion.module';
|
|
import { AiModule } from '../../integrations/ai/ai.module';
|
|
|
|
@Module({
|
|
// AiModule (AiSettingsService) is used by the page-info route to surface
|
|
// whether the anonymous public-share assistant is enabled for the workspace.
|
|
imports: [TokenModule, TransclusionModule, AiModule],
|
|
controllers: [ShareController, ShareSeoController],
|
|
providers: [ShareService],
|
|
exports: [ShareService],
|
|
})
|
|
export class ShareModule {}
|