@promptbook/cli 0.104.0-8 → 0.104.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/README.md +0 -4
- package/esm/index.es.js +261 -131
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/_packages/components.index.d.ts +0 -6
- package/esm/typings/src/_packages/core.index.d.ts +8 -6
- package/esm/typings/src/_packages/types.index.d.ts +8 -0
- package/esm/typings/src/_packages/utils.index.d.ts +2 -0
- package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +24 -0
- package/esm/typings/src/book-2.0/agent-source/AgentModelRequirements.d.ts +12 -2
- package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirements.tools.test.d.ts +1 -0
- package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.closed.test.d.ts +1 -0
- package/esm/typings/src/book-2.0/utils/generatePlaceholderAgentProfileImageUrl.d.ts +1 -1
- package/esm/typings/src/book-components/Chat/save/_common/string_chat_format_name.d.ts +1 -1
- package/esm/typings/src/book-components/Chat/types/ChatMessage.d.ts +6 -3
- package/esm/typings/src/book-components/_common/Dropdown/Dropdown.d.ts +5 -1
- package/esm/typings/src/book-components/_common/HamburgerMenu/HamburgerMenu.d.ts +5 -1
- package/esm/typings/src/book-components/icons/AboutIcon.d.ts +5 -1
- package/esm/typings/src/book-components/icons/AttachmentIcon.d.ts +6 -2
- package/esm/typings/src/book-components/icons/CameraIcon.d.ts +6 -2
- package/esm/typings/src/book-components/icons/DownloadIcon.d.ts +5 -1
- package/esm/typings/src/book-components/icons/MenuIcon.d.ts +5 -1
- package/esm/typings/src/book-components/icons/SaveIcon.d.ts +6 -2
- package/esm/typings/src/collection/agent-collection/AgentCollection.d.ts +1 -1
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +18 -12
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +6 -3
- package/esm/typings/src/commands/_common/types/Command.d.ts +1 -1
- package/esm/typings/src/commitments/META/META_DESCRIPTION.d.ts +41 -0
- package/esm/typings/src/commitments/USE_SEARCH_ENGINE/USE_SEARCH_ENGINE.d.ts +2 -2
- package/esm/typings/src/commitments/_base/BookCommitment.d.ts +1 -1
- package/esm/typings/src/config.d.ts +8 -1
- package/esm/typings/src/formfactors/_common/FormfactorDefinition.d.ts +1 -1
- package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForTestingAndScriptsAndPlayground.d.ts +1 -1
- package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForWizardOrCli.d.ts +1 -1
- package/esm/typings/src/llm-providers/_common/utils/count-total-usage/LlmExecutionToolsWithTotalUsage.d.ts +1 -1
- package/esm/typings/src/llm-providers/_common/utils/count-total-usage/countUsage.d.ts +8 -4
- package/esm/typings/src/llm-providers/_common/utils/count-total-usage/limitTotalUsage.d.ts +1 -1
- package/esm/typings/src/llm-providers/_multiple/getSingleLlmExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/_multiple/joinLlmExecutionTools.d.ts +12 -8
- package/esm/typings/src/llm-providers/agent/Agent.d.ts +7 -1
- package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/openai/utils/mapToolsToOpenAi.d.ts +8 -0
- package/esm/typings/src/remote-server/ui/ServerApp.d.ts +5 -1
- package/esm/typings/src/scrapers/_common/utils/promptbookFetch.test.d.ts +1 -0
- package/esm/typings/src/search-engines/SearchEngine.d.ts +9 -0
- package/esm/typings/src/search-engines/SearchResult.d.ts +18 -0
- package/esm/typings/src/search-engines/bing/BingSearchEngine.d.ts +15 -0
- package/esm/typings/src/search-engines/dummy/DummySearchEngine.d.ts +15 -0
- package/esm/typings/src/types/LlmToolDefinition.d.ts +20 -0
- package/esm/typings/src/types/ModelRequirements.d.ts +13 -0
- package/esm/typings/src/types/typeAliasEmoji.d.ts +2 -2
- package/esm/typings/src/utils/random/$randomAgentPersona.d.ts +7 -2
- package/esm/typings/src/utils/random/$randomItem.d.ts +1 -1
- package/esm/typings/src/utils/random/$randomSeed.d.ts +1 -1
- package/esm/typings/src/utils/validators/url/isValidAgentUrl.d.ts +16 -0
- package/esm/typings/src/utils/validators/url/isValidAgentUrl.test.d.ts +1 -0
- package/esm/typings/src/utils/validators/url/isValidPipelineUrl.d.ts +2 -1
- package/esm/typings/src/utils/validators/url/isValidUrl.d.ts +4 -3
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +261 -131
- package/umd/index.umd.js.map +1 -1
- package/apps/agents-server/README.md +0 -3
- package/apps/agents-server/TODO.txt +0 -7
- package/apps/agents-server/config.ts +0 -128
- package/apps/agents-server/next.config.ts +0 -45
- package/apps/agents-server/package.json +0 -16
- package/apps/agents-server/postcss.config.mjs +0 -8
- package/apps/agents-server/public/.gitkeep +0 -0
- package/apps/agents-server/public/favicon.ico +0 -0
- package/apps/agents-server/public/fonts/OpenMoji-black-glyf.woff2 +0 -0
- package/apps/agents-server/public/fonts/OpenMoji-color-cbdt.woff2 +0 -0
- package/apps/agents-server/public/logo-blue-white-256.png +0 -0
- package/apps/agents-server/public/sw.js +0 -16
- package/apps/agents-server/public/swagger.json +0 -115
- package/apps/agents-server/scripts/generate-reserved-paths/generate-reserved-paths.ts +0 -54
- package/apps/agents-server/scripts/generate-reserved-paths/tsconfig.json +0 -19
- package/apps/agents-server/src/app/AddAgentButton.tsx +0 -41
- package/apps/agents-server/src/app/[agentName]/[...rest]/page.tsx +0 -11
- package/apps/agents-server/src/app/[agentName]/page.tsx +0 -1
- package/apps/agents-server/src/app/actions.ts +0 -65
- package/apps/agents-server/src/app/admin/api-tokens/ApiTokensClient.tsx +0 -186
- package/apps/agents-server/src/app/admin/api-tokens/page.tsx +0 -13
- package/apps/agents-server/src/app/admin/browser-test/BrowserTestClient.tsx +0 -85
- package/apps/agents-server/src/app/admin/browser-test/page.tsx +0 -13
- package/apps/agents-server/src/app/admin/chat-feedback/ChatFeedbackClient.tsx +0 -561
- package/apps/agents-server/src/app/admin/chat-feedback/page.tsx +0 -22
- package/apps/agents-server/src/app/admin/chat-history/ChatHistoryClient.tsx +0 -591
- package/apps/agents-server/src/app/admin/chat-history/page.tsx +0 -21
- package/apps/agents-server/src/app/admin/messages/MessagesClient.tsx +0 -294
- package/apps/agents-server/src/app/admin/messages/page.tsx +0 -13
- package/apps/agents-server/src/app/admin/messages/send-email/SendEmailClient.tsx +0 -104
- package/apps/agents-server/src/app/admin/messages/send-email/actions.ts +0 -35
- package/apps/agents-server/src/app/admin/messages/send-email/page.tsx +0 -13
- package/apps/agents-server/src/app/admin/metadata/MetadataClient.tsx +0 -481
- package/apps/agents-server/src/app/admin/metadata/page.tsx +0 -13
- package/apps/agents-server/src/app/admin/models/page.tsx +0 -22
- package/apps/agents-server/src/app/admin/users/[userId]/UserDetailClient.tsx +0 -131
- package/apps/agents-server/src/app/admin/users/[userId]/page.tsx +0 -21
- package/apps/agents-server/src/app/admin/users/page.tsx +0 -18
- package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +0 -92
- package/apps/agents-server/src/app/agents/[agentName]/AgentOptionsMenu.tsx +0 -356
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileChat.tsx +0 -134
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileWrapper.tsx +0 -90
- package/apps/agents-server/src/app/agents/[agentName]/AgentUrlCopy.tsx +0 -40
- package/apps/agents-server/src/app/agents/[agentName]/ClearAgentChatFeedbackButton.tsx +0 -63
- package/apps/agents-server/src/app/agents/[agentName]/ClearAgentChatHistoryButton.tsx +0 -63
- package/apps/agents-server/src/app/agents/[agentName]/CloneAgentButton.tsx +0 -41
- package/apps/agents-server/src/app/agents/[agentName]/CopyField.tsx +0 -44
- package/apps/agents-server/src/app/agents/[agentName]/InstallPwaButton.tsx +0 -74
- package/apps/agents-server/src/app/agents/[agentName]/ServiceWorkerRegister.tsx +0 -24
- package/apps/agents-server/src/app/agents/[agentName]/TODO.txt +0 -1
- package/apps/agents-server/src/app/agents/[agentName]/_utils.ts +0 -38
- package/apps/agents-server/src/app/agents/[agentName]/agentLinks.tsx +0 -80
- package/apps/agents-server/src/app/agents/[agentName]/api/agents/route.ts +0 -58
- package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +0 -88
- package/apps/agents-server/src/app/agents/[agentName]/api/book/test.http +0 -37
- package/apps/agents-server/src/app/agents/[agentName]/api/chat/route.ts +0 -194
- package/apps/agents-server/src/app/agents/[agentName]/api/feedback/route.ts +0 -54
- package/apps/agents-server/src/app/agents/[agentName]/api/mcp/route.ts +0 -198
- package/apps/agents-server/src/app/agents/[agentName]/api/modelRequirements/TODO.txt +0 -1
- package/apps/agents-server/src/app/agents/[agentName]/api/modelRequirements/route.ts +0 -55
- package/apps/agents-server/src/app/agents/[agentName]/api/modelRequirements/systemMessage/route.ts +0 -47
- package/apps/agents-server/src/app/agents/[agentName]/api/openai/chat/completions/route.ts +0 -10
- package/apps/agents-server/src/app/agents/[agentName]/api/openai/models/route.ts +0 -93
- package/apps/agents-server/src/app/agents/[agentName]/api/openai/v1/chat/completions/route.ts +0 -10
- package/apps/agents-server/src/app/agents/[agentName]/api/openai/v1/models/route.ts +0 -93
- package/apps/agents-server/src/app/agents/[agentName]/api/openrouter/chat/completions/route.ts +0 -10
- package/apps/agents-server/src/app/agents/[agentName]/api/profile/route.ts +0 -80
- package/apps/agents-server/src/app/agents/[agentName]/api/voice/route.ts +0 -184
- package/apps/agents-server/src/app/agents/[agentName]/book/BookEditorWrapper.tsx +0 -143
- package/apps/agents-server/src/app/agents/[agentName]/book/page.tsx +0 -48
- package/apps/agents-server/src/app/agents/[agentName]/book+chat/AgentBookAndChat.tsx +0 -75
- package/apps/agents-server/src/app/agents/[agentName]/book+chat/AgentBookAndChatComponent.tsx.todo +0 -160
- package/apps/agents-server/src/app/agents/[agentName]/book+chat/page.tsx +0 -45
- package/apps/agents-server/src/app/agents/[agentName]/book+chat/page.tsx.todo +0 -21
- package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatWrapper.tsx +0 -68
- package/apps/agents-server/src/app/agents/[agentName]/chat/page.tsx +0 -45
- package/apps/agents-server/src/app/agents/[agentName]/code/api/route.ts +0 -68
- package/apps/agents-server/src/app/agents/[agentName]/code/page.tsx +0 -223
- package/apps/agents-server/src/app/agents/[agentName]/generateAgentMetadata.ts +0 -51
- package/apps/agents-server/src/app/agents/[agentName]/history/RestoreVersionButton.tsx +0 -46
- package/apps/agents-server/src/app/agents/[agentName]/history/actions.ts +0 -12
- package/apps/agents-server/src/app/agents/[agentName]/history/page.tsx +0 -62
- package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/getAgentDefaultAvatarPrompt.ts +0 -31
- package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/route.ts +0 -157
- package/apps/agents-server/src/app/agents/[agentName]/images/icon-256.png/route.tsx +0 -92
- package/apps/agents-server/src/app/agents/[agentName]/images/page.tsx +0 -200
- package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-fullhd.png/route.tsx +0 -93
- package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-phone.png/route.tsx +0 -93
- package/apps/agents-server/src/app/agents/[agentName]/integration/SdkCodeTabs.tsx +0 -31
- package/apps/agents-server/src/app/agents/[agentName]/integration/WebsiteIntegrationTabs.tsx +0 -26
- package/apps/agents-server/src/app/agents/[agentName]/integration/page.tsx +0 -326
- package/apps/agents-server/src/app/agents/[agentName]/layout.tsx +0 -41
- package/apps/agents-server/src/app/agents/[agentName]/links/page.tsx +0 -189
- package/apps/agents-server/src/app/agents/[agentName]/opengraph-image.tsx +0 -111
- package/apps/agents-server/src/app/agents/[agentName]/page.tsx +0 -114
- package/apps/agents-server/src/app/agents/[agentName]/system-message/page.tsx +0 -100
- package/apps/agents-server/src/app/agents/[agentName]/website-integration/page.tsx +0 -89
- package/apps/agents-server/src/app/agents/page.tsx +0 -11
- package/apps/agents-server/src/app/api/admin-email/route.ts +0 -12
- package/apps/agents-server/src/app/api/agents/[agentName]/clone/route.ts +0 -45
- package/apps/agents-server/src/app/api/agents/[agentName]/restore/route.ts +0 -19
- package/apps/agents-server/src/app/api/agents/[agentName]/route.ts +0 -60
- package/apps/agents-server/src/app/api/agents/route.ts +0 -68
- package/apps/agents-server/src/app/api/api-tokens/route.ts +0 -75
- package/apps/agents-server/src/app/api/auth/change-password/route.ts +0 -75
- package/apps/agents-server/src/app/api/auth/login/route.ts +0 -27
- package/apps/agents-server/src/app/api/auth/logout/route.ts +0 -7
- package/apps/agents-server/src/app/api/browser-test/screenshot/route.ts +0 -30
- package/apps/agents-server/src/app/api/chat/route.ts +0 -32
- package/apps/agents-server/src/app/api/chat-feedback/[id]/route.ts +0 -38
- package/apps/agents-server/src/app/api/chat-feedback/export/route.ts +0 -55
- package/apps/agents-server/src/app/api/chat-feedback/route.ts +0 -157
- package/apps/agents-server/src/app/api/chat-history/[id]/route.ts +0 -37
- package/apps/agents-server/src/app/api/chat-history/export/route.ts +0 -55
- package/apps/agents-server/src/app/api/chat-history/route.ts +0 -147
- package/apps/agents-server/src/app/api/chat-streaming/route.ts +0 -48
- package/apps/agents-server/src/app/api/docs/book.md/route.ts +0 -61
- package/apps/agents-server/src/app/api/emails/incoming/sendgrid/route.ts +0 -48
- package/apps/agents-server/src/app/api/embed.js/route.ts +0 -113
- package/apps/agents-server/src/app/api/federated-agents/route.ts +0 -29
- package/apps/agents-server/src/app/api/images/[filename]/route.ts +0 -107
- package/apps/agents-server/src/app/api/long-running-task/route.ts +0 -7
- package/apps/agents-server/src/app/api/long-streaming/route.ts +0 -20
- package/apps/agents-server/src/app/api/messages/route.ts +0 -102
- package/apps/agents-server/src/app/api/metadata/route.ts +0 -115
- package/apps/agents-server/src/app/api/openai/v1/chat/completions/route.ts +0 -6
- package/apps/agents-server/src/app/api/openai/v1/models/route.ts +0 -65
- package/apps/agents-server/src/app/api/upload/route.ts +0 -166
- package/apps/agents-server/src/app/api/users/[username]/route.ts +0 -75
- package/apps/agents-server/src/app/api/users/route.ts +0 -71
- package/apps/agents-server/src/app/docs/[docId]/page.tsx +0 -42
- package/apps/agents-server/src/app/docs/page.tsx +0 -59
- package/apps/agents-server/src/app/embed/layout.tsx +0 -31
- package/apps/agents-server/src/app/embed/page.tsx +0 -37
- package/apps/agents-server/src/app/globals.css +0 -383
- package/apps/agents-server/src/app/humans.txt/route.ts +0 -15
- package/apps/agents-server/src/app/layout.tsx +0 -144
- package/apps/agents-server/src/app/manifest.ts +0 -114
- package/apps/agents-server/src/app/not-found.tsx +0 -5
- package/apps/agents-server/src/app/page.tsx +0 -144
- package/apps/agents-server/src/app/recycle-bin/RestoreAgentButton.tsx +0 -40
- package/apps/agents-server/src/app/recycle-bin/actions.ts +0 -33
- package/apps/agents-server/src/app/recycle-bin/page.tsx +0 -44
- package/apps/agents-server/src/app/restricted/page.tsx +0 -33
- package/apps/agents-server/src/app/robots.txt/route.ts +0 -15
- package/apps/agents-server/src/app/security.txt/route.ts +0 -15
- package/apps/agents-server/src/app/sitemap.xml/route.ts +0 -39
- package/apps/agents-server/src/app/swagger/page.tsx +0 -14
- package/apps/agents-server/src/app/test/og-image/README.md +0 -1
- package/apps/agents-server/src/app/test/og-image/opengraph-image.tsx +0 -37
- package/apps/agents-server/src/app/test/og-image/page.tsx +0 -22
- package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +0 -267
- package/apps/agents-server/src/components/AgentProfile/AgentProfileFromSource.tsx +0 -23
- package/apps/agents-server/src/components/AgentProfile/AgentQrCode.tsx +0 -62
- package/apps/agents-server/src/components/AgentProfile/QrCodeModal.tsx +0 -89
- package/apps/agents-server/src/components/AgentProfile/useAgentBackground.ts +0 -97
- package/apps/agents-server/src/components/Auth/AuthControls.tsx +0 -124
- package/apps/agents-server/src/components/ChangePasswordDialog/ChangePasswordDialog.tsx +0 -41
- package/apps/agents-server/src/components/ChangePasswordForm/ChangePasswordForm.tsx +0 -159
- package/apps/agents-server/src/components/DeletedAgentBanner.tsx +0 -26
- package/apps/agents-server/src/components/DocsToolbar/DocsToolbar.tsx +0 -38
- package/apps/agents-server/src/components/DocumentationContent/DocumentationContent.tsx +0 -90
- package/apps/agents-server/src/components/ErrorPage/ErrorPage.tsx +0 -33
- package/apps/agents-server/src/components/Footer/Footer.tsx +0 -175
- package/apps/agents-server/src/components/ForbiddenPage/ForbiddenPage.tsx +0 -15
- package/apps/agents-server/src/components/ForgottenPasswordDialog/ForgottenPasswordDialog.tsx +0 -61
- package/apps/agents-server/src/components/Header/Header.tsx +0 -742
- package/apps/agents-server/src/components/Homepage/AgentCard.tsx +0 -182
- package/apps/agents-server/src/components/Homepage/AgentsList.tsx +0 -136
- package/apps/agents-server/src/components/Homepage/Card.tsx +0 -18
- package/apps/agents-server/src/components/Homepage/DeletedAgentsList.tsx +0 -66
- package/apps/agents-server/src/components/Homepage/ExternalAgentsSection.tsx +0 -30
- package/apps/agents-server/src/components/Homepage/ExternalAgentsSectionClient.tsx +0 -192
- package/apps/agents-server/src/components/Homepage/ModelCard.tsx +0 -29
- package/apps/agents-server/src/components/Homepage/ModelsSection.tsx +0 -75
- package/apps/agents-server/src/components/Homepage/Section.tsx +0 -17
- package/apps/agents-server/src/components/Homepage/TechInfoCard.tsx +0 -20
- package/apps/agents-server/src/components/LayoutWrapper/LayoutWrapper.tsx +0 -58
- package/apps/agents-server/src/components/LoginDialog/LoginDialog.tsx +0 -41
- package/apps/agents-server/src/components/LoginForm/LoginForm.tsx +0 -158
- package/apps/agents-server/src/components/NotFoundPage/NotFoundPage.tsx +0 -22
- package/apps/agents-server/src/components/OpenMojiIcon/OpenMojiIcon.tsx +0 -29
- package/apps/agents-server/src/components/Portal/Portal.tsx +0 -38
- package/apps/agents-server/src/components/PrintHeader/PrintHeader.tsx +0 -18
- package/apps/agents-server/src/components/RegisterUserDialog/RegisterUserDialog.tsx +0 -61
- package/apps/agents-server/src/components/UsersList/UsersList.tsx +0 -141
- package/apps/agents-server/src/components/UsersList/useUsersAdmin.ts +0 -139
- package/apps/agents-server/src/components/VercelDeploymentCard/VercelDeploymentCard.tsx +0 -57
- package/apps/agents-server/src/components/_utils/generateMetaTxt.ts +0 -30
- package/apps/agents-server/src/components/_utils/headlessParam.tsx +0 -40
- package/apps/agents-server/src/database/$getTableName.ts +0 -18
- package/apps/agents-server/src/database/$provideSupabase.ts +0 -29
- package/apps/agents-server/src/database/$provideSupabaseForBrowser.ts +0 -41
- package/apps/agents-server/src/database/$provideSupabaseForServer.ts +0 -48
- package/apps/agents-server/src/database/$provideSupabaseForWorker.ts +0 -43
- package/apps/agents-server/src/database/getMetadata.ts +0 -31
- package/apps/agents-server/src/database/metadataDefaults.ts +0 -93
- package/apps/agents-server/src/database/migrate.ts +0 -164
- package/apps/agents-server/src/database/migrations/2025-11-0001-initial-schema.sql +0 -161
- package/apps/agents-server/src/database/migrations/2025-11-0002-metadata-table.sql +0 -14
- package/apps/agents-server/src/database/migrations/2025-12-0010-llm-cache.sql +0 -12
- package/apps/agents-server/src/database/migrations/2025-12-0060-api-tokens.sql +0 -13
- package/apps/agents-server/src/database/migrations/2025-12-0070-chat-history-source.sql +0 -2
- package/apps/agents-server/src/database/migrations/2025-12-0240-agent-public-id.sql +0 -3
- package/apps/agents-server/src/database/migrations/2025-12-0360-agent-deleted-at.sql +0 -1
- package/apps/agents-server/src/database/migrations/2025-12-0370-image-table.sql +0 -19
- package/apps/agents-server/src/database/migrations/2025-12-0380-agent-visibility.sql +0 -1
- package/apps/agents-server/src/database/migrations/2025-12-0390-upload-tracking.sql +0 -20
- package/apps/agents-server/src/database/migrations/2025-12-0401-file-upload-status.sql +0 -13
- package/apps/agents-server/src/database/migrations/2025-12-0402-message-table.sql +0 -42
- package/apps/agents-server/src/database/migrations/2025-12-0640-openai-assistant-cache.sql +0 -12
- package/apps/agents-server/src/database/schema.ts +0 -508
- package/apps/agents-server/src/deamons/longRunningTask.ts +0 -37
- package/apps/agents-server/src/generated/reservedPaths.ts +0 -32
- package/apps/agents-server/src/message-providers/email/_common/Email.ts +0 -73
- package/apps/agents-server/src/message-providers/email/_common/utils/TODO.txt +0 -1
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddress.test.ts.todo +0 -108
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddress.ts +0 -62
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddresses.test.ts.todo +0 -117
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddresses.ts +0 -19
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddress.test.ts.todo +0 -119
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddress.ts +0 -19
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddresses.test.ts.todo +0 -74
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddresses.ts +0 -14
- package/apps/agents-server/src/message-providers/email/sendgrid/SendgridMessageProvider.ts +0 -44
- package/apps/agents-server/src/message-providers/email/sendgrid/parseInboundSendgridEmail.ts +0 -49
- package/apps/agents-server/src/message-providers/email/zeptomail/ZeptomailMessageProvider.ts +0 -51
- package/apps/agents-server/src/message-providers/index.ts +0 -13
- package/apps/agents-server/src/message-providers/interfaces/MessageProvider.ts +0 -11
- package/apps/agents-server/src/middleware.ts +0 -301
- package/apps/agents-server/src/tools/$provideAgentCollectionForServer.ts +0 -54
- package/apps/agents-server/src/tools/$provideBrowserForServer.ts +0 -29
- package/apps/agents-server/src/tools/$provideCdnForServer.ts +0 -41
- package/apps/agents-server/src/tools/$provideExecutionToolsForServer.ts +0 -117
- package/apps/agents-server/src/tools/$provideOpenAiAssistantExecutionToolsForServer.ts +0 -35
- package/apps/agents-server/src/tools/$provideServer.ts +0 -39
- package/apps/agents-server/src/utils/auth.ts +0 -133
- package/apps/agents-server/src/utils/authenticateUser.ts +0 -42
- package/apps/agents-server/src/utils/cache/SupabaseCacheStorage.ts +0 -55
- package/apps/agents-server/src/utils/cdn/classes/DigitalOceanSpaces.ts +0 -119
- package/apps/agents-server/src/utils/cdn/classes/TrackedFilesStorage.ts +0 -57
- package/apps/agents-server/src/utils/cdn/classes/VercelBlobStorage.ts +0 -68
- package/apps/agents-server/src/utils/cdn/interfaces/IFilesStorage.ts +0 -50
- package/apps/agents-server/src/utils/cdn/interfaces/IStorage.ts +0 -14
- package/apps/agents-server/src/utils/cdn/utils/getUserFileCdnKey.ts +0 -28
- package/apps/agents-server/src/utils/cdn/utils/nameToSubfolderPath.ts +0 -9
- package/apps/agents-server/src/utils/cdn/utils/nextRequestToNodeRequest.ts +0 -27
- package/apps/agents-server/src/utils/chatFeedbackAdmin.ts +0 -96
- package/apps/agents-server/src/utils/chatHistoryAdmin.ts +0 -96
- package/apps/agents-server/src/utils/content/extractBodyContentFromHtml.ts +0 -19
- package/apps/agents-server/src/utils/convertToCsv.ts +0 -31
- package/apps/agents-server/src/utils/getCurrentUser.ts +0 -32
- package/apps/agents-server/src/utils/getEffectiveFederatedServers.ts +0 -22
- package/apps/agents-server/src/utils/getFederatedAgents.ts +0 -89
- package/apps/agents-server/src/utils/getFederatedServersFromMetadata.ts +0 -10
- package/apps/agents-server/src/utils/getUserIdFromRequest.ts +0 -35
- package/apps/agents-server/src/utils/getVisibleCommitmentDefinitions.ts +0 -12
- package/apps/agents-server/src/utils/handleChatCompletion.ts +0 -415
- package/apps/agents-server/src/utils/isIpAllowed.ts +0 -101
- package/apps/agents-server/src/utils/isUserAdmin.ts +0 -31
- package/apps/agents-server/src/utils/messages/sendMessage.ts +0 -91
- package/apps/agents-server/src/utils/messagesAdmin.ts +0 -72
- package/apps/agents-server/src/utils/normalization/filenameToPrompt.test.ts +0 -36
- package/apps/agents-server/src/utils/normalization/filenameToPrompt.ts +0 -25
- package/apps/agents-server/src/utils/resolveInheritedAgentSource.ts +0 -100
- package/apps/agents-server/src/utils/session.ts +0 -50
- package/apps/agents-server/src/utils/validateApiKey.ts +0 -124
- package/apps/agents-server/src/utils/validators/validateMimeType.ts +0 -24
- package/apps/agents-server/tailwind.config.ts +0 -26
- package/apps/agents-server/tsconfig.json +0 -29
- package/apps/agents-server/vercel.json +0 -7
- package/esm/typings/servers.d.ts +0 -50
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { createHash, randomBytes, scrypt, timingSafeEqual } from 'crypto';
|
|
2
|
-
import { promisify } from 'util';
|
|
3
|
-
import { PASSWORD_SECURITY_CONFIG } from '../../../../security.config';
|
|
4
|
-
|
|
5
|
-
const scryptAsync = promisify(scrypt);
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Validates password input to prevent edge cases and DoS attacks
|
|
9
|
-
*
|
|
10
|
-
* @param password The password to validate
|
|
11
|
-
* @throws Error if password is invalid
|
|
12
|
-
*/
|
|
13
|
-
function validatePasswordInput(password: string): void {
|
|
14
|
-
if (typeof password !== 'string') {
|
|
15
|
-
throw new Error('Password must be a string');
|
|
16
|
-
}
|
|
17
|
-
if (password.length === 0) {
|
|
18
|
-
throw new Error('Password cannot be empty');
|
|
19
|
-
}
|
|
20
|
-
if (password.length < PASSWORD_SECURITY_CONFIG.MIN_PASSWORD_LENGTH) {
|
|
21
|
-
throw new Error(`Password must be at least ${PASSWORD_SECURITY_CONFIG.MIN_PASSWORD_LENGTH} characters`);
|
|
22
|
-
}
|
|
23
|
-
// Note: No hard max limit - long passwords are compacted via compactPassword()
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Compacts a password for secure processing
|
|
28
|
-
*
|
|
29
|
-
* If the password is within MAX_PASSWORD_LENGTH, it is returned as-is.
|
|
30
|
-
* If longer, the password is split at MAX_PASSWORD_LENGTH and the second part
|
|
31
|
-
* is hashed with SHA256 before being appended to the first part.
|
|
32
|
-
*
|
|
33
|
-
* This prevents DoS attacks via extremely long passwords while still utilizing
|
|
34
|
-
* the full entropy of longer passwords.
|
|
35
|
-
*
|
|
36
|
-
* @param password The password to compact
|
|
37
|
-
* @returns The compacted password
|
|
38
|
-
*/
|
|
39
|
-
function compactPassword(password: string): string {
|
|
40
|
-
if (password.length <= PASSWORD_SECURITY_CONFIG.MAX_PASSWORD_LENGTH) {
|
|
41
|
-
return password;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const firstPart = password.slice(0, PASSWORD_SECURITY_CONFIG.MAX_PASSWORD_LENGTH);
|
|
45
|
-
const secondPart = password.slice(PASSWORD_SECURITY_CONFIG.MAX_PASSWORD_LENGTH);
|
|
46
|
-
|
|
47
|
-
// Hash the overflow part with SHA256 to bound its length while preserving entropy
|
|
48
|
-
const secondPartHash = createHash('sha256').update(secondPart, 'utf8').digest('hex');
|
|
49
|
-
|
|
50
|
-
return firstPart + secondPartHash;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Hashes a password using scrypt with secure parameters
|
|
55
|
-
*
|
|
56
|
-
* @param password The plain text password (minimum 8 characters, no maximum - long passwords are compacted)
|
|
57
|
-
* @returns The salt and hash formatted as "salt:hash"
|
|
58
|
-
* @throws Error if password validation fails
|
|
59
|
-
*/
|
|
60
|
-
export async function hashPassword(password: string): Promise<string> {
|
|
61
|
-
validatePasswordInput(password);
|
|
62
|
-
|
|
63
|
-
// Compact long passwords to prevent DoS while preserving entropy
|
|
64
|
-
const compactedPassword = compactPassword(password);
|
|
65
|
-
|
|
66
|
-
const salt = randomBytes(PASSWORD_SECURITY_CONFIG.SALT_LENGTH).toString('hex');
|
|
67
|
-
const derivedKey = (await scryptAsync(compactedPassword, salt, PASSWORD_SECURITY_CONFIG.KEY_LENGTH)) as Buffer;
|
|
68
|
-
|
|
69
|
-
// Clear password from memory as soon as possible (best effort)
|
|
70
|
-
// Note: JavaScript strings are immutable, so this is limited in effectiveness
|
|
71
|
-
return `${salt}:${derivedKey.toString('hex')}`;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Verifies a password against a stored hash using constant-time comparison
|
|
76
|
-
*
|
|
77
|
-
* @param password The plain text password to verify
|
|
78
|
-
* @param storedHash The stored hash in format "salt:hash"
|
|
79
|
-
* @returns True if the password matches, false otherwise
|
|
80
|
-
*/
|
|
81
|
-
export async function verifyPassword(password: string, storedHash: string): Promise<boolean> {
|
|
82
|
-
// Validate inputs
|
|
83
|
-
if (typeof password !== 'string' || typeof storedHash !== 'string') {
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (password.length === 0) {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Compact long passwords the same way as during hashing
|
|
92
|
-
const compactedPassword = compactPassword(password);
|
|
93
|
-
|
|
94
|
-
const parts = storedHash.split(':');
|
|
95
|
-
if (parts.length !== 2) {
|
|
96
|
-
return false;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const [salt, key] = parts;
|
|
100
|
-
if (!salt || !key) {
|
|
101
|
-
return false;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Validate salt and key format (should be hex strings of expected length)
|
|
105
|
-
const expectedSaltLength = PASSWORD_SECURITY_CONFIG.SALT_LENGTH * 2; // hex encoding doubles length
|
|
106
|
-
const expectedKeyLength = PASSWORD_SECURITY_CONFIG.KEY_LENGTH * 2;
|
|
107
|
-
|
|
108
|
-
if (salt.length !== expectedSaltLength || key.length !== expectedKeyLength) {
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Validate hex format
|
|
113
|
-
const hexRegex = /^[0-9a-fA-F]+$/;
|
|
114
|
-
if (!hexRegex.test(salt) || !hexRegex.test(key)) {
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
try {
|
|
119
|
-
const derivedKey = (await scryptAsync(compactedPassword, salt, PASSWORD_SECURITY_CONFIG.KEY_LENGTH)) as Buffer;
|
|
120
|
-
const keyBuffer = Buffer.from(key, 'hex');
|
|
121
|
-
|
|
122
|
-
// Ensure buffers are same length before timing-safe comparison
|
|
123
|
-
// This should always be true given our validation, but defense in depth
|
|
124
|
-
if (derivedKey.length !== keyBuffer.length) {
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return timingSafeEqual(derivedKey, keyBuffer);
|
|
129
|
-
} catch {
|
|
130
|
-
// Any error during verification should return false, not leak information
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { $getTableName } from '../database/$getTableName';
|
|
2
|
-
import { $provideSupabaseForServer } from '../database/$provideSupabaseForServer';
|
|
3
|
-
import { AgentsServerDatabase } from '../database/schema';
|
|
4
|
-
import { verifyPassword } from './auth';
|
|
5
|
-
|
|
6
|
-
export type AuthenticatedUser = {
|
|
7
|
-
username: string;
|
|
8
|
-
isAdmin: boolean;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export async function authenticateUser(username: string, password: string): Promise<AuthenticatedUser | null> {
|
|
12
|
-
// 1. Check if it's the environment admin
|
|
13
|
-
if (username === 'admin' && process.env.ADMIN_PASSWORD && password === process.env.ADMIN_PASSWORD) {
|
|
14
|
-
return { username: 'admin', isAdmin: true };
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// 2. Check DB users
|
|
18
|
-
try {
|
|
19
|
-
const supabase = $provideSupabaseForServer();
|
|
20
|
-
const { data: user, error } = await supabase
|
|
21
|
-
.from(await $getTableName('User'))
|
|
22
|
-
.select('*')
|
|
23
|
-
.eq('username', username)
|
|
24
|
-
.single();
|
|
25
|
-
|
|
26
|
-
if (error || !user) {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const userRow = user as AgentsServerDatabase['public']['Tables']['User']['Row'];
|
|
31
|
-
const isValid = await verifyPassword(password, userRow.passwordHash);
|
|
32
|
-
|
|
33
|
-
if (!isValid) {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return { username: userRow.username, isAdmin: userRow.isAdmin };
|
|
38
|
-
} catch (error) {
|
|
39
|
-
console.error('Authentication error:', error);
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { TODO_any } from '@promptbook-local/types';
|
|
2
|
-
import { $getTableName } from '../../database/$getTableName';
|
|
3
|
-
import { $provideSupabaseForServer } from '../../database/$provideSupabaseForServer';
|
|
4
|
-
import { Json } from '../../database/schema';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Storage for LLM cache using Supabase
|
|
8
|
-
*/
|
|
9
|
-
export class SupabaseCacheStorage {
|
|
10
|
-
// implements PromptbookStorage<TODO_any>
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Returns the current value associated with the given key, or null if the given key does not exist in the list associated with the object.
|
|
14
|
-
*/
|
|
15
|
-
public async getItem(key: string): Promise<TODO_any | null> {
|
|
16
|
-
const supabase = $provideSupabaseForServer();
|
|
17
|
-
const tableName = await $getTableName('LlmCache');
|
|
18
|
-
|
|
19
|
-
const { data } = await supabase.from(tableName).select('value').eq('hash', key).maybeSingle();
|
|
20
|
-
|
|
21
|
-
if (!data) {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return data.value;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
|
|
30
|
-
*/
|
|
31
|
-
public async setItem(key: string, value: TODO_any): Promise<void> {
|
|
32
|
-
const supabase = $provideSupabaseForServer();
|
|
33
|
-
const tableName = await $getTableName('LlmCache');
|
|
34
|
-
|
|
35
|
-
await supabase.from(tableName).upsert(
|
|
36
|
-
{
|
|
37
|
-
hash: key,
|
|
38
|
-
value: value as Json,
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
onConflict: 'hash',
|
|
42
|
-
},
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Removes the key/value pair with the given key from the list associated with the object, if a key/value pair with the given key exists
|
|
48
|
-
*/
|
|
49
|
-
public async removeItem(key: string): Promise<void> {
|
|
50
|
-
const supabase = $provideSupabaseForServer();
|
|
51
|
-
const tableName = await $getTableName('LlmCache');
|
|
52
|
-
|
|
53
|
-
await supabase.from(tableName).delete().eq('hash', key);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { GetObjectCommand, PutObjectCommand, PutObjectCommandInput, S3Client } from '@aws-sdk/client-s3';
|
|
2
|
-
import { NotYetImplementedError } from '@promptbook-local/core';
|
|
3
|
-
import { gzip, ungzip } from 'node-gzip';
|
|
4
|
-
import { TODO_USE } from '../../../../../../src/utils/organization/TODO_USE';
|
|
5
|
-
import { validateMimeType } from '../../validators/validateMimeType';
|
|
6
|
-
import type { IFile, IIFilesStorageWithCdn } from '../interfaces/IFilesStorage';
|
|
7
|
-
|
|
8
|
-
type IDigitalOceanSpacesConfig = {
|
|
9
|
-
readonly bucket: string;
|
|
10
|
-
readonly pathPrefix: string;
|
|
11
|
-
readonly endpoint: string;
|
|
12
|
-
readonly accessKeyId: string;
|
|
13
|
-
readonly secretAccessKey: string;
|
|
14
|
-
readonly cdnPublicUrl: URL;
|
|
15
|
-
readonly gzip: boolean;
|
|
16
|
-
|
|
17
|
-
// TODO: [⛳️] Probbably prefix should be in this config not on the consumer side
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export class DigitalOceanSpaces implements IIFilesStorageWithCdn {
|
|
21
|
-
public get cdnPublicUrl() {
|
|
22
|
-
return this.config.cdnPublicUrl;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
private s3: S3Client;
|
|
26
|
-
|
|
27
|
-
public constructor(private readonly config: IDigitalOceanSpacesConfig) {
|
|
28
|
-
this.s3 = new S3Client({
|
|
29
|
-
region: 'auto',
|
|
30
|
-
endpoint: 'https://' + config.endpoint,
|
|
31
|
-
credentials: {
|
|
32
|
-
accessKeyId: config.accessKeyId,
|
|
33
|
-
secretAccessKey: config.secretAccessKey,
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
public getItemUrl(key: string): URL {
|
|
39
|
-
return new URL(this.config.pathPrefix + '/' + key, this.cdnPublicUrl);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
public async getItem(key: string): Promise<IFile | null> {
|
|
43
|
-
const parameters = {
|
|
44
|
-
Bucket: this.config.bucket,
|
|
45
|
-
Key: this.config.pathPrefix + '/' + key,
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
try {
|
|
49
|
-
const { Body, ContentType, ContentEncoding } = await this.s3.send(new GetObjectCommand(parameters));
|
|
50
|
-
|
|
51
|
-
// const blob = new Blob([await Body?.transformToByteArray()!]);
|
|
52
|
-
|
|
53
|
-
if (ContentEncoding === 'gzip') {
|
|
54
|
-
return {
|
|
55
|
-
type: validateMimeType(ContentType),
|
|
56
|
-
data: await ungzip(await Body!.transformToByteArray()),
|
|
57
|
-
};
|
|
58
|
-
} else {
|
|
59
|
-
return {
|
|
60
|
-
type: validateMimeType(ContentType),
|
|
61
|
-
data: (await Body!.transformToByteArray()) as Buffer,
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
} catch (error) {
|
|
65
|
-
if (error instanceof Error && error.name.match(/^NoSuchKey/)) {
|
|
66
|
-
return null;
|
|
67
|
-
} else {
|
|
68
|
-
throw error;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
public async removeItem(key: string): Promise<void> {
|
|
74
|
-
TODO_USE(key);
|
|
75
|
-
throw new NotYetImplementedError(`DigitalOceanSpaces.removeItem is not implemented yet`);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
public async setItem(key: string, file: IFile): Promise<void> {
|
|
79
|
-
// TODO: Put putObjectRequestAdditional into processedFile
|
|
80
|
-
const putObjectRequestAdditional: Partial<PutObjectCommandInput> = {};
|
|
81
|
-
|
|
82
|
-
let processedFile: IFile;
|
|
83
|
-
if (this.config.gzip) {
|
|
84
|
-
const gzipped = await gzip(file.data);
|
|
85
|
-
const sizePercentageAfterCompression = gzipped.byteLength / file.data.byteLength;
|
|
86
|
-
if (sizePercentageAfterCompression < 0.7) {
|
|
87
|
-
// consolex.log(`Gzipping ${key} (${Math.floor(sizePercentageAfterCompression * 100)}%)`);
|
|
88
|
-
processedFile = { ...file, data: gzipped };
|
|
89
|
-
putObjectRequestAdditional.ContentEncoding = 'gzip';
|
|
90
|
-
} else {
|
|
91
|
-
processedFile = file;
|
|
92
|
-
// consolex.log(`NOT Gzipping ${key} (${Math.floor(sizePercentageAfterCompression * 100)}%)`);
|
|
93
|
-
}
|
|
94
|
-
} else {
|
|
95
|
-
processedFile = file;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const uploadResult = await this.s3.send(
|
|
99
|
-
new PutObjectCommand({
|
|
100
|
-
Bucket: this.config.bucket,
|
|
101
|
-
Key: this.config.pathPrefix + '/' + key,
|
|
102
|
-
ContentType: processedFile.type,
|
|
103
|
-
...putObjectRequestAdditional,
|
|
104
|
-
Body: processedFile.data,
|
|
105
|
-
// TODO: Public read access / just private to extending class
|
|
106
|
-
ACL: 'public-read',
|
|
107
|
-
}),
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
if (!uploadResult.ETag) {
|
|
111
|
-
throw new Error(`Upload result does not contain ETag`);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* TODO: Implement Read-only mode
|
|
118
|
-
* TODO: [☹️] Unite with `PromptbookStorage` and move to `/src/...`
|
|
119
|
-
*/
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
-
import { $getTableName } from '../../../database/$getTableName';
|
|
3
|
-
import { AgentsServerDatabase } from '../../../database/schema';
|
|
4
|
-
import type { IFile, IIFilesStorageWithCdn } from '../interfaces/IFilesStorage';
|
|
5
|
-
|
|
6
|
-
export class TrackedFilesStorage implements IIFilesStorageWithCdn {
|
|
7
|
-
public constructor(
|
|
8
|
-
private readonly inner: IIFilesStorageWithCdn,
|
|
9
|
-
private readonly supabase: SupabaseClient<AgentsServerDatabase>,
|
|
10
|
-
) {}
|
|
11
|
-
|
|
12
|
-
public get cdnPublicUrl(): URL {
|
|
13
|
-
return this.inner.cdnPublicUrl;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
public get pathPrefix(): string | undefined {
|
|
17
|
-
return this.inner.pathPrefix;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
public getItemUrl(key: string): URL {
|
|
21
|
-
return this.inner.getItemUrl(key);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public async getItem(key: string): Promise<IFile | null> {
|
|
25
|
-
return this.inner.getItem(key);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
public async removeItem(key: string): Promise<void> {
|
|
29
|
-
return this.inner.removeItem(key);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
public async setItem(key: string, file: IFile): Promise<void> {
|
|
33
|
-
console.log('!!! 0', { key, file });
|
|
34
|
-
|
|
35
|
-
await this.inner.setItem(key, file);
|
|
36
|
-
|
|
37
|
-
try {
|
|
38
|
-
const { userId, purpose } = file;
|
|
39
|
-
const cdnUrl = this.getItemUrl(key).href;
|
|
40
|
-
|
|
41
|
-
console.log('!!! 1', { userId, purpose, cdnUrl, key, file });
|
|
42
|
-
|
|
43
|
-
await this.supabase.from(await $getTableName('File')).insert({
|
|
44
|
-
userId: userId || null,
|
|
45
|
-
fileName: key,
|
|
46
|
-
fileSize: file.fileSize ?? file.data.length,
|
|
47
|
-
fileType: file.type,
|
|
48
|
-
cdnUrl,
|
|
49
|
-
purpose: purpose || 'UNKNOWN',
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
console.log('!!! 2', { userId, purpose, cdnUrl, key, file });
|
|
53
|
-
} catch (error) {
|
|
54
|
-
console.error('Failed to track upload:', error);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { del, put } from '@vercel/blob';
|
|
2
|
-
import { validateMimeType } from '../../validators/validateMimeType';
|
|
3
|
-
import type { IFile, IIFilesStorageWithCdn } from '../interfaces/IFilesStorage';
|
|
4
|
-
|
|
5
|
-
type IVercelBlobStorageConfig = {
|
|
6
|
-
readonly token: string;
|
|
7
|
-
readonly cdnPublicUrl: URL;
|
|
8
|
-
readonly pathPrefix?: string;
|
|
9
|
-
// Note: Vercel Blob automatically handles compression/serving
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export class VercelBlobStorage implements IIFilesStorageWithCdn {
|
|
13
|
-
public get cdnPublicUrl() {
|
|
14
|
-
return this.config.cdnPublicUrl;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
public get pathPrefix() {
|
|
18
|
-
return this.config.pathPrefix;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
public constructor(private readonly config: IVercelBlobStorageConfig) {}
|
|
22
|
-
|
|
23
|
-
public getItemUrl(key: string): URL {
|
|
24
|
-
const path = this.config.pathPrefix ? `${this.config.pathPrefix}/${key}` : key;
|
|
25
|
-
return new URL(path, this.cdnPublicUrl);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
public async getItem(key: string): Promise<IFile | null> {
|
|
29
|
-
const url = this.getItemUrl(key);
|
|
30
|
-
|
|
31
|
-
const response = await fetch(url);
|
|
32
|
-
|
|
33
|
-
if (response.status === 404) {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (!response.ok) {
|
|
38
|
-
throw new Error(`Failed to fetch blob from ${url}: ${response.statusText}`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
42
|
-
const buffer = Buffer.from(arrayBuffer);
|
|
43
|
-
const contentType = response.headers.get('content-type') || 'application/octet-stream';
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
type: validateMimeType(contentType),
|
|
47
|
-
data: buffer,
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
public async removeItem(key: string): Promise<void> {
|
|
52
|
-
const url = this.getItemUrl(key).toString();
|
|
53
|
-
await del(url, { token: this.config.token });
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
public async setItem(key: string, file: IFile): Promise<void> {
|
|
57
|
-
const path = this.config.pathPrefix ? `${this.config.pathPrefix}/${key}` : key;
|
|
58
|
-
|
|
59
|
-
await put(path, file.data, {
|
|
60
|
-
access: 'public',
|
|
61
|
-
addRandomSuffix: false,
|
|
62
|
-
contentType: file.type,
|
|
63
|
-
token: this.config.token,
|
|
64
|
-
allowOverwrite: true, // <- TODO: This is inefficient, we should check first if the file exists and only then decide to overwrite or not
|
|
65
|
-
// Note: We rely on Vercel Blob for compression
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import type { string_mime_type } from '../../../../../../src/types/typeAliases';
|
|
2
|
-
import type { IStorage } from './IStorage';
|
|
3
|
-
|
|
4
|
-
export type IFile = {
|
|
5
|
-
// Maybe TODO name: string_name;
|
|
6
|
-
type: string_mime_type;
|
|
7
|
-
data: Buffer;
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* User who uploaded the file
|
|
11
|
-
*/
|
|
12
|
-
userId?: number;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Purpose of the upload (e.g. KNOWLEDGE, SERVER_FAVICON_URL)
|
|
16
|
-
*/
|
|
17
|
-
purpose?: string;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Size of the file in bytes
|
|
21
|
-
*
|
|
22
|
-
* Note: This is optional, if not provided, the size of the buffer is used
|
|
23
|
-
*/
|
|
24
|
-
fileSize?: number;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Represents storage that will store each keypair in a separate file.
|
|
29
|
-
*/
|
|
30
|
-
export type IFilesStorage = Omit<IStorage<IFile>, 'length' | 'clear' | 'key'>;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Represents storage that can give public deterministic URL for each file
|
|
34
|
-
*/
|
|
35
|
-
export type IIFilesStorageWithCdn = IFilesStorage & {
|
|
36
|
-
readonly cdnPublicUrl: URL;
|
|
37
|
-
readonly pathPrefix?: string;
|
|
38
|
-
getItemUrl(key: string): URL;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* TODO: Probably not deterministic and async getItemUrl
|
|
43
|
-
* TODO: Probably just createUrlMaker
|
|
44
|
-
* TODO: List method
|
|
45
|
-
* TODO: Glob method
|
|
46
|
-
* TODO: Subfolder (similar to PrefixStorage) method
|
|
47
|
-
* TODO: Subscribe, list, sub(folder) should be part of LIB everstorage
|
|
48
|
-
* TODO: Probably implement observe through RxJS
|
|
49
|
-
* TODO: [☹️] Unite with `PromptbookStorage` and move to `/src/...`
|
|
50
|
-
*/
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// Note: This is a simplified version of the IStorage interface based on the usage in the project.
|
|
2
|
-
export type IStorage<T> = {
|
|
3
|
-
readonly length: Promise<number>;
|
|
4
|
-
clear(): Promise<void>;
|
|
5
|
-
getItem(key: string): Promise<T | null>;
|
|
6
|
-
key(index: number): Promise<string | null>;
|
|
7
|
-
removeItem(key: string): Promise<void>;
|
|
8
|
-
setItem(key: string, value: T): Promise<void>;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* TODO: [☹️] Unite with `PromptbookStorage` and move to `/src/...`
|
|
14
|
-
*/
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import hexEncoder from 'crypto-js/enc-hex';
|
|
2
|
-
import sha256 from 'crypto-js/sha256';
|
|
3
|
-
import type { string_uri } from '../../../../../../src/types/typeAliases';
|
|
4
|
-
import { titleToName } from '../../../../../../src/utils/normalization/titleToName';
|
|
5
|
-
import { nameToSubfolderPath } from './nameToSubfolderPath';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Generates a path for the user content
|
|
9
|
-
*/
|
|
10
|
-
export function getUserFileCdnKey(file: Buffer, originalFilename: string): string_uri {
|
|
11
|
-
const hash = sha256(hexEncoder.parse(file.toString('hex'))).toString(/* hex */);
|
|
12
|
-
// <- TODO: [🥬] Encapsulate sha256 to some private utility function
|
|
13
|
-
|
|
14
|
-
const originalFilenameParts = originalFilename.split('.');
|
|
15
|
-
const extension = originalFilenameParts.pop();
|
|
16
|
-
const name = titleToName(originalFilenameParts.join('.'));
|
|
17
|
-
|
|
18
|
-
const filename = name + '.' + extension;
|
|
19
|
-
// <- Note: [⛳️] Preserving original file name
|
|
20
|
-
|
|
21
|
-
return `user/files/${nameToSubfolderPath(hash).join('/')}/${filename}`;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* TODO: [🌍] Unite this logic in one place
|
|
26
|
-
* TODO: Way to garbage unused uploaded files
|
|
27
|
-
* TODO: Probably separate util countBufferHash
|
|
28
|
-
*/
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { string_name } from '../../../../../../src/types/typeAliases';
|
|
2
|
-
|
|
3
|
-
export function nameToSubfolderPath(name: string_name): Array<string> {
|
|
4
|
-
return [name.substr(0, 2).toLowerCase(), name.substr(2, 5).toLowerCase()];
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* TODO: [🐱🚀] Use `nameToSubfolderPath` from src
|
|
9
|
-
*/
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { TODO_any } from '@promptbook-local/types';
|
|
2
|
-
import { NextRequest } from 'next/server';
|
|
3
|
-
import { Readable } from 'node:stream';
|
|
4
|
-
|
|
5
|
-
export async function nextRequestToNodeRequest(nextRequest: NextRequest): Promise<Readable> {
|
|
6
|
-
const reader = nextRequest.body?.getReader();
|
|
7
|
-
|
|
8
|
-
if (!reader) {
|
|
9
|
-
throw new Error(`Can not get nextRequest.body.getReader()`);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const nodeStream = new Readable({
|
|
13
|
-
async read() {
|
|
14
|
-
const { done, value } = await reader.read();
|
|
15
|
-
if (done) this.push(null);
|
|
16
|
-
else this.push(Buffer.from(value));
|
|
17
|
-
},
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
// Fake IncomingMessage with headers
|
|
21
|
-
(nodeStream as TODO_any).headers = Object.fromEntries(nextRequest.headers.entries());
|
|
22
|
-
(nodeStream as TODO_any).method = nextRequest.method;
|
|
23
|
-
(nodeStream as TODO_any).url = nextRequest.url;
|
|
24
|
-
(nodeStream as TODO_any).socket = {}; // required by formidable
|
|
25
|
-
|
|
26
|
-
return nodeStream;
|
|
27
|
-
}
|