@promptbook/cli 0.104.0-0 → 0.104.0-10
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/apps/agents-server/config.ts +1 -3
- package/apps/agents-server/next.config.ts +2 -2
- package/apps/agents-server/package.json +7 -3
- package/apps/agents-server/public/fonts/OpenMoji-color-cbdt.woff2 +0 -0
- package/apps/agents-server/public/swagger.json +115 -0
- package/apps/agents-server/scripts/generate-reserved-paths/generate-reserved-paths.ts +54 -0
- package/apps/agents-server/scripts/generate-reserved-paths/tsconfig.json +19 -0
- package/apps/agents-server/src/app/AddAgentButton.tsx +47 -21
- package/apps/agents-server/src/app/actions.ts +22 -5
- package/apps/agents-server/src/app/admin/browser-test/BrowserTestClient.tsx +211 -0
- package/apps/agents-server/src/app/admin/browser-test/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/chat-feedback/ChatFeedbackClient.tsx +221 -274
- package/apps/agents-server/src/app/admin/chat-history/ChatHistoryClient.tsx +94 -137
- package/apps/agents-server/src/app/admin/messages/MessagesClient.tsx +294 -0
- package/apps/agents-server/src/app/admin/messages/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/messages/send-email/SendEmailClient.tsx +104 -0
- package/apps/agents-server/src/app/admin/messages/send-email/actions.ts +35 -0
- package/apps/agents-server/src/app/admin/messages/send-email/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/metadata/MetadataClient.tsx +23 -19
- package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +15 -1
- package/apps/agents-server/src/app/agents/[agentName]/AgentOptionsMenu.tsx +51 -9
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileChat.tsx +47 -4
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileWrapper.tsx +53 -11
- package/apps/agents-server/src/app/agents/[agentName]/_utils.ts +23 -3
- package/apps/agents-server/src/app/agents/[agentName]/agentLinks.tsx +8 -8
- package/apps/agents-server/src/app/agents/[agentName]/api/agents/route.ts +17 -26
- package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +4 -2
- package/apps/agents-server/src/app/agents/[agentName]/api/chat/route.ts +20 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/mcp/route.ts +6 -11
- package/apps/agents-server/src/app/agents/[agentName]/api/profile/route.ts +5 -1
- package/apps/agents-server/src/app/agents/[agentName]/api/voice/route.ts +5 -2
- package/apps/agents-server/src/app/agents/[agentName]/book/BookEditorWrapper.tsx +20 -16
- package/apps/agents-server/src/app/agents/[agentName]/book/page.tsx +15 -2
- package/apps/agents-server/src/app/agents/[agentName]/book+chat/page.tsx +15 -2
- package/apps/agents-server/src/app/agents/[agentName]/chat/page.tsx +12 -0
- package/apps/agents-server/src/app/agents/[agentName]/code/api/route.ts +68 -0
- package/apps/agents-server/src/app/agents/[agentName]/code/page.tsx +223 -0
- package/apps/agents-server/src/app/agents/[agentName]/generateAgentMetadata.ts +5 -0
- package/apps/agents-server/src/app/agents/[agentName]/history/actions.ts +2 -2
- package/apps/agents-server/src/app/agents/[agentName]/history/page.tsx +10 -3
- package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/getAgentDefaultAvatarPrompt.ts +31 -0
- package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/route.ts +194 -0
- package/apps/agents-server/src/app/agents/[agentName]/images/icon-256.png/route.tsx +14 -2
- package/apps/agents-server/src/app/agents/[agentName]/images/page.tsx +200 -0
- package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-fullhd.png/route.tsx +4 -3
- package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-phone.png/route.tsx +4 -3
- package/apps/agents-server/src/app/agents/[agentName]/integration/WebsiteIntegrationTabs.tsx +26 -0
- package/apps/agents-server/src/app/agents/[agentName]/integration/page.tsx +32 -8
- package/apps/agents-server/src/app/agents/[agentName]/links/page.tsx +11 -4
- package/apps/agents-server/src/app/agents/[agentName]/opengraph-image.tsx +11 -2
- package/apps/agents-server/src/app/agents/[agentName]/page.tsx +18 -10
- package/apps/agents-server/src/app/agents/[agentName]/system-message/page.tsx +100 -0
- package/apps/agents-server/src/app/agents/[agentName]/website-integration/page.tsx +35 -18
- package/apps/agents-server/src/app/api/admin-email/route.ts +12 -0
- package/apps/agents-server/src/app/api/agents/[agentName]/clone/route.ts +13 -14
- package/apps/agents-server/src/app/api/agents/[agentName]/restore/route.ts +20 -0
- package/apps/agents-server/src/app/api/agents/[agentName]/route.ts +43 -1
- package/apps/agents-server/src/app/api/agents/route.ts +28 -3
- package/apps/agents-server/src/app/api/api-tokens/route.ts +6 -7
- package/apps/agents-server/src/app/api/browser-test/act/route.ts +141 -0
- package/apps/agents-server/src/app/api/browser-test/screenshot/route.ts +30 -0
- package/apps/agents-server/src/app/api/browser-test/scroll-facebook/route.ts +62 -0
- package/apps/agents-server/src/app/api/docs/book.md/route.ts +61 -0
- package/apps/agents-server/src/app/api/emails/incoming/sendgrid/route.ts +48 -0
- package/apps/agents-server/src/app/api/embed.js/route.ts +87 -67
- package/apps/agents-server/src/app/api/federated-agents/route.ts +12 -0
- package/apps/agents-server/src/app/api/images/[filename]/route.ts +107 -0
- package/apps/agents-server/src/app/api/messages/route.ts +102 -0
- package/apps/agents-server/src/app/api/metadata/route.ts +5 -6
- package/apps/agents-server/src/app/api/upload/route.ts +128 -45
- package/apps/agents-server/src/app/docs/[docId]/page.tsx +2 -3
- package/apps/agents-server/src/app/docs/page.tsx +12 -12
- package/apps/agents-server/src/app/embed/layout.tsx +31 -0
- package/apps/agents-server/src/app/embed/page.tsx +22 -9
- package/apps/agents-server/src/app/globals.css +140 -33
- package/apps/agents-server/src/app/humans.txt/route.ts +1 -1
- package/apps/agents-server/src/app/layout.tsx +27 -22
- package/apps/agents-server/src/app/page.tsx +54 -6
- package/apps/agents-server/src/app/recycle-bin/actions.ts +20 -14
- package/apps/agents-server/src/app/recycle-bin/page.tsx +27 -41
- package/apps/agents-server/src/app/robots.txt/route.ts +1 -1
- package/apps/agents-server/src/app/security.txt/route.ts +1 -1
- package/apps/agents-server/src/app/sitemap.xml/route.ts +9 -7
- package/apps/agents-server/src/app/swagger/page.tsx +14 -0
- package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +41 -116
- package/apps/agents-server/src/components/AgentProfile/AgentProfileImage.tsx +92 -0
- package/apps/agents-server/src/components/AgentProfile/QrCodeModal.tsx +0 -1
- package/apps/agents-server/src/components/AgentProfile/useAgentBackground.ts +97 -0
- package/apps/agents-server/src/components/Auth/AuthControls.tsx +5 -4
- package/apps/agents-server/src/components/DeletedAgentBanner.tsx +26 -0
- package/apps/agents-server/src/components/DocsToolbar/DocsToolbar.tsx +38 -0
- package/apps/agents-server/src/components/DocumentationContent/DocumentationContent.tsx +11 -9
- package/apps/agents-server/src/components/Footer/Footer.tsx +5 -5
- package/apps/agents-server/src/components/ForgottenPasswordDialog/ForgottenPasswordDialog.tsx +61 -0
- package/apps/agents-server/src/components/Header/Header.tsx +114 -40
- package/apps/agents-server/src/components/Homepage/AgentCard.tsx +145 -23
- package/apps/agents-server/src/components/Homepage/AgentsList.tsx +93 -15
- package/apps/agents-server/src/components/Homepage/DeletedAgentsList.tsx +66 -0
- package/apps/agents-server/src/components/Homepage/ExternalAgentsSection.tsx +12 -3
- package/apps/agents-server/src/components/Homepage/ExternalAgentsSectionClient.tsx +19 -10
- package/apps/agents-server/src/components/LayoutWrapper/LayoutWrapper.tsx +3 -2
- package/apps/agents-server/src/components/LoginForm/LoginForm.tsx +50 -1
- package/apps/agents-server/src/components/NewAgentDialog/NewAgentDialog.tsx +88 -0
- package/apps/agents-server/src/components/NotFoundPage/NotFoundPage.tsx +7 -2
- package/apps/agents-server/src/components/OpenMojiIcon/OpenMojiIcon.tsx +16 -7
- package/apps/agents-server/src/components/PrintHeader/PrintHeader.tsx +4 -4
- package/apps/agents-server/src/components/RegisterUserDialog/RegisterUserDialog.tsx +61 -0
- package/apps/agents-server/src/components/VercelDeploymentCard/VercelDeploymentCard.tsx +2 -0
- package/apps/agents-server/src/components/_utils/generateMetaTxt.ts +12 -10
- package/apps/agents-server/src/components/_utils/headlessParam.tsx +7 -3
- package/apps/agents-server/src/database/$provideSupabaseForBrowser.ts +3 -3
- package/apps/agents-server/src/database/$provideSupabaseForServer.ts +1 -1
- package/apps/agents-server/src/database/$provideSupabaseForWorker.ts +3 -3
- package/apps/agents-server/src/database/metadataDefaults.ts +19 -1
- package/apps/agents-server/src/database/migrate.ts +34 -1
- package/apps/agents-server/src/database/migrations/2025-11-0001-initial-schema.sql +1 -3
- package/apps/agents-server/src/database/migrations/2025-11-0002-metadata-table.sql +1 -3
- package/apps/agents-server/src/database/migrations/2025-12-0240-agent-public-id.sql +3 -0
- package/apps/agents-server/src/database/migrations/2025-12-0360-agent-deleted-at.sql +1 -0
- package/apps/agents-server/src/database/migrations/2025-12-0370-image-table.sql +19 -0
- package/apps/agents-server/src/database/migrations/2025-12-0380-agent-visibility.sql +1 -0
- package/apps/agents-server/src/database/migrations/2025-12-0390-upload-tracking.sql +20 -0
- package/apps/agents-server/src/database/migrations/2025-12-0401-file-upload-status.sql +13 -0
- package/apps/agents-server/src/database/migrations/2025-12-0402-message-table.sql +42 -0
- package/apps/agents-server/src/database/migrations/2025-12-0403-generation-lock-table.sql +15 -0
- package/apps/agents-server/src/database/migrations/2025-12-0640-openai-assistant-cache.sql +12 -0
- package/apps/agents-server/src/database/migrations/2025-12-0820-agent-history-permanent-id.sql +29 -0
- package/apps/agents-server/src/database/schema.ts +231 -4
- package/apps/agents-server/src/generated/reservedPaths.ts +32 -0
- package/apps/agents-server/src/message-providers/email/_common/Email.ts +73 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/TODO.txt +1 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddress.test.ts.todo +108 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddress.ts +62 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddresses.test.ts.todo +117 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddresses.ts +19 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddress.test.ts.todo +119 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddress.ts +19 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddresses.test.ts.todo +74 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddresses.ts +14 -0
- package/apps/agents-server/src/message-providers/email/sendgrid/SendgridMessageProvider.ts +44 -0
- package/apps/agents-server/src/message-providers/email/sendgrid/parseInboundSendgridEmail.ts +49 -0
- package/apps/agents-server/src/message-providers/email/zeptomail/ZeptomailMessageProvider.ts +51 -0
- package/apps/agents-server/src/message-providers/index.ts +13 -0
- package/apps/agents-server/src/message-providers/interfaces/MessageProvider.ts +11 -0
- package/apps/agents-server/src/middleware.ts +19 -23
- package/apps/agents-server/src/tools/$provideBrowserForServer.ts +32 -0
- package/apps/agents-server/src/tools/$provideCdnForServer.ts +7 -2
- package/apps/agents-server/src/utils/auth.ts +117 -17
- package/apps/agents-server/src/utils/cdn/classes/TrackedFilesStorage.ts +57 -0
- package/apps/agents-server/src/utils/cdn/classes/VercelBlobStorage.ts +4 -0
- package/apps/agents-server/src/utils/cdn/interfaces/IFilesStorage.ts +18 -0
- package/apps/agents-server/src/utils/content/extractBodyContentFromHtml.ts +19 -0
- package/apps/agents-server/src/utils/getUserIdFromRequest.ts +35 -0
- package/apps/agents-server/src/utils/handleChatCompletion.ts +65 -5
- package/apps/agents-server/src/utils/messages/sendMessage.ts +91 -0
- package/apps/agents-server/src/utils/messagesAdmin.ts +72 -0
- package/apps/agents-server/src/utils/normalization/filenameToPrompt.test.ts +36 -0
- package/apps/agents-server/src/utils/normalization/filenameToPrompt.ts +25 -0
- package/apps/agents-server/src/utils/validateApiKey.ts +7 -11
- package/esm/index.es.js +2890 -2737
- package/esm/index.es.js.map +1 -1
- package/esm/typings/servers.d.ts +8 -0
- package/esm/typings/src/_packages/core.index.d.ts +2 -0
- package/esm/typings/src/_packages/types.index.d.ts +10 -2
- package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +6 -1
- package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirements.d.ts +6 -6
- 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 +3 -3
- package/esm/typings/src/book-components/Chat/Chat/ChatMessageItem.d.ts +5 -1
- package/esm/typings/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
- package/esm/typings/src/book-components/Chat/CodeBlock/CodeBlock.d.ts +13 -0
- package/esm/typings/src/book-components/Chat/MarkdownContent/MarkdownContent.d.ts +1 -0
- package/esm/typings/src/book-components/Chat/types/ChatMessage.d.ts +7 -11
- package/esm/typings/src/book-components/_common/Dropdown/Dropdown.d.ts +2 -2
- package/esm/typings/src/book-components/_common/MenuHoisting/MenuHoistingContext.d.ts +56 -0
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +21 -11
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +80 -14
- package/esm/typings/src/commitments/DICTIONARY/DICTIONARY.d.ts +46 -0
- package/esm/typings/src/commitments/index.d.ts +2 -1
- package/esm/typings/src/llm-providers/_multiple/MultipleLlmExecutionTools.d.ts +6 -2
- package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/ollama/OllamaExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/openai/createOpenAiCompatibleExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/remote/RemoteLlmExecutionTools.d.ts +1 -0
- package/esm/typings/src/types/Message.d.ts +49 -0
- package/esm/typings/src/types/ModelRequirements.d.ts +38 -14
- package/esm/typings/src/types/typeAliases.d.ts +23 -1
- package/esm/typings/src/utils/color/utils/colorToDataUrl.d.ts +2 -1
- package/esm/typings/src/utils/environment/$detectRuntimeEnvironment.d.ts +4 -4
- package/esm/typings/src/utils/environment/$isRunningInBrowser.d.ts +1 -1
- package/esm/typings/src/utils/environment/$isRunningInJest.d.ts +1 -1
- package/esm/typings/src/utils/environment/$isRunningInNode.d.ts +1 -1
- package/esm/typings/src/utils/environment/$isRunningInWebWorker.d.ts +1 -1
- package/esm/typings/src/utils/markdown/extractAllBlocksFromMarkdown.d.ts +2 -2
- package/esm/typings/src/utils/markdown/extractOneBlockFromMarkdown.d.ts +2 -2
- package/esm/typings/src/utils/random/$randomBase58.d.ts +12 -0
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +4018 -3865
- package/umd/index.umd.js.map +1 -1
- package/apps/agents-server/package-lock.json +0 -27
- package/apps/agents-server/public/fonts/download-font.js +0 -22
- package/apps/agents-server/src/components/PrintButton/PrintButton.tsx +0 -18
- package/esm/typings/src/book-2.0/utils/generateGravatarUrl.d.ts +0 -10
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { spaceTrim } from '@promptbook-local/utils';
|
|
1
2
|
import { NextRequest, NextResponse } from 'next/server';
|
|
2
3
|
|
|
3
4
|
export async function GET(request: NextRequest) {
|
|
@@ -5,84 +6,103 @@ export async function GET(request: NextRequest) {
|
|
|
5
6
|
const host = request.nextUrl.host;
|
|
6
7
|
const baseUrl = `${protocol}//${host}`;
|
|
7
8
|
|
|
8
|
-
const script = `
|
|
9
|
-
(
|
|
10
|
-
if (customElements.get('promptbook-agent')) {
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
9
|
+
const script = spaceTrim(`
|
|
10
|
+
console.info('[🔌] Promptbook integration script from ${baseUrl}');
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
12
|
+
(function() {
|
|
13
|
+
if (customElements.get('promptbook-agent-integration')) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
class PromptbookAgentIntegrationElement extends HTMLElement {
|
|
18
|
+
constructor() {
|
|
19
|
+
super();
|
|
20
|
+
console.info('[🔌] Initializing <promptbook-agent-integration/>',this);
|
|
21
|
+
this.iframe = null;
|
|
22
|
+
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
24
|
+
static get observedAttributes() {
|
|
25
|
+
return ['agent-url', 'meta'];
|
|
26
|
+
}
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
connectedCallback() {
|
|
29
|
+
this.render();
|
|
30
|
+
window.addEventListener('message', this.handleMessage.bind(this));
|
|
31
|
+
}
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
}
|
|
33
|
+
disconnectedCallback() {
|
|
34
|
+
window.removeEventListener('message', this.handleMessage.bind(this));
|
|
35
|
+
}
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
this.iframe.style.height = '650px';
|
|
44
|
-
this.iframe.style.maxHeight = '90vh';
|
|
45
|
-
this.iframe.style.maxWidth = '90vw';
|
|
46
|
-
this.iframe.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)';
|
|
47
|
-
this.iframe.style.borderRadius = '12px';
|
|
48
|
-
} else {
|
|
49
|
-
this.iframe.style.width = '60px';
|
|
50
|
-
this.iframe.style.height = '60px';
|
|
51
|
-
this.iframe.style.boxShadow = 'none';
|
|
52
|
-
this.iframe.style.borderRadius = '0';
|
|
37
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
38
|
+
if ((name === 'agent-url' || name === 'meta') && oldValue !== newValue) {
|
|
39
|
+
this.render();
|
|
40
|
+
}
|
|
53
41
|
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
42
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
43
|
+
handleMessage(event) {
|
|
44
|
+
if (event.data && event.data.type === 'PROMPTBOOK_AGENT_RESIZE') {
|
|
45
|
+
if (event.data.isOpen) {
|
|
46
|
+
// Match PromptbookAgentSeamlessIntegration.module.css dimensions
|
|
47
|
+
// Window is 380x600 + 20px padding on each side
|
|
48
|
+
this.iframe.style.width = '420px';
|
|
49
|
+
this.iframe.style.height = '640px';
|
|
50
|
+
this.iframe.style.maxHeight = 'calc(80vh + 40px)';
|
|
51
|
+
this.iframe.style.maxWidth = 'calc(100vw - 20px)';
|
|
52
|
+
} else {
|
|
53
|
+
// Closed state - button area with padding and shadow space
|
|
54
|
+
// Button is ~140px wide + 20px right margin + shadow space
|
|
55
|
+
this.iframe.style.width = '180px';
|
|
56
|
+
this.iframe.style.height = '100px';
|
|
57
|
+
this.iframe.style.maxHeight = 'none';
|
|
58
|
+
this.iframe.style.maxWidth = 'none';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
60
62
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
this.iframe.style.border = 'none';
|
|
65
|
-
this.iframe.style.position = 'fixed';
|
|
66
|
-
this.iframe.style.bottom = '20px';
|
|
67
|
-
this.iframe.style.right = '20px';
|
|
68
|
-
this.iframe.style.width = '60px';
|
|
69
|
-
this.iframe.style.height = '60px';
|
|
70
|
-
this.iframe.style.zIndex = '2147483647'; // Max z-index
|
|
71
|
-
this.iframe.style.transition = 'width 0.3s ease, height 0.3s ease';
|
|
72
|
-
this.iframe.style.backgroundColor = 'transparent';
|
|
73
|
-
this.iframe.setAttribute('allow', 'microphone'); // Allow microphone if needed for voice
|
|
74
|
-
this.shadowRoot.appendChild(this.iframe);
|
|
75
|
-
}
|
|
63
|
+
render() {
|
|
64
|
+
const agentUrl = this.getAttribute('agent-url');
|
|
65
|
+
if (!agentUrl) return;
|
|
76
66
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
67
|
+
if (!this.iframe) {
|
|
68
|
+
this.attachShadow({ mode: 'open' });
|
|
69
|
+
this.iframe = document.createElement('iframe');
|
|
70
|
+
this.iframe.style.border = 'none';
|
|
71
|
+
this.iframe.style.position = 'fixed';
|
|
72
|
+
this.iframe.style.bottom = '0';
|
|
73
|
+
this.iframe.style.right = '0';
|
|
74
|
+
// Initial size for the closed button state (with padding and shadow space)
|
|
75
|
+
this.iframe.style.width = '180px';
|
|
76
|
+
this.iframe.style.height = '100px';
|
|
77
|
+
this.iframe.style.zIndex = '2147483647'; // Max z-index
|
|
78
|
+
this.iframe.style.transition = 'width 0.3s ease, height 0.3s ease';
|
|
79
|
+
this.iframe.style.backgroundColor = 'transparent';
|
|
80
|
+
this.iframe.setAttribute('allow', 'microphone'); // Allow microphone if needed for voice
|
|
81
|
+
this.shadowRoot.appendChild(this.iframe);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Construct embed URL pointing to the Next.js page we created
|
|
85
|
+
let embedUrl = '${baseUrl}/embed?agentUrl=' + encodeURIComponent(agentUrl);
|
|
86
|
+
|
|
87
|
+
// Add meta parameter if provided
|
|
88
|
+
const metaAttr = this.getAttribute('meta');
|
|
89
|
+
if (metaAttr) {
|
|
90
|
+
try {
|
|
91
|
+
// Validate that it's valid JSON
|
|
92
|
+
JSON.parse(metaAttr);
|
|
93
|
+
embedUrl += '&meta=' + encodeURIComponent(metaAttr);
|
|
94
|
+
} catch (e) {
|
|
95
|
+
console.error('[🔌] Invalid meta JSON:', e);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this.iframe.src = embedUrl;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
82
102
|
|
|
83
|
-
|
|
84
|
-
})();
|
|
85
|
-
|
|
103
|
+
customElements.define('promptbook-agent-integration', PromptbookAgentIntegrationElement);
|
|
104
|
+
})();
|
|
105
|
+
`);
|
|
86
106
|
|
|
87
107
|
return new NextResponse(script, {
|
|
88
108
|
headers: {
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server';
|
|
2
2
|
import { getFederatedServersFromMetadata } from '../../../utils/getFederatedServersFromMetadata';
|
|
3
|
+
import { getMetadata } from '../../../database/getMetadata';
|
|
4
|
+
import { getCurrentUser } from '../../../utils/getCurrentUser';
|
|
3
5
|
|
|
4
6
|
export const dynamic = 'force-dynamic';
|
|
5
7
|
|
|
6
8
|
export async function GET() {
|
|
7
9
|
try {
|
|
10
|
+
const currentUser = await getCurrentUser();
|
|
11
|
+
const showFederatedServersPublicly = ((await getMetadata('SHOW_FEDERATED_SERVERS_PUBLICLY')) || 'false') === 'true';
|
|
12
|
+
|
|
13
|
+
// Only show federated servers if user is authenticated or if SHOW_FEDERATED_SERVERS_PUBLICLY is true
|
|
14
|
+
if (!currentUser && !showFederatedServersPublicly) {
|
|
15
|
+
return NextResponse.json({
|
|
16
|
+
federatedServers: [],
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
8
20
|
const federatedServers = await getFederatedServersFromMetadata();
|
|
9
21
|
|
|
10
22
|
return NextResponse.json({
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { $getTableName } from '@/src/database/$getTableName';
|
|
2
|
+
import { serializeError } from '@promptbook-local/utils';
|
|
3
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
4
|
+
import { assertsError } from '../../../../../../../src/errors/assertsError';
|
|
5
|
+
import type { LlmExecutionTools } from '../../../../../../../src/execution/LlmExecutionTools';
|
|
6
|
+
import { getSingleLlmExecutionTools } from '../../../../../../../src/llm-providers/_multiple/getSingleLlmExecutionTools';
|
|
7
|
+
import { string_url } from '../../../../../../../src/types/typeAliases';
|
|
8
|
+
import { $provideSupabaseForServer } from '../../../../database/$provideSupabaseForServer';
|
|
9
|
+
import { $provideCdnForServer } from '../../../../tools/$provideCdnForServer';
|
|
10
|
+
import { $provideExecutionToolsForServer } from '../../../../tools/$provideExecutionToolsForServer';
|
|
11
|
+
import { filenameToPrompt } from '../../../../utils/normalization/filenameToPrompt';
|
|
12
|
+
|
|
13
|
+
export async function GET(request: NextRequest, { params }: { params: Promise<{ filename: string }> }) {
|
|
14
|
+
try {
|
|
15
|
+
const { filename } = await params;
|
|
16
|
+
|
|
17
|
+
if (!filename) {
|
|
18
|
+
return NextResponse.json({ error: 'Filename is required' }, { status: 400 });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const supabase = $provideSupabaseForServer();
|
|
22
|
+
|
|
23
|
+
// Check if image already exists in database
|
|
24
|
+
const { data: existingImage, error: selectError } = await supabase
|
|
25
|
+
.from(await $getTableName(`Image`))
|
|
26
|
+
.select('cdnUrl')
|
|
27
|
+
.eq('filename', filename)
|
|
28
|
+
.single();
|
|
29
|
+
|
|
30
|
+
if (selectError && selectError.code !== 'PGRST116') {
|
|
31
|
+
// PGRST116 is "not found"
|
|
32
|
+
throw selectError;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (existingImage) {
|
|
36
|
+
// Image exists, redirect to CDN
|
|
37
|
+
return NextResponse.redirect(existingImage.cdnUrl as string_url);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Image doesn't exist, generate it
|
|
41
|
+
const prompt = filenameToPrompt(filename);
|
|
42
|
+
|
|
43
|
+
const executionTools = await $provideExecutionToolsForServer();
|
|
44
|
+
const llmTools = getSingleLlmExecutionTools(executionTools.llm) as LlmExecutionTools;
|
|
45
|
+
|
|
46
|
+
if (!llmTools.callImageGenerationModel) {
|
|
47
|
+
throw new Error('Image generation is not supported by the current LLM configuration');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const imageResult = await llmTools.callImageGenerationModel({
|
|
51
|
+
title: `Generate image for ${filename}`,
|
|
52
|
+
content: prompt,
|
|
53
|
+
parameters: {},
|
|
54
|
+
modelRequirements: {
|
|
55
|
+
modelVariant: 'IMAGE_GENERATION',
|
|
56
|
+
modelName: 'dall-e-3', // Use DALL-E 3 for high quality
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (!imageResult.content) {
|
|
61
|
+
throw new Error('Failed to generate image: no content returned');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Download the generated image
|
|
65
|
+
const imageResponse = await fetch(imageResult.content);
|
|
66
|
+
if (!imageResponse.ok) {
|
|
67
|
+
throw new Error(`Failed to download generated image: ${imageResponse.status}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const imageBuffer = await imageResponse.arrayBuffer();
|
|
71
|
+
const buffer = Buffer.from(imageBuffer);
|
|
72
|
+
|
|
73
|
+
// Upload to CDN
|
|
74
|
+
const cdn = $provideCdnForServer();
|
|
75
|
+
const cdnKey = `generated-images/${filename}`;
|
|
76
|
+
await cdn.setItem(cdnKey, {
|
|
77
|
+
type: 'image/png', // DALL-E generates PNG
|
|
78
|
+
data: buffer,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const cdnUrl = cdn.getItemUrl(cdnKey);
|
|
82
|
+
|
|
83
|
+
// Save to database
|
|
84
|
+
const { error: insertError } = await supabase.from(await $getTableName(`Image`)).insert({
|
|
85
|
+
filename,
|
|
86
|
+
prompt,
|
|
87
|
+
cdnUrl: cdnUrl.href,
|
|
88
|
+
cdnKey,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
if (insertError) {
|
|
92
|
+
throw insertError;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Redirect to the newly created image
|
|
96
|
+
return NextResponse.redirect(cdnUrl.href as string_url);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
assertsError(error);
|
|
99
|
+
|
|
100
|
+
console.error('Error serving image:', error);
|
|
101
|
+
|
|
102
|
+
return new Response(JSON.stringify(serializeError(error), null, 4), {
|
|
103
|
+
status: 500,
|
|
104
|
+
headers: { 'Content-Type': 'application/json' },
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { $getTableName } from '../../../database/$getTableName';
|
|
3
|
+
import { $provideSupabase } from '../../../database/$provideSupabase';
|
|
4
|
+
import { isUserAdmin } from '../../../utils/isUserAdmin';
|
|
5
|
+
|
|
6
|
+
const DEFAULT_PAGE_SIZE = 20;
|
|
7
|
+
const MAX_PAGE_SIZE = 100;
|
|
8
|
+
|
|
9
|
+
function parsePositiveInt(value: string | null, fallback: number): number {
|
|
10
|
+
if (!value) return fallback;
|
|
11
|
+
const parsed = parseInt(value, 10);
|
|
12
|
+
if (Number.isNaN(parsed) || parsed <= 0) return fallback;
|
|
13
|
+
return parsed;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* List messages with filters, search and pagination.
|
|
18
|
+
*/
|
|
19
|
+
export async function GET(request: NextRequest) {
|
|
20
|
+
if (!(await isUserAdmin())) {
|
|
21
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const searchParams = request.nextUrl.searchParams;
|
|
26
|
+
|
|
27
|
+
const page = parsePositiveInt(searchParams.get('page'), 1);
|
|
28
|
+
const pageSize = Math.min(MAX_PAGE_SIZE, parsePositiveInt(searchParams.get('pageSize'), DEFAULT_PAGE_SIZE));
|
|
29
|
+
const search = searchParams.get('search')?.trim() || '';
|
|
30
|
+
const channel = searchParams.get('channel');
|
|
31
|
+
const direction = searchParams.get('direction');
|
|
32
|
+
|
|
33
|
+
const supabase = $provideSupabase();
|
|
34
|
+
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
|
+
let query = supabase.from(await $getTableName('Message')).select('*', { count: 'exact' });
|
|
37
|
+
|
|
38
|
+
if (channel) {
|
|
39
|
+
query = query.eq('channel', channel);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (direction) {
|
|
43
|
+
query = query.eq('direction', direction);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (search) {
|
|
47
|
+
// Search in content, subject (if in metadata?), sender/recipient emails
|
|
48
|
+
// Note: sender and recipients are JSONB, so ilike might not work directly on them unless cast to text
|
|
49
|
+
// Content is TEXT.
|
|
50
|
+
const escaped = search.replace(/%/g, '\\%').replace(/_/g, '\\_');
|
|
51
|
+
// Assuming simple search on content for now to avoid complexity with JSONB search in generic supabase client
|
|
52
|
+
query = query.ilike('content', `%${escaped}%`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Default sort by createdAt desc
|
|
56
|
+
query = query.order('createdAt', { ascending: false });
|
|
57
|
+
|
|
58
|
+
const from = (page - 1) * pageSize;
|
|
59
|
+
const to = from + pageSize - 1;
|
|
60
|
+
|
|
61
|
+
query = query.range(from, to);
|
|
62
|
+
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
|
+
const { data: messages, error, count } = (await query) as { data: any[]; error: any; count: number };
|
|
65
|
+
|
|
66
|
+
if (error) {
|
|
67
|
+
console.error('List messages error:', error);
|
|
68
|
+
return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Fetch attempts for these messages
|
|
72
|
+
if (messages && messages.length > 0) {
|
|
73
|
+
const messageIds = messages.map((m) => m.id);
|
|
74
|
+
const { data: attempts, error: attemptsError } = await supabase
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
76
|
+
.from(await $getTableName('MessageSendAttempt'))
|
|
77
|
+
.select('*')
|
|
78
|
+
.in('messageId', messageIds);
|
|
79
|
+
|
|
80
|
+
if (attemptsError) {
|
|
81
|
+
console.error('Fetch message attempts error:', attemptsError);
|
|
82
|
+
// We don't fail the whole request, just log it.
|
|
83
|
+
} else {
|
|
84
|
+
// Attach attempts to messages
|
|
85
|
+
for (const message of messages) {
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
87
|
+
(message as any).sendAttempts = attempts?.filter((a: any) => a.messageId === message.id) || [];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return NextResponse.json({
|
|
93
|
+
items: messages ?? [],
|
|
94
|
+
total: count ?? 0,
|
|
95
|
+
page,
|
|
96
|
+
pageSize,
|
|
97
|
+
});
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error('List messages error:', error);
|
|
100
|
+
return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { keepUnused } from '../../../../../../src/utils/organization/keepUnused';
|
|
1
3
|
import { $getTableName } from '../../../database/$getTableName';
|
|
2
4
|
import { $provideSupabase } from '../../../database/$provideSupabase';
|
|
3
5
|
import { isUserAdmin } from '../../../utils/isUserAdmin';
|
|
4
|
-
import { NextRequest, NextResponse } from 'next/server';
|
|
5
6
|
|
|
6
7
|
export async function GET(request: NextRequest) {
|
|
8
|
+
keepUnused(request);
|
|
9
|
+
|
|
7
10
|
if (!(await isUserAdmin())) {
|
|
8
11
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
9
12
|
}
|
|
@@ -36,11 +39,7 @@ export async function POST(request: NextRequest) {
|
|
|
36
39
|
const supabase = $provideSupabase();
|
|
37
40
|
const table = await $getTableName('Metadata');
|
|
38
41
|
|
|
39
|
-
const { data, error } = await supabase
|
|
40
|
-
.from(table)
|
|
41
|
-
.insert({ key, value, note })
|
|
42
|
-
.select()
|
|
43
|
-
.single();
|
|
42
|
+
const { data, error } = await supabase.from(table).insert({ key, value, note }).select().single();
|
|
44
43
|
|
|
45
44
|
if (error) {
|
|
46
45
|
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
@@ -1,70 +1,144 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { $getTableName } from '@/src/database/$getTableName';
|
|
2
|
+
import { $provideSupabase } from '@/src/database/$provideSupabase';
|
|
3
3
|
import { serializeError } from '@promptbook-local/utils';
|
|
4
|
-
import
|
|
5
|
-
import { readFile } from 'fs/promises';
|
|
4
|
+
import { handleUpload, type HandleUploadBody } from '@vercel/blob/client';
|
|
6
5
|
import { NextRequest, NextResponse } from 'next/server';
|
|
7
|
-
import { forTime } from 'waitasecond';
|
|
8
6
|
import { assertsError } from '../../../../../../src/errors/assertsError';
|
|
9
|
-
import {
|
|
10
|
-
import { keepUnused } from '../../../../../../src/utils/organization/keepUnused';
|
|
11
|
-
import { $provideCdnForServer } from '../../../../src/tools/$provideCdnForServer';
|
|
12
|
-
import { getUserFileCdnKey } from '../../../../src/utils/cdn/utils/getUserFileCdnKey';
|
|
13
|
-
import { validateMimeType } from '../../../../src/utils/validators/validateMimeType';
|
|
7
|
+
import { getUserIdFromRequest } from '../../../../src/utils/getUserIdFromRequest';
|
|
14
8
|
import { getMetadata } from '../../../database/getMetadata';
|
|
15
9
|
|
|
16
10
|
export async function POST(request: NextRequest) {
|
|
17
11
|
try {
|
|
18
|
-
await
|
|
19
|
-
|
|
12
|
+
const body = (await request.json()) as HandleUploadBody;
|
|
13
|
+
const userId = await getUserIdFromRequest(request);
|
|
14
|
+
const supabase = $provideSupabase();
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
// Handle Vercel Blob client upload protocol
|
|
17
|
+
const jsonResponse = await handleUpload({
|
|
18
|
+
body,
|
|
19
|
+
request,
|
|
20
|
+
token: process.env.VERCEL_BLOB_READ_WRITE_TOKEN!,
|
|
21
|
+
onBeforeGenerateToken: async (pathname, clientPayload) => {
|
|
22
|
+
// Authenticate user and validate upload
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
// Parse client payload for additional metadata
|
|
25
|
+
const payload = clientPayload ? JSON.parse(clientPayload) : {};
|
|
26
|
+
const { purpose, contentType } = payload;
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
let maxFileSizeMb = Number((await getMetadata('MAX_FILE_UPLOAD_SIZE_MB')) || '50'); // <- TODO: [🌲] To /config.ts
|
|
29
|
+
if (Number.isNaN(maxFileSizeMb)) {
|
|
30
|
+
maxFileSizeMb = 50; // <- TODO: [🌲] To /config.ts
|
|
31
|
+
}
|
|
32
|
+
const maxFileSize = maxFileSizeMb * 1024 * 1024;
|
|
33
|
+
|
|
34
|
+
// Generate the proper path with prefix
|
|
35
|
+
// Note: With client uploads, we use the original filename provided by the client
|
|
36
|
+
// The file will be stored at: {pathPrefix}/user/files/{filename}
|
|
37
|
+
const pathPrefix = process.env.NEXT_PUBLIC_CDN_PATH_PREFIX || '';
|
|
29
38
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
39
|
+
// Create a DB record at the start of the upload to track it
|
|
40
|
+
const uploadPurpose = purpose || 'GENERIC_UPLOAD';
|
|
41
|
+
const { data: insertedFile, error: insertError } = await supabase
|
|
42
|
+
.from(await $getTableName('File'))
|
|
43
|
+
.insert({
|
|
44
|
+
userId: userId || null,
|
|
45
|
+
fileName: pathname,
|
|
46
|
+
fileSize: 0, // <- Will be updated when upload completes
|
|
47
|
+
fileType: contentType || 'application/octet-stream',
|
|
48
|
+
storageUrl: null, // <- To be updated on completion
|
|
49
|
+
shortUrl: null, // <- To be updated on completion
|
|
50
|
+
purpose: uploadPurpose,
|
|
51
|
+
status: 'UPLOADING',
|
|
52
|
+
})
|
|
53
|
+
.select('id')
|
|
54
|
+
.single();
|
|
34
55
|
|
|
35
|
-
if (
|
|
36
|
-
|
|
56
|
+
if (insertError) {
|
|
57
|
+
console.error('🔼 Failed to create file record:', insertError);
|
|
37
58
|
}
|
|
38
|
-
resolve(files);
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
59
|
|
|
42
|
-
|
|
60
|
+
console.info('🔼 Upload started, tracking file:', {
|
|
61
|
+
pathname,
|
|
62
|
+
fileId: insertedFile?.id,
|
|
63
|
+
purpose: uploadPurpose,
|
|
64
|
+
});
|
|
43
65
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
66
|
+
return {
|
|
67
|
+
allowedContentTypes: contentType ? [contentType] : undefined,
|
|
68
|
+
maximumSizeInBytes: maxFileSize,
|
|
69
|
+
addRandomSuffix: true, // Add random suffix to avoid filename collisions since we can't hash content
|
|
70
|
+
tokenPayload: JSON.stringify({
|
|
71
|
+
userId: userId || null,
|
|
72
|
+
purpose: uploadPurpose,
|
|
73
|
+
fileId: insertedFile?.id || null,
|
|
74
|
+
uploadPath: pathname,
|
|
75
|
+
pathPrefix,
|
|
76
|
+
}),
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
onUploadCompleted: async ({ blob, tokenPayload }) => {
|
|
80
|
+
// !!!!
|
|
81
|
+
// ⚠️ IMPORTANT: This callback is a WEBHOOK called by Vercel's servers AFTER the upload completes
|
|
82
|
+
// - It runs in a DIFFERENT request context (not the original user request)
|
|
83
|
+
// - It WON'T work in local development (Vercel can't reach localhost)
|
|
84
|
+
// - All data must come from tokenPayload (userId, fileId, etc.)
|
|
85
|
+
// - Need to create a fresh supabase client here
|
|
86
|
+
console.info('🔼 Upload completed (webhook callback):', { blob, tokenPayload });
|
|
50
87
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const key = getUserFileCdnKey(fileBuffer, uploadedFile.originalFilename || uploadedFile.newFilename);
|
|
88
|
+
try {
|
|
89
|
+
const payload = tokenPayload ? JSON.parse(tokenPayload) : {};
|
|
90
|
+
const { fileId, userId: tokenUserId, purpose: tokenPurpose, uploadPath } = payload;
|
|
55
91
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
92
|
+
// Create fresh supabase client for this webhook context
|
|
93
|
+
const supabase = $provideSupabase();
|
|
94
|
+
|
|
95
|
+
if (fileId) {
|
|
96
|
+
// Update the existing record by ID
|
|
97
|
+
const { error: updateError } = await supabase
|
|
98
|
+
.from(await $getTableName('File'))
|
|
99
|
+
.update({
|
|
100
|
+
userId: tokenUserId || null,
|
|
101
|
+
fileSize: 0, // <- !!!!
|
|
102
|
+
fileType: blob.contentType,
|
|
103
|
+
storageUrl: blob.url,
|
|
104
|
+
// <- TODO: !!!! Split between storageUrl and shortUrl
|
|
105
|
+
purpose: tokenPurpose || 'GENERIC_UPLOAD',
|
|
106
|
+
status: 'COMPLETED',
|
|
107
|
+
})
|
|
108
|
+
.eq('id', fileId);
|
|
60
109
|
|
|
61
|
-
|
|
110
|
+
if (updateError) {
|
|
111
|
+
console.error('🔼 Failed to update file record:', updateError);
|
|
112
|
+
} else {
|
|
113
|
+
console.info('🔼 File record updated successfully:', { fileId, shortUrl: blob.url });
|
|
114
|
+
}
|
|
115
|
+
} else if (uploadPath) {
|
|
116
|
+
// Fallback: Update by uploadPath if fileId is not available
|
|
117
|
+
const { error: updateError } = await supabase
|
|
118
|
+
.from(await $getTableName('File'))
|
|
119
|
+
.update({
|
|
120
|
+
fileSize: 0, // <- !!!!
|
|
121
|
+
fileType: blob.contentType,
|
|
122
|
+
storageUrl: blob.url,
|
|
123
|
+
status: 'COMPLETED',
|
|
124
|
+
})
|
|
125
|
+
.eq('id', fileId);
|
|
62
126
|
|
|
63
|
-
|
|
127
|
+
if (updateError) {
|
|
128
|
+
console.error('🔼 Failed to update file record by uploadPath:', updateError);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error('🔼 Error in onUploadCompleted:', error);
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
return NextResponse.json(jsonResponse);
|
|
64
138
|
} catch (error) {
|
|
65
139
|
assertsError(error);
|
|
66
140
|
|
|
67
|
-
console.error(error);
|
|
141
|
+
console.error('🔼', error);
|
|
68
142
|
|
|
69
143
|
return new Response(
|
|
70
144
|
JSON.stringify(
|
|
@@ -81,3 +155,12 @@ export async function POST(request: NextRequest) {
|
|
|
81
155
|
);
|
|
82
156
|
}
|
|
83
157
|
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* TODO: !!!! Change uploaded URLs from `storageUrl` to `shortUrl`
|
|
161
|
+
* TODO: !!!! Record both `storageUrl` (actual storage location) and `shortUrl` in `File` table
|
|
162
|
+
* TODO: !!!! Record `purpose` in `File` table
|
|
163
|
+
* TODO: !!!! Record `userId` in `File` table
|
|
164
|
+
* TODO: !!!! Record all things into `File` table
|
|
165
|
+
* TODO: !!!! File type (mime type) of `.book` files should be `application/book` <- [🧠] !!!! Best mime type?!
|
|
166
|
+
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { notFound } from 'next/navigation';
|
|
2
2
|
import { BookCommitment } from '../../../../../../src/commitments/_base/BookCommitment';
|
|
3
3
|
import { getVisibleCommitmentDefinitions } from '../../../utils/getVisibleCommitmentDefinitions';
|
|
4
|
-
import {
|
|
4
|
+
import { DocsToolbar } from '../../../components/DocsToolbar/DocsToolbar';
|
|
5
5
|
import { PrintHeader } from '../../../components/PrintHeader/PrintHeader';
|
|
6
6
|
import { DocumentationContent } from '../../../components/DocumentationContent/DocumentationContent';
|
|
7
7
|
|
|
@@ -27,9 +27,8 @@ export default async function DocPage(props: DocPageProps) {
|
|
|
27
27
|
|
|
28
28
|
return (
|
|
29
29
|
<div className="min-h-screen bg-gradient-to-br from-blue-50 via-white to-purple-50">
|
|
30
|
-
<PrintButton />
|
|
31
|
-
|
|
32
30
|
<div className="container mx-auto px-4 py-16">
|
|
31
|
+
<DocsToolbar />
|
|
33
32
|
<PrintHeader title={primary.type} />
|
|
34
33
|
|
|
35
34
|
<DocumentationContent
|