@promptbook/cli 0.112.0-96 → 0.112.0-98
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/playwright.config.ts +2 -1
- package/apps/agents-server/src/app/admin/cli-access/CliAccessClient.tsx +99 -0
- package/apps/agents-server/src/app/admin/cli-access/page.tsx +14 -0
- package/apps/agents-server/src/app/admin/code-runners/CodeRunnersClient.tsx +124 -34
- package/apps/agents-server/src/app/admin/servers/CreateServerDialog.tsx +46 -505
- package/apps/agents-server/src/app/admin/servers/ServersClient.tsx +23 -11
- package/apps/agents-server/src/app/admin/servers/ServersRegistryApi.ts +5 -0
- package/apps/agents-server/src/app/admin/servers/ServersRegistryDnsTypes.ts +87 -0
- package/apps/agents-server/src/app/admin/servers/ServersRegistryTable.tsx +258 -128
- package/apps/agents-server/src/app/admin/servers/useCreateServerWizard.ts +46 -334
- package/apps/agents-server/src/app/admin/servers/useServersRegistryState.ts +26 -2
- package/apps/agents-server/src/app/admin/update/UpdateClient.tsx +435 -0
- package/apps/agents-server/src/app/admin/update/page.tsx +14 -0
- package/apps/agents-server/src/app/agents/[agentName]/chat/CanonicalAgentChatSurface.tsx +24 -0
- package/apps/agents-server/src/app/api/admin/cli-access/route.ts +137 -0
- package/apps/agents-server/src/app/api/admin/code-runners/authentication/route.ts +140 -0
- package/apps/agents-server/src/app/api/admin/code-runners/route.ts +4 -35
- package/apps/agents-server/src/app/api/admin/servers/[serverId]/route.ts +7 -2
- package/apps/agents-server/src/app/api/admin/servers/route.ts +95 -4
- package/apps/agents-server/src/app/api/admin/update/route.ts +52 -0
- package/apps/agents-server/src/app/api/auth/login/route.ts +8 -0
- package/apps/agents-server/src/app/api/auth/logout/route.ts +10 -2
- package/apps/agents-server/src/app/api/chat/export/pdf/route.ts +63 -0
- package/apps/agents-server/src/app/page.tsx +10 -0
- package/apps/agents-server/src/components/AdminTerminal/AdminTerminalCard.tsx +279 -0
- package/apps/agents-server/src/components/AdminTerminal/useAdminTerminalSession.ts +336 -0
- package/apps/agents-server/src/components/Header/buildHeaderSystemMenuItems.ts +10 -0
- package/apps/agents-server/src/languages/ServerTranslationKeys.ts +2 -0
- package/apps/agents-server/src/languages/translations/czech.yaml +2 -0
- package/apps/agents-server/src/languages/translations/english.yaml +2 -0
- package/apps/agents-server/src/middleware.ts +32 -0
- package/apps/agents-server/src/tools/BrowserConnectionProvider.ts +1 -1
- package/apps/agents-server/src/utils/chatExport/downloadChatPdfFromServer.ts +59 -0
- package/apps/agents-server/src/utils/chatExport/renderHtmlToPdfOnServer.ts +37 -0
- package/apps/agents-server/src/utils/codeRunnerAuthentication.ts +234 -0
- package/apps/agents-server/src/utils/codeRunnerConfiguration.ts +67 -0
- package/apps/agents-server/src/utils/createInteractiveTerminalEventStream.ts +84 -0
- package/apps/agents-server/src/utils/interactiveTerminalSession.ts +442 -0
- package/apps/agents-server/src/utils/serverCliAccess.ts +221 -0
- package/apps/agents-server/src/utils/serverManagement/standaloneVpsServerMetadata.ts +145 -0
- package/apps/agents-server/src/utils/serverRegistry.ts +3 -2
- package/apps/agents-server/src/utils/session.ts +37 -9
- package/apps/agents-server/src/utils/shibboleth/createShibbolethAuthenticationLogPayload.ts +173 -0
- package/apps/agents-server/src/utils/shibboleth/writeShibbolethAuthenticationLog.ts +27 -0
- package/apps/agents-server/src/utils/standaloneVpsDnsDiagnostics.ts +258 -0
- package/apps/agents-server/src/utils/standaloneVpsRawIpBootstrap.ts +87 -0
- package/apps/agents-server/src/utils/vpsConfiguration.ts +87 -13
- package/apps/agents-server/src/utils/vpsSelfUpdate.ts +664 -0
- package/esm/apps/agents-server/src/utils/serverRegistry.d.ts +1 -1
- package/esm/index.es.js +7 -5
- package/esm/index.es.js.map +1 -1
- package/esm/src/book-components/Chat/Chat/ChatActionsBar.d.ts +2 -0
- package/esm/src/book-components/Chat/Chat/ChatProps.d.ts +6 -0
- package/esm/src/book-components/Chat/save/_common/ChatSaveFormatHandler.d.ts +35 -0
- package/esm/src/book-components/Chat/save/_common/createChatExportFilename.d.ts +11 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/book-components/Chat/Chat/Chat.tsx +2 -0
- package/src/book-components/Chat/Chat/ChatActionsBar.tsx +17 -9
- package/src/book-components/Chat/Chat/ChatProps.tsx +7 -0
- package/src/book-components/Chat/save/_common/ChatSaveFormatHandler.ts +40 -0
- package/src/book-components/Chat/save/_common/createChatExportFilename.ts +20 -0
- package/src/book-components/Chat/utils/renderMarkdown.ts +1 -3
- package/src/other/templates/getTemplatesPipelineCollection.ts +718 -790
- package/src/scrapers/document/DocumentScraper.ts +1 -1
- package/src/scrapers/document-legacy/LegacyDocumentScraper.ts +1 -1
- package/src/version.ts +2 -2
- package/src/versions.txt +2 -0
- package/umd/apps/agents-server/src/utils/serverRegistry.d.ts +1 -1
- package/umd/index.umd.js +7 -5
- package/umd/index.umd.js.map +1 -1
- package/umd/src/book-components/Chat/Chat/ChatActionsBar.d.ts +2 -0
- package/umd/src/book-components/Chat/Chat/ChatProps.d.ts +6 -0
- package/umd/src/book-components/Chat/save/_common/ChatSaveFormatHandler.d.ts +35 -0
- package/umd/src/book-components/Chat/save/_common/createChatExportFilename.d.ts +11 -0
- package/umd/src/version.d.ts +1 -1
- package/src/conversion/validation/_importPipeline.ts +0 -88
- /package/esm/src/conversion/validation/{_importPipeline.d.ts → _importPipeline.test.d.ts} +0 -0
- /package/umd/src/conversion/validation/{_importPipeline.d.ts → _importPipeline.test.d.ts} +0 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { isUserGlobalAdmin } from '@/src/utils/isUserGlobalAdmin';
|
|
3
|
+
import { createInteractiveTerminalEventStream } from '@/src/utils/createInteractiveTerminalEventStream';
|
|
4
|
+
import {
|
|
5
|
+
getCodeRunnerAuthenticationSession,
|
|
6
|
+
getLatestCodeRunnerAuthenticationSession,
|
|
7
|
+
startCodeRunnerAuthenticationSession,
|
|
8
|
+
stopCodeRunnerAuthenticationSession,
|
|
9
|
+
subscribeToCodeRunnerAuthenticationSession,
|
|
10
|
+
writeCodeRunnerAuthenticationSessionInput,
|
|
11
|
+
} from '@/src/utils/codeRunnerAuthentication';
|
|
12
|
+
import { readConfiguredCodeRunner } from '@/src/utils/codeRunnerConfiguration';
|
|
13
|
+
|
|
14
|
+
export const runtime = 'nodejs';
|
|
15
|
+
export const dynamic = 'force-dynamic';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Loads the latest authentication session for the saved runner or streams a specific session.
|
|
19
|
+
*/
|
|
20
|
+
export async function GET(request: Request) {
|
|
21
|
+
if (!(await isUserGlobalAdmin())) {
|
|
22
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const { searchParams } = new URL(request.url);
|
|
27
|
+
const sessionId = searchParams.get('sessionId')?.trim() || '';
|
|
28
|
+
const isStreamRequested = searchParams.get('stream') === '1';
|
|
29
|
+
|
|
30
|
+
if (isStreamRequested) {
|
|
31
|
+
if (!sessionId) {
|
|
32
|
+
return NextResponse.json({ error: 'Authentication session id is required.' }, { status: 400 });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const session = getCodeRunnerAuthenticationSession(sessionId);
|
|
36
|
+
if (!session) {
|
|
37
|
+
return NextResponse.json({ error: 'Authentication session was not found.' }, { status: 404 });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return createInteractiveTerminalEventStream(
|
|
41
|
+
request,
|
|
42
|
+
sessionId,
|
|
43
|
+
session,
|
|
44
|
+
subscribeToCodeRunnerAuthenticationSession,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const { agent } = await readConfiguredCodeRunner();
|
|
49
|
+
return NextResponse.json({
|
|
50
|
+
session: getLatestCodeRunnerAuthenticationSession(agent),
|
|
51
|
+
});
|
|
52
|
+
} catch (error) {
|
|
53
|
+
return NextResponse.json(
|
|
54
|
+
{ error: error instanceof Error ? error.message : 'Failed to load the authentication session.' },
|
|
55
|
+
{ status: 500 },
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Starts a new browser-driven authentication terminal for the saved runner.
|
|
62
|
+
*/
|
|
63
|
+
export async function POST() {
|
|
64
|
+
if (!(await isUserGlobalAdmin())) {
|
|
65
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const { agent } = await readConfiguredCodeRunner();
|
|
70
|
+
return NextResponse.json({
|
|
71
|
+
session: await startCodeRunnerAuthenticationSession(agent),
|
|
72
|
+
});
|
|
73
|
+
} catch (error) {
|
|
74
|
+
return NextResponse.json(
|
|
75
|
+
{ error: error instanceof Error ? error.message : 'Failed to start the authentication session.' },
|
|
76
|
+
{ status: 500 },
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Sends terminal input to a running authentication session.
|
|
83
|
+
*/
|
|
84
|
+
export async function PATCH(request: Request) {
|
|
85
|
+
if (!(await isUserGlobalAdmin())) {
|
|
86
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
const body = (await request.json().catch(() => null)) as
|
|
91
|
+
| {
|
|
92
|
+
readonly sessionId?: string;
|
|
93
|
+
readonly input?: string;
|
|
94
|
+
}
|
|
95
|
+
| null;
|
|
96
|
+
|
|
97
|
+
if (!body?.sessionId || typeof body.input !== 'string') {
|
|
98
|
+
return NextResponse.json({ error: 'Authentication session input is required.' }, { status: 400 });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return NextResponse.json({
|
|
102
|
+
session: writeCodeRunnerAuthenticationSessionInput(body.sessionId, body.input),
|
|
103
|
+
});
|
|
104
|
+
} catch (error) {
|
|
105
|
+
return NextResponse.json(
|
|
106
|
+
{ error: error instanceof Error ? error.message : 'Failed to send authentication input.' },
|
|
107
|
+
{ status: 500 },
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Stops one authentication terminal from the admin UI.
|
|
114
|
+
*/
|
|
115
|
+
export async function DELETE(request: Request) {
|
|
116
|
+
if (!(await isUserGlobalAdmin())) {
|
|
117
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
const body = (await request.json().catch(() => null)) as
|
|
122
|
+
| {
|
|
123
|
+
readonly sessionId?: string;
|
|
124
|
+
}
|
|
125
|
+
| null;
|
|
126
|
+
|
|
127
|
+
if (!body?.sessionId) {
|
|
128
|
+
return NextResponse.json({ error: 'Authentication session id is required.' }, { status: 400 });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return NextResponse.json({
|
|
132
|
+
session: stopCodeRunnerAuthenticationSession(body.sessionId),
|
|
133
|
+
});
|
|
134
|
+
} catch (error) {
|
|
135
|
+
return NextResponse.json(
|
|
136
|
+
{ error: error instanceof Error ? error.message : 'Failed to stop the authentication session.' },
|
|
137
|
+
{ status: 500 },
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import { execFile } from 'child_process';
|
|
2
|
-
import { promisify } from 'util';
|
|
3
1
|
import { NextResponse } from 'next/server';
|
|
4
2
|
import { isUserGlobalAdmin } from '@/src/utils/isUserGlobalAdmin';
|
|
3
|
+
import { readConfiguredCodeRunner, resolveCodeRunnerStatus } from '@/src/utils/codeRunnerConfiguration';
|
|
5
4
|
import {
|
|
6
5
|
applyVpsCodeRunnerConfiguration,
|
|
7
|
-
listVpsEnvironmentVariables,
|
|
8
6
|
updateVpsEnvironmentVariables,
|
|
9
7
|
} from '@/src/utils/vpsConfiguration';
|
|
10
8
|
|
|
11
|
-
const execFileAsync = promisify(execFile);
|
|
12
|
-
|
|
13
9
|
/**
|
|
14
10
|
* Loads configured code-runner settings from the editable VPS environment.
|
|
15
11
|
*/
|
|
@@ -19,16 +15,11 @@ export async function GET() {
|
|
|
19
15
|
}
|
|
20
16
|
|
|
21
17
|
try {
|
|
22
|
-
const
|
|
23
|
-
const environmentByKey = Object.fromEntries(
|
|
24
|
-
snapshot.variables.map((variable) => [variable.key, variable.value]),
|
|
25
|
-
) as Record<string, string>;
|
|
18
|
+
const configuredCodeRunner = await readConfiguredCodeRunner();
|
|
26
19
|
|
|
27
20
|
return NextResponse.json({
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
thinkingLevel: environmentByKey.PTBK_THINKING_LEVEL || process.env.PTBK_THINKING_LEVEL || 'xhigh',
|
|
31
|
-
status: await resolveRunnerStatus(environmentByKey.PTBK_AGENT || process.env.PTBK_AGENT || 'github-copilot'),
|
|
21
|
+
...configuredCodeRunner,
|
|
22
|
+
status: await resolveCodeRunnerStatus(configuredCodeRunner.agent),
|
|
32
23
|
});
|
|
33
24
|
} catch (error) {
|
|
34
25
|
return NextResponse.json(
|
|
@@ -80,25 +71,3 @@ export async function PATCH(request: Request) {
|
|
|
80
71
|
);
|
|
81
72
|
}
|
|
82
73
|
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Resolves a short runner-authentication status for the configured runner.
|
|
86
|
-
*
|
|
87
|
-
* @param agent - Runner id.
|
|
88
|
-
* @returns Human-readable status.
|
|
89
|
-
*/
|
|
90
|
-
async function resolveRunnerStatus(agent: string): Promise<string> {
|
|
91
|
-
if (agent !== 'github-copilot') {
|
|
92
|
-
return 'Status check is currently available for GitHub Copilot CLI only.';
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
try {
|
|
96
|
-
const { stdout, stderr } = await execFileAsync('copilot', ['auth', 'status'], {
|
|
97
|
-
timeout: 10_000,
|
|
98
|
-
maxBuffer: 128 * 1024,
|
|
99
|
-
});
|
|
100
|
-
return [stdout, stderr].filter(Boolean).join('\n').trim() || 'GitHub Copilot CLI returned no status output.';
|
|
101
|
-
} catch (error) {
|
|
102
|
-
return error instanceof Error ? error.message : 'GitHub Copilot CLI status check failed.';
|
|
103
|
-
}
|
|
104
|
-
}
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
updateManagedServer,
|
|
16
16
|
type UpdateServerInput,
|
|
17
17
|
} from '../../../../../utils/serverManagement';
|
|
18
|
+
import { applyStandaloneVpsServerMetadata } from '../../../../../utils/serverManagement/standaloneVpsServerMetadata';
|
|
18
19
|
import {
|
|
19
20
|
applyVpsRuntimeConfiguration,
|
|
20
21
|
listConfiguredVpsDomains,
|
|
@@ -38,6 +39,10 @@ export async function PATCH(request: Request, context: { params: Promise<{ serve
|
|
|
38
39
|
|
|
39
40
|
if (isAgentsServerSqliteMode()) {
|
|
40
41
|
const updatedServer = await updateStandaloneVpsServerDomain(parsedServerId, body.domain);
|
|
42
|
+
await applyStandaloneVpsServerMetadata({
|
|
43
|
+
tablePrefix: updatedServer.tablePrefix,
|
|
44
|
+
name: body.name,
|
|
45
|
+
});
|
|
41
46
|
return NextResponse.json({ server: updatedServer });
|
|
42
47
|
}
|
|
43
48
|
|
|
@@ -126,7 +131,7 @@ async function updateStandaloneVpsServerDomain(serverId: number, rawDomain: stri
|
|
|
126
131
|
const domains = await listConfiguredVpsDomains();
|
|
127
132
|
const nextDomains = domains.map((domain, index) => (index === serverIndex ? normalizedDomain : domain));
|
|
128
133
|
await updateConfiguredVpsDomains(nextDomains);
|
|
129
|
-
await applyVpsRuntimeConfiguration();
|
|
134
|
+
await applyVpsRuntimeConfiguration({ isProcessRestartEnabled: false });
|
|
130
135
|
|
|
131
136
|
const updatedServer = listEnvironmentRegisteredServers().find((server) => server.domain === normalizedDomain);
|
|
132
137
|
if (!updatedServer) {
|
|
@@ -150,5 +155,5 @@ async function deleteStandaloneVpsServerDomain(serverId: number): Promise<void>
|
|
|
150
155
|
|
|
151
156
|
const domains = await listConfiguredVpsDomains();
|
|
152
157
|
await updateConfiguredVpsDomains(domains.filter((_domain, index) => index !== serverIndex));
|
|
153
|
-
await applyVpsRuntimeConfiguration();
|
|
158
|
+
await applyVpsRuntimeConfiguration({ isProcessRestartEnabled: false });
|
|
154
159
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server';
|
|
2
|
+
import { spaceTrim } from 'spacetrim';
|
|
3
|
+
import { DatabaseError } from '../../../../../../../src/errors/DatabaseError';
|
|
2
4
|
import { isAgentsServerSqliteMode } from '../../../../database/agentsServerDatabaseMode';
|
|
3
5
|
import { resolveCurrentServerRegistryContext } from '../../../../utils/currentServerRegistryContext';
|
|
4
6
|
import { isUserAdmin } from '../../../../utils/isUserAdmin';
|
|
5
7
|
import { isUserGlobalAdmin } from '../../../../utils/isUserGlobalAdmin';
|
|
8
|
+
import { buildServerTablePrefix } from '../../../../utils/buildServerTablePrefix';
|
|
6
9
|
import {
|
|
7
10
|
createServerPublicUrl,
|
|
8
11
|
listEnvironmentRegisteredServers,
|
|
@@ -14,6 +17,12 @@ import {
|
|
|
14
17
|
resolveManagedServerErrorStatus,
|
|
15
18
|
type CreateServerInput,
|
|
16
19
|
} from '../../../../utils/serverManagement';
|
|
20
|
+
import { ManagedServerInputNormalizer } from '../../../../utils/serverManagement/ManagedServerInputNormalizer';
|
|
21
|
+
import {
|
|
22
|
+
applyStandaloneVpsServerMetadata,
|
|
23
|
+
resolveStandaloneVpsServerDisplayName,
|
|
24
|
+
} from '../../../../utils/serverManagement/standaloneVpsServerMetadata';
|
|
25
|
+
import { createStandaloneVpsDomainDnsDiagnostic } from '../../../../utils/standaloneVpsDnsDiagnostics';
|
|
17
26
|
import {
|
|
18
27
|
applyVpsRuntimeConfiguration,
|
|
19
28
|
listConfiguredVpsDomains,
|
|
@@ -32,10 +41,15 @@ export async function GET() {
|
|
|
32
41
|
}
|
|
33
42
|
|
|
34
43
|
const context = await resolveCurrentServerRegistryContext();
|
|
44
|
+
const servers = isAgentsServerSqliteMode()
|
|
45
|
+
? await createStandaloneVpsServersResponse(context.registeredServers)
|
|
46
|
+
: context.registeredServers;
|
|
47
|
+
|
|
35
48
|
return NextResponse.json({
|
|
36
|
-
servers
|
|
49
|
+
servers,
|
|
37
50
|
currentServerId: context.currentServer?.id ?? null,
|
|
38
51
|
canEdit: await isUserGlobalAdmin(),
|
|
52
|
+
isStandaloneVps: isAgentsServerSqliteMode(),
|
|
39
53
|
});
|
|
40
54
|
} catch (error) {
|
|
41
55
|
return NextResponse.json(
|
|
@@ -47,6 +61,30 @@ export async function GET() {
|
|
|
47
61
|
}
|
|
48
62
|
}
|
|
49
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Enriches standalone VPS server rows with display metadata and DNS diagnostics.
|
|
66
|
+
*
|
|
67
|
+
* @param servers - Virtual standalone server rows.
|
|
68
|
+
* @returns Browser-safe server rows with DNS setup guidance.
|
|
69
|
+
*/
|
|
70
|
+
async function createStandaloneVpsServersResponse(
|
|
71
|
+
servers: Awaited<ReturnType<typeof resolveCurrentServerRegistryContext>>['registeredServers'],
|
|
72
|
+
) {
|
|
73
|
+
const primaryDomain = servers[0]?.domain ?? null;
|
|
74
|
+
|
|
75
|
+
return Promise.all(
|
|
76
|
+
servers.map(async (server) => ({
|
|
77
|
+
...server,
|
|
78
|
+
name: await resolveStandaloneVpsServerDisplayName(server),
|
|
79
|
+
dnsDiagnostic: await createStandaloneVpsDomainDnsDiagnostic({
|
|
80
|
+
domain: server.domain,
|
|
81
|
+
publicIpAddress: process.env.PTBK_PUBLIC_IP_ADDRESS,
|
|
82
|
+
fallbackCnameTargetDomain: primaryDomain && primaryDomain !== server.domain ? primaryDomain : null,
|
|
83
|
+
}),
|
|
84
|
+
})),
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
50
88
|
/**
|
|
51
89
|
* Creates a new same-instance server.
|
|
52
90
|
*
|
|
@@ -57,17 +95,25 @@ export async function POST(request: Request) {
|
|
|
57
95
|
try {
|
|
58
96
|
assertGlobalAdminAccess(await isUserGlobalAdmin());
|
|
59
97
|
|
|
60
|
-
const body = (await request.json()) as CreateServerInput;
|
|
98
|
+
const body = withEnvironmentAdminUser((await request.json()) as CreateServerInput);
|
|
61
99
|
if (isAgentsServerSqliteMode()) {
|
|
62
100
|
const normalizedDomain = normalizeServerDomain(body.domain);
|
|
63
101
|
if (!normalizedDomain) {
|
|
64
102
|
return NextResponse.json({ error: 'A valid domain is required.' }, { status: 400 });
|
|
65
103
|
}
|
|
104
|
+
const tablePrefix = normalizeStandaloneVpsCreateServerTablePrefix(body);
|
|
66
105
|
|
|
67
106
|
const existingDomains = await listConfiguredVpsDomains();
|
|
68
|
-
await updateConfiguredVpsDomains([...existingDomains, normalizedDomain]);
|
|
69
|
-
await applyVpsRuntimeConfiguration();
|
|
107
|
+
await updateConfiguredVpsDomains([...existingDomains, normalizedDomain], { tablePrefix });
|
|
108
|
+
await applyVpsRuntimeConfiguration({ isProcessRestartEnabled: false });
|
|
70
109
|
const createdServer = listEnvironmentRegisteredServers().find((server) => server.domain === normalizedDomain);
|
|
110
|
+
if (createdServer) {
|
|
111
|
+
await applyStandaloneVpsServerMetadata({
|
|
112
|
+
tablePrefix: createdServer.tablePrefix,
|
|
113
|
+
name: body.name,
|
|
114
|
+
iconUrl: body.iconUrl,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
71
117
|
|
|
72
118
|
return NextResponse.json(
|
|
73
119
|
{
|
|
@@ -107,3 +153,48 @@ export async function POST(request: Request) {
|
|
|
107
153
|
);
|
|
108
154
|
}
|
|
109
155
|
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Uses the installer-managed environment admin when the browser no longer collects admin credentials.
|
|
159
|
+
*
|
|
160
|
+
* @param input - Raw create-server payload.
|
|
161
|
+
* @returns Payload compatible with the existing managed-server bootstrap flow.
|
|
162
|
+
*/
|
|
163
|
+
function withEnvironmentAdminUser(input: CreateServerInput): CreateServerInput {
|
|
164
|
+
const adminPassword = process.env.ADMIN_PASSWORD || input.adminUser?.password || '';
|
|
165
|
+
const adminUsername = input.adminUser?.username?.trim() || 'admin';
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
...input,
|
|
169
|
+
adminUser: {
|
|
170
|
+
username: adminUsername,
|
|
171
|
+
password: adminPassword,
|
|
172
|
+
isAdmin: true,
|
|
173
|
+
},
|
|
174
|
+
additionalUsers: input.additionalUsers || [],
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Validates the generated server table prefix used by standalone VPS setup.
|
|
180
|
+
*
|
|
181
|
+
* @param input - Create-server payload with generated identifier and table prefix.
|
|
182
|
+
* @returns Validated server-level table prefix.
|
|
183
|
+
*/
|
|
184
|
+
function normalizeStandaloneVpsCreateServerTablePrefix(input: CreateServerInput): string {
|
|
185
|
+
const identifier = ManagedServerInputNormalizer.normalizeServerIdentifier(input.identifier);
|
|
186
|
+
const tablePrefix = ManagedServerInputNormalizer.validateServerTablePrefix(input.tablePrefix);
|
|
187
|
+
const expectedTablePrefix = buildServerTablePrefix(identifier);
|
|
188
|
+
|
|
189
|
+
if (tablePrefix !== expectedTablePrefix) {
|
|
190
|
+
throw new DatabaseError(
|
|
191
|
+
spaceTrim(`
|
|
192
|
+
Table prefix \`${tablePrefix}\` does not match generated server identifier \`${identifier}\`.
|
|
193
|
+
|
|
194
|
+
Expected \`${expectedTablePrefix}\`.
|
|
195
|
+
`),
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return tablePrefix;
|
|
200
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { isUserGlobalAdmin } from '@/src/utils/isUserGlobalAdmin';
|
|
3
|
+
import { readVpsSelfUpdateOverview, startVpsSelfUpdate } from '@/src/utils/vpsSelfUpdate';
|
|
4
|
+
|
|
5
|
+
export const runtime = 'nodejs';
|
|
6
|
+
export const dynamic = 'force-dynamic';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Loads the current standalone VPS self-update overview for the super-admin UI.
|
|
10
|
+
*/
|
|
11
|
+
export async function GET() {
|
|
12
|
+
if (!(await isUserGlobalAdmin())) {
|
|
13
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
return NextResponse.json(await readVpsSelfUpdateOverview());
|
|
18
|
+
} catch (error) {
|
|
19
|
+
return NextResponse.json(
|
|
20
|
+
{ error: error instanceof Error ? error.message : 'Failed to load the update overview.' },
|
|
21
|
+
{ status: 500 },
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Starts a detached standalone VPS self-update for the selected environment.
|
|
28
|
+
*/
|
|
29
|
+
export async function POST(request: Request) {
|
|
30
|
+
if (!(await isUserGlobalAdmin())) {
|
|
31
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const body = (await request.json().catch(() => null)) as
|
|
36
|
+
| {
|
|
37
|
+
readonly environment?: string;
|
|
38
|
+
}
|
|
39
|
+
| null;
|
|
40
|
+
|
|
41
|
+
if (!body?.environment || typeof body.environment !== 'string') {
|
|
42
|
+
return NextResponse.json({ error: 'Update environment is required.' }, { status: 400 });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return NextResponse.json(await startVpsSelfUpdate(body.environment), { status: 202 });
|
|
46
|
+
} catch (error) {
|
|
47
|
+
return NextResponse.json(
|
|
48
|
+
{ error: error instanceof Error ? error.message : 'Failed to start the update.' },
|
|
49
|
+
{ status: 500 },
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { authenticateUser } from '../../../../utils/authenticateUser';
|
|
2
2
|
import { setSession } from '../../../../utils/session';
|
|
3
|
+
import { writeShibbolethAuthenticationLog } from '../../../../utils/shibboleth/writeShibbolethAuthenticationLog';
|
|
3
4
|
import { NextResponse } from 'next/server';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -7,6 +8,13 @@ import { NextResponse } from 'next/server';
|
|
|
7
8
|
*/
|
|
8
9
|
export async function POST(request: Request) {
|
|
9
10
|
try {
|
|
11
|
+
writeShibbolethAuthenticationLog(request.headers, {
|
|
12
|
+
event: 'login-route-request',
|
|
13
|
+
pathname: '/api/auth/login',
|
|
14
|
+
method: request.method,
|
|
15
|
+
hasSessionCookie: (request.headers.get('cookie') || '').includes('sessionToken='),
|
|
16
|
+
});
|
|
17
|
+
|
|
10
18
|
const body = await request.json();
|
|
11
19
|
const { username, password } = body;
|
|
12
20
|
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
import { clearSession } from '../../../../utils/session';
|
|
2
1
|
import { NextResponse } from 'next/server';
|
|
2
|
+
import { clearSession } from '../../../../utils/session';
|
|
3
|
+
import { writeShibbolethAuthenticationLog } from '../../../../utils/shibboleth/writeShibbolethAuthenticationLog';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Handles post.
|
|
6
7
|
*/
|
|
7
|
-
export async function POST() {
|
|
8
|
+
export async function POST(request: Request) {
|
|
9
|
+
writeShibbolethAuthenticationLog(request.headers, {
|
|
10
|
+
event: 'logout-route-request',
|
|
11
|
+
pathname: '/api/auth/logout',
|
|
12
|
+
method: request.method,
|
|
13
|
+
hasSessionCookie: (request.headers.get('cookie') || '').includes('sessionToken='),
|
|
14
|
+
});
|
|
15
|
+
|
|
8
16
|
await clearSession();
|
|
9
17
|
return NextResponse.json({ success: true });
|
|
10
18
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { buildChatHtml } from '../../../../../../../../src/book-components/Chat/save/html/htmlSaveFormatDefinition';
|
|
2
|
+
import type { ChatMessage } from '../../../../../../../../src/book-components/Chat/types/ChatMessage';
|
|
3
|
+
import type { ChatParticipant } from '../../../../../../../../src/book-components/Chat/types/ChatParticipant';
|
|
4
|
+
import { createChatExportFilename } from '../../../../../../../../src/book-components/Chat/save/_common/createChatExportFilename';
|
|
5
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
6
|
+
import { renderHtmlToPdfOnServer } from '@/src/utils/chatExport/renderHtmlToPdfOnServer';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* PDF export requires the Node.js runtime because it depends on Playwright.
|
|
10
|
+
*/
|
|
11
|
+
export const runtime = 'nodejs';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Minimal request payload accepted by the chat PDF export endpoint.
|
|
15
|
+
*
|
|
16
|
+
* @private internal type for POST /api/chat/export/pdf
|
|
17
|
+
*/
|
|
18
|
+
type ChatPdfExportRequestBody = {
|
|
19
|
+
readonly title: string;
|
|
20
|
+
readonly messages: ReadonlyArray<ChatMessage>;
|
|
21
|
+
readonly participants: ReadonlyArray<ChatParticipant>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Builds a server-rendered PDF from the standalone HTML chat export.
|
|
26
|
+
*/
|
|
27
|
+
export async function POST(request: NextRequest) {
|
|
28
|
+
let requestBody: ChatPdfExportRequestBody;
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
requestBody = (await request.json()) as ChatPdfExportRequestBody;
|
|
32
|
+
} catch {
|
|
33
|
+
return NextResponse.json({ error: 'Invalid JSON payload.' }, { status: 400 });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (
|
|
37
|
+
typeof requestBody?.title !== 'string' ||
|
|
38
|
+
!Array.isArray(requestBody.messages) ||
|
|
39
|
+
!Array.isArray(requestBody.participants)
|
|
40
|
+
) {
|
|
41
|
+
return NextResponse.json(
|
|
42
|
+
{ error: 'Expected `title`, `messages`, and `participants` in the PDF export payload.' },
|
|
43
|
+
{ status: 400 },
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const pdfBuffer = await renderHtmlToPdfOnServer(
|
|
49
|
+
buildChatHtml(requestBody.title, requestBody.messages, requestBody.participants),
|
|
50
|
+
);
|
|
51
|
+
const filename = createChatExportFilename(requestBody.title, 'pdf');
|
|
52
|
+
|
|
53
|
+
return new NextResponse(pdfBuffer, {
|
|
54
|
+
headers: {
|
|
55
|
+
'Content-Type': 'application/pdf',
|
|
56
|
+
'Content-Disposition': `attachment; filename="${filename}"`,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error('Failed to export chat PDF:', error);
|
|
61
|
+
return NextResponse.json({ error: 'Failed to export chat as PDF.' }, { status: 500 });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
resolveRegisteredServerByHost,
|
|
14
14
|
type ServerRecord,
|
|
15
15
|
} from '../utils/serverRegistry';
|
|
16
|
+
import { isStandaloneVpsRawIpBootstrapActive } from '../utils/standaloneVpsRawIpBootstrap';
|
|
16
17
|
import { getHomePageAgents } from './_data/getHomePageAgents';
|
|
17
18
|
|
|
18
19
|
/**
|
|
@@ -77,6 +78,15 @@ async function resolveIpAddressRouting(host: string | null): Promise<'LOGIN' | '
|
|
|
77
78
|
return (await isUserGlobalAdmin()) ? 'CONFIGURE' : 'LOGIN';
|
|
78
79
|
}
|
|
79
80
|
|
|
81
|
+
if (
|
|
82
|
+
isStandaloneVpsRawIpBootstrapActive({
|
|
83
|
+
nextPublicSiteUrl: process.env.NEXT_PUBLIC_SITE_URL,
|
|
84
|
+
publicIpAddress: process.env.PTBK_PUBLIC_IP_ADDRESS,
|
|
85
|
+
})
|
|
86
|
+
) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
80
90
|
if (registeredServers.length === 1) {
|
|
81
91
|
redirect(createServerPublicUrl(registeredServers[0]!.domain).href);
|
|
82
92
|
}
|