Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion server.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,18 @@ import stripAnsi from 'strip-ansi';
import { spawn as ptySpawn } from 'node-pty';
import { getSSHExecutionService } from './src/server/ssh-execution-service.js';
import { getDatabase } from './src/server/database-prisma.js';
import { registerGlobalErrorHandlers } from './src/server/logging/globalHandlers.js';
// Fallback minimal global error handlers for Node runtime (avoid TS import)
function registerGlobalErrorHandlers() {
if (registerGlobalErrorHandlers._registered) return;
registerGlobalErrorHandlers._registered = true;
process.on('uncaughtException', (err) => {
console.error('uncaught_exception', err);
});
process.on('unhandledRejection', (reason) => {
console.error('unhandled_rejection', reason);
});
}
registerGlobalErrorHandlers._registered = false;

const dev = process.env.NODE_ENV !== 'production';
const hostname = '0.0.0.0';
Expand Down
23 changes: 20 additions & 3 deletions src/app/_components/ServerForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,21 @@ export function ServerForm({ onSubmit, initialData, isEditing = false, onCancel
const handleChange = (field: keyof CreateServerData) => (
e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>
) => {
setFormData(prev => ({ ...prev, [field]: e.target.value }));
// Special handling for numeric ssh_port: keep it strictly numeric
if (field === 'ssh_port') {
const raw = (e.target as HTMLInputElement).value ?? '';
const digitsOnly = raw.replace(/\D+/g, '');
setFormData(prev => ({
...prev,
ssh_port: digitsOnly ? parseInt(digitsOnly, 10) : undefined,
}));
if (errors.ssh_port) {
setErrors(prev => ({ ...prev, ssh_port: undefined }));
}
return;
}

setFormData(prev => ({ ...prev, [field]: (e.target as HTMLInputElement).value }));
// Clear error when user starts typing
if (errors[field]) {
setErrors(prev => ({ ...prev, [field]: undefined }));
Expand Down Expand Up @@ -246,14 +260,17 @@ export function ServerForm({ onSubmit, initialData, isEditing = false, onCancel
<input
type="number"
id="ssh_port"
inputMode="numeric"
pattern="[0-9]*"
autoComplete="off"
value={formData.ssh_port ?? 22}
onChange={handleChange('ssh_port')}
className={`w-full px-3 py-2 border rounded-md shadow-sm bg-card text-foreground placeholder-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:border-ring ${
errors.ssh_port ? 'border-destructive' : 'border-border'
}`}
placeholder="22"
min="1"
max="65535"
min={1}
max={65535}
/>
{errors.ssh_port && <p className="mt-1 text-sm text-destructive">{errors.ssh_port}</p>}
</div>
Expand Down
6 changes: 4 additions & 2 deletions src/server/database-prisma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class DatabaseServicePrisma {
// Server CRUD operations
async createServer(serverData: CreateServerData) {
const { name, ip, user, password, auth_type, ssh_key, ssh_key_passphrase, ssh_port, color, key_generated } = serverData;
const normalizedPort = ssh_port !== undefined ? parseInt(String(ssh_port), 10) : 22;

let ssh_key_path = null;

Expand All @@ -38,7 +39,7 @@ class DatabaseServicePrisma {
auth_type: auth_type ?? 'password',
ssh_key,
ssh_key_passphrase,
ssh_port: ssh_port ?? 22,
ssh_port: Number.isNaN(normalizedPort) ? 22 : normalizedPort,
ssh_key_path,
key_generated: Boolean(key_generated),
color,
Expand All @@ -60,6 +61,7 @@ class DatabaseServicePrisma {

async updateServer(id: number, serverData: CreateServerData) {
const { name, ip, user, password, auth_type, ssh_key, ssh_key_passphrase, ssh_port, color, key_generated } = serverData;
const normalizedPort = ssh_port !== undefined ? parseInt(String(ssh_port), 10) : undefined;

// Get existing server to check for key changes
const existingServer = await this.getServerById(id);
Expand Down Expand Up @@ -109,7 +111,7 @@ class DatabaseServicePrisma {
auth_type: auth_type ?? 'password',
ssh_key,
ssh_key_passphrase,
ssh_port: ssh_port ?? 22,
ssh_port: normalizedPort ?? 22,
ssh_key_path,
key_generated: key_generated !== undefined ? Boolean(key_generated) : (existingServer?.key_generated ?? false),
color,
Expand Down