Clipboard & Shell
Electron clipboard.* / shell.* 호환 API. Frontend JS + Zig/Rust/Go/Node 백엔드 SDK
모두 노출된다.
플랫폼 지원
섹션 제목: “플랫폼 지원”| API | macOS | Linux | Windows |
|---|---|---|---|
clipboard.readText/writeText/clear | ✅ NSPasteboard | ✅ GTK clipboard text | ✅ Win32 CF_UNICODETEXT |
clipboard.readHTML/writeHTML | ✅ NSPasteboard public.html | ✅ GTK text/html target | ✅ Win32 CF_HTML (HTML Format) |
shell.openExternal | ✅ NSWorkspace + URL scheme 검사 | ✅ GIO default URI handler | ✅ ShellExecuteW + scheme 검사 |
shell.openPath | ✅ NSWorkspace file:// | ✅ GIO file URI default handler | ✅ ShellExecuteW |
shell.showItemInFolder | ✅ activateFileViewerSelectingURLs: + 사전 fileExistsAtPath: | ✅ FileManager1 D-Bus ShowItems | ✅ explorer.exe /select |
shell.beep | ✅ NSBeep | ✅ GDK display beep | ✅ MessageBeep |
shell.trashItem | ✅ NSFileManager Trash | ✅ GIO g_file_trash | ✅ SHFileOperationW |
Linux는 GTK clipboard text/HTML target과 GIO default URI handler/file URI/Trash, FileManager1 D-Bus, GDK beep 경로를 사용한다.
Windows는 plain text에는 CF_UNICODETEXT, HTML에는 Win32 HTML Format (CF_HTML) 오프셋 헤더를 사용하고,
shell API는 ShellExecute/explorer/MessageBeep/SHFileOperation 계열을 사용한다.
RTF/image/buffer 같은 clipboard 확장 format은 아직 macOS 중심이며,
미지원 format은 graceful 응답 (success: false / 빈 값)으로 떨어진다.
Clipboard
섹션 제목: “Clipboard”Frontend JS (@suji/api)
섹션 제목: “Frontend JS (@suji/api)”import { clipboard } from '@suji/api';
await clipboard.readText(); // → string (빈 문자열이면 클립보드 빔)await clipboard.writeText(text); // → boolean (성공 여부)await clipboard.clear(); // → booleanZig 백엔드 (suji.clipboard.*)
섹션 제목: “Zig 백엔드 (suji.clipboard.*)”const r = suji.clipboard.readText(); // ?[]const u8 — raw JSONconst r = suji.clipboard.writeText("hi");const r = suji.clipboard.clear();Rust 백엔드 (suji::clipboard::*)
섹션 제목: “Rust 백엔드 (suji::clipboard::*)”let r = suji::clipboard::read_text(); // Option<String>let r = suji::clipboard::write_text("hi");let r = suji::clipboard::clear();Go 백엔드 (github.com/ohah/suji-go/clipboard)
섹션 제목: “Go 백엔드 (github.com/ohah/suji-go/clipboard)”import "github.com/ohah/suji-go/clipboard"text := clipboard.ReadText()clipboard.WriteText("hi")clipboard.Clear()Node 백엔드 (@suji/node)
섹션 제목: “Node 백엔드 (@suji/node)”import { clipboard } from '@suji/node';await clipboard.readText();await clipboard.writeText("hi");await clipboard.clear();Shell
섹션 제목: “Shell”Frontend JS
섹션 제목: “Frontend JS”import { shell } from '@suji/api';
await shell.openExternal("https://example.com"); // → booleanawait shell.showItemInFolder("/tmp/file.txt"); // → boolean (경로 존재해야 true)await shell.beep(); // → booleanawait shell.trashItem("/tmp/file.txt"); // → boolean백엔드 — 4개 SDK 동일 패턴
섹션 제목: “백엔드 — 4개 SDK 동일 패턴”suji.shell.openExternal("https://...");suji.shell.showItemInFolder("/path");suji.shell.beep();suji.shell.trashItem("/path");suji::shell::open_external("https://...");suji::shell::show_item_in_folder("/path");suji::shell::beep();suji::shell::trash_item("/path");import "github.com/ohah/suji-go/shell"shell.OpenExternal("https://...")shell.ShowItemInFolder("/path")shell.Beep()shell.TrashItem("/path")import { shell } from '@suji/node';await shell.openExternal("https://...");await shell.showItemInFolder("/path");await shell.beep();await shell.trashItem("/path");동작 정밀
섹션 제목: “동작 정밀”openExternal
섹션 제목: “openExternal”URL 검증 단계:
- JSON unescape →
text.len + 1 > 4096이면 false 즉시 (path 한도) - scheme 존재/문법 검사 — 빈 scheme 또는 control char 포함이면 false
- macOS:
NSURL.URLWithString+NSWorkspace.openURL - Linux: GIO
g_app_info_launch_default_for_uri - Windows:
ShellExecuteW("open", url); scheme 없는 상대 입력과 control char는 사전 차단
scheme 없는 input("noschemejustwords" 같은 relative URL)은 사전 차단 — URLWithString이
relative URL을 통과시켜 그대로 openURL/ShellExecuteW에 보내면 OS가 원치 않는 dialog나
path 추측을 할 수 있어 회피한다.
openPath
섹션 제목: “openPath”- 존재하지 않는 path는 false
- macOS/Windows: 시스템 기본 앱으로 path를 open
- Linux:
GFile존재 검증 →file://URI 변환 → GIO default application launch
등록된 기본 앱이 없거나 desktop environment가 launch를 거부하면 false.
showItemInFolder
섹션 제목: “showItemInFolder”- 존재하지 않는 path는 false
- macOS:
NSURL.fileURLWithPath:+NSArray.arrayWithObject:→NSWorkspace.activateFileViewerSelectingURLs:(modern API.selectFile:inFileViewerRootedAtPath:은 deprecated) - Linux:
GFile존재 검증 →file://URI 변환 → session D-Busorg.freedesktop.FileManager1.ShowItems - Windows: path 존재 검증 후
explorer.exe /select,"<path>"를ShellExecuteW로 실행
Linux에서 FileManager1 서비스가 없거나 D-Bus 호출이 실패하면 false.
beep
섹션 제목: “beep”- macOS:
NSBeep()직접 호출 — AppKit C symbol - Linux:
gdk_display_beep(gdk_display_get_default()) - Windows:
MessageBeep(MB_OK)
동기 호출이며, Linux에서 display가 없으면 no-op로 반환한다.
trashItem
섹션 제목: “trashItem”- macOS:
NSFileManager.trashItemAtURL:resultingItemURL:error: - Linux: GIO
g_file_trash(freedesktop Trash spec) - Windows:
SHFileOperationW+FOF_ALLOWUNDO
존재하지 않는 path, path 한도 초과, 또는 filesystem이 Trash를 지원하지 않는 경우 false.
JSON wire 안전성
섹션 제목: “JSON wire 안전성”text/path/url 페이로드는 모두 escapeJsonStrFull로 인코딩 — \n/\t/\r 보존,
control char \u00XX. 백슬래시/따옴표 round-trip 정확. UTF-8 멀티바이트(한글/이모지)
그대로 통과.
응답 디코딩(클립보드 read의 text 필드)도 동일 — 모든 control char 보존.
- 텍스트/HTML 클립보드 플랫폼 — macOS(NSPasteboard), Linux(GTK clipboard text/html),
Windows(CF_UNICODETEXT + CF_HTML)는 native 동작. RTF/image/buffer 확장은 아직 macOS 중심이며, 미지원 format은
false를 반환한다. - Clipboard 텍스트 16KB 한도 — 텍스트가 16KB를 초과하면
false를 반환한다. - URL/path 4KB 한도 — URL 및 path는 4KB를 초과할 수 없다.
- Linux 확장 format —
clipboard.readImage/writeBuffer동등 기능은 향후 지원 예정이다.