fix(update): randomUUID crypto change is not working after being implemented on the online server.

This commit is contained in:
KodekaTeam committed 2026-06-05 14:19:45 +07:00
1 parent 17cbc2fb98
commit c30f828d2c
6 files changed
+96 -61

No files matched your search

@@ -31,6 +31,7 @@ import {
normalizeNotificationActionKeys,
NOTIFICATION_ACTION_OPTIONS,
} from "@/app/notifications/components/notification-actions";
import { createClientId } from "@/lib/random-id";
import type {
EditableNotificationSettings,
NotificationProviderItem,
@@ -153,10 +154,7 @@ function createProvider(
type: NotificationProviderKind,
): NotificationProviderItem {
return {
id:
typeof crypto !== "undefined" && typeof crypto.randomUUID === "function"
? crypto.randomUUID()
: `provider-${Date.now()}-${Math.random().toString(16).slice(2)}`,
id: createClientId("provider"),
type,
name:
PROVIDER_OPTIONS.find((item) => item.type === type)?.label ||
@@ -11,6 +11,7 @@ import {
TerminalSquare,
} from "lucide-react";
import { terminal as terminalApi } from "@/lib/api";
import { createClientId } from "@/lib/random-id";
import { sanitizeTerminalStreamChunk } from "@/lib/terminal-output";
import type {
TerminalCommandPreset,
@@ -23,7 +24,12 @@ interface TerminalTabPanelProps {
terminal: TerminalTabData;
}
type TerminalStatus = "idle" | "connecting" | "connected" | "disconnected" | "error";
type TerminalStatus =
| "idle"
| "connecting"
| "connected"
| "disconnected"
| "error";
type TerminalSender = (data: string) => boolean;
type StoredTerminalSession = {
id: string;
@@ -46,17 +52,17 @@ const summaryToneColor: Record<
cyan: "var(--accent-cyan)",
};
const historyClass: Record<TerminalTabData["history"][number]["status"], string> =
{
Completed: "badge-online",
Running: "badge-warning",
Failed: "badge-danger",
};
const historyClass: Record<
TerminalTabData["history"][number]["status"],
string
> = {
Completed: "badge-online",
Running: "badge-warning",
Failed: "badge-danger",
};
function presetTone(preset: TerminalCommandPreset) {
return preset.tone === "warning"
? "rgba(245,158,11,0.1)"
: "var(--bg-input)";
return preset.tone === "warning" ? "rgba(245,158,11,0.1)" : "var(--bg-input)";
}
function formatTime(date: Date) {
@@ -75,12 +81,8 @@ function createSessionId(terminal: TerminalTabData) {
const safeSessionTarget = terminal.execTarget
.replace(/[^a-zA-Z0-9_-]/g, "")
.slice(0, 72);
const suffix =
typeof crypto !== "undefined" && "randomUUID" in crypto
? crypto.randomUUID()
: `${Date.now()}-${Math.random().toString(36).slice(2)}`;
return `container-${safeSessionTarget}-${suffix}`.slice(0, 128);
return `container-${safeSessionTarget}-${createClientId()}`.slice(0, 128);
}
function getStorageId(terminal: TerminalTabData) {
@@ -93,7 +95,9 @@ function readStoredSessions(): Record<string, StoredTerminalSession> {
try {
const raw = localStorage.getItem(STORAGE_KEY);
const parsed = raw ? JSON.parse(raw) : {};
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
return typeof parsed === "object" &&
parsed !== null &&
!Array.isArray(parsed)
? (parsed as Record<string, StoredTerminalSession>)
: {};
} catch {
@@ -348,9 +352,7 @@ function ContainerTerminalPane({
ws.onopen = () => {
onStatusChange("connected");
onSenderChange(sendInput);
enqueueTerminalOutput(
"\x1b[32mSSH connection established\x1b[0m\r\n",
);
enqueueTerminalOutput("\x1b[32mSSH connection established\x1b[0m\r\n");
enqueueTerminalOutput(
`\x1b[36mOpening container shell: ${terminal.execTarget}\x1b[0m\r\n`,
);
@@ -489,9 +491,12 @@ export default function TerminalTabPanel({ terminal }: TerminalTabPanelProps) {
const [sessionHistory, setSessionHistory] = useState<TerminalSessionEvent[]>(
terminal.history,
);
const handleSenderChange = useCallback((nextSender: TerminalSender | null) => {
setSender(() => nextSender);
}, []);
const handleSenderChange = useCallback(
(nextSender: TerminalSender | null) => {
setSender(() => nextSender);
},
[],
);
const handleSessionInitialized = useCallback(() => {
writeStoredSession(storageId, { ...session, initialized: true });
}, [session, storageId]);
@@ -609,13 +614,15 @@ export default function TerminalTabPanel({ terminal }: TerminalTabPanelProps) {
title="Container Terminal"
action={
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
<span className={`ui-badge ${
status === "connected"
? "badge-online"
: status === "error"
? "badge-danger"
: "badge-warning"
}`}>
<span
className={`ui-badge ${
status === "connected"
? "badge-online"
: status === "error"
? "badge-danger"
: "badge-warning"
}`}
>
{status === "connecting" ? (
<Loader2 size={12} className="animate-spin" />
) : null}
@@ -667,10 +674,14 @@ export default function TerminalTabPanel({ terminal }: TerminalTabPanelProps) {
padding: 24,
}}
>
<TerminalSquare size={30} style={{ color: "var(--accent-yellow)" }} />
<TerminalSquare
size={30}
style={{ color: "var(--accent-yellow)" }}
/>
<strong>Container terminal is unavailable</strong>
<span style={{ color: "var(--text-muted)", fontSize: 12 }}>
Start this container first, then reconnect to open an interactive shell.
Start this container first, then reconnect to open an
interactive shell.
</span>
</div>
)}
@@ -705,7 +716,10 @@ export default function TerminalTabPanel({ terminal }: TerminalTabPanelProps) {
borderRadius: 7,
background: presetTone(preset),
padding: 11,
cursor: sender && status === "connected" ? "pointer" : "not-allowed",
cursor:
sender && status === "connected"
? "pointer"
: "not-allowed",
opacity: sender && status === "connected" ? 1 : 0.62,
}}
>
@@ -772,9 +786,7 @@ export default function TerminalTabPanel({ terminal }: TerminalTabPanelProps) {
fontSize: 12,
}}
>
<span style={{ color: "var(--text-muted)" }}>
{item.label}
</span>
<span style={{ color: "var(--text-muted)" }}>{item.label}</span>
<span
style={{
color: "var(--text-primary)",
@@ -834,7 +846,8 @@ export default function TerminalTabPanel({ terminal }: TerminalTabPanelProps) {
{sessionHistory.length === 0 ? (
<tr>
<td colSpan={5} style={{ color: "var(--text-muted)" }}>
Preset commands executed in this page session will appear here.
Preset commands executed in this page session will appear
here.
</td>
</tr>
) : null}
+2 -1
View File
@@ -15,6 +15,7 @@ import {
terminal as terminalApi,
Server as ServerType,
} from "@/lib/api";
import { createClientId } from "@/lib/random-id";
import { sanitizeTerminalStreamChunk } from "@/lib/terminal-output";
import { useSearchParams } from "next/navigation";
@@ -488,7 +489,7 @@ function TerminalPageContent() {
const id = `${serverId}-${Date.now()}`;
const tab: Tab = {
id,
sessionId: crypto.randomUUID(),
sessionId: createClientId(),
serverId,
serverName: name,
serverIp: ip,
+3 -16
View File
@@ -35,16 +35,7 @@ function resolveRuntimeOrigin(protocol: "http" | "ws") {
return null;
}
const scheme =
protocol === "ws"
? window.location.protocol === "https:"
? "wss"
: "ws"
: window.location.protocol === "https:"
? "https"
: "http";
return `${scheme}://${window.location.hostname}:${DEFAULT_API_PORT}`;
return `ws://${window.location.hostname}:${DEFAULT_API_PORT}`;
}
export function getApiBaseUrl() {
@@ -54,12 +45,8 @@ export function getApiBaseUrl() {
);
}
function getWsBaseUrl() {
return (
process.env.NEXT_PUBLIC_WS_URL ||
resolveRuntimeOrigin("ws") ||
`ws://localhost:${DEFAULT_API_PORT}`
);
function getWsBaseUrl(): string | undefined {
return process.env.NEXT_PUBLIC_WS_URL || undefined;
}
export function getHealthUrl() {
+2 -4
View File
@@ -1,4 +1,5 @@
import type { GitProviderType } from "@/lib/api";
import { createClientId } from "@/lib/random-id";
const CALLBACK_INTENT_TTL_SECONDS = 15 * 60;
@@ -25,10 +26,7 @@ export function markGitProviderCallbackIntent(provider: GitProviderType): void {
return;
}
const nonce =
typeof crypto !== "undefined" && typeof crypto.randomUUID === "function"
? crypto.randomUUID()
: `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
const nonce = createClientId();
document.cookie = `${getCallbackIntentCookieName(provider)}=${encodeURIComponent(nonce)}; ${buildCookieAttributes(provider).join("; ")}`;
}
+38
View File
@@ -0,0 +1,38 @@
function createUuidFromRandomValues(cryptoApi: Crypto): string | null {
if (typeof cryptoApi.getRandomValues !== "function") {
return null;
}
const bytes = new Uint8Array(16);
cryptoApi.getRandomValues(bytes);
bytes[6] = (bytes[6] & 0x0f) | 0x40;
bytes[8] = (bytes[8] & 0x3f) | 0x80;
const hex = Array.from(bytes, (byte) =>
byte.toString(16).padStart(2, "0"),
);
return [
hex.slice(0, 4).join(""),
hex.slice(4, 6).join(""),
hex.slice(6, 8).join(""),
hex.slice(8, 10).join(""),
hex.slice(10, 16).join(""),
].join("-");
}
export function createClientId(prefix?: string): string {
const cryptoApi =
typeof globalThis !== "undefined" ? globalThis.crypto : undefined;
const suffix =
typeof cryptoApi?.randomUUID === "function"
? cryptoApi.randomUUID()
: cryptoApi
? createUuidFromRandomValues(cryptoApi)
: null;
const id =
suffix || `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
return prefix ? `${prefix}-${id}` : id;
}