@promptbook/cli 0.104.0-1 → 0.104.0-3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +3 -3
- package/apps/agents-server/src/app/actions.ts +17 -5
- 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/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 +2 -0
- package/apps/agents-server/src/app/agents/[agentName]/_utils.ts +18 -0
- 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/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 +1 -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 +214 -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]/integration/page.tsx +1 -1
- package/apps/agents-server/src/app/agents/[agentName]/links/page.tsx +2 -2
- package/apps/agents-server/src/app/agents/[agentName]/page.tsx +12 -6
- package/apps/agents-server/src/app/agents/[agentName]/system-message/page.tsx +87 -0
- 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 +10 -12
- package/apps/agents-server/src/app/api/agents/[agentName]/restore/route.ts +19 -0
- package/apps/agents-server/src/app/api/agents/[agentName]/route.ts +41 -0
- 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/docs/book.md/route.ts +61 -0
- 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/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/globals.css +140 -33
- package/apps/agents-server/src/app/layout.tsx +27 -22
- package/apps/agents-server/src/app/page.tsx +50 -4
- package/apps/agents-server/src/app/recycle-bin/actions.ts +20 -14
- package/apps/agents-server/src/app/recycle-bin/page.tsx +25 -41
- package/apps/agents-server/src/app/sitemap.xml/route.ts +6 -3
- package/apps/agents-server/src/app/swagger/page.tsx +14 -0
- package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +9 -98
- 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 +106 -40
- package/apps/agents-server/src/components/Homepage/AgentCard.tsx +104 -20
- package/apps/agents-server/src/components/Homepage/AgentsList.tsx +72 -12
- package/apps/agents-server/src/components/Homepage/DeletedAgentsList.tsx +50 -0
- 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/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/_utils/headlessParam.tsx +7 -3
- package/apps/agents-server/src/database/metadataDefaults.ts +19 -1
- 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-0640-openai-assistant-cache.sql +12 -0
- package/apps/agents-server/src/database/schema.ts +109 -0
- package/apps/agents-server/src/generated/reservedPaths.ts +32 -0
- package/apps/agents-server/src/middleware.ts +19 -23
- package/apps/agents-server/src/tools/$provideCdnForServer.ts +6 -1
- 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/getUserIdFromRequest.ts +35 -0
- package/apps/agents-server/src/utils/handleChatCompletion.ts +65 -5
- package/apps/agents-server/src/utils/normalization/filenameToPrompt.ts +21 -0
- package/apps/agents-server/src/utils/validateApiKey.ts +7 -11
- package/esm/index.es.js +194 -34
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/_packages/types.index.d.ts +8 -2
- package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +6 -1
- 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 +13 -7
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +6 -0
- 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/ollama/OllamaExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/openai/createOpenAiCompatibleExecutionTools.d.ts +1 -1
- package/esm/typings/src/types/Message.d.ts +49 -0
- package/esm/typings/src/types/typeAliases.d.ts +12 -0
- 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 +200 -40
- 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
|
@@ -1,15 +1,20 @@
|
|
|
1
|
+
import { HomeIcon } from 'lucide-react';
|
|
1
2
|
import Link from 'next/link';
|
|
2
3
|
import { ErrorPage } from '../ErrorPage/ErrorPage';
|
|
3
4
|
|
|
4
5
|
export function NotFoundPage() {
|
|
5
6
|
return (
|
|
6
|
-
<ErrorPage
|
|
7
|
+
<ErrorPage
|
|
8
|
+
title="Agent Not Found :("
|
|
9
|
+
message="The agent you are looking for does not exist, but you can create your own!"
|
|
10
|
+
>
|
|
7
11
|
<div className="flex justify-center">
|
|
8
12
|
<Link
|
|
9
13
|
href="/"
|
|
10
14
|
className="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
|
|
11
15
|
>
|
|
12
|
-
|
|
16
|
+
<HomeIcon className="inline w-5 h-5 mr-2" />
|
|
17
|
+
Home
|
|
13
18
|
</Link>
|
|
14
19
|
</div>
|
|
15
20
|
</ErrorPage>
|
|
@@ -1,19 +1,28 @@
|
|
|
1
|
+
import { string_char_emoji } from '@promptbook-local/types';
|
|
1
2
|
import { DetailedHTMLProps, HTMLAttributes } from 'react';
|
|
2
3
|
|
|
3
4
|
type OpenMojiIconProps = DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
|
|
4
|
-
|
|
5
|
+
/**
|
|
6
|
+
* The OpenMoji character to display
|
|
7
|
+
*/
|
|
8
|
+
icon: string_char_emoji | string;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @default 'black'
|
|
12
|
+
*/
|
|
13
|
+
variant?: 'black' | 'color';
|
|
5
14
|
};
|
|
6
15
|
|
|
7
16
|
/**
|
|
8
17
|
* Renders an emoji using the OpenMoji black and white font
|
|
9
18
|
*/
|
|
10
|
-
export function OpenMojiIcon(
|
|
19
|
+
export function OpenMojiIcon(props: OpenMojiIconProps) {
|
|
20
|
+
const { icon, variant = 'black', className, style, ...rest } = props;
|
|
21
|
+
|
|
22
|
+
const fontFamily = variant === 'black' ? '"OpenMojiBlack", sans-serif' : '"OpenMojiColor", sans-serif';
|
|
23
|
+
|
|
11
24
|
return (
|
|
12
|
-
<span
|
|
13
|
-
className={className}
|
|
14
|
-
style={{ ...style, fontFamily: '"OpenMojiBlack", sans-serif' }}
|
|
15
|
-
{...rest}
|
|
16
|
-
>
|
|
25
|
+
<span className={className} style={{ ...style, fontFamily }} {...rest}>
|
|
17
26
|
{icon}
|
|
18
27
|
</span>
|
|
19
28
|
);
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
export function PrintHeader({ title }: { title?: string }) {
|
|
2
2
|
return (
|
|
3
|
-
<div className="hidden print:block mb-
|
|
3
|
+
<div className="hidden print:block mb-6 border-b-2 border-blue-600 pb-2">
|
|
4
4
|
<div className="flex justify-between items-end">
|
|
5
5
|
<div>
|
|
6
|
-
<h1 className="text-
|
|
6
|
+
<h1 className="text-2xl font-bold text-gray-900 font-poppins">Agents Server</h1>
|
|
7
7
|
<div className="text-sm text-gray-500 mt-1 flex items-center gap-1">
|
|
8
8
|
Powered by <span className="font-semibold text-blue-600">Promptbook</span>
|
|
9
9
|
</div>
|
|
10
10
|
</div>
|
|
11
|
-
{title && <h2 className="text-
|
|
11
|
+
{title && <h2 className="text-lg font-semibold text-gray-700">{title}</h2>}
|
|
12
12
|
</div>
|
|
13
|
-
<div className="text-xs text-gray-400 mt-
|
|
13
|
+
<div className="text-xs text-gray-400 mt-1 text-right">
|
|
14
14
|
{new Date().toLocaleDateString()}
|
|
15
15
|
</div>
|
|
16
16
|
</div>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { X } from 'lucide-react';
|
|
4
|
+
import { Portal } from '../Portal/Portal';
|
|
5
|
+
|
|
6
|
+
type RegisterUserDialogProps = {
|
|
7
|
+
isOpen: boolean;
|
|
8
|
+
onClose: () => void;
|
|
9
|
+
adminEmail: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export function RegisterUserDialog(props: RegisterUserDialogProps) {
|
|
13
|
+
const { isOpen, onClose, adminEmail } = props;
|
|
14
|
+
|
|
15
|
+
if (!isOpen) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Portal>
|
|
21
|
+
<div className="fixed inset-0 z-[9999] flex items-center justify-center bg-black/50 backdrop-blur-sm animate-in fade-in duration-200">
|
|
22
|
+
<div className="relative w-full max-w-md bg-white rounded-lg shadow-lg border border-gray-200 p-6 animate-in zoom-in-95 duration-200">
|
|
23
|
+
<button
|
|
24
|
+
onClick={onClose}
|
|
25
|
+
className="absolute top-4 right-4 text-gray-400 hover:text-gray-500 transition-colors"
|
|
26
|
+
>
|
|
27
|
+
<X className="w-5 h-5" />
|
|
28
|
+
<span className="sr-only">Close</span>
|
|
29
|
+
</button>
|
|
30
|
+
|
|
31
|
+
<div className="mb-6">
|
|
32
|
+
<h2 className="text-xl font-semibold text-gray-900">Register New User</h2>
|
|
33
|
+
<p className="text-sm text-gray-500 mt-1">Create a new user account</p>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div className="space-y-4">
|
|
37
|
+
<div className="p-4 bg-blue-50 border border-blue-200 rounded-md">
|
|
38
|
+
<p className="text-sm text-blue-800">
|
|
39
|
+
This Promptbook server has no email capability. Please contact the administrator at{' '}
|
|
40
|
+
<a
|
|
41
|
+
href={`mailto:${adminEmail}`}
|
|
42
|
+
className="font-medium text-blue-900 underline hover:text-blue-800"
|
|
43
|
+
>
|
|
44
|
+
{adminEmail}
|
|
45
|
+
</a>{' '}
|
|
46
|
+
to register new user.
|
|
47
|
+
</p>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<button
|
|
51
|
+
onClick={onClose}
|
|
52
|
+
className="w-full inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 bg-gray-100 text-gray-900 hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition-colors"
|
|
53
|
+
>
|
|
54
|
+
Close
|
|
55
|
+
</button>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</Portal>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Utility to append ?headless param if present in current URL
|
|
2
|
-
import { usePathname, useSearchParams } from 'next/navigation';
|
|
3
2
|
import Link, { LinkProps } from 'next/link';
|
|
3
|
+
import { useSearchParams } from 'next/navigation';
|
|
4
4
|
import { useMemo } from 'react';
|
|
5
5
|
|
|
6
6
|
// Returns true if ?headless is present in current search params
|
|
@@ -18,7 +18,11 @@ export function appendHeadlessParam(href: string, isHeadless: boolean): string {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
// Custom Link that preserves headless param
|
|
21
|
-
export function HeadlessLink({
|
|
21
|
+
export function HeadlessLink({
|
|
22
|
+
href,
|
|
23
|
+
children,
|
|
24
|
+
...rest
|
|
25
|
+
}: LinkProps & { children: React.ReactNode } & React.AnchorHTMLAttributes<HTMLAnchorElement>) {
|
|
22
26
|
const isHeadless = useIsHeadless();
|
|
23
27
|
const finalHref = useMemo(() => appendHeadlessParam(String(href), isHeadless), [href, isHeadless]);
|
|
24
28
|
return (
|
|
@@ -28,7 +32,7 @@ export function HeadlessLink({ href, children, ...rest }: LinkProps & { children
|
|
|
28
32
|
);
|
|
29
33
|
}
|
|
30
34
|
|
|
31
|
-
import { useRouter } from
|
|
35
|
+
import { useRouter } from 'next/navigation';
|
|
32
36
|
|
|
33
37
|
// Helper for router.push
|
|
34
38
|
export function pushWithHeadless(router: ReturnType<typeof useRouter>, href: string, isHeadless: boolean) {
|
|
@@ -38,7 +38,13 @@ export const metadataDefaults = [
|
|
|
38
38
|
type: 'TEXT',
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
|
-
key: '
|
|
41
|
+
key: 'SHOW_FEDERATED_SERVERS_PUBLICLY',
|
|
42
|
+
value: 'false',
|
|
43
|
+
note: 'Whether to show federated servers and their agents to anonymous users. When false, federated servers are only visible to authenticated users.',
|
|
44
|
+
type: 'BOOLEAN',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
key: 'IS_EXPERIMENTAL_VOICE_CALLING_ENABLED',
|
|
42
48
|
value: 'false',
|
|
43
49
|
note: 'Enable or disable voice calling features for agents. When disabled, voice API endpoints will return 403 Forbidden.',
|
|
44
50
|
type: 'BOOLEAN',
|
|
@@ -67,6 +73,18 @@ export const metadataDefaults = [
|
|
|
67
73
|
note: 'Language for generating new agent names. Possible values: ENGLISH, CZECH.',
|
|
68
74
|
type: 'TEXT_SINGLE_LINE',
|
|
69
75
|
},
|
|
76
|
+
{
|
|
77
|
+
key: 'ADMIN_EMAIL',
|
|
78
|
+
value: 'support@ptbk.io',
|
|
79
|
+
note: 'Administrator email address used for password reset and user registration requests.',
|
|
80
|
+
type: 'TEXT_SINGLE_LINE',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
key: 'DEFAULT_AGENT_VISIBILITY',
|
|
84
|
+
value: 'PRIVATE',
|
|
85
|
+
note: 'Default visibility for new agents. Can be PUBLIC or PRIVATE.',
|
|
86
|
+
type: 'TEXT_SINGLE_LINE',
|
|
87
|
+
},
|
|
70
88
|
] as const satisfies ReadonlyArray<{
|
|
71
89
|
key: string;
|
|
72
90
|
value: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE "prefix_Agent" ADD COLUMN "deletedAt" TEXT;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS "prefix_Image" (
|
|
2
|
+
"id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
|
3
|
+
"createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
|
|
4
|
+
"updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
|
|
5
|
+
|
|
6
|
+
"filename" TEXT NOT NULL,
|
|
7
|
+
"prompt" TEXT NOT NULL,
|
|
8
|
+
"cdnUrl" TEXT NOT NULL,
|
|
9
|
+
"cdnKey" TEXT NOT NULL
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "prefix_Image_filename_idx" ON "prefix_Image" ("filename");
|
|
13
|
+
|
|
14
|
+
ALTER TABLE "prefix_Image" ENABLE ROW LEVEL SECURITY;
|
|
15
|
+
|
|
16
|
+
COMMENT ON COLUMN "prefix_Image"."filename" IS 'The original filename requested (e.g., cat-sitting-on-keyboard.png)';
|
|
17
|
+
COMMENT ON COLUMN "prefix_Image"."prompt" IS 'The normalized prompt used to generate the image';
|
|
18
|
+
COMMENT ON COLUMN "prefix_Image"."cdnUrl" IS 'The full URL of the uploaded image in CDN';
|
|
19
|
+
COMMENT ON COLUMN "prefix_Image"."cdnKey" IS 'The key used to identify the image in CDN storage';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE "prefix_Agent" ADD COLUMN "visibility" TEXT NOT NULL DEFAULT 'PRIVATE' CHECK ("visibility" IN ('PUBLIC', 'PRIVATE'));
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS "prefix_File" (
|
|
2
|
+
"id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
|
3
|
+
"createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
|
|
4
|
+
|
|
5
|
+
"userId" BIGINT REFERENCES "prefix_User"("id"),
|
|
6
|
+
"fileName" TEXT NOT NULL,
|
|
7
|
+
"fileSize" BIGINT NOT NULL,
|
|
8
|
+
"fileType" TEXT NOT NULL,
|
|
9
|
+
"cdnUrl" TEXT NOT NULL,
|
|
10
|
+
"purpose" TEXT NOT NULL
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
ALTER TABLE "prefix_File" ENABLE ROW LEVEL SECURITY;
|
|
14
|
+
|
|
15
|
+
COMMENT ON COLUMN "prefix_File"."userId" IS 'Reference to the user who uploaded the file';
|
|
16
|
+
COMMENT ON COLUMN "prefix_File"."fileName" IS 'Original name of the uploaded file';
|
|
17
|
+
COMMENT ON COLUMN "prefix_File"."fileSize" IS 'Size of the file in bytes';
|
|
18
|
+
COMMENT ON COLUMN "prefix_File"."fileType" IS 'MIME type of the file';
|
|
19
|
+
COMMENT ON COLUMN "prefix_File"."cdnUrl" IS 'Public URL of the file in CDN';
|
|
20
|
+
COMMENT ON COLUMN "prefix_File"."purpose" IS 'Purpose of the upload (e.g. KNOWLEDGE, SERVER_FAVICON_URL)';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
-- Add status column to track file upload progress
|
|
2
|
+
ALTER TABLE "prefix_File" ADD COLUMN IF NOT EXISTS "status" TEXT NOT NULL DEFAULT 'COMPLETED';
|
|
3
|
+
|
|
4
|
+
-- Add check constraint for valid status values
|
|
5
|
+
-- ALTER TABLE "prefix_File" ADD CONSTRAINT "File_status_check" CHECK ("status" IN ('UPLOADING', 'COMPLETED', 'FAILED'));
|
|
6
|
+
|
|
7
|
+
-- Drop the column cdnUrl if it exists
|
|
8
|
+
ALTER TABLE "prefix_File" DROP COLUMN IF EXISTS "cdnUrl";
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
-- Add nullable columns storageUrl and shortUrl
|
|
12
|
+
ALTER TABLE "prefix_File" ADD COLUMN IF NOT EXISTS "storageUrl" TEXT NULL;
|
|
13
|
+
ALTER TABLE "prefix_File" ADD COLUMN IF NOT EXISTS "shortUrl" TEXT NULL;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS "prefix_OpenAiAssistantCache" (
|
|
2
|
+
"id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
|
3
|
+
"createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
|
|
4
|
+
"updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
|
|
5
|
+
|
|
6
|
+
"agentHash" TEXT NOT NULL,
|
|
7
|
+
"assistantId" TEXT NOT NULL
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "prefix_OpenAiAssistantCache_agentHash_idx" ON "prefix_OpenAiAssistantCache" ("agentHash");
|
|
11
|
+
|
|
12
|
+
ALTER TABLE "prefix_OpenAiAssistantCache" ENABLE ROW LEVEL SECURITY;
|
|
@@ -47,6 +47,7 @@ export type AgentsServerDatabase = {
|
|
|
47
47
|
agentName: string;
|
|
48
48
|
createdAt: string;
|
|
49
49
|
updatedAt: string | null;
|
|
50
|
+
permanentId: string | null;
|
|
50
51
|
agentHash: string;
|
|
51
52
|
agentSource: string;
|
|
52
53
|
agentProfile: Json;
|
|
@@ -54,12 +55,15 @@ export type AgentsServerDatabase = {
|
|
|
54
55
|
usage: Json | null;
|
|
55
56
|
preparedModelRequirements: Json | null;
|
|
56
57
|
preparedExternals: Json | null;
|
|
58
|
+
deletedAt: string | null;
|
|
59
|
+
visibility: 'PUBLIC' | 'PRIVATE';
|
|
57
60
|
};
|
|
58
61
|
Insert: {
|
|
59
62
|
id?: number;
|
|
60
63
|
agentName: string;
|
|
61
64
|
createdAt: string;
|
|
62
65
|
updatedAt?: string | null;
|
|
66
|
+
permanentId?: string | null;
|
|
63
67
|
agentHash: string;
|
|
64
68
|
agentSource: string;
|
|
65
69
|
agentProfile: Json;
|
|
@@ -67,12 +71,15 @@ export type AgentsServerDatabase = {
|
|
|
67
71
|
usage?: Json | null;
|
|
68
72
|
preparedModelRequirements?: Json | null;
|
|
69
73
|
preparedExternals?: Json | null;
|
|
74
|
+
deletedAt?: string | null;
|
|
75
|
+
visibility?: 'PUBLIC' | 'PRIVATE';
|
|
70
76
|
};
|
|
71
77
|
Update: {
|
|
72
78
|
id?: number;
|
|
73
79
|
agentName?: string;
|
|
74
80
|
createdAt?: string;
|
|
75
81
|
updatedAt?: string | null;
|
|
82
|
+
permanentId?: string | null;
|
|
76
83
|
agentHash?: string;
|
|
77
84
|
agentSource?: string;
|
|
78
85
|
agentProfile?: Json;
|
|
@@ -80,6 +87,8 @@ export type AgentsServerDatabase = {
|
|
|
80
87
|
usage?: Json | null;
|
|
81
88
|
preparedModelRequirements?: Json | null;
|
|
82
89
|
preparedExternals?: Json | null;
|
|
90
|
+
deletedAt?: string | null;
|
|
91
|
+
visibility?: 'PUBLIC' | 'PRIVATE';
|
|
83
92
|
};
|
|
84
93
|
Relationships: [];
|
|
85
94
|
};
|
|
@@ -272,6 +281,30 @@ export type AgentsServerDatabase = {
|
|
|
272
281
|
};
|
|
273
282
|
Relationships: [];
|
|
274
283
|
};
|
|
284
|
+
OpenAiAssistantCache: {
|
|
285
|
+
Row: {
|
|
286
|
+
id: number;
|
|
287
|
+
createdAt: string;
|
|
288
|
+
updatedAt: string;
|
|
289
|
+
agentHash: string;
|
|
290
|
+
assistantId: string;
|
|
291
|
+
};
|
|
292
|
+
Insert: {
|
|
293
|
+
id?: number;
|
|
294
|
+
createdAt?: string;
|
|
295
|
+
updatedAt?: string;
|
|
296
|
+
agentHash: string;
|
|
297
|
+
assistantId: string;
|
|
298
|
+
};
|
|
299
|
+
Update: {
|
|
300
|
+
id?: number;
|
|
301
|
+
createdAt?: string;
|
|
302
|
+
updatedAt?: string;
|
|
303
|
+
agentHash?: string;
|
|
304
|
+
assistantId?: string;
|
|
305
|
+
};
|
|
306
|
+
Relationships: [];
|
|
307
|
+
};
|
|
275
308
|
ApiTokens: {
|
|
276
309
|
Row: {
|
|
277
310
|
id: number;
|
|
@@ -299,6 +332,82 @@ export type AgentsServerDatabase = {
|
|
|
299
332
|
};
|
|
300
333
|
Relationships: [];
|
|
301
334
|
};
|
|
335
|
+
Image: {
|
|
336
|
+
Row: {
|
|
337
|
+
id: number;
|
|
338
|
+
createdAt: string;
|
|
339
|
+
updatedAt: string;
|
|
340
|
+
filename: string;
|
|
341
|
+
prompt: string;
|
|
342
|
+
cdnUrl: string;
|
|
343
|
+
cdnKey: string;
|
|
344
|
+
};
|
|
345
|
+
Insert: {
|
|
346
|
+
id?: number;
|
|
347
|
+
createdAt?: string;
|
|
348
|
+
updatedAt?: string;
|
|
349
|
+
filename: string;
|
|
350
|
+
prompt: string;
|
|
351
|
+
cdnUrl: string;
|
|
352
|
+
cdnKey: string;
|
|
353
|
+
};
|
|
354
|
+
Update: {
|
|
355
|
+
id?: number;
|
|
356
|
+
createdAt?: string;
|
|
357
|
+
updatedAt?: string;
|
|
358
|
+
filename?: string;
|
|
359
|
+
prompt?: string;
|
|
360
|
+
cdnUrl?: string;
|
|
361
|
+
cdnKey?: string;
|
|
362
|
+
};
|
|
363
|
+
Relationships: [];
|
|
364
|
+
};
|
|
365
|
+
File: {
|
|
366
|
+
Row: {
|
|
367
|
+
id: number;
|
|
368
|
+
createdAt: string;
|
|
369
|
+
userId: number | null;
|
|
370
|
+
fileName: string;
|
|
371
|
+
fileSize: number;
|
|
372
|
+
fileType: string;
|
|
373
|
+
storageUrl: string | null;
|
|
374
|
+
shortUrl: string | null;
|
|
375
|
+
purpose: string;
|
|
376
|
+
status: 'UPLOADING' | 'COMPLETED' | 'FAILED';
|
|
377
|
+
};
|
|
378
|
+
Insert: {
|
|
379
|
+
id?: number;
|
|
380
|
+
createdAt?: string;
|
|
381
|
+
userId?: number | null;
|
|
382
|
+
fileName: string;
|
|
383
|
+
fileSize: number;
|
|
384
|
+
fileType: string;
|
|
385
|
+
storageUrl?: string | null;
|
|
386
|
+
shortUrl?: string | null;
|
|
387
|
+
purpose: string;
|
|
388
|
+
status?: 'UPLOADING' | 'COMPLETED' | 'FAILED';
|
|
389
|
+
};
|
|
390
|
+
Update: {
|
|
391
|
+
id?: number;
|
|
392
|
+
createdAt?: string;
|
|
393
|
+
userId?: number | null;
|
|
394
|
+
fileName?: string;
|
|
395
|
+
fileSize?: number;
|
|
396
|
+
fileType?: string;
|
|
397
|
+
storageUrl?: string | null;
|
|
398
|
+
shortUrl?: string | null;
|
|
399
|
+
purpose?: string;
|
|
400
|
+
status?: 'UPLOADING' | 'COMPLETED' | 'FAILED';
|
|
401
|
+
};
|
|
402
|
+
Relationships: [
|
|
403
|
+
{
|
|
404
|
+
foreignKeyName: 'File_userId_fkey';
|
|
405
|
+
columns: ['userId'];
|
|
406
|
+
referencedRelation: 'User';
|
|
407
|
+
referencedColumns: ['id'];
|
|
408
|
+
},
|
|
409
|
+
];
|
|
410
|
+
};
|
|
302
411
|
};
|
|
303
412
|
Views: Record<string, never>;
|
|
304
413
|
Functions: Record<string, never>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reserved paths that should not be treated as agent names.
|
|
3
|
+
* This file is auto-generated by scripts/generate-reserved-paths.js
|
|
4
|
+
*
|
|
5
|
+
* ⚠️ WARNING: This code has been generated so that any manual changes will be overwritten
|
|
6
|
+
*
|
|
7
|
+
* @see /apps/agents-server/src/app - source directory for routes
|
|
8
|
+
* @see /apps/agents-server/public - source directory for static files
|
|
9
|
+
* @see /apps/agents-server/src/middleware.ts - where this is used
|
|
10
|
+
*/
|
|
11
|
+
export const RESERVED_PATHS: readonly string[] = [
|
|
12
|
+
"_next",
|
|
13
|
+
"admin",
|
|
14
|
+
"agents",
|
|
15
|
+
"api",
|
|
16
|
+
"docs",
|
|
17
|
+
"embed",
|
|
18
|
+
"favicon.ico",
|
|
19
|
+
"fonts",
|
|
20
|
+
"humans.txt",
|
|
21
|
+
"logo-blue-white-256.png",
|
|
22
|
+
"manifest.webmanifest",
|
|
23
|
+
"recycle-bin",
|
|
24
|
+
"restricted",
|
|
25
|
+
"robots.txt",
|
|
26
|
+
"security.txt",
|
|
27
|
+
"sitemap.xml",
|
|
28
|
+
"sw.js",
|
|
29
|
+
"swagger",
|
|
30
|
+
"swagger.json",
|
|
31
|
+
"test"
|
|
32
|
+
] as const;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { TODO_any } from '@promptbook-local/types';
|
|
2
2
|
import { createClient } from '@supabase/supabase-js';
|
|
3
3
|
import { NextRequest, NextResponse } from 'next/server';
|
|
4
|
-
import { SERVERS
|
|
4
|
+
import { SERVERS } from '../config';
|
|
5
|
+
import { $getTableName } from './database/$getTableName';
|
|
6
|
+
import { RESERVED_PATHS } from './generated/reservedPaths';
|
|
5
7
|
import { isIpAllowed } from './utils/isIpAllowed';
|
|
6
8
|
|
|
7
|
-
// Note: Re-implementing normalizeTo_PascalCase to avoid importing from @promptbook-local/utils which might have Node.js dependencies
|
|
9
|
+
// Note: Re-implementing normalizeTo_PascalCase to avoid importing from @promptbook-local/utils which might have Node.js dependencies !!!!
|
|
8
10
|
function normalizeTo_PascalCase(text: string): string {
|
|
9
11
|
return text
|
|
10
|
-
.replace(/(?:^\w|[A-Z]|\b\w)/g, (word
|
|
12
|
+
.replace(/(?:^\w|[A-Z]|\b\w)/g, (word) => {
|
|
11
13
|
return word.toUpperCase();
|
|
12
14
|
})
|
|
13
15
|
.replace(/\s+/g, '');
|
|
@@ -33,8 +35,12 @@ export async function middleware(req: NextRequest) {
|
|
|
33
35
|
const host = req.headers.get('host');
|
|
34
36
|
|
|
35
37
|
if (host) {
|
|
38
|
+
/*
|
|
39
|
+
Note: [🐔] This code was commented out because results of it are unused
|
|
40
|
+
|
|
36
41
|
let tablePrefix = SUPABASE_TABLE_PREFIX;
|
|
37
42
|
|
|
43
|
+
|
|
38
44
|
if (SERVERS && SERVERS.length > 0) {
|
|
39
45
|
// Logic mirrored from src/tools/$provideServer.ts
|
|
40
46
|
if (SERVERS.some((server) => server === host)) {
|
|
@@ -44,6 +50,7 @@ export async function middleware(req: NextRequest) {
|
|
|
44
50
|
tablePrefix = `server_${serverName}_`;
|
|
45
51
|
}
|
|
46
52
|
}
|
|
53
|
+
*/
|
|
47
54
|
|
|
48
55
|
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
|
49
56
|
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
|
@@ -58,7 +65,7 @@ export async function middleware(req: NextRequest) {
|
|
|
58
65
|
});
|
|
59
66
|
|
|
60
67
|
const { data } = await supabase
|
|
61
|
-
.from(
|
|
68
|
+
.from(await $getTableName(`Metadata`))
|
|
62
69
|
.select('value')
|
|
63
70
|
.eq('key', 'RESTRICT_IP')
|
|
64
71
|
.single();
|
|
@@ -82,6 +89,9 @@ export async function middleware(req: NextRequest) {
|
|
|
82
89
|
const token = authHeader.split(' ')[1];
|
|
83
90
|
|
|
84
91
|
if (token.startsWith('ptbk_')) {
|
|
92
|
+
/*
|
|
93
|
+
Note: [🐔] This code was commented out because results of it are unused
|
|
94
|
+
|
|
85
95
|
const host = req.headers.get('host');
|
|
86
96
|
let tablePrefix = SUPABASE_TABLE_PREFIX;
|
|
87
97
|
|
|
@@ -93,6 +103,7 @@ export async function middleware(req: NextRequest) {
|
|
|
93
103
|
tablePrefix = `server_${serverName}_`;
|
|
94
104
|
}
|
|
95
105
|
}
|
|
106
|
+
*/
|
|
96
107
|
|
|
97
108
|
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
|
98
109
|
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
|
@@ -107,7 +118,7 @@ export async function middleware(req: NextRequest) {
|
|
|
107
118
|
});
|
|
108
119
|
|
|
109
120
|
const { data } = await supabase
|
|
110
|
-
.from(
|
|
121
|
+
.from(await $getTableName(`ApiTokens`))
|
|
111
122
|
.select('id')
|
|
112
123
|
.eq('token', token)
|
|
113
124
|
.eq('isRevoked', false)
|
|
@@ -186,22 +197,7 @@ export async function middleware(req: NextRequest) {
|
|
|
186
197
|
|
|
187
198
|
if (
|
|
188
199
|
potentialAgentName &&
|
|
189
|
-
!
|
|
190
|
-
'agents',
|
|
191
|
-
'api',
|
|
192
|
-
'admin',
|
|
193
|
-
'docs',
|
|
194
|
-
'test',
|
|
195
|
-
'embed',
|
|
196
|
-
'_next',
|
|
197
|
-
'manifest.webmanifest',
|
|
198
|
-
'sw.js',
|
|
199
|
-
'favicon.ico',
|
|
200
|
-
'sitemap.xml',
|
|
201
|
-
'robots.txt',
|
|
202
|
-
'security.txt',
|
|
203
|
-
'humans.txt',
|
|
204
|
-
].includes(potentialAgentName) &&
|
|
200
|
+
!RESERVED_PATHS.includes(potentialAgentName) &&
|
|
205
201
|
!potentialAgentName.startsWith('.') &&
|
|
206
202
|
// Note: Other static files are excluded by the matcher configuration below
|
|
207
203
|
true
|
|
@@ -243,7 +239,7 @@ export async function middleware(req: NextRequest) {
|
|
|
243
239
|
let serverName = serverHost;
|
|
244
240
|
serverName = serverName.replace(/\.ptbk\.io$/, '');
|
|
245
241
|
serverName = normalizeTo_PascalCase(serverName);
|
|
246
|
-
const prefix = `server_${serverName}_`;
|
|
242
|
+
// const prefix = `server_${serverName}_`;
|
|
247
243
|
|
|
248
244
|
// Search for agent with matching META LINK
|
|
249
245
|
// agentProfile->links is an array of strings
|
|
@@ -256,7 +252,7 @@ export async function middleware(req: NextRequest) {
|
|
|
256
252
|
|
|
257
253
|
try {
|
|
258
254
|
const { data } = await supabase
|
|
259
|
-
.from(
|
|
255
|
+
.from(await $getTableName(`Agent`))
|
|
260
256
|
.select('agentName')
|
|
261
257
|
.or(orFilter)
|
|
262
258
|
.limit(1)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { $provideSupabaseForServer } from '../database/$provideSupabaseForServer';
|
|
2
|
+
import { TrackedFilesStorage } from '../utils/cdn/classes/TrackedFilesStorage';
|
|
1
3
|
import { VercelBlobStorage } from '../utils/cdn/classes/VercelBlobStorage';
|
|
2
4
|
import { IIFilesStorageWithCdn } from '../utils/cdn/interfaces/IFilesStorage';
|
|
3
5
|
|
|
@@ -13,12 +15,15 @@ let cdn: IIFilesStorageWithCdn | null = null;
|
|
|
13
15
|
*/
|
|
14
16
|
export function $provideCdnForServer(): IIFilesStorageWithCdn {
|
|
15
17
|
if (!cdn) {
|
|
16
|
-
|
|
18
|
+
const inner = new VercelBlobStorage({
|
|
17
19
|
token: process.env.VERCEL_BLOB_READ_WRITE_TOKEN!,
|
|
18
20
|
pathPrefix: process.env.NEXT_PUBLIC_CDN_PATH_PREFIX!,
|
|
19
21
|
cdnPublicUrl: new URL(process.env.NEXT_PUBLIC_CDN_PUBLIC_URL!),
|
|
20
22
|
});
|
|
21
23
|
|
|
24
|
+
const supabase = $provideSupabaseForServer();
|
|
25
|
+
cdn = new TrackedFilesStorage(inner, supabase);
|
|
26
|
+
|
|
22
27
|
/*
|
|
23
28
|
cdn = new DigitalOceanSpaces({
|
|
24
29
|
bucket: process.env.CDN_BUCKET!,
|