diff --git a/src/app/(dashboard)/dashboard/playground/components/ExportCodeModal.tsx b/src/app/(dashboard)/dashboard/playground/components/ExportCodeModal.tsx new file mode 100644 index 0000000000..db872cb6d6 --- /dev/null +++ b/src/app/(dashboard)/dashboard/playground/components/ExportCodeModal.tsx @@ -0,0 +1,157 @@ +"use client"; + +// src/app/(dashboard)/dashboard/playground/components/ExportCodeModal.tsx + +import { useState, useEffect, useCallback } from "react"; +import type { PlaygroundState, ExportLanguage } from "@/lib/playground/codeExport"; +import { exportAllLanguages, API_KEY_PLACEHOLDER } from "@/lib/playground/codeExport"; + +interface ExportCodeModalProps { + state: PlaygroundState; + onClose: () => void; +} + +const LANGUAGE_TABS: Array<{ id: ExportLanguage; label: string }> = [ + { id: "curl", label: "curl" }, + { id: "python", label: "Python" }, + { id: "typescript", label: "TypeScript" }, +]; + +/** + * ExportCodeModal — shows curl / Python / TypeScript snippets for the current playground state. + * + * Security: always uses API_KEY_PLACEHOLDER ("$OMNIROUTE_API_KEY") — never a real key (D11 / Hard Rule #1). + */ +export default function ExportCodeModal({ state, onClose }: ExportCodeModalProps) { + const [activeLanguage, setActiveLanguage] = useState("curl"); + const [copied, setCopied] = useState(false); + + // Generate all snippets once (state is passed in from parent, not re-fetched). + const snippets = exportAllLanguages(state); + const currentCode = snippets[activeLanguage]; + + // Verify that no real API key is embedded (assertion — Hard Rule #1 / D11). + // The regex checks for typical API key patterns (sk-, or other 16+ char alphanumeric strings + // that are NOT the placeholder). + const hasRealKey = /sk-[A-Za-z0-9_-]{16,}/.test(currentCode); + + const handleCopy = useCallback(async () => { + if (hasRealKey) return; // Never copy if somehow a real key slipped through + try { + await navigator.clipboard.writeText(currentCode); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } catch { + // Clipboard API unavailable (e.g. insecure context) — fail silently + } + }, [currentCode, hasRealKey]); + + // Close on Escape + useEffect(() => { + function onKeyDown(e: KeyboardEvent) { + if (e.key === "Escape") { + onClose(); + } + } + document.addEventListener("keydown", onKeyDown); + return () => document.removeEventListener("keydown", onKeyDown); + }, [onClose]); + + return ( +
+
e.stopPropagation()} + > + {/* Modal header */} +
+
+ </> +

Export code

+
+ +
+ + {/* Language tabs */} +
+ {LANGUAGE_TABS.map((lang) => ( + + ))} +
+ + {/* Code block */} +
+ {hasRealKey ? ( +
+ Security warning: export blocked — a real API key was detected in the output. + Please reset your API key and try again. +
+ ) : ( +
+              {currentCode}
+            
+ )} + + {/* Placeholder hint */} +

+ Replace{" "} + {API_KEY_PLACEHOLDER} + {" "}with your actual API key, or set it as an environment variable. +

+
+ + {/* Footer with copy button */} +
+ + +
+
+
+ ); +}