@promptbook/cli 0.112.0-101 → 0.112.0-103
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/package.json +1 -1
- package/apps/agents-server/scripts/prerender-homepage.js +76 -1
- package/apps/agents-server/src/app/actions.ts +0 -6
- package/apps/agents-server/src/app/admin/about/page.tsx +1 -1
- package/apps/agents-server/src/app/admin/image-generator-test/ImageAttachmentsEditor.tsx +11 -6
- package/apps/agents-server/src/app/admin/login-methods/shibboleth/page.tsx +365 -0
- package/apps/agents-server/src/app/admin/metadata/MetadataClient.tsx +13 -15
- package/apps/agents-server/src/app/admin/servers/ServersRegistryTable.tsx +3 -3
- package/apps/agents-server/src/app/admin/servers/useCreateServerWizard.ts +13 -14
- package/apps/agents-server/src/app/admin/update/UpdateClient.tsx +12 -3
- package/apps/agents-server/src/app/admin/usage/UsageClientTimelineChart.tsx +1 -1
- package/apps/agents-server/src/app/admin/users/[userId]/UserDetailClient.tsx +21 -14
- package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatPageLayout.tsx +2 -2
- package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatSidebarDefault.tsx +11 -7
- package/apps/agents-server/src/app/api/admin/cli-access/route.ts +27 -123
- package/apps/agents-server/src/app/api/admin/code-runners/authentication/route.ts +33 -125
- package/apps/agents-server/src/app/api/auth/login/route.ts +0 -10
- package/apps/agents-server/src/app/api/auth/shibboleth/acs/route.ts +77 -57
- package/apps/agents-server/src/app/api/auth/shibboleth/login/route.ts +57 -33
- package/apps/agents-server/src/app/api/auth/shibboleth/metadata/route.ts +4 -29
- package/apps/agents-server/src/app/api/auth/shibboleth/status/route.ts +17 -0
- package/apps/agents-server/src/app/api/upload/route.ts +148 -209
- package/apps/agents-server/src/app/api/users/[username]/route.ts +1 -1
- package/apps/agents-server/src/app/api/users/route.ts +5 -5
- package/apps/agents-server/src/app/dashboard/page.tsx +1 -1
- package/apps/agents-server/src/app/docs/[docId]/page.tsx +1 -1
- package/apps/agents-server/src/app/docs/page.tsx +1 -1
- package/apps/agents-server/src/app/globals.css +100 -0
- package/apps/agents-server/src/app/layout.tsx +7 -0
- package/apps/agents-server/src/app/recycle-bin/page.tsx +1 -1
- package/apps/agents-server/src/app/system/settings/KeybindingsSettingsClient.tsx +13 -7
- package/apps/agents-server/src/components/AdminTerminal/useAdminTerminalSession.ts +29 -1
- package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +3 -3
- package/apps/agents-server/src/components/AgentProfile/AgentProfileImage.tsx +8 -2
- package/apps/agents-server/src/components/DocsToolbar/DocsToolbar.tsx +4 -4
- package/apps/agents-server/src/components/DocumentationContent/DocumentationContent.tsx +9 -9
- package/apps/agents-server/src/components/Footer/Footer.tsx +7 -7
- package/apps/agents-server/src/components/Header/Header.tsx +24 -4
- package/apps/agents-server/src/components/Header/HeaderTypes.ts +6 -0
- package/apps/agents-server/src/components/Header/buildHeaderSystemMenuItems.ts +51 -1
- package/apps/agents-server/src/components/Homepage/Card.tsx +1 -1
- package/apps/agents-server/src/components/Homepage/Section.tsx +3 -1
- package/apps/agents-server/src/components/LayoutWrapper/LayoutWrapper.tsx +12 -1
- package/apps/agents-server/src/components/LoginForm/LoginForm.tsx +100 -149
- package/apps/agents-server/src/components/Skeleton/ConsolePageLoadingSkeleton.tsx +1 -1
- package/apps/agents-server/src/components/Skeleton/DocumentationRouteLoadingSkeleton.tsx +1 -1
- package/apps/agents-server/src/components/Skeleton/HomepageLoadingSkeleton.tsx +1 -1
- package/apps/agents-server/src/components/UsersList/UsersList.tsx +20 -4
- package/apps/agents-server/src/components/UsersList/useUsersAdmin.ts +3 -0
- package/apps/agents-server/src/constants/shibbolethAuth.ts +139 -0
- package/apps/agents-server/src/database/metadataDefaults.ts +54 -80
- package/apps/agents-server/src/database/migrate.ts +30 -1
- package/apps/agents-server/src/database/migrations/2026-06-0100-shibboleth-auth.sql +136 -0
- package/apps/agents-server/src/database/sqlite/$provideLocalSqliteSupabase.ts +88 -36
- package/apps/agents-server/src/languages/ServerTranslationKeys.ts +4 -2
- package/apps/agents-server/src/languages/translations/czech.yaml +4 -2
- package/apps/agents-server/src/languages/translations/english.yaml +5 -3
- package/apps/agents-server/src/tools/$provideCdnForServer.ts +54 -11
- package/apps/agents-server/src/utils/cdn/classes/DigitalOceanSpaces.ts +18 -2
- package/apps/agents-server/src/utils/cdn/classes/TrackedFilesStorage.ts +6 -5
- package/apps/agents-server/src/utils/cdn/interfaces/IFilesStorage.ts +5 -0
- package/apps/agents-server/src/utils/chatExport/renderHtmlToPdfOnServer.ts +11 -0
- package/apps/agents-server/src/utils/createAdminTerminalRouteHandlers.ts +264 -0
- package/apps/agents-server/src/utils/shareTargetPayloads.ts +19 -66
- package/apps/agents-server/src/utils/shibbolethAuthentication.ts +729 -621
- package/apps/agents-server/src/utils/upload/createBookEditorUploadHandler.ts +19 -28
- package/apps/agents-server/src/utils/upload/uploadFileToServer.ts +113 -0
- package/esm/index.es.js +194 -35
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-codex-prompts/common/waitForPause.d.ts +12 -0
- package/esm/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -1
- package/esm/scripts/run-codex-prompts/ui/buildCoderRunUiFrame.d.ts +1 -0
- package/esm/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +1 -1
- package/esm/src/book-components/Chat/MarkdownContent/MarkdownContent.d.ts +1 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +2 -2
- package/src/book-components/Chat/MarkdownContent/MarkdownContent.tsx +63 -4
- package/src/other/templates/getTemplatesPipelineCollection.ts +730 -739
- package/src/version.ts +2 -2
- package/src/versions.txt +2 -0
- package/umd/index.umd.js +194 -35
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-codex-prompts/common/waitForPause.d.ts +12 -0
- package/umd/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -1
- package/umd/scripts/run-codex-prompts/ui/buildCoderRunUiFrame.d.ts +1 -0
- package/umd/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +1 -1
- package/umd/src/book-components/Chat/MarkdownContent/MarkdownContent.d.ts +1 -0
- package/umd/src/version.d.ts +1 -1
- package/apps/agents-server/src/app/api/auth/methods/route.ts +0 -44
- package/apps/agents-server/src/constants/authenticationMethods.ts +0 -74
- package/apps/agents-server/src/constants/shibbolethAuthentication.ts +0 -107
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { upload } from '@vercel/blob/client';
|
|
4
3
|
import { useCallback, useMemo, useRef, useState, type ChangeEvent, type RefObject } from 'react';
|
|
5
4
|
import { showAlert } from '../../../components/AsyncDialogs/asyncDialogs';
|
|
6
5
|
import { useDirtyModalGuard } from '../../../components/utils/useDirtyModalGuard';
|
|
@@ -8,6 +7,7 @@ import { buildServerTablePrefix } from '../../../utils/buildServerTablePrefix';
|
|
|
8
7
|
import type { ChatFeedbackMode } from '../../../utils/chatFeedbackMode';
|
|
9
8
|
import { getSafeCdnPath } from '../../../utils/cdn/utils/getSafeCdnPath';
|
|
10
9
|
import { normalizeUploadFilename } from '../../../utils/normalization/normalizeUploadFilename';
|
|
10
|
+
import { buildDefaultUserFileUploadPath, uploadFileToServer } from '../../../utils/upload/uploadFileToServer';
|
|
11
11
|
import type { ManagedServerEnvironment } from './useServersRegistryState';
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -425,22 +425,21 @@ export function useCreateServerWizard(options: UseCreateServerWizardOptions): Us
|
|
|
425
425
|
setIsUploadingIcon(true);
|
|
426
426
|
setWizardError(null);
|
|
427
427
|
|
|
428
|
-
const pathPrefix = process.env.NEXT_PUBLIC_CDN_PATH_PREFIX || '';
|
|
429
428
|
const normalizedFilename = normalizeUploadFilename(file.name);
|
|
430
|
-
const uploadPath =
|
|
431
|
-
|
|
432
|
-
:
|
|
433
|
-
|
|
434
|
-
const blob = await upload(getSafeCdnPath({ pathname: uploadPath }), file, {
|
|
435
|
-
access: 'public',
|
|
436
|
-
handleUploadUrl: '/api/upload',
|
|
437
|
-
clientPayload: JSON.stringify({
|
|
438
|
-
purpose: 'SERVER_ICON',
|
|
439
|
-
contentType: file.type,
|
|
440
|
-
}),
|
|
429
|
+
const uploadPath = buildDefaultUserFileUploadPath(normalizedFilename);
|
|
430
|
+
const safeUploadPath = getSafeCdnPath({
|
|
431
|
+
pathname: uploadPath,
|
|
432
|
+
pathPrefix: process.env.NEXT_PUBLIC_CDN_PATH_PREFIX,
|
|
441
433
|
});
|
|
442
434
|
|
|
443
|
-
|
|
435
|
+
const uploadResult = await uploadFileToServer({
|
|
436
|
+
file,
|
|
437
|
+
pathname: safeUploadPath,
|
|
438
|
+
purpose: 'SERVER_ICON',
|
|
439
|
+
contentType: file.type,
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
updateWizardField('iconUrl', uploadResult.url);
|
|
444
443
|
} catch (uploadError) {
|
|
445
444
|
setWizardError({
|
|
446
445
|
message: uploadError instanceof Error ? uploadError.message : 'Failed to upload the server icon.',
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { CheckCircle2, Download, Loader2, RefreshCcw, Rocket, Server, TriangleAlert } from 'lucide-react';
|
|
4
4
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
5
|
+
import { AdminXtermTerminal } from '../../../components/AdminTerminal/AdminXtermTerminal';
|
|
5
6
|
import { Card } from '../../../components/Homepage/Card';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -121,6 +122,9 @@ export function UpdateClient() {
|
|
|
121
122
|
const isEnvironmentSwitchRequired =
|
|
122
123
|
Boolean(selectedEnvironment) && selectedEnvironment?.id !== overview?.currentEnvironment.id;
|
|
123
124
|
const isUpdateRunning = overview?.job.status === 'running';
|
|
125
|
+
const updateTerminalId = `standalone-vps-update:${overview?.job.startedAt || overview?.job.finishedAt || overview?.job.status || 'loading'}`;
|
|
126
|
+
const updateTerminalEmptyState =
|
|
127
|
+
isLoading && !overview ? 'Loading update log...' : 'No persisted update log output yet.';
|
|
124
128
|
|
|
125
129
|
/**
|
|
126
130
|
* Starts one detached update run for the selected environment.
|
|
@@ -406,9 +410,14 @@ export function UpdateClient() {
|
|
|
406
410
|
<span className="ml-2 font-mono text-slate-700">{overview.job.logFilePath}</span>
|
|
407
411
|
</div>
|
|
408
412
|
)}
|
|
409
|
-
<
|
|
410
|
-
{
|
|
411
|
-
|
|
413
|
+
<AdminXtermTerminal
|
|
414
|
+
terminalId={updateTerminalId}
|
|
415
|
+
output={overview?.job.logTail || ''}
|
|
416
|
+
emptyState={updateTerminalEmptyState}
|
|
417
|
+
isReadOnly
|
|
418
|
+
isPlainTextOutput
|
|
419
|
+
ariaLabel="Standalone VPS update log"
|
|
420
|
+
/>
|
|
412
421
|
</div>
|
|
413
422
|
</Card>
|
|
414
423
|
</div>
|
|
@@ -81,7 +81,7 @@ export function UsageClientTimelineChart(props: UsageClientTimelineChartProps) {
|
|
|
81
81
|
|
|
82
82
|
return (
|
|
83
83
|
<div>
|
|
84
|
-
<div className="w-full overflow-x-auto rounded-lg border border-gray-100 bg-gradient-to-br from-slate-50 via-white to-blue-50 p-2">
|
|
84
|
+
<div className="w-full overflow-x-auto rounded-lg border border-gray-100 bg-gradient-to-br from-slate-50 via-white to-blue-50 p-2 dark:from-slate-950 dark:via-slate-950 dark:to-slate-900">
|
|
85
85
|
<svg
|
|
86
86
|
width="100%"
|
|
87
87
|
viewBox={`0 0 ${chartGeometry.width} ${chartGeometry.height}`}
|
|
@@ -86,33 +86,40 @@ export function UserDetailClient({ userId }: UserDetailClientProps) {
|
|
|
86
86
|
{t('users.adminRole')}
|
|
87
87
|
</span>
|
|
88
88
|
)}
|
|
89
|
+
{user.authenticationProvider?.includes('SHIBBOLETH') && (
|
|
90
|
+
<Link
|
|
91
|
+
href="/admin/login-methods/shibboleth"
|
|
92
|
+
className="ml-2 inline-block bg-emerald-100 text-emerald-800 text-xs px-2 py-1 rounded mt-1 hover:bg-emerald-200"
|
|
93
|
+
>
|
|
94
|
+
Shibboleth
|
|
95
|
+
</Link>
|
|
96
|
+
)}
|
|
89
97
|
<p className="text-gray-500 text-sm mt-2">
|
|
90
98
|
{t('users.idLabel')}: {user.id}
|
|
91
99
|
</p>
|
|
100
|
+
{user.displayName && (
|
|
101
|
+
<p className="text-gray-500 text-sm mt-1">Display name: {user.displayName}</p>
|
|
102
|
+
)}
|
|
103
|
+
{user.email && <p className="text-gray-500 text-sm mt-1">Email: {user.email}</p>}
|
|
104
|
+
{user.authenticationProvider && (
|
|
105
|
+
<p className="text-gray-500 text-sm mt-1">
|
|
106
|
+
Authentication: {user.authenticationProvider}
|
|
107
|
+
</p>
|
|
108
|
+
)}
|
|
92
109
|
<p className="text-gray-500 text-sm mt-1">
|
|
93
110
|
{t('users.createdAtLabel')}:{' '}
|
|
94
|
-
{user.createdAt
|
|
95
|
-
? new Date(user.createdAt).toLocaleString()
|
|
96
|
-
: t('users.unknownValue')}
|
|
111
|
+
{user.createdAt ? new Date(user.createdAt).toLocaleString() : t('users.unknownValue')}
|
|
97
112
|
</p>
|
|
98
113
|
<p className="text-gray-500 text-sm mt-1">
|
|
99
114
|
{t('users.lastUpdatedLabel')}:{' '}
|
|
100
|
-
{user.updatedAt
|
|
101
|
-
? new Date(user.updatedAt).toLocaleString()
|
|
102
|
-
: t('users.unknownValue')}
|
|
115
|
+
{user.updatedAt ? new Date(user.updatedAt).toLocaleString() : t('users.unknownValue')}
|
|
103
116
|
</p>
|
|
104
117
|
</div>
|
|
105
118
|
<div className="space-x-2">
|
|
106
|
-
<button
|
|
107
|
-
onClick={handleToggleAdmin}
|
|
108
|
-
className="text-sm text-blue-600 hover:text-blue-800"
|
|
109
|
-
>
|
|
119
|
+
<button onClick={handleToggleAdmin} className="text-sm text-blue-600 hover:text-blue-800">
|
|
110
120
|
{user.isAdmin ? t('users.removeAdmin') : t('users.makeAdmin')}
|
|
111
121
|
</button>
|
|
112
|
-
<button
|
|
113
|
-
onClick={handleDelete}
|
|
114
|
-
className="text-sm text-red-600 hover:text-red-800"
|
|
115
|
-
>
|
|
122
|
+
<button onClick={handleDelete} className="text-sm text-red-600 hover:text-red-800">
|
|
116
123
|
{t('users.deleteUserAction')}
|
|
117
124
|
</button>
|
|
118
125
|
</div>
|
|
@@ -24,11 +24,11 @@ export function AgentChatPageLayout({
|
|
|
24
24
|
children,
|
|
25
25
|
}: AgentChatPageLayoutProps) {
|
|
26
26
|
if (isHeadlessMode) {
|
|
27
|
-
return <div className="flex h-full min-h-0 w-full overflow-hidden bg-slate-50/80">{children}</div>;
|
|
27
|
+
return <div className="flex h-full min-h-0 w-full overflow-hidden bg-slate-50/80 dark:bg-slate-950">{children}</div>;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
return (
|
|
31
|
-
<div className="flex h-full min-h-0 w-full overflow-hidden bg-slate-50/80">
|
|
31
|
+
<div className="flex h-full min-h-0 w-full overflow-hidden bg-slate-50/80 dark:bg-slate-950">
|
|
32
32
|
{sidebar}
|
|
33
33
|
<section className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden">{children}</section>
|
|
34
34
|
</div>
|
|
@@ -183,7 +183,7 @@ function AgentChatSidebarDefaultCollapsedRow({
|
|
|
183
183
|
onClick={() => onChatSelect(item.id)}
|
|
184
184
|
className={`group relative flex w-full min-w-0 flex-col items-center gap-1 rounded-2xl border px-1.5 py-2 transition focus-visible:outline focus-visible:outline-blue-400 focus-visible:outline-offset-2 ${
|
|
185
185
|
item.isActive
|
|
186
|
-
? 'border-blue-300 bg-blue-50 text-blue-700 shadow-sm dark:border-blue-500/40 dark:bg-blue-500/12 dark:text-blue-100'
|
|
186
|
+
? 'agent-chat-sidebar-item-active border-blue-300 bg-blue-50 text-blue-700 shadow-sm dark:border-blue-500/40 dark:bg-blue-500/12 dark:text-blue-100'
|
|
187
187
|
: 'border-transparent bg-slate-100/80 text-slate-700 hover:border-slate-300 hover:bg-slate-100 dark:bg-slate-900/88 dark:text-slate-300 dark:hover:border-slate-700 dark:hover:bg-slate-900'
|
|
188
188
|
} ${item.isEmpty && !item.isActive ? 'opacity-40' : ''}`}
|
|
189
189
|
aria-label={item.content.accessibilityLabel}
|
|
@@ -206,14 +206,16 @@ function AgentChatSidebarDefaultCollapsedRow({
|
|
|
206
206
|
{item.content.messagesCount}
|
|
207
207
|
</span>
|
|
208
208
|
<div
|
|
209
|
-
className={`aspect-square w-full overflow-hidden rounded-xl border px-1.5 py-1.5 text-left ${
|
|
209
|
+
className={`agent-chat-sidebar-item-preview-card aspect-square w-full overflow-hidden rounded-xl border px-1.5 py-1.5 text-left ${
|
|
210
210
|
item.isActive
|
|
211
211
|
? 'border-blue-300 bg-white/90 text-blue-700 dark:border-blue-500/40 dark:bg-slate-950/82 dark:text-blue-100'
|
|
212
212
|
: 'border-slate-200 bg-white/90 text-slate-600 dark:border-slate-700 dark:bg-slate-950/78 dark:text-slate-300'
|
|
213
213
|
}`}
|
|
214
214
|
>
|
|
215
|
-
<div className="max-w-full truncate text-[10px] font-semibold leading-none">
|
|
216
|
-
|
|
215
|
+
<div className="agent-chat-sidebar-item-title max-w-full truncate text-[10px] font-semibold leading-none">
|
|
216
|
+
{item.content.title}
|
|
217
|
+
</div>
|
|
218
|
+
<div className="agent-chat-sidebar-item-preview mt-1 max-w-full truncate text-[9px] leading-tight text-slate-500 dark:text-slate-400">
|
|
217
219
|
{item.content.preview}
|
|
218
220
|
</div>
|
|
219
221
|
</div>
|
|
@@ -241,7 +243,7 @@ function AgentChatSidebarDefaultExpandedRow({
|
|
|
241
243
|
<div
|
|
242
244
|
className={`group relative rounded-xl border ${
|
|
243
245
|
item.isActive
|
|
244
|
-
? 'border-blue-300 bg-blue-50 shadow-sm dark:border-blue-500/40 dark:bg-blue-500/12'
|
|
246
|
+
? 'agent-chat-sidebar-item-active border-blue-300 bg-blue-50 shadow-sm dark:border-blue-500/40 dark:bg-blue-500/12'
|
|
245
247
|
: 'border-transparent hover:border-slate-200 hover:bg-slate-100/80 dark:hover:border-slate-700 dark:hover:bg-slate-900/88'
|
|
246
248
|
} ${item.isEmpty && !item.isActive ? 'opacity-40' : ''}`}
|
|
247
249
|
>
|
|
@@ -256,7 +258,7 @@ function AgentChatSidebarDefaultExpandedRow({
|
|
|
256
258
|
title={item.content.accessibilityLabel}
|
|
257
259
|
>
|
|
258
260
|
<div className="flex items-center gap-2">
|
|
259
|
-
<div className="min-w-0 flex-1 truncate text-sm font-medium text-slate-800 dark:text-slate-100">
|
|
261
|
+
<div className="agent-chat-sidebar-item-title min-w-0 flex-1 truncate text-sm font-medium text-slate-800 dark:text-slate-100">
|
|
260
262
|
{item.content.title}
|
|
261
263
|
</div>
|
|
262
264
|
{item.content.sourceChipLabel && (
|
|
@@ -265,7 +267,9 @@ function AgentChatSidebarDefaultExpandedRow({
|
|
|
265
267
|
</span>
|
|
266
268
|
)}
|
|
267
269
|
</div>
|
|
268
|
-
<div className="mt-1 truncate text-xs text-slate-500 dark:text-slate-400">
|
|
270
|
+
<div className="agent-chat-sidebar-item-preview mt-1 truncate text-xs text-slate-500 dark:text-slate-400">
|
|
271
|
+
{item.content.preview}
|
|
272
|
+
</div>
|
|
269
273
|
<div className="mt-2 flex items-center justify-between gap-2">
|
|
270
274
|
<div className={`truncate text-[11px] ${statusClassName}`}>
|
|
271
275
|
{item.content.activityIndicator.compactLabel || item.content.lastActivity}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { isUserGlobalAdmin } from '@/src/utils/isUserGlobalAdmin';
|
|
3
|
-
import { createInteractiveTerminalEventStream } from '@/src/utils/createInteractiveTerminalEventStream';
|
|
1
|
+
import { createAdminTerminalRouteHandlers } from '@/src/utils/createAdminTerminalRouteHandlers';
|
|
4
2
|
import {
|
|
5
3
|
getLatestServerCliAccessSession,
|
|
6
4
|
getServerCliAccessSession,
|
|
@@ -14,124 +12,30 @@ export const runtime = 'nodejs';
|
|
|
14
12
|
export const dynamic = 'force-dynamic';
|
|
15
13
|
|
|
16
14
|
/**
|
|
17
|
-
*
|
|
15
|
+
* Shared route handlers for the raw server shell terminal.
|
|
18
16
|
*/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return NextResponse.json({
|
|
48
|
-
session: getLatestServerCliAccessSession(),
|
|
49
|
-
});
|
|
50
|
-
} catch (error) {
|
|
51
|
-
return NextResponse.json(
|
|
52
|
-
{ error: error instanceof Error ? error.message : 'Failed to load the CLI access session.' },
|
|
53
|
-
{ status: 500 },
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Starts or reconnects to the raw server shell exposed in the browser.
|
|
60
|
-
*/
|
|
61
|
-
export async function POST() {
|
|
62
|
-
if (!(await isUserGlobalAdmin())) {
|
|
63
|
-
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
return NextResponse.json({
|
|
68
|
-
session: await startServerCliAccessSession(),
|
|
69
|
-
});
|
|
70
|
-
} catch (error) {
|
|
71
|
-
return NextResponse.json(
|
|
72
|
-
{ error: error instanceof Error ? error.message : 'Failed to start the CLI access session.' },
|
|
73
|
-
{ status: 500 },
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Sends raw input to the running CLI access shell.
|
|
80
|
-
*/
|
|
81
|
-
export async function PATCH(request: Request) {
|
|
82
|
-
if (!(await isUserGlobalAdmin())) {
|
|
83
|
-
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
try {
|
|
87
|
-
const body = (await request.json().catch(() => null)) as
|
|
88
|
-
| {
|
|
89
|
-
readonly sessionId?: string;
|
|
90
|
-
readonly input?: string;
|
|
91
|
-
}
|
|
92
|
-
| null;
|
|
93
|
-
|
|
94
|
-
if (!body?.sessionId || typeof body.input !== 'string') {
|
|
95
|
-
return NextResponse.json({ error: 'CLI access session input is required.' }, { status: 400 });
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return NextResponse.json({
|
|
99
|
-
session: writeServerCliAccessSessionInput(body.sessionId, body.input),
|
|
100
|
-
});
|
|
101
|
-
} catch (error) {
|
|
102
|
-
return NextResponse.json(
|
|
103
|
-
{ error: error instanceof Error ? error.message : 'Failed to send CLI access input.' },
|
|
104
|
-
{ status: 500 },
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Stops one running CLI access shell session.
|
|
111
|
-
*/
|
|
112
|
-
export async function DELETE(request: Request) {
|
|
113
|
-
if (!(await isUserGlobalAdmin())) {
|
|
114
|
-
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
try {
|
|
118
|
-
const body = (await request.json().catch(() => null)) as
|
|
119
|
-
| {
|
|
120
|
-
readonly sessionId?: string;
|
|
121
|
-
}
|
|
122
|
-
| null;
|
|
123
|
-
|
|
124
|
-
if (!body?.sessionId) {
|
|
125
|
-
return NextResponse.json({ error: 'CLI access session id is required.' }, { status: 400 });
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return NextResponse.json({
|
|
129
|
-
session: stopServerCliAccessSession(body.sessionId),
|
|
130
|
-
});
|
|
131
|
-
} catch (error) {
|
|
132
|
-
return NextResponse.json(
|
|
133
|
-
{ error: error instanceof Error ? error.message : 'Failed to stop the CLI access session.' },
|
|
134
|
-
{ status: 500 },
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
17
|
+
const cliAccessTerminalRouteHandlers = createAdminTerminalRouteHandlers(
|
|
18
|
+
{
|
|
19
|
+
getLatestSession: getLatestServerCliAccessSession,
|
|
20
|
+
getSession: getServerCliAccessSession,
|
|
21
|
+
startSession: startServerCliAccessSession,
|
|
22
|
+
writeSessionInput: writeServerCliAccessSessionInput,
|
|
23
|
+
stopSession: stopServerCliAccessSession,
|
|
24
|
+
subscribeToSession: subscribeToServerCliAccessSession,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
loadErrorMessage: 'Failed to load the CLI access session.',
|
|
28
|
+
missingStreamSessionIdMessage: 'CLI access session id is required.',
|
|
29
|
+
sessionNotFoundMessage: 'CLI access session was not found.',
|
|
30
|
+
startErrorMessage: 'Failed to start the CLI access session.',
|
|
31
|
+
missingInputMessage: 'CLI access session input is required.',
|
|
32
|
+
sendErrorMessage: 'Failed to send CLI access input.',
|
|
33
|
+
missingStopSessionIdMessage: 'CLI access session id is required.',
|
|
34
|
+
stopErrorMessage: 'Failed to stop the CLI access session.',
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
export const GET = cliAccessTerminalRouteHandlers.GET;
|
|
39
|
+
export const POST = cliAccessTerminalRouteHandlers.POST;
|
|
40
|
+
export const PATCH = cliAccessTerminalRouteHandlers.PATCH;
|
|
41
|
+
export const DELETE = cliAccessTerminalRouteHandlers.DELETE;
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { NextResponse } from 'next/server';
|
|
2
|
-
import { isUserGlobalAdmin } from '@/src/utils/isUserGlobalAdmin';
|
|
3
|
-
import { createInteractiveTerminalEventStream } from '@/src/utils/createInteractiveTerminalEventStream';
|
|
4
1
|
import {
|
|
5
2
|
getCodeRunnerAuthenticationSession,
|
|
6
3
|
getLatestCodeRunnerAuthenticationSession,
|
|
@@ -9,132 +6,43 @@ import {
|
|
|
9
6
|
subscribeToCodeRunnerAuthenticationSession,
|
|
10
7
|
writeCodeRunnerAuthenticationSessionInput,
|
|
11
8
|
} from '@/src/utils/codeRunnerAuthentication';
|
|
9
|
+
import { createAdminTerminalRouteHandlers } from '@/src/utils/createAdminTerminalRouteHandlers';
|
|
12
10
|
import { readConfiguredCodeRunner } from '@/src/utils/codeRunnerConfiguration';
|
|
13
11
|
|
|
14
12
|
export const runtime = 'nodejs';
|
|
15
13
|
export const dynamic = 'force-dynamic';
|
|
16
14
|
|
|
17
15
|
/**
|
|
18
|
-
*
|
|
16
|
+
* Shared route handlers for the code-runner authentication terminal.
|
|
19
17
|
*/
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
}
|
|
18
|
+
const authenticationTerminalRouteHandlers = createAdminTerminalRouteHandlers(
|
|
19
|
+
{
|
|
20
|
+
async getLatestSession() {
|
|
21
|
+
const { agent } = await readConfiguredCodeRunner();
|
|
22
|
+
return getLatestCodeRunnerAuthenticationSession(agent);
|
|
23
|
+
},
|
|
24
|
+
getSession: getCodeRunnerAuthenticationSession,
|
|
25
|
+
async startSession() {
|
|
26
|
+
const { agent } = await readConfiguredCodeRunner();
|
|
27
|
+
return startCodeRunnerAuthenticationSession(agent);
|
|
28
|
+
},
|
|
29
|
+
writeSessionInput: writeCodeRunnerAuthenticationSessionInput,
|
|
30
|
+
stopSession: stopCodeRunnerAuthenticationSession,
|
|
31
|
+
subscribeToSession: subscribeToCodeRunnerAuthenticationSession,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
loadErrorMessage: 'Failed to load the authentication session.',
|
|
35
|
+
missingStreamSessionIdMessage: 'Authentication session id is required.',
|
|
36
|
+
sessionNotFoundMessage: 'Authentication session was not found.',
|
|
37
|
+
startErrorMessage: 'Failed to start the authentication session.',
|
|
38
|
+
missingInputMessage: 'Authentication session input is required.',
|
|
39
|
+
sendErrorMessage: 'Failed to send authentication input.',
|
|
40
|
+
missingStopSessionIdMessage: 'Authentication session id is required.',
|
|
41
|
+
stopErrorMessage: 'Failed to stop the authentication session.',
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
export const GET = authenticationTerminalRouteHandlers.GET;
|
|
46
|
+
export const POST = authenticationTerminalRouteHandlers.POST;
|
|
47
|
+
export const PATCH = authenticationTerminalRouteHandlers.PATCH;
|
|
48
|
+
export const DELETE = authenticationTerminalRouteHandlers.DELETE;
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { authenticateUser } from '../../../../utils/authenticateUser';
|
|
2
2
|
import { setSession } from '../../../../utils/session';
|
|
3
3
|
import { NextResponse } from 'next/server';
|
|
4
|
-
import {
|
|
5
|
-
AUTHENTICATION_METHODS_METADATA_KEY,
|
|
6
|
-
isAuthenticationMethodEnabled,
|
|
7
|
-
} from '../../../../constants/authenticationMethods';
|
|
8
|
-
import { getMetadata } from '../../../../database/getMetadata';
|
|
9
4
|
|
|
10
5
|
/**
|
|
11
6
|
* Handles post.
|
|
@@ -19,11 +14,6 @@ export async function POST(request: Request) {
|
|
|
19
14
|
return NextResponse.json({ error: 'Username and password are required' }, { status: 400 });
|
|
20
15
|
}
|
|
21
16
|
|
|
22
|
-
if (!isAuthenticationMethodEnabled(await getMetadata(AUTHENTICATION_METHODS_METADATA_KEY), 'PASSWORD')) {
|
|
23
|
-
console.info('Password login rejected because PASSWORD authentication is disabled in metadata.');
|
|
24
|
-
return NextResponse.json({ error: 'Password login is disabled on this server' }, { status: 403 });
|
|
25
|
-
}
|
|
26
|
-
|
|
27
17
|
const user = await authenticateUser(username, password);
|
|
28
18
|
|
|
29
19
|
if (user) {
|