@promptbook/cli 0.103.0-47 → 0.103.0-49
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/README.md +1 -1
- package/apps/agents-server/TODO.txt +6 -5
- package/apps/agents-server/config.ts +130 -0
- package/apps/agents-server/next.config.ts +1 -1
- package/apps/agents-server/public/fonts/OpenMoji-black-glyf.woff2 +0 -0
- package/apps/agents-server/public/fonts/download-font.js +22 -0
- package/apps/agents-server/src/app/[agentName]/[...rest]/page.tsx +6 -0
- package/apps/agents-server/src/app/[agentName]/page.tsx +1 -0
- package/apps/agents-server/src/app/actions.ts +37 -2
- package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +68 -0
- package/apps/agents-server/src/app/agents/[agentName]/AgentQrCode.tsx +55 -0
- package/apps/agents-server/src/app/agents/[agentName]/AgentUrlCopy.tsx +4 -5
- package/apps/agents-server/src/app/agents/[agentName]/CopyField.tsx +44 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +8 -8
- package/apps/agents-server/src/app/agents/[agentName]/api/chat/route.ts +100 -18
- package/apps/agents-server/src/app/agents/[agentName]/api/feedback/route.ts +54 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/modelRequirements/route.ts +6 -6
- package/apps/agents-server/src/app/agents/[agentName]/api/modelRequirements/systemMessage/route.ts +3 -3
- package/apps/agents-server/src/app/agents/[agentName]/api/profile/route.ts +6 -7
- package/apps/agents-server/src/app/agents/[agentName]/book/BookEditorWrapper.tsx +6 -7
- package/apps/agents-server/src/app/agents/[agentName]/book/page.tsx +9 -2
- package/apps/agents-server/src/app/agents/[agentName]/book+chat/AgentBookAndChat.tsx +23 -0
- package/apps/agents-server/src/app/agents/[agentName]/book+chat/{AgentBookAndChatComponent.tsx → AgentBookAndChatComponent.tsx.todo} +6 -8
- package/apps/agents-server/src/app/agents/[agentName]/book+chat/page.tsx +28 -17
- package/apps/agents-server/src/app/agents/[agentName]/book+chat/page.tsx.todo +21 -0
- package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatWrapper.tsx +34 -4
- package/apps/agents-server/src/app/agents/[agentName]/chat/page.tsx +4 -1
- package/apps/agents-server/src/app/agents/[agentName]/generateAgentMetadata.ts +42 -0
- package/apps/agents-server/src/app/agents/[agentName]/page.tsx +111 -108
- package/apps/agents-server/src/app/agents/page.tsx +1 -1
- package/apps/agents-server/src/app/api/auth/login/route.ts +65 -0
- package/apps/agents-server/src/app/api/auth/logout/route.ts +7 -0
- package/apps/agents-server/src/app/api/metadata/route.ts +116 -0
- package/apps/agents-server/src/app/api/upload/route.ts +7 -7
- package/apps/agents-server/src/app/api/users/[username]/route.ts +75 -0
- package/apps/agents-server/src/app/api/users/route.ts +71 -0
- package/apps/agents-server/src/app/globals.css +35 -1
- package/apps/agents-server/src/app/layout.tsx +43 -23
- package/apps/agents-server/src/app/metadata/MetadataClient.tsx +271 -0
- package/apps/agents-server/src/app/metadata/page.tsx +13 -0
- package/apps/agents-server/src/app/not-found.tsx +5 -0
- package/apps/agents-server/src/app/page.tsx +84 -46
- package/apps/agents-server/src/components/Auth/AuthControls.tsx +123 -0
- package/apps/agents-server/src/components/ErrorPage/ErrorPage.tsx +33 -0
- package/apps/agents-server/src/components/ForbiddenPage/ForbiddenPage.tsx +15 -0
- package/apps/agents-server/src/components/Header/Header.tsx +146 -0
- package/apps/agents-server/src/components/LayoutWrapper/LayoutWrapper.tsx +27 -0
- package/apps/agents-server/src/components/LoginDialog/LoginDialog.tsx +40 -0
- package/apps/agents-server/src/components/LoginForm/LoginForm.tsx +109 -0
- package/apps/agents-server/src/components/NotFoundPage/NotFoundPage.tsx +17 -0
- package/apps/agents-server/src/components/UsersList/UsersList.tsx +190 -0
- package/apps/agents-server/src/components/VercelDeploymentCard/VercelDeploymentCard.tsx +60 -0
- package/apps/agents-server/src/database/$getTableName.ts +18 -0
- package/apps/agents-server/src/database/$provideSupabase.ts +29 -0
- package/apps/agents-server/src/{supabase/getSupabaseForBrowser.ts → database/$provideSupabaseForBrowser.ts} +9 -5
- package/apps/agents-server/src/{supabase/getSupabaseForServer.ts → database/$provideSupabaseForServer.ts} +7 -7
- package/apps/agents-server/src/{supabase/getSupabaseForWorker.ts → database/$provideSupabaseForWorker.ts} +5 -4
- package/apps/agents-server/src/database/getMetadata.ts +31 -0
- package/apps/agents-server/src/database/metadataDefaults.ts +32 -0
- package/apps/agents-server/src/database/schema.sql +179 -0
- package/apps/agents-server/src/database/schema.ts +251 -0
- package/apps/agents-server/src/middleware.ts +162 -0
- package/apps/agents-server/src/tools/$provideAgentCollectionForServer.ts +14 -10
- package/apps/agents-server/src/tools/$provideCdnForServer.ts +1 -1
- package/apps/agents-server/src/tools/$provideExecutionToolsForServer.ts +11 -13
- package/apps/agents-server/src/tools/$provideOpenAiAssistantExecutionToolsForServer.ts +7 -7
- package/apps/agents-server/src/tools/$provideServer.ts +39 -0
- package/apps/agents-server/src/utils/auth.ts +33 -0
- package/apps/agents-server/src/utils/cdn/utils/getUserFileCdnKey.ts +2 -1
- package/apps/agents-server/src/utils/cdn/utils/nameToSubfolderPath.ts +1 -1
- package/apps/agents-server/src/utils/getCurrentUser.ts +32 -0
- package/apps/agents-server/src/utils/isIpAllowed.ts +101 -0
- package/apps/agents-server/src/utils/isUserAdmin.ts +31 -0
- package/apps/agents-server/src/utils/session.ts +50 -0
- package/apps/agents-server/tailwind.config.ts +2 -0
- package/esm/index.es.js +310 -49
- package/esm/index.es.js.map +1 -1
- package/esm/typings/servers.d.ts +1 -0
- package/esm/typings/src/_packages/core.index.d.ts +6 -0
- package/esm/typings/src/_packages/types.index.d.ts +4 -0
- package/esm/typings/src/_packages/utils.index.d.ts +2 -0
- package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +17 -3
- package/esm/typings/src/book-2.0/agent-source/AgentSourceParseResult.d.ts +2 -1
- package/esm/typings/src/book-2.0/agent-source/computeAgentHash.d.ts +8 -0
- package/esm/typings/src/book-2.0/agent-source/computeAgentHash.test.d.ts +1 -0
- package/esm/typings/src/book-2.0/agent-source/createDefaultAgentName.d.ts +8 -0
- package/esm/typings/src/book-2.0/agent-source/normalizeAgentName.d.ts +9 -0
- package/esm/typings/src/book-2.0/agent-source/normalizeAgentName.test.d.ts +1 -0
- package/esm/typings/src/book-2.0/agent-source/parseAgentSourceWithCommitments.d.ts +1 -1
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +14 -8
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabaseOptions.d.ts +10 -0
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +57 -32
- package/esm/typings/src/commitments/MESSAGE/InitialMessageCommitmentDefinition.d.ts +28 -0
- package/esm/typings/src/commitments/index.d.ts +2 -1
- package/esm/typings/src/config.d.ts +1 -0
- package/esm/typings/src/errors/DatabaseError.d.ts +2 -2
- package/esm/typings/src/errors/WrappedError.d.ts +2 -2
- package/esm/typings/src/execution/ExecutionTask.d.ts +2 -2
- package/esm/typings/src/execution/LlmExecutionTools.d.ts +6 -1
- package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForWizardOrCli.d.ts +2 -2
- package/esm/typings/src/llm-providers/_common/utils/assertUniqueModels.d.ts +12 -0
- package/esm/typings/src/llm-providers/agent/Agent.d.ts +17 -4
- package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +10 -1
- package/esm/typings/src/llm-providers/agent/RemoteAgent.d.ts +6 -2
- package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionTools.d.ts +30 -4
- package/esm/typings/src/llm-providers/openai/openai-models.test.d.ts +4 -0
- package/esm/typings/src/remote-server/startAgentServer.d.ts +2 -2
- package/esm/typings/src/remote-server/startRemoteServer.d.ts +1 -2
- package/esm/typings/src/transpilers/openai-sdk/register.d.ts +1 -1
- package/esm/typings/src/types/typeAliases.d.ts +6 -0
- package/esm/typings/src/utils/color/Color.d.ts +7 -0
- package/esm/typings/src/utils/color/Color.test.d.ts +1 -0
- package/esm/typings/src/utils/environment/$getGlobalScope.d.ts +2 -2
- package/esm/typings/src/utils/misc/computeHash.d.ts +11 -0
- package/esm/typings/src/utils/misc/computeHash.test.d.ts +1 -0
- package/esm/typings/src/utils/normalization/normalize-to-kebab-case.d.ts +2 -0
- package/esm/typings/src/utils/normalization/normalizeTo_PascalCase.d.ts +3 -0
- package/esm/typings/src/utils/normalization/normalizeTo_camelCase.d.ts +2 -0
- package/esm/typings/src/utils/normalization/titleToName.d.ts +2 -0
- package/esm/typings/src/utils/organization/$sideEffect.d.ts +2 -2
- package/esm/typings/src/utils/organization/$side_effect.d.ts +2 -2
- package/esm/typings/src/utils/organization/TODO_USE.d.ts +2 -2
- package/esm/typings/src/utils/organization/keepUnused.d.ts +2 -2
- package/esm/typings/src/utils/organization/preserve.d.ts +3 -3
- package/esm/typings/src/utils/organization/really_any.d.ts +7 -0
- package/esm/typings/src/utils/serialization/asSerializable.d.ts +2 -2
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +311 -50
- package/umd/index.umd.js.map +1 -1
- package/apps/agents-server/config.ts.todo +0 -312
- package/apps/agents-server/src/supabase/TODO.txt +0 -1
- package/apps/agents-server/src/supabase/getSupabase.ts +0 -25
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AUTO-GENERATED TYPES FROM `schema.sql`
|
|
3
|
+
* Source of truth: `schema.sql` *(do not edit table structure here manually)*
|
|
4
|
+
*
|
|
5
|
+
* [💽] Prompt:
|
|
6
|
+
* Re-generate supabase typescript schema from the `./schema.sql`
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Json helper (Supabase style)
|
|
10
|
+
export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[];
|
|
11
|
+
|
|
12
|
+
// Public schema database interface (Supabase convention)
|
|
13
|
+
export type AgentsServerDatabase = {
|
|
14
|
+
// <- TODO: [🧠][🕜] Better naming
|
|
15
|
+
public: {
|
|
16
|
+
Tables: {
|
|
17
|
+
Metadata: {
|
|
18
|
+
Row: {
|
|
19
|
+
id: number;
|
|
20
|
+
createdAt: string;
|
|
21
|
+
updatedAt: string;
|
|
22
|
+
key: string;
|
|
23
|
+
value: string;
|
|
24
|
+
note: string | null;
|
|
25
|
+
};
|
|
26
|
+
Insert: {
|
|
27
|
+
id?: number;
|
|
28
|
+
createdAt?: string;
|
|
29
|
+
updatedAt?: string;
|
|
30
|
+
key: string;
|
|
31
|
+
value: string;
|
|
32
|
+
note?: string | null;
|
|
33
|
+
};
|
|
34
|
+
Update: {
|
|
35
|
+
id?: number;
|
|
36
|
+
createdAt?: string;
|
|
37
|
+
updatedAt?: string;
|
|
38
|
+
key?: string;
|
|
39
|
+
value?: string;
|
|
40
|
+
note?: string | null;
|
|
41
|
+
};
|
|
42
|
+
Relationships: [];
|
|
43
|
+
};
|
|
44
|
+
Agent: {
|
|
45
|
+
Row: {
|
|
46
|
+
id: number;
|
|
47
|
+
agentName: string;
|
|
48
|
+
createdAt: string;
|
|
49
|
+
updatedAt: string | null;
|
|
50
|
+
agentHash: string;
|
|
51
|
+
agentSource: string;
|
|
52
|
+
agentProfile: Json;
|
|
53
|
+
promptbookEngineVersion: string;
|
|
54
|
+
usage: Json | null;
|
|
55
|
+
preparedModelRequirements: Json | null;
|
|
56
|
+
preparedExternals: Json | null;
|
|
57
|
+
};
|
|
58
|
+
Insert: {
|
|
59
|
+
id?: number;
|
|
60
|
+
agentName: string;
|
|
61
|
+
createdAt: string;
|
|
62
|
+
updatedAt?: string | null;
|
|
63
|
+
agentHash: string;
|
|
64
|
+
agentSource: string;
|
|
65
|
+
agentProfile: Json;
|
|
66
|
+
promptbookEngineVersion: string;
|
|
67
|
+
usage?: Json | null;
|
|
68
|
+
preparedModelRequirements?: Json | null;
|
|
69
|
+
preparedExternals?: Json | null;
|
|
70
|
+
};
|
|
71
|
+
Update: {
|
|
72
|
+
id?: number;
|
|
73
|
+
agentName?: string;
|
|
74
|
+
createdAt?: string;
|
|
75
|
+
updatedAt?: string | null;
|
|
76
|
+
agentHash?: string;
|
|
77
|
+
agentSource?: string;
|
|
78
|
+
agentProfile?: Json;
|
|
79
|
+
promptbookEngineVersion?: string;
|
|
80
|
+
usage?: Json | null;
|
|
81
|
+
preparedModelRequirements?: Json | null;
|
|
82
|
+
preparedExternals?: Json | null;
|
|
83
|
+
};
|
|
84
|
+
Relationships: [];
|
|
85
|
+
};
|
|
86
|
+
AgentHistory: {
|
|
87
|
+
Row: {
|
|
88
|
+
id: number;
|
|
89
|
+
createdAt: string;
|
|
90
|
+
agentName: string;
|
|
91
|
+
agentHash: string;
|
|
92
|
+
previousAgentHash: string | null;
|
|
93
|
+
agentSource: string;
|
|
94
|
+
promptbookEngineVersion: string;
|
|
95
|
+
};
|
|
96
|
+
Insert: {
|
|
97
|
+
id?: number;
|
|
98
|
+
createdAt: string;
|
|
99
|
+
agentName: string;
|
|
100
|
+
agentHash: string;
|
|
101
|
+
previousAgentHash?: string | null;
|
|
102
|
+
agentSource: string;
|
|
103
|
+
promptbookEngineVersion: string;
|
|
104
|
+
};
|
|
105
|
+
Update: {
|
|
106
|
+
id?: number;
|
|
107
|
+
createdAt?: string;
|
|
108
|
+
agentName?: string;
|
|
109
|
+
agentHash?: string;
|
|
110
|
+
previousAgentHash?: string | null;
|
|
111
|
+
agentSource?: string;
|
|
112
|
+
promptbookEngineVersion?: string;
|
|
113
|
+
};
|
|
114
|
+
Relationships: [];
|
|
115
|
+
};
|
|
116
|
+
ChatHistory: {
|
|
117
|
+
Row: {
|
|
118
|
+
id: number;
|
|
119
|
+
createdAt: string;
|
|
120
|
+
messageHash: string;
|
|
121
|
+
previousMessageHash: string | null;
|
|
122
|
+
agentName: string;
|
|
123
|
+
agentHash: string;
|
|
124
|
+
message: Json;
|
|
125
|
+
promptbookEngineVersion: string | null;
|
|
126
|
+
url: string | null;
|
|
127
|
+
ip: string | null;
|
|
128
|
+
userAgent: string | null;
|
|
129
|
+
language: string | null;
|
|
130
|
+
platform: string | null;
|
|
131
|
+
};
|
|
132
|
+
Insert: {
|
|
133
|
+
id?: number;
|
|
134
|
+
createdAt: string;
|
|
135
|
+
messageHash: string;
|
|
136
|
+
previousMessageHash?: string | null;
|
|
137
|
+
agentName: string;
|
|
138
|
+
agentHash: string;
|
|
139
|
+
message: Json;
|
|
140
|
+
promptbookEngineVersion?: string | null;
|
|
141
|
+
url?: string | null;
|
|
142
|
+
ip?: string | null;
|
|
143
|
+
userAgent?: string | null;
|
|
144
|
+
language?: string | null;
|
|
145
|
+
platform?: string | null;
|
|
146
|
+
};
|
|
147
|
+
Update: {
|
|
148
|
+
id?: number;
|
|
149
|
+
createdAt?: string;
|
|
150
|
+
messageHash?: string;
|
|
151
|
+
previousMessageHash?: string | null;
|
|
152
|
+
agentName?: string;
|
|
153
|
+
agentHash?: string;
|
|
154
|
+
message?: Json;
|
|
155
|
+
promptbookEngineVersion?: string | null;
|
|
156
|
+
url?: string | null;
|
|
157
|
+
ip?: string | null;
|
|
158
|
+
userAgent?: string | null;
|
|
159
|
+
language?: string | null;
|
|
160
|
+
platform?: string | null;
|
|
161
|
+
};
|
|
162
|
+
Relationships: [];
|
|
163
|
+
};
|
|
164
|
+
ChatFeedback: {
|
|
165
|
+
Row: {
|
|
166
|
+
id: number;
|
|
167
|
+
createdAt: string;
|
|
168
|
+
agentName: string;
|
|
169
|
+
agentHash: string;
|
|
170
|
+
rating: string | null;
|
|
171
|
+
textRating: string | null;
|
|
172
|
+
chatThread: string | null;
|
|
173
|
+
userNote: string | null;
|
|
174
|
+
expectedAnswer: string | null;
|
|
175
|
+
promptbookEngineVersion: string | null;
|
|
176
|
+
url: string | null;
|
|
177
|
+
ip: string | null;
|
|
178
|
+
userAgent: string | null;
|
|
179
|
+
language: string | null;
|
|
180
|
+
platform: string | null;
|
|
181
|
+
};
|
|
182
|
+
Insert: {
|
|
183
|
+
id?: number;
|
|
184
|
+
createdAt: string;
|
|
185
|
+
agentName: string;
|
|
186
|
+
agentHash: string;
|
|
187
|
+
rating?: string | null;
|
|
188
|
+
textRating?: string | null;
|
|
189
|
+
chatThread?: string | null;
|
|
190
|
+
userNote?: string | null;
|
|
191
|
+
expectedAnswer?: string | null;
|
|
192
|
+
promptbookEngineVersion?: string | null;
|
|
193
|
+
url?: string | null;
|
|
194
|
+
ip?: string | null;
|
|
195
|
+
userAgent?: string | null;
|
|
196
|
+
language?: string | null;
|
|
197
|
+
platform?: string | null;
|
|
198
|
+
};
|
|
199
|
+
Update: {
|
|
200
|
+
id?: number;
|
|
201
|
+
createdAt?: string;
|
|
202
|
+
agentName?: string;
|
|
203
|
+
agentHash?: string;
|
|
204
|
+
rating?: string | null;
|
|
205
|
+
textRating?: string | null;
|
|
206
|
+
chatThread?: string | null;
|
|
207
|
+
userNote?: string | null;
|
|
208
|
+
expectedAnswer?: string | null;
|
|
209
|
+
promptbookEngineVersion?: string | null;
|
|
210
|
+
url?: string | null;
|
|
211
|
+
ip?: string | null;
|
|
212
|
+
userAgent?: string | null;
|
|
213
|
+
language?: string | null;
|
|
214
|
+
platform?: string | null;
|
|
215
|
+
};
|
|
216
|
+
Relationships: [];
|
|
217
|
+
};
|
|
218
|
+
User: {
|
|
219
|
+
Row: {
|
|
220
|
+
id: number;
|
|
221
|
+
createdAt: string;
|
|
222
|
+
updatedAt: string;
|
|
223
|
+
username: string;
|
|
224
|
+
passwordHash: string;
|
|
225
|
+
isAdmin: boolean;
|
|
226
|
+
};
|
|
227
|
+
Insert: {
|
|
228
|
+
id?: number;
|
|
229
|
+
createdAt?: string;
|
|
230
|
+
updatedAt?: string;
|
|
231
|
+
username: string;
|
|
232
|
+
passwordHash: string;
|
|
233
|
+
isAdmin?: boolean;
|
|
234
|
+
};
|
|
235
|
+
Update: {
|
|
236
|
+
id?: number;
|
|
237
|
+
createdAt?: string;
|
|
238
|
+
updatedAt?: string;
|
|
239
|
+
username?: string;
|
|
240
|
+
passwordHash?: string;
|
|
241
|
+
isAdmin?: boolean;
|
|
242
|
+
};
|
|
243
|
+
Relationships: [];
|
|
244
|
+
};
|
|
245
|
+
};
|
|
246
|
+
Views: Record<string, never>;
|
|
247
|
+
Functions: Record<string, never>;
|
|
248
|
+
Enums: Record<string, never>;
|
|
249
|
+
CompositeTypes: Record<string, never>;
|
|
250
|
+
};
|
|
251
|
+
};
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { TODO_any } from '@promptbook-local/types';
|
|
2
|
+
import { createClient } from '@supabase/supabase-js';
|
|
3
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
4
|
+
import { SERVERS, SUPABASE_TABLE_PREFIX } from '../config';
|
|
5
|
+
import { isIpAllowed } from './utils/isIpAllowed';
|
|
6
|
+
|
|
7
|
+
// Note: Re-implementing normalizeTo_PascalCase to avoid importing from @promptbook-local/utils which might have Node.js dependencies
|
|
8
|
+
function normalizeTo_PascalCase(text: string): string {
|
|
9
|
+
return text
|
|
10
|
+
.replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => {
|
|
11
|
+
return word.toUpperCase();
|
|
12
|
+
})
|
|
13
|
+
.replace(/\s+/g, '');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function middleware(req: NextRequest) {
|
|
17
|
+
// 1. Get client IP
|
|
18
|
+
let ip = (req as TODO_any).ip;
|
|
19
|
+
const xForwardedFor = req.headers.get('x-forwarded-for');
|
|
20
|
+
if (!ip && xForwardedFor) {
|
|
21
|
+
ip = xForwardedFor.split(',')[0].trim();
|
|
22
|
+
}
|
|
23
|
+
// Fallback for local development if needed, though req.ip is usually ::1 or 127.0.0.1
|
|
24
|
+
ip = ip || '127.0.0.1';
|
|
25
|
+
|
|
26
|
+
// 2. Determine allowed IPs
|
|
27
|
+
// Priority: Metadata > Environment Variable
|
|
28
|
+
|
|
29
|
+
const allowedIpsEnv = process.env.RESTRICT_IP;
|
|
30
|
+
let allowedIpsMetadata: string | null = null;
|
|
31
|
+
|
|
32
|
+
// To fetch metadata, we need to know the table name, which depends on the host
|
|
33
|
+
const host = req.headers.get('host');
|
|
34
|
+
|
|
35
|
+
if (host) {
|
|
36
|
+
let tablePrefix = SUPABASE_TABLE_PREFIX;
|
|
37
|
+
|
|
38
|
+
if (SERVERS && SERVERS.length > 0) {
|
|
39
|
+
// Logic mirrored from src/tools/$provideServer.ts
|
|
40
|
+
if (SERVERS.some((server) => server === host)) {
|
|
41
|
+
let serverName = host;
|
|
42
|
+
serverName = serverName.replace(/\.ptbk\.io$/, '');
|
|
43
|
+
serverName = normalizeTo_PascalCase(serverName);
|
|
44
|
+
tablePrefix = `server_${serverName}_`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
|
49
|
+
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
|
50
|
+
|
|
51
|
+
if (supabaseUrl && supabaseKey) {
|
|
52
|
+
try {
|
|
53
|
+
const supabase = createClient(supabaseUrl, supabaseKey, {
|
|
54
|
+
auth: {
|
|
55
|
+
persistSession: false,
|
|
56
|
+
autoRefreshToken: false,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const { data } = await supabase
|
|
61
|
+
.from(`${tablePrefix}Metadata`)
|
|
62
|
+
.select('value')
|
|
63
|
+
.eq('key', 'RESTRICT_IP')
|
|
64
|
+
.single();
|
|
65
|
+
|
|
66
|
+
if (data && data.value) {
|
|
67
|
+
allowedIpsMetadata = data.value;
|
|
68
|
+
}
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error('Error fetching metadata in middleware:', error);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const allowedIps = allowedIpsMetadata !== null && allowedIpsMetadata !== undefined ? allowedIpsMetadata : allowedIpsEnv;
|
|
76
|
+
|
|
77
|
+
if (isIpAllowed(ip, allowedIps)) {
|
|
78
|
+
// 3. Custom Domain Routing
|
|
79
|
+
// If the host is not one of the configured SERVERS, try to find an agent with a matching META LINK
|
|
80
|
+
|
|
81
|
+
if (host && SERVERS && !SERVERS.some((server) => server === host)) {
|
|
82
|
+
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
|
83
|
+
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
|
84
|
+
|
|
85
|
+
if (supabaseUrl && supabaseKey) {
|
|
86
|
+
const supabase = createClient(supabaseUrl, supabaseKey, {
|
|
87
|
+
auth: {
|
|
88
|
+
persistSession: false,
|
|
89
|
+
autoRefreshToken: false,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Determine prefixes to check
|
|
94
|
+
// We check all configured servers because the custom domain could point to any of them
|
|
95
|
+
// (or if they share the database, we need to check the relevant tables)
|
|
96
|
+
const serversToCheck = SERVERS;
|
|
97
|
+
|
|
98
|
+
// TODO: [🧠] If there are many servers, this loop might be slow. Optimize if needed.
|
|
99
|
+
for (const serverHost of serversToCheck) {
|
|
100
|
+
let serverName = serverHost;
|
|
101
|
+
serverName = serverName.replace(/\.ptbk\.io$/, '');
|
|
102
|
+
serverName = normalizeTo_PascalCase(serverName);
|
|
103
|
+
const prefix = `server_${serverName}_`;
|
|
104
|
+
|
|
105
|
+
// Search for agent with matching META LINK
|
|
106
|
+
// agentProfile->links is an array of strings
|
|
107
|
+
// We check if it contains the host, or https://host, or http://host
|
|
108
|
+
|
|
109
|
+
const searchLinks = [host, `https://${host}`, `http://${host}`];
|
|
110
|
+
|
|
111
|
+
// Construct OR filter: agentProfile.cs.{"links":["link1"]},agentProfile.cs.{"links":["link2"]},...
|
|
112
|
+
const orFilter = searchLinks.map(link => `agentProfile.cs.{"links":["${link}"]}`).join(',');
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const { data } = await supabase
|
|
116
|
+
.from(`${prefix}Agent`)
|
|
117
|
+
.select('agentName')
|
|
118
|
+
.or(orFilter)
|
|
119
|
+
.limit(1)
|
|
120
|
+
.single();
|
|
121
|
+
|
|
122
|
+
if (data && data.agentName) {
|
|
123
|
+
// Found the agent!
|
|
124
|
+
const url = req.nextUrl.clone();
|
|
125
|
+
url.pathname = `/${data.agentName}`;
|
|
126
|
+
|
|
127
|
+
// Pass the server context to the app via header
|
|
128
|
+
const requestHeaders = new Headers(req.headers);
|
|
129
|
+
requestHeaders.set('x-promptbook-server', serverHost);
|
|
130
|
+
|
|
131
|
+
return NextResponse.rewrite(url, {
|
|
132
|
+
request: {
|
|
133
|
+
headers: requestHeaders,
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
} catch (error) {
|
|
138
|
+
// Ignore error (e.g. table not found, or agent not found) and continue to next server
|
|
139
|
+
// console.error(`Error checking server ${serverHost} for custom domain ${host}:`, error);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return NextResponse.next();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return new NextResponse('Forbidden', { status: 403 });
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export const config = {
|
|
152
|
+
matcher: [
|
|
153
|
+
/*
|
|
154
|
+
* Match all request paths except for the ones starting with:
|
|
155
|
+
* - _next/static (static files)
|
|
156
|
+
* - _next/image (image optimization files)
|
|
157
|
+
* - favicon.ico (favicon file)
|
|
158
|
+
* - public folder
|
|
159
|
+
*/
|
|
160
|
+
'/((?!_next/static|_next/image|favicon.ico|logo-|fonts/).*)',
|
|
161
|
+
],
|
|
162
|
+
};
|
|
@@ -2,32 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
import { AgentCollectionInSupabase } from '@promptbook-local/core';
|
|
4
4
|
import { AgentCollection } from '@promptbook-local/types';
|
|
5
|
-
import {
|
|
5
|
+
import { just } from '../../../../src/utils/organization/just';
|
|
6
|
+
import { $provideSupabaseForServer } from '../database/$provideSupabaseForServer';
|
|
7
|
+
import { $provideServer } from './$provideServer';
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Cache of provided agent collection
|
|
9
|
-
*
|
|
11
|
+
*
|
|
10
12
|
* @private internal cache for `$provideAgentCollectionForServer`
|
|
11
13
|
*/
|
|
12
14
|
let agentCollection: null | AgentCollection = null;
|
|
13
15
|
|
|
14
16
|
/**
|
|
15
|
-
*
|
|
17
|
+
* [🐱🚀]
|
|
16
18
|
*/
|
|
17
19
|
export async function $provideAgentCollectionForServer(): Promise<AgentCollection> {
|
|
18
20
|
// <- Note: This function is potentially async
|
|
19
21
|
|
|
20
|
-
// TODO:
|
|
22
|
+
// TODO: [🐱🚀] [🌕] DRY
|
|
21
23
|
|
|
22
|
-
const isVerbose = true; // <- TODO:
|
|
24
|
+
const isVerbose = true; // <- TODO: [🐱🚀] Pass
|
|
23
25
|
|
|
24
|
-
if (agentCollection !== null) {
|
|
25
|
-
console.log('
|
|
26
|
+
if (agentCollection !== null && just(false /* <- TODO: [🐱🚀] Fix caching */)) {
|
|
27
|
+
console.log('[🐱🚀] Returning cached agent collection');
|
|
26
28
|
return agentCollection;
|
|
27
|
-
// TODO:
|
|
29
|
+
// TODO: [🐱🚀] Be aware of options changes
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
console.log('
|
|
32
|
+
console.log('[🐱🚀] Creating NEW agent collection');
|
|
31
33
|
|
|
32
34
|
/*
|
|
33
35
|
// TODO: [🧟♂️][◽] DRY:
|
|
@@ -40,10 +42,12 @@ export async function $provideAgentCollectionForServer(): Promise<AgentCollectio
|
|
|
40
42
|
});
|
|
41
43
|
*/
|
|
42
44
|
|
|
43
|
-
const supabase =
|
|
45
|
+
const supabase = $provideSupabaseForServer();
|
|
46
|
+
const { tablePrefix } = await $provideServer();
|
|
44
47
|
|
|
45
48
|
agentCollection = new AgentCollectionInSupabase(supabase, {
|
|
46
49
|
isVerbose,
|
|
50
|
+
tablePrefix,
|
|
47
51
|
});
|
|
48
52
|
|
|
49
53
|
return agentCollection;
|
|
@@ -43,11 +43,11 @@ $sideEffect(
|
|
|
43
43
|
_MarkitdownScraperMetadataRegistration,
|
|
44
44
|
_PdfScraperMetadataRegistration,
|
|
45
45
|
_WebsiteScraperMetadataRegistration,
|
|
46
|
-
// <- TODO:
|
|
46
|
+
// <- TODO: [🐱🚀] Export all registrations from one variabile in `@promptbook/core`
|
|
47
47
|
);
|
|
48
48
|
$sideEffect(/* [㊗] */ _OpenAiRegistration);
|
|
49
49
|
$sideEffect(/* [㊗] */ _GoogleRegistration);
|
|
50
|
-
// <- TODO:
|
|
50
|
+
// <- TODO: [🐱🚀] Allow to dynamically install required metadata
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* Cache of provided execution tools
|
|
@@ -56,8 +56,6 @@ $sideEffect(/* [㊗] */ _GoogleRegistration);
|
|
|
56
56
|
*/
|
|
57
57
|
let executionTools: null | ExecutionTools = null;
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
59
|
/*
|
|
62
60
|
TODO: [▶️]
|
|
63
61
|
type ProvideExecutionToolsForServerOptions = {
|
|
@@ -66,25 +64,25 @@ type ProvideExecutionToolsForServerOptions = {
|
|
|
66
64
|
*/
|
|
67
65
|
|
|
68
66
|
/**
|
|
69
|
-
*
|
|
67
|
+
* [🐱🚀]
|
|
70
68
|
*/
|
|
71
69
|
export async function $provideExecutionToolsForServer(): Promise<ExecutionTools> {
|
|
72
|
-
// TODO:
|
|
70
|
+
// TODO: [🐱🚀] [🌕] DRY
|
|
73
71
|
|
|
74
|
-
// const path = '../../agents'; // <- TODO:
|
|
75
|
-
const isVerbose = true; // <- TODO:
|
|
76
|
-
const isCacheReloaded = false; // <- TODO:
|
|
72
|
+
// const path = '../../agents'; // <- TODO: [🐱🚀] Pass
|
|
73
|
+
const isVerbose = true; // <- TODO: [🐱🚀] Pass
|
|
74
|
+
const isCacheReloaded = false; // <- TODO: [🐱🚀] Pass
|
|
77
75
|
const cliOptions = {
|
|
78
76
|
provider: 'BRING_YOUR_OWN_KEYS',
|
|
79
|
-
} as TODO_any; // <- TODO:
|
|
77
|
+
} as TODO_any; // <- TODO: [🐱🚀] Pass
|
|
80
78
|
|
|
81
79
|
if (executionTools !== null) {
|
|
82
|
-
console.log('
|
|
80
|
+
console.log('[🐱🚀] Returning cached execution tools');
|
|
83
81
|
return executionTools;
|
|
84
|
-
// TODO:
|
|
82
|
+
// TODO: [🐱🚀] Be aware of options changes
|
|
85
83
|
}
|
|
86
84
|
|
|
87
|
-
console.log('
|
|
85
|
+
console.log('[🐱🚀] Creating NEW execution tools');
|
|
88
86
|
|
|
89
87
|
// TODO: DRY [◽]
|
|
90
88
|
const prepareAndScrapeOptions = {
|
|
@@ -10,23 +10,23 @@ import { OpenAiAssistantExecutionTools } from '@promptbook-local/openai';
|
|
|
10
10
|
let executionTools: null | OpenAiAssistantExecutionTools = null;
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* [🐱🚀]
|
|
14
14
|
*/
|
|
15
15
|
export async function $provideOpenAiAssistantExecutionToolsForServer(): Promise<OpenAiAssistantExecutionTools> {
|
|
16
|
-
// TODO:
|
|
17
|
-
const isVerbose = true; // <- TODO:
|
|
16
|
+
// TODO: [🐱🚀] [🌕] DRY
|
|
17
|
+
const isVerbose = true; // <- TODO: [🐱🚀] Pass
|
|
18
18
|
|
|
19
19
|
if (executionTools !== null) {
|
|
20
|
-
console.log('
|
|
20
|
+
console.log('[🐱🚀] Returning cached OpenAiAssistantExecutionTools');
|
|
21
21
|
return executionTools;
|
|
22
|
-
// TODO:
|
|
22
|
+
// TODO: [🐱🚀] Be aware of options changes
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
console.log('
|
|
25
|
+
console.log('[🐱🚀] Creating NEW OpenAiAssistantExecutionTools');
|
|
26
26
|
|
|
27
27
|
executionTools = new OpenAiAssistantExecutionTools({
|
|
28
28
|
apiKey: process.env.OPENAI_API_KEY,
|
|
29
|
-
assistantId: '
|
|
29
|
+
assistantId: 'abstract_assistant', // <- TODO: [🐱🚀] In `OpenAiAssistantExecutionTools` Allow to create abstract assistants with `isCreatingNewAssistantsAllowed`
|
|
30
30
|
isCreatingNewAssistantsAllowed: true,
|
|
31
31
|
isVerbose,
|
|
32
32
|
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { NEXT_PUBLIC_URL, SERVERS, SUPABASE_TABLE_PREFIX } from '@/config';
|
|
2
|
+
import { normalizeTo_PascalCase } from '@promptbook-local/utils';
|
|
3
|
+
import { headers } from 'next/headers';
|
|
4
|
+
|
|
5
|
+
export async function $provideServer() {
|
|
6
|
+
if (!SERVERS) {
|
|
7
|
+
return {
|
|
8
|
+
publicUrl: NEXT_PUBLIC_URL || new URL(`https://${(await headers()).get('host') || 'localhost:4440'}`),
|
|
9
|
+
tablePrefix: SUPABASE_TABLE_PREFIX,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const headersList = await headers();
|
|
14
|
+
let host = headersList.get('host');
|
|
15
|
+
const xPromptbookServer = headersList.get('x-promptbook-server');
|
|
16
|
+
|
|
17
|
+
if (host === null) {
|
|
18
|
+
throw new Error('Host header is missing');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// If host is not in known servers, check if we have a context header from middleware
|
|
22
|
+
if (!SERVERS.some((server) => server === host)) {
|
|
23
|
+
if (xPromptbookServer && SERVERS.some((server) => server === xPromptbookServer)) {
|
|
24
|
+
host = xPromptbookServer;
|
|
25
|
+
} else {
|
|
26
|
+
throw new Error(`Server with host "${host}" is not configured in SERVERS`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let serverName = host;
|
|
31
|
+
|
|
32
|
+
serverName = serverName.replace(/\.ptbk\.io$/, '');
|
|
33
|
+
serverName = normalizeTo_PascalCase(serverName);
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
publicUrl: new URL(`https://${host}`),
|
|
37
|
+
tablePrefix: `server_${serverName}_`,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { randomBytes, scrypt, timingSafeEqual } from 'crypto';
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
|
|
4
|
+
const scryptAsync = promisify(scrypt);
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Hashes a password using scrypt
|
|
8
|
+
*
|
|
9
|
+
* @param password The plain text password
|
|
10
|
+
* @returns The salt and hash formatted as "salt:hash"
|
|
11
|
+
*/
|
|
12
|
+
export async function hashPassword(password: string): Promise<string> {
|
|
13
|
+
const salt = randomBytes(16).toString('hex');
|
|
14
|
+
const derivedKey = (await scryptAsync(password, salt, 64)) as Buffer;
|
|
15
|
+
return `${salt}:${derivedKey.toString('hex')}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Verifies a password against a stored hash
|
|
20
|
+
*
|
|
21
|
+
* @param password The plain text password
|
|
22
|
+
* @param storedHash The stored hash in format "salt:hash"
|
|
23
|
+
* @returns True if the password matches
|
|
24
|
+
*/
|
|
25
|
+
export async function verifyPassword(password: string, storedHash: string): Promise<boolean> {
|
|
26
|
+
const [salt, key] = storedHash.split(':');
|
|
27
|
+
if (!salt || !key) return false;
|
|
28
|
+
|
|
29
|
+
const derivedKey = (await scryptAsync(password, salt, 64)) as Buffer;
|
|
30
|
+
const keyBuffer = Buffer.from(key, 'hex');
|
|
31
|
+
|
|
32
|
+
return timingSafeEqual(derivedKey, keyBuffer);
|
|
33
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { titleToName } from '../../../../../../src/utils/normalization/titleToName';
|
|
2
1
|
import hexEncoder from 'crypto-js/enc-hex';
|
|
3
2
|
import sha256 from 'crypto-js/sha256';
|
|
4
3
|
import type { string_uri } from '../../../../../../src/types/typeAliases';
|
|
4
|
+
import { titleToName } from '../../../../../../src/utils/normalization/titleToName';
|
|
5
5
|
import { nameToSubfolderPath } from './nameToSubfolderPath';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -9,6 +9,7 @@ import { nameToSubfolderPath } from './nameToSubfolderPath';
|
|
|
9
9
|
*/
|
|
10
10
|
export function getUserFileCdnKey(file: Buffer, originalFilename: string): string_uri {
|
|
11
11
|
const hash = sha256(hexEncoder.parse(file.toString('hex'))).toString(/* hex */);
|
|
12
|
+
// <- TODO: [🥬] Encapsulate sha256 to some private utility function
|
|
12
13
|
|
|
13
14
|
const originalFilenameParts = originalFilename.split('.');
|
|
14
15
|
const extension = originalFilenameParts.pop();
|