ruflo 3.42.2 → 3.42.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 +422 -422
- package/bin/ruflo.js +77 -77
- package/package.json +117 -117
- package/src/chat-ui/Dockerfile +25 -25
- package/src/chat-ui/patch-mcp-url-safety.sh +28 -28
- package/src/config/config.example.json +76 -76
- package/src/mcp-bridge/Dockerfile +47 -47
- package/src/mcp-bridge/index.js +1780 -1780
- package/src/mcp-bridge/mcp-stdio-kernel.js +159 -159
- package/src/mcp-bridge/package.json +17 -17
- package/src/mcp-bridge/test-harness.js +470 -470
- package/src/mcp-bridge/test-runtime-security.mjs +208 -208
- package/src/mcp-bridge/test-security-lock.js +121 -121
- package/src/nginx/Dockerfile +10 -10
- package/src/nginx/nginx.conf +67 -67
- package/src/nginx/static/favicon-dark.svg +4 -4
- package/src/nginx/static/favicon.svg +4 -4
- package/src/nginx/static/icon.svg +5 -5
- package/src/nginx/static/logo.svg +9 -9
- package/src/nginx/static/manifest.json +22 -22
- package/src/nginx/static/welcome.js +184 -184
- package/src/ruvocal/.claude/skills/add-model-descriptions/SKILL.md +73 -73
- package/src/ruvocal/.devcontainer/Dockerfile +9 -9
- package/src/ruvocal/.devcontainer/devcontainer.json +36 -36
- package/src/ruvocal/.dockerignore +16 -16
- package/src/ruvocal/.eslintignore +13 -13
- package/src/ruvocal/.eslintrc.cjs +45 -45
- package/src/ruvocal/.gcloudignore +18 -18
- package/src/ruvocal/.github/ISSUE_TEMPLATE/bug-report--chat-ui-.md +43 -43
- package/src/ruvocal/.github/ISSUE_TEMPLATE/config-support.md +9 -9
- package/src/ruvocal/.github/ISSUE_TEMPLATE/feature-request--chat-ui-.md +17 -17
- package/src/ruvocal/.github/ISSUE_TEMPLATE/huggingchat.md +11 -11
- package/src/ruvocal/.github/release.yml +16 -16
- package/src/ruvocal/.github/workflows/build-docs.yml +18 -18
- package/src/ruvocal/.github/workflows/build-image.yml +142 -142
- package/src/ruvocal/.github/workflows/build-pr-docs.yml +20 -20
- package/src/ruvocal/.github/workflows/deploy-dev.yml +63 -63
- package/src/ruvocal/.github/workflows/deploy-prod.yml +78 -78
- package/src/ruvocal/.github/workflows/lint-and-test.yml +84 -84
- package/src/ruvocal/.github/workflows/slugify.yaml +72 -72
- package/src/ruvocal/.github/workflows/trufflehog.yml +17 -17
- package/src/ruvocal/.github/workflows/upload-pr-documentation.yml +16 -16
- package/src/ruvocal/.husky/lint-stage-config.js +4 -4
- package/src/ruvocal/.husky/pre-commit +2 -2
- package/src/ruvocal/.prettierignore +14 -14
- package/src/ruvocal/.prettierrc +7 -7
- package/src/ruvocal/CLAUDE.md +126 -126
- package/src/ruvocal/Dockerfile +96 -96
- package/src/ruvocal/LICENSE +202 -202
- package/src/ruvocal/PRIVACY.md +41 -41
- package/src/ruvocal/README.md +164 -164
- package/src/ruvocal/chart/Chart.yaml +5 -5
- package/src/ruvocal/chart/env/dev.yaml +260 -260
- package/src/ruvocal/chart/env/prod.yaml +273 -273
- package/src/ruvocal/chart/templates/_helpers.tpl +22 -22
- package/src/ruvocal/chart/templates/config.yaml +10 -10
- package/src/ruvocal/chart/templates/deployment.yaml +81 -81
- package/src/ruvocal/chart/templates/hpa.yaml +45 -45
- package/src/ruvocal/chart/templates/infisical.yaml +24 -24
- package/src/ruvocal/chart/templates/ingress-internal.yaml +32 -32
- package/src/ruvocal/chart/templates/ingress.yaml +32 -32
- package/src/ruvocal/chart/templates/network-policy.yaml +36 -36
- package/src/ruvocal/chart/templates/service-account.yaml +13 -13
- package/src/ruvocal/chart/templates/service-monitor.yaml +17 -17
- package/src/ruvocal/chart/templates/service.yaml +21 -21
- package/src/ruvocal/chart/values.yaml +73 -73
- package/src/ruvocal/cloudbuild.yaml +68 -68
- package/src/ruvocal/config/branding.env.example +19 -19
- package/src/ruvocal/docker-compose.yml +21 -21
- package/src/ruvocal/docs/adr/ADR-029-HUGGINGFACE-CHAT-UI-CLOUD-RUN.md +1236 -1236
- package/src/ruvocal/docs/adr/ADR-033-RUVECTOR-RUFLO-MCP-INTEGRATION.md +111 -111
- package/src/ruvocal/docs/adr/ADR-034-OPTIONAL-MCP-BACKENDS.md +117 -117
- package/src/ruvocal/docs/adr/ADR-035-MCP-TOOL-GROUPS.md +186 -186
- package/src/ruvocal/docs/adr/ADR-037-AUTOPILOT-CHAT-MODE.md +1500 -1500
- package/src/ruvocal/docs/adr/ADR-038-RUVOCAL-FORK.md +286 -286
- package/src/ruvocal/docs/source/_toctree.yml +30 -30
- package/src/ruvocal/docs/source/configuration/common-issues.md +38 -38
- package/src/ruvocal/docs/source/configuration/llm-router.md +105 -105
- package/src/ruvocal/docs/source/configuration/mcp-tools.md +84 -84
- package/src/ruvocal/docs/source/configuration/metrics.md +9 -9
- package/src/ruvocal/docs/source/configuration/open-id.md +57 -57
- package/src/ruvocal/docs/source/configuration/overview.md +89 -89
- package/src/ruvocal/docs/source/configuration/theming.md +20 -20
- package/src/ruvocal/docs/source/developing/architecture.md +48 -48
- package/src/ruvocal/docs/source/index.md +53 -53
- package/src/ruvocal/docs/source/installation/docker.md +43 -43
- package/src/ruvocal/docs/source/installation/helm.md +43 -43
- package/src/ruvocal/docs/source/installation/local.md +62 -62
- package/src/ruvocal/entrypoint.sh +18 -18
- package/src/ruvocal/mcp-bridge/Dockerfile +47 -47
- package/src/ruvocal/mcp-bridge/cloudbuild.yaml +49 -49
- package/src/ruvocal/mcp-bridge/index.js +1995 -1995
- package/src/ruvocal/mcp-bridge/mcp-stdio-kernel.js +159 -159
- package/src/ruvocal/mcp-bridge/package-lock.json +762 -762
- package/src/ruvocal/mcp-bridge/package.json +17 -17
- package/src/ruvocal/mcp-bridge/test-harness.js +470 -470
- package/src/ruvocal/package-lock.json +11741 -11741
- package/src/ruvocal/package.json +121 -121
- package/src/ruvocal/postcss.config.js +6 -6
- package/src/ruvocal/rvf.manifest.json +204 -204
- package/src/ruvocal/scripts/config.ts +64 -64
- package/src/ruvocal/scripts/generate-welcome.mjs +181 -181
- package/src/ruvocal/scripts/populate.ts +288 -288
- package/src/ruvocal/scripts/samples.txt +194 -194
- package/src/ruvocal/scripts/setups/vitest-setup-server.ts +44 -44
- package/src/ruvocal/scripts/updateLocalEnv.ts +48 -48
- package/src/ruvocal/src/ambient.d.ts +7 -7
- package/src/ruvocal/src/app.d.ts +29 -29
- package/src/ruvocal/src/app.html +53 -53
- package/src/ruvocal/src/hooks.server.ts +32 -32
- package/src/ruvocal/src/hooks.ts +6 -6
- package/src/ruvocal/src/lib/APIClient.ts +148 -148
- package/src/ruvocal/src/lib/actions/clickOutside.ts +18 -18
- package/src/ruvocal/src/lib/actions/snapScrollToBottom.ts +346 -346
- package/src/ruvocal/src/lib/buildPrompt.ts +33 -33
- package/src/ruvocal/src/lib/components/AnnouncementBanner.svelte +20 -20
- package/src/ruvocal/src/lib/components/BackgroundGenerationPoller.svelte +168 -168
- package/src/ruvocal/src/lib/components/CodeBlock.svelte +73 -73
- package/src/ruvocal/src/lib/components/CopyToClipBoardBtn.svelte +92 -92
- package/src/ruvocal/src/lib/components/DeleteConversationModal.svelte +75 -75
- package/src/ruvocal/src/lib/components/EditConversationModal.svelte +100 -100
- package/src/ruvocal/src/lib/components/ExpandNavigation.svelte +22 -22
- package/src/ruvocal/src/lib/components/FoundationBackground.svelte +242 -242
- package/src/ruvocal/src/lib/components/HoverTooltip.svelte +44 -44
- package/src/ruvocal/src/lib/components/HtmlPreviewModal.svelte +143 -143
- package/src/ruvocal/src/lib/components/InfiniteScroll.svelte +50 -50
- package/src/ruvocal/src/lib/components/MobileNav.svelte +300 -300
- package/src/ruvocal/src/lib/components/Modal.svelte +115 -115
- package/src/ruvocal/src/lib/components/ModelCardMetadata.svelte +71 -71
- package/src/ruvocal/src/lib/components/NavConversationItem.svelte +151 -151
- package/src/ruvocal/src/lib/components/NavMenu.svelte +313 -313
- package/src/ruvocal/src/lib/components/Pagination.svelte +97 -97
- package/src/ruvocal/src/lib/components/PaginationArrow.svelte +27 -27
- package/src/ruvocal/src/lib/components/Portal.svelte +24 -24
- package/src/ruvocal/src/lib/components/RetryBtn.svelte +18 -18
- package/src/ruvocal/src/lib/components/RuFloUniverse.svelte +185 -185
- package/src/ruvocal/src/lib/components/RufloHelpModal.svelte +411 -411
- package/src/ruvocal/src/lib/components/ScrollToBottomBtn.svelte +47 -47
- package/src/ruvocal/src/lib/components/ScrollToPreviousBtn.svelte +77 -77
- package/src/ruvocal/src/lib/components/ShareConversationModal.svelte +182 -182
- package/src/ruvocal/src/lib/components/StopGeneratingBtn.svelte +69 -69
- package/src/ruvocal/src/lib/components/SubscribeModal.svelte +87 -87
- package/src/ruvocal/src/lib/components/Switch.svelte +36 -36
- package/src/ruvocal/src/lib/components/SystemPromptModal.svelte +44 -44
- package/src/ruvocal/src/lib/components/Toast.svelte +27 -27
- package/src/ruvocal/src/lib/components/Tooltip.svelte +30 -30
- package/src/ruvocal/src/lib/components/WelcomeModal.svelte +46 -46
- package/src/ruvocal/src/lib/components/chat/Alternatives.svelte +77 -77
- package/src/ruvocal/src/lib/components/chat/BlockWrapper.svelte +72 -72
- package/src/ruvocal/src/lib/components/chat/ChatInput.svelte +490 -490
- package/src/ruvocal/src/lib/components/chat/ChatIntroduction.svelte +123 -123
- package/src/ruvocal/src/lib/components/chat/ChatMessage.svelte +548 -548
- package/src/ruvocal/src/lib/components/chat/ChatWindow.svelte +1057 -1057
- package/src/ruvocal/src/lib/components/chat/FileDropzone.svelte +92 -92
- package/src/ruvocal/src/lib/components/chat/ImageLightbox.svelte +66 -66
- package/src/ruvocal/src/lib/components/chat/MarkdownBlock.svelte +23 -23
- package/src/ruvocal/src/lib/components/chat/MarkdownRenderer.svelte +69 -69
- package/src/ruvocal/src/lib/components/chat/MarkdownRenderer.svelte.test.ts +58 -58
- package/src/ruvocal/src/lib/components/chat/MessageAvatar.svelte +103 -103
- package/src/ruvocal/src/lib/components/chat/ModelSwitch.svelte +64 -64
- package/src/ruvocal/src/lib/components/chat/OpenReasoningResults.svelte +81 -81
- package/src/ruvocal/src/lib/components/chat/TaskGroup.svelte +88 -88
- package/src/ruvocal/src/lib/components/chat/ToolUpdate.svelte +273 -273
- package/src/ruvocal/src/lib/components/chat/UploadedFile.svelte +253 -253
- package/src/ruvocal/src/lib/components/chat/UrlFetchModal.svelte +203 -203
- package/src/ruvocal/src/lib/components/chat/VoiceRecorder.svelte +214 -214
- package/src/ruvocal/src/lib/components/icons/IconBurger.svelte +20 -20
- package/src/ruvocal/src/lib/components/icons/IconCheap.svelte +20 -20
- package/src/ruvocal/src/lib/components/icons/IconChevron.svelte +24 -24
- package/src/ruvocal/src/lib/components/icons/IconDazzled.svelte +40 -40
- package/src/ruvocal/src/lib/components/icons/IconFast.svelte +20 -20
- package/src/ruvocal/src/lib/components/icons/IconLoading.svelte +22 -22
- package/src/ruvocal/src/lib/components/icons/IconMCP.svelte +28 -28
- package/src/ruvocal/src/lib/components/icons/IconMoon.svelte +21 -21
- package/src/ruvocal/src/lib/components/icons/IconNew.svelte +20 -20
- package/src/ruvocal/src/lib/components/icons/IconOmni.svelte +90 -90
- package/src/ruvocal/src/lib/components/icons/IconPaperclip.svelte +24 -24
- package/src/ruvocal/src/lib/components/icons/IconPro.svelte +37 -37
- package/src/ruvocal/src/lib/components/icons/IconShare.svelte +21 -21
- package/src/ruvocal/src/lib/components/icons/IconSun.svelte +93 -93
- package/src/ruvocal/src/lib/components/icons/Logo.svelte +68 -68
- package/src/ruvocal/src/lib/components/icons/LogoHuggingFaceBorderless.svelte +54 -54
- package/src/ruvocal/src/lib/components/mcp/AddServerForm.svelte +250 -250
- package/src/ruvocal/src/lib/components/mcp/MCPServerManager.svelte +185 -185
- package/src/ruvocal/src/lib/components/mcp/ServerCard.svelte +203 -203
- package/src/ruvocal/src/lib/components/players/AudioPlayer.svelte +82 -82
- package/src/ruvocal/src/lib/components/voice/AudioWaveform.svelte +96 -96
- package/src/ruvocal/src/lib/components/wasm/GalleryPanel.svelte +357 -357
- package/src/ruvocal/src/lib/constants/mcpExamples.ts +114 -114
- package/src/ruvocal/src/lib/constants/mime.ts +11 -11
- package/src/ruvocal/src/lib/constants/pagination.ts +1 -1
- package/src/ruvocal/src/lib/constants/publicSepToken.ts +1 -1
- package/src/ruvocal/src/lib/constants/routerExamples.ts +133 -133
- package/src/ruvocal/src/lib/constants/rvagentPresets.ts +206 -206
- package/src/ruvocal/src/lib/createShareLink.ts +27 -27
- package/src/ruvocal/src/lib/jobs/refresh-conversation-stats.ts +297 -297
- package/src/ruvocal/src/lib/migrations/lock.ts +56 -56
- package/src/ruvocal/src/lib/migrations/migrations.spec.ts +74 -74
- package/src/ruvocal/src/lib/migrations/migrations.ts +109 -109
- package/src/ruvocal/src/lib/migrations/routines/01-update-search-assistants.ts +50 -50
- package/src/ruvocal/src/lib/migrations/routines/02-update-assistants-models.ts +48 -48
- package/src/ruvocal/src/lib/migrations/routines/04-update-message-updates.ts +151 -151
- package/src/ruvocal/src/lib/migrations/routines/05-update-message-files.ts +56 -56
- package/src/ruvocal/src/lib/migrations/routines/06-trim-message-updates.ts +56 -56
- package/src/ruvocal/src/lib/migrations/routines/08-update-featured-to-review.ts +32 -32
- package/src/ruvocal/src/lib/migrations/routines/09-delete-empty-conversations.spec.ts +214 -214
- package/src/ruvocal/src/lib/migrations/routines/09-delete-empty-conversations.ts +88 -88
- package/src/ruvocal/src/lib/migrations/routines/10-update-reports-assistantid.ts +29 -29
- package/src/ruvocal/src/lib/migrations/routines/index.ts +15 -15
- package/src/ruvocal/src/lib/server/__tests__/conversation-stop-generating.spec.ts +103 -103
- package/src/ruvocal/src/lib/server/abortRegistry.ts +57 -57
- package/src/ruvocal/src/lib/server/abortedGenerations.ts +43 -43
- package/src/ruvocal/src/lib/server/adminToken.ts +62 -62
- package/src/ruvocal/src/lib/server/api/__tests__/conversations-id.spec.ts +296 -296
- package/src/ruvocal/src/lib/server/api/__tests__/conversations-message.spec.ts +216 -216
- package/src/ruvocal/src/lib/server/api/__tests__/conversations.spec.ts +235 -235
- package/src/ruvocal/src/lib/server/api/__tests__/misc.spec.ts +72 -72
- package/src/ruvocal/src/lib/server/api/__tests__/testHelpers.ts +86 -86
- package/src/ruvocal/src/lib/server/api/__tests__/user-reports.spec.ts +78 -78
- package/src/ruvocal/src/lib/server/api/__tests__/user.spec.ts +239 -239
- package/src/ruvocal/src/lib/server/api/types.ts +37 -37
- package/src/ruvocal/src/lib/server/api/utils/requireAuth.ts +22 -22
- package/src/ruvocal/src/lib/server/api/utils/resolveConversation.ts +69 -69
- package/src/ruvocal/src/lib/server/api/utils/resolveModel.ts +27 -27
- package/src/ruvocal/src/lib/server/api/utils/superjsonResponse.ts +15 -15
- package/src/ruvocal/src/lib/server/apiToken.ts +11 -11
- package/src/ruvocal/src/lib/server/auth.ts +554 -554
- package/src/ruvocal/src/lib/server/config.ts +187 -187
- package/src/ruvocal/src/lib/server/conversation.ts +83 -83
- package/src/ruvocal/src/lib/server/database/__tests__/rvf.spec.ts +709 -709
- package/src/ruvocal/src/lib/server/database/postgres.ts +700 -700
- package/src/ruvocal/src/lib/server/database/rvf.ts +1078 -1078
- package/src/ruvocal/src/lib/server/database.ts +145 -145
- package/src/ruvocal/src/lib/server/endpoints/document.ts +68 -68
- package/src/ruvocal/src/lib/server/endpoints/endpoints.ts +43 -43
- package/src/ruvocal/src/lib/server/endpoints/images.ts +211 -211
- package/src/ruvocal/src/lib/server/endpoints/openai/endpointOai.ts +266 -266
- package/src/ruvocal/src/lib/server/endpoints/openai/openAIChatToTextGenerationStream.ts +212 -212
- package/src/ruvocal/src/lib/server/endpoints/openai/openAICompletionToTextGenerationStream.ts +32 -32
- package/src/ruvocal/src/lib/server/endpoints/preprocessMessages.ts +61 -61
- package/src/ruvocal/src/lib/server/exitHandler.ts +59 -59
- package/src/ruvocal/src/lib/server/files/downloadFile.ts +34 -34
- package/src/ruvocal/src/lib/server/files/uploadFile.ts +29 -29
- package/src/ruvocal/src/lib/server/findRepoRoot.ts +13 -13
- package/src/ruvocal/src/lib/server/generateFromDefaultEndpoint.ts +46 -46
- package/src/ruvocal/src/lib/server/hooks/error.ts +37 -37
- package/src/ruvocal/src/lib/server/hooks/fetch.ts +22 -22
- package/src/ruvocal/src/lib/server/hooks/handle.ts +250 -250
- package/src/ruvocal/src/lib/server/hooks/init.ts +51 -51
- package/src/ruvocal/src/lib/server/isURLLocal.spec.ts +31 -31
- package/src/ruvocal/src/lib/server/isURLLocal.ts +74 -74
- package/src/ruvocal/src/lib/server/logger.ts +42 -42
- package/src/ruvocal/src/lib/server/mcp/clientPool.spec.ts +175 -175
- package/src/ruvocal/src/lib/server/mcp/hf.ts +32 -32
- package/src/ruvocal/src/lib/server/mcp/httpClient.ts +122 -122
- package/src/ruvocal/src/lib/server/mcp/registry.ts +76 -76
- package/src/ruvocal/src/lib/server/mcp/tools.ts +196 -196
- package/src/ruvocal/src/lib/server/metrics.ts +255 -255
- package/src/ruvocal/src/lib/server/models.ts +518 -518
- package/src/ruvocal/src/lib/server/requestContext.ts +55 -55
- package/src/ruvocal/src/lib/server/router/arch.ts +230 -230
- package/src/ruvocal/src/lib/server/router/endpoint.ts +316 -316
- package/src/ruvocal/src/lib/server/router/multimodal.ts +28 -28
- package/src/ruvocal/src/lib/server/router/policy.ts +49 -49
- package/src/ruvocal/src/lib/server/router/toolsRoute.ts +51 -51
- package/src/ruvocal/src/lib/server/router/types.ts +21 -21
- package/src/ruvocal/src/lib/server/sendSlack.ts +23 -23
- package/src/ruvocal/src/lib/server/textGeneration/generate.ts +258 -258
- package/src/ruvocal/src/lib/server/textGeneration/index.ts +96 -96
- package/src/ruvocal/src/lib/server/textGeneration/mcp/fileRefs.ts +155 -155
- package/src/ruvocal/src/lib/server/textGeneration/mcp/routerResolution.ts +108 -108
- package/src/ruvocal/src/lib/server/textGeneration/mcp/runMcpFlow.ts +831 -831
- package/src/ruvocal/src/lib/server/textGeneration/mcp/toolInvocation.ts +349 -349
- package/src/ruvocal/src/lib/server/textGeneration/mcp/wasmTools.test.ts +633 -633
- package/src/ruvocal/src/lib/server/textGeneration/reasoning.ts +23 -23
- package/src/ruvocal/src/lib/server/textGeneration/title.ts +83 -83
- package/src/ruvocal/src/lib/server/textGeneration/types.ts +28 -28
- package/src/ruvocal/src/lib/server/textGeneration/utils/prepareFiles.ts +88 -88
- package/src/ruvocal/src/lib/server/textGeneration/utils/routing.ts +21 -21
- package/src/ruvocal/src/lib/server/textGeneration/utils/toolPrompt.ts +49 -49
- package/src/ruvocal/src/lib/server/urlSafety.ts +77 -77
- package/src/ruvocal/src/lib/server/usageLimits.ts +30 -30
- package/src/ruvocal/src/lib/stores/autopilotStore.svelte.ts +175 -175
- package/src/ruvocal/src/lib/stores/backgroundGenerations.svelte.ts +32 -32
- package/src/ruvocal/src/lib/stores/backgroundGenerations.ts +1 -1
- package/src/ruvocal/src/lib/stores/errors.ts +9 -9
- package/src/ruvocal/src/lib/stores/isAborted.ts +3 -3
- package/src/ruvocal/src/lib/stores/isPro.ts +4 -4
- package/src/ruvocal/src/lib/stores/loading.ts +3 -3
- package/src/ruvocal/src/lib/stores/mcpServers.ts +534 -534
- package/src/ruvocal/src/lib/stores/pendingChatInput.ts +3 -3
- package/src/ruvocal/src/lib/stores/pendingMessage.ts +9 -9
- package/src/ruvocal/src/lib/stores/settings.ts +182 -182
- package/src/ruvocal/src/lib/stores/shareModal.ts +13 -13
- package/src/ruvocal/src/lib/stores/titleUpdate.ts +8 -8
- package/src/ruvocal/src/lib/stores/wasmMcp.ts +472 -472
- package/src/ruvocal/src/lib/switchTheme.ts +124 -124
- package/src/ruvocal/src/lib/types/AbortedGeneration.ts +8 -8
- package/src/ruvocal/src/lib/types/Assistant.ts +31 -31
- package/src/ruvocal/src/lib/types/AssistantStats.ts +11 -11
- package/src/ruvocal/src/lib/types/ConfigKey.ts +4 -4
- package/src/ruvocal/src/lib/types/ConvSidebar.ts +9 -9
- package/src/ruvocal/src/lib/types/Conversation.ts +27 -27
- package/src/ruvocal/src/lib/types/ConversationStats.ts +13 -13
- package/src/ruvocal/src/lib/types/Message.ts +41 -41
- package/src/ruvocal/src/lib/types/MessageEvent.ts +10 -10
- package/src/ruvocal/src/lib/types/MessageUpdate.ts +139 -139
- package/src/ruvocal/src/lib/types/MigrationResult.ts +7 -7
- package/src/ruvocal/src/lib/types/Model.ts +23 -23
- package/src/ruvocal/src/lib/types/Report.ts +12 -12
- package/src/ruvocal/src/lib/types/Review.ts +6 -6
- package/src/ruvocal/src/lib/types/Semaphore.ts +19 -19
- package/src/ruvocal/src/lib/types/Session.ts +22 -22
- package/src/ruvocal/src/lib/types/Settings.ts +93 -93
- package/src/ruvocal/src/lib/types/SharedConversation.ts +9 -9
- package/src/ruvocal/src/lib/types/Template.ts +6 -6
- package/src/ruvocal/src/lib/types/Timestamps.ts +4 -4
- package/src/ruvocal/src/lib/types/TokenCache.ts +6 -6
- package/src/ruvocal/src/lib/types/Tool.ts +77 -77
- package/src/ruvocal/src/lib/types/UrlDependency.ts +5 -5
- package/src/ruvocal/src/lib/types/User.ts +14 -14
- package/src/ruvocal/src/lib/utils/PublicConfig.svelte.ts +75 -75
- package/src/ruvocal/src/lib/utils/auth.ts +17 -17
- package/src/ruvocal/src/lib/utils/chunk.ts +33 -33
- package/src/ruvocal/src/lib/utils/cookiesAreEnabled.ts +13 -13
- package/src/ruvocal/src/lib/utils/debounce.ts +17 -17
- package/src/ruvocal/src/lib/utils/deepestChild.ts +6 -6
- package/src/ruvocal/src/lib/utils/favicon.ts +21 -21
- package/src/ruvocal/src/lib/utils/fetchJSON.ts +23 -23
- package/src/ruvocal/src/lib/utils/file2base64.ts +14 -14
- package/src/ruvocal/src/lib/utils/formatUserCount.ts +37 -37
- package/src/ruvocal/src/lib/utils/generationState.spec.ts +75 -75
- package/src/ruvocal/src/lib/utils/generationState.ts +26 -26
- package/src/ruvocal/src/lib/utils/getHref.ts +41 -41
- package/src/ruvocal/src/lib/utils/getReturnFromGenerator.ts +7 -7
- package/src/ruvocal/src/lib/utils/haptics.ts +64 -64
- package/src/ruvocal/src/lib/utils/hashConv.ts +12 -12
- package/src/ruvocal/src/lib/utils/hf.ts +17 -17
- package/src/ruvocal/src/lib/utils/isDesktop.ts +7 -7
- package/src/ruvocal/src/lib/utils/isUrl.ts +8 -8
- package/src/ruvocal/src/lib/utils/isVirtualKeyboard.ts +16 -16
- package/src/ruvocal/src/lib/utils/loadAttachmentsFromUrls.ts +115 -115
- package/src/ruvocal/src/lib/utils/marked.spec.ts +96 -96
- package/src/ruvocal/src/lib/utils/marked.ts +531 -531
- package/src/ruvocal/src/lib/utils/mcpValidation.ts +147 -147
- package/src/ruvocal/src/lib/utils/mergeAsyncGenerators.ts +38 -38
- package/src/ruvocal/src/lib/utils/messageUpdates.spec.ts +286 -286
- package/src/ruvocal/src/lib/utils/messageUpdates.ts +332 -332
- package/src/ruvocal/src/lib/utils/mime.ts +56 -56
- package/src/ruvocal/src/lib/utils/models.ts +14 -14
- package/src/ruvocal/src/lib/utils/parseBlocks.ts +120 -120
- package/src/ruvocal/src/lib/utils/parseIncompleteMarkdown.ts +644 -644
- package/src/ruvocal/src/lib/utils/parseStringToList.ts +10 -10
- package/src/ruvocal/src/lib/utils/randomUuid.ts +14 -14
- package/src/ruvocal/src/lib/utils/searchTokens.ts +33 -33
- package/src/ruvocal/src/lib/utils/sha256.ts +7 -7
- package/src/ruvocal/src/lib/utils/stringifyError.ts +12 -12
- package/src/ruvocal/src/lib/utils/sum.ts +3 -3
- package/src/ruvocal/src/lib/utils/template.spec.ts +59 -59
- package/src/ruvocal/src/lib/utils/template.ts +53 -53
- package/src/ruvocal/src/lib/utils/timeout.ts +9 -9
- package/src/ruvocal/src/lib/utils/toolProgress.spec.ts +46 -46
- package/src/ruvocal/src/lib/utils/toolProgress.ts +11 -11
- package/src/ruvocal/src/lib/utils/tree/addChildren.spec.ts +102 -102
- package/src/ruvocal/src/lib/utils/tree/addChildren.ts +48 -48
- package/src/ruvocal/src/lib/utils/tree/addSibling.spec.ts +81 -81
- package/src/ruvocal/src/lib/utils/tree/addSibling.ts +41 -41
- package/src/ruvocal/src/lib/utils/tree/buildSubtree.spec.ts +110 -110
- package/src/ruvocal/src/lib/utils/tree/buildSubtree.ts +24 -24
- package/src/ruvocal/src/lib/utils/tree/convertLegacyConversation.spec.ts +31 -31
- package/src/ruvocal/src/lib/utils/tree/convertLegacyConversation.ts +36 -36
- package/src/ruvocal/src/lib/utils/tree/isMessageId.spec.ts +15 -15
- package/src/ruvocal/src/lib/utils/tree/isMessageId.ts +5 -5
- package/src/ruvocal/src/lib/utils/tree/tree.d.ts +14 -14
- package/src/ruvocal/src/lib/utils/tree/treeHelpers.spec.ts +167 -167
- package/src/ruvocal/src/lib/utils/updates.ts +39 -39
- package/src/ruvocal/src/lib/utils/urlParams.ts +13 -13
- package/src/ruvocal/src/lib/wasm/idb.ts +438 -438
- package/src/ruvocal/src/lib/wasm/index.ts +1213 -1213
- package/src/ruvocal/src/lib/wasm/tests/wasm-capabilities.test.ts +565 -565
- package/src/ruvocal/src/lib/wasm/wasm.worker.ts +332 -332
- package/src/ruvocal/src/lib/wasm/workerClient.ts +166 -166
- package/src/ruvocal/src/lib/workers/autopilotWorker.ts +221 -221
- package/src/ruvocal/src/lib/workers/detailFetchWorker.ts +100 -100
- package/src/ruvocal/src/lib/workers/markdownWorker.ts +61 -61
- package/src/ruvocal/src/routes/+error.svelte +20 -20
- package/src/ruvocal/src/routes/+layout.svelte +324 -324
- package/src/ruvocal/src/routes/+layout.ts +91 -91
- package/src/ruvocal/src/routes/+page.svelte +168 -168
- package/src/ruvocal/src/routes/.well-known/oauth-cimd/+server.ts +37 -37
- package/src/ruvocal/src/routes/__debug/openai/+server.ts +21 -21
- package/src/ruvocal/src/routes/admin/export/+server.ts +159 -159
- package/src/ruvocal/src/routes/admin/stats/compute/+server.ts +16 -16
- package/src/ruvocal/src/routes/api/conversation/[id]/+server.ts +40 -40
- package/src/ruvocal/src/routes/api/conversation/[id]/message/[messageId]/+server.ts +42 -42
- package/src/ruvocal/src/routes/api/conversations/+server.ts +48 -48
- package/src/ruvocal/src/routes/api/fetch-url/+server.ts +147 -147
- package/src/ruvocal/src/routes/api/mcp/health/+server.ts +292 -292
- package/src/ruvocal/src/routes/api/mcp/servers/+server.ts +32 -32
- package/src/ruvocal/src/routes/api/models/+server.ts +25 -25
- package/src/ruvocal/src/routes/api/transcribe/+server.ts +104 -104
- package/src/ruvocal/src/routes/api/user/+server.ts +15 -15
- package/src/ruvocal/src/routes/api/user/validate-token/+server.ts +20 -20
- package/src/ruvocal/src/routes/api/v2/conversations/+server.ts +48 -48
- package/src/ruvocal/src/routes/api/v2/conversations/[id]/+server.ts +94 -94
- package/src/ruvocal/src/routes/api/v2/conversations/[id]/message/[messageId]/+server.ts +43 -43
- package/src/ruvocal/src/routes/api/v2/conversations/import-share/+server.ts +23 -23
- package/src/ruvocal/src/routes/api/v2/debug/config/+server.ts +16 -16
- package/src/ruvocal/src/routes/api/v2/debug/refresh/+server.ts +30 -30
- package/src/ruvocal/src/routes/api/v2/export/+server.ts +196 -196
- package/src/ruvocal/src/routes/api/v2/feature-flags/+server.ts +14 -14
- package/src/ruvocal/src/routes/api/v2/models/+server.ts +38 -38
- package/src/ruvocal/src/routes/api/v2/models/[namespace]/+server.ts +8 -8
- package/src/ruvocal/src/routes/api/v2/models/[namespace]/[model]/+server.ts +8 -8
- package/src/ruvocal/src/routes/api/v2/models/[namespace]/[model]/subscribe/+server.ts +28 -28
- package/src/ruvocal/src/routes/api/v2/models/[namespace]/subscribe/+server.ts +28 -28
- package/src/ruvocal/src/routes/api/v2/models/old/+server.ts +7 -7
- package/src/ruvocal/src/routes/api/v2/models/refresh/+server.ts +33 -33
- package/src/ruvocal/src/routes/api/v2/public-config/+server.ts +7 -7
- package/src/ruvocal/src/routes/api/v2/user/+server.ts +17 -17
- package/src/ruvocal/src/routes/api/v2/user/billing-orgs/+server.ts +73 -73
- package/src/ruvocal/src/routes/api/v2/user/reports/+server.ts +17 -17
- package/src/ruvocal/src/routes/api/v2/user/settings/+server.ts +110 -110
- package/src/ruvocal/src/routes/conversation/+server.ts +115 -115
- package/src/ruvocal/src/routes/conversation/[id]/+page.svelte +593 -593
- package/src/ruvocal/src/routes/conversation/[id]/+page.ts +60 -60
- package/src/ruvocal/src/routes/conversation/[id]/+server.ts +740 -740
- package/src/ruvocal/src/routes/conversation/[id]/message/[messageId]/prompt/+server.ts +66 -66
- package/src/ruvocal/src/routes/conversation/[id]/share/+server.ts +69 -69
- package/src/ruvocal/src/routes/conversation/[id]/stop-generating/+server.ts +35 -35
- package/src/ruvocal/src/routes/healthcheck/+server.ts +3 -3
- package/src/ruvocal/src/routes/login/+server.ts +5 -5
- package/src/ruvocal/src/routes/login/callback/+server.ts +103 -103
- package/src/ruvocal/src/routes/login/callback/updateUser.spec.ts +157 -157
- package/src/ruvocal/src/routes/login/callback/updateUser.ts +215 -215
- package/src/ruvocal/src/routes/logout/+server.ts +18 -18
- package/src/ruvocal/src/routes/metrics/+server.ts +18 -18
- package/src/ruvocal/src/routes/models/+page.svelte +233 -233
- package/src/ruvocal/src/routes/models/[...model]/+page.svelte +161 -161
- package/src/ruvocal/src/routes/models/[...model]/+page.ts +14 -14
- package/src/ruvocal/src/routes/models/[...model]/thumbnail.png/+server.ts +64 -64
- package/src/ruvocal/src/routes/models/[...model]/thumbnail.png/ModelThumbnail.svelte +28 -28
- package/src/ruvocal/src/routes/privacy/+page.svelte +11 -11
- package/src/ruvocal/src/routes/r/[id]/+page.ts +34 -34
- package/src/ruvocal/src/routes/settings/(nav)/+layout.svelte +282 -282
- package/src/ruvocal/src/routes/settings/(nav)/+layout.ts +1 -1
- package/src/ruvocal/src/routes/settings/(nav)/+server.ts +59 -59
- package/src/ruvocal/src/routes/settings/(nav)/[...model]/+page.svelte +464 -464
- package/src/ruvocal/src/routes/settings/(nav)/[...model]/+page.ts +14 -14
- package/src/ruvocal/src/routes/settings/(nav)/application/+page.svelte +362 -362
- package/src/ruvocal/src/routes/settings/+layout.svelte +40 -40
- package/src/ruvocal/src/styles/highlight-js.css +195 -195
- package/src/ruvocal/src/styles/main.css +144 -144
- package/src/ruvocal/static/chatui/favicon-dark.svg +3 -3
- package/src/ruvocal/static/chatui/favicon-dev.svg +3 -3
- package/src/ruvocal/static/chatui/favicon.svg +3 -3
- package/src/ruvocal/static/chatui/icon.svg +3 -3
- package/src/ruvocal/static/chatui/logo.svg +7 -7
- package/src/ruvocal/static/chatui/manifest.json +54 -54
- package/src/ruvocal/static/chatui/welcome.js +184 -184
- package/src/ruvocal/static/huggingchat/favicon-dark.svg +4 -4
- package/src/ruvocal/static/huggingchat/favicon-dev.svg +4 -4
- package/src/ruvocal/static/huggingchat/favicon.svg +4 -4
- package/src/ruvocal/static/huggingchat/fulltext-logo.svg +1 -1
- package/src/ruvocal/static/huggingchat/icon.svg +4 -4
- package/src/ruvocal/static/huggingchat/logo.svg +4 -4
- package/src/ruvocal/static/huggingchat/manifest.json +54 -54
- package/src/ruvocal/static/huggingchat/routes.chat.json +226 -226
- package/src/ruvocal/static/robots.txt +10 -10
- package/src/ruvocal/static/wasm/rvagent_wasm.js +1539 -1539
- package/src/ruvocal/stub/@reflink/reflink/package.json +5 -5
- package/src/ruvocal/svelte.config.js +53 -53
- package/src/ruvocal/tailwind.config.cjs +30 -30
- package/src/ruvocal/tsconfig.json +19 -19
- package/src/ruvocal/vite.config.ts +87 -87
- package/src/scripts/deploy.sh +116 -116
- package/src/scripts/generate-config.js +245 -245
- package/src/scripts/generate-welcome.js +187 -187
- package/src/scripts/package-rvf.sh +116 -116
|
@@ -1,235 +1,235 @@
|
|
|
1
|
-
import { describe, expect, it, afterEach } from "vitest";
|
|
2
|
-
import superjson from "superjson";
|
|
3
|
-
import { collections } from "$lib/server/database";
|
|
4
|
-
import { CONV_NUM_PER_PAGE } from "$lib/constants/pagination";
|
|
5
|
-
import {
|
|
6
|
-
createTestLocals,
|
|
7
|
-
createTestUser,
|
|
8
|
-
createTestConversation,
|
|
9
|
-
cleanupTestData,
|
|
10
|
-
} from "./testHelpers";
|
|
11
|
-
|
|
12
|
-
import { GET, DELETE } from "../../../../routes/api/v2/conversations/+server";
|
|
13
|
-
|
|
14
|
-
async function parseResponse<T = unknown>(res: Response): Promise<T> {
|
|
15
|
-
return superjson.parse(await res.text()) as T;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function mockUrl(params?: Record<string, string>): URL {
|
|
19
|
-
const url = new URL("http://localhost:5173/api/v2/conversations");
|
|
20
|
-
if (params) {
|
|
21
|
-
for (const [key, value] of Object.entries(params)) {
|
|
22
|
-
url.searchParams.set(key, value);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return url;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
describe.sequential("GET /api/v2/conversations", () => {
|
|
29
|
-
afterEach(async () => {
|
|
30
|
-
await cleanupTestData();
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it("returns conversations for authenticated user", { timeout: 30000 }, async () => {
|
|
34
|
-
const { locals } = await createTestUser();
|
|
35
|
-
const conv = await createTestConversation(locals, { title: "My Chat" });
|
|
36
|
-
|
|
37
|
-
const res = await GET({
|
|
38
|
-
locals,
|
|
39
|
-
url: mockUrl(),
|
|
40
|
-
} as never);
|
|
41
|
-
|
|
42
|
-
expect(res.status).toBe(200);
|
|
43
|
-
const data = await parseResponse<{
|
|
44
|
-
conversations: Array<{ title: string; _id: { toString(): string } }>;
|
|
45
|
-
hasMore: boolean;
|
|
46
|
-
}>(res);
|
|
47
|
-
expect(data.conversations).toHaveLength(1);
|
|
48
|
-
expect(data.conversations[0].title).toBe("My Chat");
|
|
49
|
-
expect(data.conversations[0]._id.toString()).toBe(conv._id.toString());
|
|
50
|
-
expect(data.hasMore).toBe(false);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it("returns empty array for user with no conversations", async () => {
|
|
54
|
-
const { locals } = await createTestUser();
|
|
55
|
-
|
|
56
|
-
const res = await GET({
|
|
57
|
-
locals,
|
|
58
|
-
url: mockUrl(),
|
|
59
|
-
} as never);
|
|
60
|
-
|
|
61
|
-
expect(res.status).toBe(200);
|
|
62
|
-
const data = await parseResponse<{ conversations: unknown[]; hasMore: boolean }>(res);
|
|
63
|
-
expect(data.conversations).toHaveLength(0);
|
|
64
|
-
expect(data.hasMore).toBe(false);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it("supports pagination with p=0 and p=1", async () => {
|
|
68
|
-
const { locals } = await createTestUser();
|
|
69
|
-
|
|
70
|
-
// Create CONV_NUM_PER_PAGE + 5 conversations with distinct updatedAt values
|
|
71
|
-
for (let i = 0; i < CONV_NUM_PER_PAGE + 5; i++) {
|
|
72
|
-
await createTestConversation(locals, {
|
|
73
|
-
title: `Conv ${i}`,
|
|
74
|
-
updatedAt: new Date(Date.now() - (CONV_NUM_PER_PAGE + 5 - i) * 1000),
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const resPage0 = await GET({
|
|
79
|
-
locals,
|
|
80
|
-
url: mockUrl({ p: "0" }),
|
|
81
|
-
} as never);
|
|
82
|
-
|
|
83
|
-
const dataPage0 = await parseResponse<{
|
|
84
|
-
conversations: Array<{ title: string }>;
|
|
85
|
-
hasMore: boolean;
|
|
86
|
-
}>(resPage0);
|
|
87
|
-
expect(dataPage0.conversations).toHaveLength(CONV_NUM_PER_PAGE);
|
|
88
|
-
expect(dataPage0.hasMore).toBe(true);
|
|
89
|
-
|
|
90
|
-
const resPage1 = await GET({
|
|
91
|
-
locals,
|
|
92
|
-
url: mockUrl({ p: "1" }),
|
|
93
|
-
} as never);
|
|
94
|
-
|
|
95
|
-
const dataPage1 = await parseResponse<{
|
|
96
|
-
conversations: Array<{ title: string }>;
|
|
97
|
-
hasMore: boolean;
|
|
98
|
-
}>(resPage1);
|
|
99
|
-
expect(dataPage1.conversations).toHaveLength(5);
|
|
100
|
-
expect(dataPage1.hasMore).toBe(false);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it("returns hasMore=true when more than CONV_NUM_PER_PAGE exist", async () => {
|
|
104
|
-
const { locals } = await createTestUser();
|
|
105
|
-
|
|
106
|
-
for (let i = 0; i < CONV_NUM_PER_PAGE + 1; i++) {
|
|
107
|
-
await createTestConversation(locals, {
|
|
108
|
-
title: `Conv ${i}`,
|
|
109
|
-
updatedAt: new Date(Date.now() - i * 1000),
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const res = await GET({
|
|
114
|
-
locals,
|
|
115
|
-
url: mockUrl(),
|
|
116
|
-
} as never);
|
|
117
|
-
|
|
118
|
-
const data = await parseResponse<{ conversations: unknown[]; hasMore: boolean }>(res);
|
|
119
|
-
expect(data.conversations).toHaveLength(CONV_NUM_PER_PAGE);
|
|
120
|
-
expect(data.hasMore).toBe(true);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it("sorts by updatedAt descending", async () => {
|
|
124
|
-
const { locals } = await createTestUser();
|
|
125
|
-
|
|
126
|
-
await createTestConversation(locals, {
|
|
127
|
-
title: "Oldest",
|
|
128
|
-
updatedAt: new Date("2024-01-01"),
|
|
129
|
-
});
|
|
130
|
-
await createTestConversation(locals, {
|
|
131
|
-
title: "Newest",
|
|
132
|
-
updatedAt: new Date("2024-06-01"),
|
|
133
|
-
});
|
|
134
|
-
await createTestConversation(locals, {
|
|
135
|
-
title: "Middle",
|
|
136
|
-
updatedAt: new Date("2024-03-01"),
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
const res = await GET({
|
|
140
|
-
locals,
|
|
141
|
-
url: mockUrl(),
|
|
142
|
-
} as never);
|
|
143
|
-
|
|
144
|
-
const data = await parseResponse<{ conversations: Array<{ title: string }> }>(res);
|
|
145
|
-
expect(data.conversations[0].title).toBe("Newest");
|
|
146
|
-
expect(data.conversations[1].title).toBe("Middle");
|
|
147
|
-
expect(data.conversations[2].title).toBe("Oldest");
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it("throws 401 for unauthenticated request", async () => {
|
|
151
|
-
const locals = createTestLocals({ sessionId: undefined, user: undefined });
|
|
152
|
-
|
|
153
|
-
try {
|
|
154
|
-
await GET({
|
|
155
|
-
locals,
|
|
156
|
-
url: mockUrl(),
|
|
157
|
-
} as never);
|
|
158
|
-
expect.fail("Should have thrown");
|
|
159
|
-
} catch (e: unknown) {
|
|
160
|
-
expect((e as { status: number }).status).toBe(401);
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it("does not return other users' conversations", async () => {
|
|
165
|
-
const { locals: localsA } = await createTestUser();
|
|
166
|
-
const { locals: localsB } = await createTestUser();
|
|
167
|
-
|
|
168
|
-
await createTestConversation(localsA, { title: "User A Chat" });
|
|
169
|
-
await createTestConversation(localsB, { title: "User B Chat" });
|
|
170
|
-
|
|
171
|
-
const res = await GET({
|
|
172
|
-
locals: localsA,
|
|
173
|
-
url: mockUrl(),
|
|
174
|
-
} as never);
|
|
175
|
-
|
|
176
|
-
const data = await parseResponse<{ conversations: Array<{ title: string }> }>(res);
|
|
177
|
-
expect(data.conversations).toHaveLength(1);
|
|
178
|
-
expect(data.conversations[0].title).toBe("User A Chat");
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
describe.sequential("DELETE /api/v2/conversations", () => {
|
|
183
|
-
afterEach(async () => {
|
|
184
|
-
await cleanupTestData();
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it("removes all conversations for authenticated user", async () => {
|
|
188
|
-
const { locals } = await createTestUser();
|
|
189
|
-
|
|
190
|
-
await createTestConversation(locals, { title: "Chat 1" });
|
|
191
|
-
await createTestConversation(locals, { title: "Chat 2" });
|
|
192
|
-
await createTestConversation(locals, { title: "Chat 3" });
|
|
193
|
-
|
|
194
|
-
const res = await DELETE({ locals } as never);
|
|
195
|
-
expect(res.status).toBe(200);
|
|
196
|
-
|
|
197
|
-
const data = await parseResponse<number>(res);
|
|
198
|
-
expect(data).toBe(3);
|
|
199
|
-
|
|
200
|
-
const remaining = await collections.conversations.countDocuments();
|
|
201
|
-
expect(remaining).toBe(0);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
it("throws 401 for unauthenticated request", async () => {
|
|
205
|
-
const locals = createTestLocals({ sessionId: undefined, user: undefined });
|
|
206
|
-
|
|
207
|
-
try {
|
|
208
|
-
await DELETE({ locals } as never);
|
|
209
|
-
expect.fail("Should have thrown");
|
|
210
|
-
} catch (e: unknown) {
|
|
211
|
-
expect((e as { status: number }).status).toBe(401);
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
it("does not remove other users' conversations", async () => {
|
|
216
|
-
const { locals: localsA } = await createTestUser();
|
|
217
|
-
const { locals: localsB } = await createTestUser();
|
|
218
|
-
|
|
219
|
-
await createTestConversation(localsA, { title: "User A Chat" });
|
|
220
|
-
await createTestConversation(localsB, { title: "User B Chat" });
|
|
221
|
-
|
|
222
|
-
const res = await DELETE({ locals: localsA } as never);
|
|
223
|
-
const data = await parseResponse<number>(res);
|
|
224
|
-
expect(data).toBe(1);
|
|
225
|
-
|
|
226
|
-
const remaining = await collections.conversations.countDocuments();
|
|
227
|
-
expect(remaining).toBe(1);
|
|
228
|
-
|
|
229
|
-
const userBConvs = await collections.conversations
|
|
230
|
-
.find({ userId: localsB.user?._id })
|
|
231
|
-
.toArray();
|
|
232
|
-
expect(userBConvs).toHaveLength(1);
|
|
233
|
-
expect(userBConvs[0].title).toBe("User B Chat");
|
|
234
|
-
});
|
|
235
|
-
});
|
|
1
|
+
import { describe, expect, it, afterEach } from "vitest";
|
|
2
|
+
import superjson from "superjson";
|
|
3
|
+
import { collections } from "$lib/server/database";
|
|
4
|
+
import { CONV_NUM_PER_PAGE } from "$lib/constants/pagination";
|
|
5
|
+
import {
|
|
6
|
+
createTestLocals,
|
|
7
|
+
createTestUser,
|
|
8
|
+
createTestConversation,
|
|
9
|
+
cleanupTestData,
|
|
10
|
+
} from "./testHelpers";
|
|
11
|
+
|
|
12
|
+
import { GET, DELETE } from "../../../../routes/api/v2/conversations/+server";
|
|
13
|
+
|
|
14
|
+
async function parseResponse<T = unknown>(res: Response): Promise<T> {
|
|
15
|
+
return superjson.parse(await res.text()) as T;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function mockUrl(params?: Record<string, string>): URL {
|
|
19
|
+
const url = new URL("http://localhost:5173/api/v2/conversations");
|
|
20
|
+
if (params) {
|
|
21
|
+
for (const [key, value] of Object.entries(params)) {
|
|
22
|
+
url.searchParams.set(key, value);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return url;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
describe.sequential("GET /api/v2/conversations", () => {
|
|
29
|
+
afterEach(async () => {
|
|
30
|
+
await cleanupTestData();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("returns conversations for authenticated user", { timeout: 30000 }, async () => {
|
|
34
|
+
const { locals } = await createTestUser();
|
|
35
|
+
const conv = await createTestConversation(locals, { title: "My Chat" });
|
|
36
|
+
|
|
37
|
+
const res = await GET({
|
|
38
|
+
locals,
|
|
39
|
+
url: mockUrl(),
|
|
40
|
+
} as never);
|
|
41
|
+
|
|
42
|
+
expect(res.status).toBe(200);
|
|
43
|
+
const data = await parseResponse<{
|
|
44
|
+
conversations: Array<{ title: string; _id: { toString(): string } }>;
|
|
45
|
+
hasMore: boolean;
|
|
46
|
+
}>(res);
|
|
47
|
+
expect(data.conversations).toHaveLength(1);
|
|
48
|
+
expect(data.conversations[0].title).toBe("My Chat");
|
|
49
|
+
expect(data.conversations[0]._id.toString()).toBe(conv._id.toString());
|
|
50
|
+
expect(data.hasMore).toBe(false);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("returns empty array for user with no conversations", async () => {
|
|
54
|
+
const { locals } = await createTestUser();
|
|
55
|
+
|
|
56
|
+
const res = await GET({
|
|
57
|
+
locals,
|
|
58
|
+
url: mockUrl(),
|
|
59
|
+
} as never);
|
|
60
|
+
|
|
61
|
+
expect(res.status).toBe(200);
|
|
62
|
+
const data = await parseResponse<{ conversations: unknown[]; hasMore: boolean }>(res);
|
|
63
|
+
expect(data.conversations).toHaveLength(0);
|
|
64
|
+
expect(data.hasMore).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("supports pagination with p=0 and p=1", async () => {
|
|
68
|
+
const { locals } = await createTestUser();
|
|
69
|
+
|
|
70
|
+
// Create CONV_NUM_PER_PAGE + 5 conversations with distinct updatedAt values
|
|
71
|
+
for (let i = 0; i < CONV_NUM_PER_PAGE + 5; i++) {
|
|
72
|
+
await createTestConversation(locals, {
|
|
73
|
+
title: `Conv ${i}`,
|
|
74
|
+
updatedAt: new Date(Date.now() - (CONV_NUM_PER_PAGE + 5 - i) * 1000),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const resPage0 = await GET({
|
|
79
|
+
locals,
|
|
80
|
+
url: mockUrl({ p: "0" }),
|
|
81
|
+
} as never);
|
|
82
|
+
|
|
83
|
+
const dataPage0 = await parseResponse<{
|
|
84
|
+
conversations: Array<{ title: string }>;
|
|
85
|
+
hasMore: boolean;
|
|
86
|
+
}>(resPage0);
|
|
87
|
+
expect(dataPage0.conversations).toHaveLength(CONV_NUM_PER_PAGE);
|
|
88
|
+
expect(dataPage0.hasMore).toBe(true);
|
|
89
|
+
|
|
90
|
+
const resPage1 = await GET({
|
|
91
|
+
locals,
|
|
92
|
+
url: mockUrl({ p: "1" }),
|
|
93
|
+
} as never);
|
|
94
|
+
|
|
95
|
+
const dataPage1 = await parseResponse<{
|
|
96
|
+
conversations: Array<{ title: string }>;
|
|
97
|
+
hasMore: boolean;
|
|
98
|
+
}>(resPage1);
|
|
99
|
+
expect(dataPage1.conversations).toHaveLength(5);
|
|
100
|
+
expect(dataPage1.hasMore).toBe(false);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("returns hasMore=true when more than CONV_NUM_PER_PAGE exist", async () => {
|
|
104
|
+
const { locals } = await createTestUser();
|
|
105
|
+
|
|
106
|
+
for (let i = 0; i < CONV_NUM_PER_PAGE + 1; i++) {
|
|
107
|
+
await createTestConversation(locals, {
|
|
108
|
+
title: `Conv ${i}`,
|
|
109
|
+
updatedAt: new Date(Date.now() - i * 1000),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const res = await GET({
|
|
114
|
+
locals,
|
|
115
|
+
url: mockUrl(),
|
|
116
|
+
} as never);
|
|
117
|
+
|
|
118
|
+
const data = await parseResponse<{ conversations: unknown[]; hasMore: boolean }>(res);
|
|
119
|
+
expect(data.conversations).toHaveLength(CONV_NUM_PER_PAGE);
|
|
120
|
+
expect(data.hasMore).toBe(true);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("sorts by updatedAt descending", async () => {
|
|
124
|
+
const { locals } = await createTestUser();
|
|
125
|
+
|
|
126
|
+
await createTestConversation(locals, {
|
|
127
|
+
title: "Oldest",
|
|
128
|
+
updatedAt: new Date("2024-01-01"),
|
|
129
|
+
});
|
|
130
|
+
await createTestConversation(locals, {
|
|
131
|
+
title: "Newest",
|
|
132
|
+
updatedAt: new Date("2024-06-01"),
|
|
133
|
+
});
|
|
134
|
+
await createTestConversation(locals, {
|
|
135
|
+
title: "Middle",
|
|
136
|
+
updatedAt: new Date("2024-03-01"),
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const res = await GET({
|
|
140
|
+
locals,
|
|
141
|
+
url: mockUrl(),
|
|
142
|
+
} as never);
|
|
143
|
+
|
|
144
|
+
const data = await parseResponse<{ conversations: Array<{ title: string }> }>(res);
|
|
145
|
+
expect(data.conversations[0].title).toBe("Newest");
|
|
146
|
+
expect(data.conversations[1].title).toBe("Middle");
|
|
147
|
+
expect(data.conversations[2].title).toBe("Oldest");
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("throws 401 for unauthenticated request", async () => {
|
|
151
|
+
const locals = createTestLocals({ sessionId: undefined, user: undefined });
|
|
152
|
+
|
|
153
|
+
try {
|
|
154
|
+
await GET({
|
|
155
|
+
locals,
|
|
156
|
+
url: mockUrl(),
|
|
157
|
+
} as never);
|
|
158
|
+
expect.fail("Should have thrown");
|
|
159
|
+
} catch (e: unknown) {
|
|
160
|
+
expect((e as { status: number }).status).toBe(401);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("does not return other users' conversations", async () => {
|
|
165
|
+
const { locals: localsA } = await createTestUser();
|
|
166
|
+
const { locals: localsB } = await createTestUser();
|
|
167
|
+
|
|
168
|
+
await createTestConversation(localsA, { title: "User A Chat" });
|
|
169
|
+
await createTestConversation(localsB, { title: "User B Chat" });
|
|
170
|
+
|
|
171
|
+
const res = await GET({
|
|
172
|
+
locals: localsA,
|
|
173
|
+
url: mockUrl(),
|
|
174
|
+
} as never);
|
|
175
|
+
|
|
176
|
+
const data = await parseResponse<{ conversations: Array<{ title: string }> }>(res);
|
|
177
|
+
expect(data.conversations).toHaveLength(1);
|
|
178
|
+
expect(data.conversations[0].title).toBe("User A Chat");
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
describe.sequential("DELETE /api/v2/conversations", () => {
|
|
183
|
+
afterEach(async () => {
|
|
184
|
+
await cleanupTestData();
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it("removes all conversations for authenticated user", async () => {
|
|
188
|
+
const { locals } = await createTestUser();
|
|
189
|
+
|
|
190
|
+
await createTestConversation(locals, { title: "Chat 1" });
|
|
191
|
+
await createTestConversation(locals, { title: "Chat 2" });
|
|
192
|
+
await createTestConversation(locals, { title: "Chat 3" });
|
|
193
|
+
|
|
194
|
+
const res = await DELETE({ locals } as never);
|
|
195
|
+
expect(res.status).toBe(200);
|
|
196
|
+
|
|
197
|
+
const data = await parseResponse<number>(res);
|
|
198
|
+
expect(data).toBe(3);
|
|
199
|
+
|
|
200
|
+
const remaining = await collections.conversations.countDocuments();
|
|
201
|
+
expect(remaining).toBe(0);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("throws 401 for unauthenticated request", async () => {
|
|
205
|
+
const locals = createTestLocals({ sessionId: undefined, user: undefined });
|
|
206
|
+
|
|
207
|
+
try {
|
|
208
|
+
await DELETE({ locals } as never);
|
|
209
|
+
expect.fail("Should have thrown");
|
|
210
|
+
} catch (e: unknown) {
|
|
211
|
+
expect((e as { status: number }).status).toBe(401);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it("does not remove other users' conversations", async () => {
|
|
216
|
+
const { locals: localsA } = await createTestUser();
|
|
217
|
+
const { locals: localsB } = await createTestUser();
|
|
218
|
+
|
|
219
|
+
await createTestConversation(localsA, { title: "User A Chat" });
|
|
220
|
+
await createTestConversation(localsB, { title: "User B Chat" });
|
|
221
|
+
|
|
222
|
+
const res = await DELETE({ locals: localsA } as never);
|
|
223
|
+
const data = await parseResponse<number>(res);
|
|
224
|
+
expect(data).toBe(1);
|
|
225
|
+
|
|
226
|
+
const remaining = await collections.conversations.countDocuments();
|
|
227
|
+
expect(remaining).toBe(1);
|
|
228
|
+
|
|
229
|
+
const userBConvs = await collections.conversations
|
|
230
|
+
.find({ userId: localsB.user?._id })
|
|
231
|
+
.toArray();
|
|
232
|
+
expect(userBConvs).toHaveLength(1);
|
|
233
|
+
expect(userBConvs[0].title).toBe("User B Chat");
|
|
234
|
+
});
|
|
235
|
+
});
|
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
|
-
import superjson from "superjson";
|
|
3
|
-
import { createTestLocals, createTestUser, cleanupTestData } from "./testHelpers";
|
|
4
|
-
import { GET as featureFlagsGET } from "../../../../routes/api/v2/feature-flags/+server";
|
|
5
|
-
import { GET as publicConfigGET } from "../../../../routes/api/v2/public-config/+server";
|
|
6
|
-
import type { FeatureFlags } from "$lib/server/api/types";
|
|
7
|
-
|
|
8
|
-
async function parseResponse<T = unknown>(res: Response): Promise<T> {
|
|
9
|
-
return superjson.parse(await res.text()) as T;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function mockRequestEvent(locals: App.Locals) {
|
|
13
|
-
return {
|
|
14
|
-
locals,
|
|
15
|
-
url: new URL("http://localhost"),
|
|
16
|
-
request: new Request("http://localhost"),
|
|
17
|
-
} as Parameters<typeof featureFlagsGET>[0];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
describe("GET /api/v2/feature-flags", () => {
|
|
21
|
-
beforeEach(async () => {
|
|
22
|
-
await cleanupTestData();
|
|
23
|
-
}, 20000);
|
|
24
|
-
|
|
25
|
-
it("returns correct shape with expected fields", async () => {
|
|
26
|
-
const locals = createTestLocals();
|
|
27
|
-
|
|
28
|
-
const res = await featureFlagsGET(mockRequestEvent(locals));
|
|
29
|
-
const data = await parseResponse<FeatureFlags>(res);
|
|
30
|
-
|
|
31
|
-
expect(data).toHaveProperty("enableAssistants");
|
|
32
|
-
expect(data).toHaveProperty("loginEnabled");
|
|
33
|
-
expect(data).toHaveProperty("isAdmin");
|
|
34
|
-
expect(data).toHaveProperty("transcriptionEnabled");
|
|
35
|
-
expect(typeof data.enableAssistants).toBe("boolean");
|
|
36
|
-
expect(typeof data.loginEnabled).toBe("boolean");
|
|
37
|
-
expect(typeof data.isAdmin).toBe("boolean");
|
|
38
|
-
expect(typeof data.transcriptionEnabled).toBe("boolean");
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it("reflects isAdmin from locals for non-admin user", async () => {
|
|
42
|
-
const locals = createTestLocals({ isAdmin: false });
|
|
43
|
-
|
|
44
|
-
const res = await featureFlagsGET(mockRequestEvent(locals));
|
|
45
|
-
const data = await parseResponse<FeatureFlags>(res);
|
|
46
|
-
|
|
47
|
-
expect(data.isAdmin).toBe(false);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it("reflects isAdmin from locals for admin user", async () => {
|
|
51
|
-
const { locals } = await createTestUser();
|
|
52
|
-
locals.isAdmin = true;
|
|
53
|
-
|
|
54
|
-
const res = await featureFlagsGET(mockRequestEvent(locals));
|
|
55
|
-
const data = await parseResponse<FeatureFlags>(res);
|
|
56
|
-
|
|
57
|
-
expect(data.isAdmin).toBe(true);
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
describe("GET /api/v2/public-config", () => {
|
|
62
|
-
it("returns an object", async () => {
|
|
63
|
-
const locals = createTestLocals();
|
|
64
|
-
|
|
65
|
-
const res = await publicConfigGET(mockRequestEvent(locals));
|
|
66
|
-
const data = await parseResponse<Record<string, unknown>>(res);
|
|
67
|
-
|
|
68
|
-
expect(data).toBeDefined();
|
|
69
|
-
expect(typeof data).toBe("object");
|
|
70
|
-
expect(data).not.toBeNull();
|
|
71
|
-
});
|
|
72
|
-
});
|
|
1
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
|
+
import superjson from "superjson";
|
|
3
|
+
import { createTestLocals, createTestUser, cleanupTestData } from "./testHelpers";
|
|
4
|
+
import { GET as featureFlagsGET } from "../../../../routes/api/v2/feature-flags/+server";
|
|
5
|
+
import { GET as publicConfigGET } from "../../../../routes/api/v2/public-config/+server";
|
|
6
|
+
import type { FeatureFlags } from "$lib/server/api/types";
|
|
7
|
+
|
|
8
|
+
async function parseResponse<T = unknown>(res: Response): Promise<T> {
|
|
9
|
+
return superjson.parse(await res.text()) as T;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function mockRequestEvent(locals: App.Locals) {
|
|
13
|
+
return {
|
|
14
|
+
locals,
|
|
15
|
+
url: new URL("http://localhost"),
|
|
16
|
+
request: new Request("http://localhost"),
|
|
17
|
+
} as Parameters<typeof featureFlagsGET>[0];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe("GET /api/v2/feature-flags", () => {
|
|
21
|
+
beforeEach(async () => {
|
|
22
|
+
await cleanupTestData();
|
|
23
|
+
}, 20000);
|
|
24
|
+
|
|
25
|
+
it("returns correct shape with expected fields", async () => {
|
|
26
|
+
const locals = createTestLocals();
|
|
27
|
+
|
|
28
|
+
const res = await featureFlagsGET(mockRequestEvent(locals));
|
|
29
|
+
const data = await parseResponse<FeatureFlags>(res);
|
|
30
|
+
|
|
31
|
+
expect(data).toHaveProperty("enableAssistants");
|
|
32
|
+
expect(data).toHaveProperty("loginEnabled");
|
|
33
|
+
expect(data).toHaveProperty("isAdmin");
|
|
34
|
+
expect(data).toHaveProperty("transcriptionEnabled");
|
|
35
|
+
expect(typeof data.enableAssistants).toBe("boolean");
|
|
36
|
+
expect(typeof data.loginEnabled).toBe("boolean");
|
|
37
|
+
expect(typeof data.isAdmin).toBe("boolean");
|
|
38
|
+
expect(typeof data.transcriptionEnabled).toBe("boolean");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("reflects isAdmin from locals for non-admin user", async () => {
|
|
42
|
+
const locals = createTestLocals({ isAdmin: false });
|
|
43
|
+
|
|
44
|
+
const res = await featureFlagsGET(mockRequestEvent(locals));
|
|
45
|
+
const data = await parseResponse<FeatureFlags>(res);
|
|
46
|
+
|
|
47
|
+
expect(data.isAdmin).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("reflects isAdmin from locals for admin user", async () => {
|
|
51
|
+
const { locals } = await createTestUser();
|
|
52
|
+
locals.isAdmin = true;
|
|
53
|
+
|
|
54
|
+
const res = await featureFlagsGET(mockRequestEvent(locals));
|
|
55
|
+
const data = await parseResponse<FeatureFlags>(res);
|
|
56
|
+
|
|
57
|
+
expect(data.isAdmin).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe("GET /api/v2/public-config", () => {
|
|
62
|
+
it("returns an object", async () => {
|
|
63
|
+
const locals = createTestLocals();
|
|
64
|
+
|
|
65
|
+
const res = await publicConfigGET(mockRequestEvent(locals));
|
|
66
|
+
const data = await parseResponse<Record<string, unknown>>(res);
|
|
67
|
+
|
|
68
|
+
expect(data).toBeDefined();
|
|
69
|
+
expect(typeof data).toBe("object");
|
|
70
|
+
expect(data).not.toBeNull();
|
|
71
|
+
});
|
|
72
|
+
});
|