Skip to content

API map ​

Every call on the backend's app next to its page twin on tiny, one row per operation. A page's tiny.app.X is the backend's app.X, and tiny.win.X (the page's own window) pairs with app.win.X (the main window); app.window(id) handles have the same window methods as app.win minus open, windows and setHideOnClose, and their close() takes no id.

Generated from tiny.d.ts, checked against the live app and tiny objects and line by line against the code — 135 same · 36 page only · 12 backend only · 3 args differ · 2 returns differ.

bridge · windows · menus · tray · hotkeys · dialogs · notifications · app · system · theme · clipboard · store · audio · macos only · events · deprecated

"returns differ" mostly means the page resolves true where the backend returns nothing

Bridge ​

backend apppage tinynotes
—tiny.api.call(method: string, params?: unknown) → Promise<any>page only
Call a backend api method; resolves with its return value.
—tiny.api.off(event: string, fn: (data: any) => void) → voidpage only
unhook a handler passed to on() by reference (the tiny.*.on sugar wraps yours, so keep the function those return instead)
—tiny.api.on(event: string, fn: (data: any) => void) → () => voidpage only
Subscribe to backend push events (app.push / broadcasts).
app.debug(…)
not in tiny.d.ts
—backend only
app.done: Promise<{ exit_status: number; }>—backend only
resolves when the window process ends
—tiny.fetch(url: string, init?: TinyFetchInit) → Promise<Response>page only
Like window.fetch, but the request runs in the backend (a native process) — no CORS, CSP, or mixed-content limits, so the page can reach any origin.
—tiny.fileURL(path: string) → stringpage only
A correct file:// URL for a disk path on every platform — use for <audio>/<img>/<video> src of backend-provided paths.
—tiny.log(msg: unknown) → Promise<true>page only
print to the backend's console (the tinyjs dev terminal); any JSON value
—tiny.proxyURL(url: string) → stringpage only
A same-app URL (tiny-media://…) that streams a remote http(s) resource through the native layer with permissive CORS.
app.push(event: string, data?: unknown) → void—backend only
push an event to EVERY window (tiny.api.on) — app.win.push reaches main only.
app.reload(newHtml?: string) → Promise<void>—backend only
app.spawnHidden(args: string[], opts?: any) → any—backend only
tjs.spawn without the console window a GUI app gets on Windows

Windows ​

backend apppage tinynotes
app.win.center() → void
also app.center() (main window)
tiny.win.center() → Promise<void>same
app.win.close(id?: string) → voidtiny.win.close(id?: string) → Promise<void>same
close a window; no id = this window ('main' quits the app)
—tiny.win.dragOut(opts: TinyDragOutOptions) → Promise<void>page only
drag files out of the window (same as startDrag({ files }))
app.win.ensureOnScreen() → void
also app.ensureOnScreen() (main window)
tiny.win.ensureOnScreen() → Promise<void>same
clamp this window onto the nearest screen if it's (nearly) off all
app.win.eval(js: string) → void
also app.eval() (main window)
—backend only
—tiny.win.find(term: string, opts?: { forward?: boolean; matchCase?: boolean; }) → Promise<{ found: boolean; matches?: number; activeMatch?: number; }>page only
Find-in-page: selects and scrolls to the next match; call again to step.
app.win.fullscreen() → void
also app.fullscreen() (main window)
tiny.win.fullscreen() → Promise<void>same
toggle
app.win.getState() → Promise<TinyWinState | null>tiny.win.getState() → Promise<TinyWinState | null>same
null if the window is already gone
app.win.hide(opts?: TinyHideOptions) → void
also app.hide() (main window)
tiny.win.hide(opts?: TinyHideOptions) → Promise<void>same
hides the APP (NSApp hide): focus returns to the previous app — palettes can hide-then-paste with no frontmost tracking.
app.win.id: stringtiny.win.id: stringsame
which window this page lives in ('main' or a tiny.win.open id)
app.win.menu.get(id: string) → Promise<TinyMenuItemState>tiny.win.menu.get(id: string) → Promise<TinyMenuItemState>same
app.win.menu.reset() → voidtiny.win.menu.reset() → Promise<void>same
back to showing the app menu
app.win.menu.set(menus: TinyMenu[]) → voidtiny.win.menu.set(menus: TinyMenu[]) → Promise<void>same
app.win.menu.update(id: string, patch?: { label?: string; checked?: boolean; enabled?: boolean; }) → voidtiny.win.menu.update(id: string, patch?: { label?: string; checked?: boolean; enabled?: boolean; }) → Promise<void>same
patch an item in THIS window's bar only
app.win.minimize() → void
also app.minimize() (main window)
tiny.win.minimize() → Promise<void>same
—tiny.win.onDrop(fn: (paths: string[]) => void) → () => voidpage only
files dragged onto the window — real filesystem paths
—tiny.win.onState(fn: (state: TinyWindowStateEvent) => void) → () => voidpage only
fullscreen/maximized/minimized/focused transitions, from any cause.
app.win.open(id: string, opts?: TinyOpenWindowOptions) → voidtiny.win.open(id: string, opts?: TinyOpenWindowOptions) → Promise<void>same
With "mainWindow": false there is no main window; open named ones on demand.
app.win.print() → void
also app.print() (main window)
tiny.win.print() → Promise<void>same
print THIS window's page (its own print panel)
app.win.printToPDF(path: string) → Promise<{ path: string; }>
also app.printToPDF() (main window)
tiny.win.printToPDF(path: string) → Promise<{ path: string; }>same
render the page to a PDF file (vector) -> the path written.
app.win.push(event: string, data?: unknown) → void—backend only
main only — app.push broadcasts to every window.
app.win.restore() → void
also app.restore() (main window)
tiny.win.restore() → Promise<void>same
app.win.setAllSpaces(enabled: boolean) → void
also app.setAllSpaces() (main window)
tiny.win.setAllSpaces(enabled: boolean) → Promise<void>same
follow the user across every Space + float over fullscreen apps
app.win.setAlwaysOnTop(enabled: boolean) → void
also app.setAlwaysOnTop() (main window)
tiny.win.setAlwaysOnTop(enabled: boolean) → Promise<void>same
app.win.setChrome(opts: TinyChromeOptions) → void
also app.setChrome() (main window)
tiny.win.setChrome(opts: TinyChromeOptions) → Promise<void>same
app.win.setClickThrough(enabled: boolean) → void
also app.setClickThrough() (main window)
tiny.win.setClickThrough(enabled: boolean) → Promise<void>same
mouse events pass through to whatever is behind the window
app.win.setFullscreen(enabled: boolean, opts?: TinyFullscreenOptions) → void
also app.setFullscreen() (main window)
tiny.win.setFullscreen(enabled: boolean, opts?: TinyFullscreenOptions) → Promise<void>same
app.win.setHideOnClose(enabled: boolean) → void
also app.setHideOnClose() (main window)
tiny.win.setHideOnClose(enabled: boolean) → Promise<void>same
true: the close button hides the window instead of quitting.
app.win.setLevel(level: TinyWindowLevel) → void
also app.setLevel() (main window)
tiny.win.setLevel(level: TinyWindowLevel) → Promise<void>same
app.win.setMinSize(width: number, height: number) → voidtiny.win.setMinSize(width: number, height: number) → Promise<void>same
floor for user resizes
app.win.setPosition(x: number, y: number, opts?: TinyPositionOptions) → void
also app.setPosition() (main window)
tiny.win.setPosition(x: number, y: number, opts?: TinyPositionOptions) → Promise<void>same
top-left origin, screen points (global).
app.win.setResizable(enabled: boolean) → void
also app.setResizable() (main window)
tiny.win.setResizable(enabled: boolean) → Promise<void>same
app.win.setSize(width: number, height: number, opts?: TinySizeOptions) → void
also app.setSize() (main window)
tiny.win.setSize(width: number, height: number, opts?: TinySizeOptions) → Promise<void>same
resize the PAGE's box (decorations excluded), top-left anchored — the same units getState().width/height reports back
app.win.setTitle(title: string) → void
also app.setTitle() (main window)
tiny.win.setTitle(title: string) → Promise<void>same
app.win.setZoom(factor: number) → voidtiny.win.setZoom(factor: number) → Promise<void>same
Native page zoom, 0.25–5 — the WEBVIEW's own (WKWebView pageZoom, WebView2 ZoomFactor, webkit_web_view_set_zoom_level), so it renders crisp and the page keeps laying out in ordinary CSS px with fewer of them.
app.win.share(opts?: TinyShareOptions) → booleantiny.win.share(opts?: TinyShareOptions) → Promise<boolean>same
native share sheet — anchor at the click's clientX/clientY.
app.win.show(opts?: TinyShowOptions) → void
also app.show() (main window)
tiny.win.show(opts?: TinyShowOptions) → Promise<void>same
show({ activate: false }) surfaces the window without stealing focus
app.win.startDrag() → void
also app.startDrag() (main window)
tiny.win.startDrag(opts?: TinyDragOutOptions) → Promise<void>args differ
No args: drag the window (frameless chrome).
app.win.startResize(edge?: TinyResizeEdge) → void
also app.startResize() (main window)
tiny.win.startResize(edge?: TinyResizeEdge) → Promise<void>same
begin a resize from an edge (frameless windows' own grips)
—tiny.win.stopFind() → Promise<void>page only
clear the find selection
app.win.windows() → Promise<string[]>
also app.windows() (main window)
tiny.win.windows() → Promise<string[]>same
app.win.zoom() → void
also app.zoom() (main window)
tiny.win.zoom() → Promise<void>same
app.window(id: string) → TinyWindowHandle—backend only
backend apppage tinynotes
app.menu.get(id: string) → Promise<TinyMenuItemState>tiny.menu.get(id: string) → Promise<TinyMenuItemState>same
—tiny.menu.on(fn: (id: string) => void) → () => voidpage only
With `"about": "menu"` in tinyjs.json, the macOS About menu item fires here with the reserved id 'about' instead of showing the standard panel.
—tiny.menu.onContext(fn: (id: string) => void) → () => voidpage only
app.menu.set(menus: TinyMenu[]) → voidtiny.menu.set(menus: TinyMenu[]) → Promise<void>same
The APP menu: every window shows it, including windows opened later.
app.menu.setContext(items: TinyMenuItem[] | null) → voidtiny.menu.setContext(items: TinyMenuItem[] | null) → Promise<void>same
replace the right-click menu; null restores WebKit's default
app.menu.update(id: string, patch?: { label?: string; checked?: boolean; enabled?: boolean; }) → voidtiny.menu.update(id: string, patch?: { label?: string; checked?: boolean; enabled?: boolean; }) → Promise<void>same
patch a live item without redeclaring the menu — every window's copy of the id moves.

Tray ​

backend apppage tinynotes
—tiny.tray.on(fn: (id: string) => void) → () => voidpage only
—tiny.tray.onClick(fn: () => void) → () => voidpage only
app.tray.position() → Promise<{ x: number; y: number; width: number; height: number; } | null>tiny.tray.position() → Promise<{ x: number; y: number; width: number; height: number; } | null>same
the tray icon's rect { x, y, width, height } (top-left) | null.
app.tray.remove() → voidtiny.tray.remove() → Promise<void>same
app.tray.set(spec: TinyTraySpec) → voidtiny.tray.set(spec: TinyTraySpec) → Promise<void>same

Hotkeys ​

backend apppage tinynotes
—tiny.hotkey.on(fn: (id: string) => void) → () => voidpage only
app.hotkey.register(id: string, combo: string) → Promise<boolean>tiny.hotkey.register(id: string, combo: string) → Promise<boolean>same
true once the system has the hotkey; false if the combo isn't valid or another app holds it (the reason is logged).
app.hotkey.unregister(id: string) → voidtiny.hotkey.unregister(id: string) → Promise<void>same

Dialogs ​

backend apppage tinynotes
app.dialog.alert(message: string, opts?: string | { detail?: string; ok?: string; }) → Promise<true>tiny.dialog.alert(message: string, opts?: string | { detail?: string; ok?: string; }) → Promise<true>same
`alert`/`confirm`/`prompt` are native panels with the message as the headline.
app.dialog.confirm(message: string, opts?: string | { detail?: string; ok?: string; cancel?: string; }) → Promise<boolean>tiny.dialog.confirm(message: string, opts?: string | { detail?: string; ok?: string; cancel?: string; }) → Promise<boolean>same
app.dialog.openFile(opts?: { types?: string[]; }) → Promise<string | null>tiny.dialog.openFile(opts?: { types?: string[]; }) → Promise<string | null>same
`types`: extensions without dots (`['md', 'txt']`) limiting what's choosable — allowedContentTypes / COMDLG_FILTERSPEC / GtkFileFilter.
app.dialog.openFiles(opts?: { types?: string[]; }) → Promise<string[] | null>tiny.dialog.openFiles(opts?: { types?: string[]; }) → Promise<string[] | null>same
app.dialog.pickFolder() → Promise<string | null>tiny.dialog.pickFolder() → Promise<string | null>same
app.dialog.prompt(message: string, opts?: { default?: string; ok?: string; cancel?: string; }) → Promise<string | null>tiny.dialog.prompt(message: string, opts?: { default?: string; ok?: string; cancel?: string; }) → Promise<string | null>same
app.dialog.saveFile(opts?: { types?: string[]; name?: string; }) → Promise<string | null>tiny.dialog.saveFile(opts?: { types?: string[]; name?: string; }) → Promise<string | null>same

Notifications ​

backend apppage tinynotes
app.notify(title: string, body?: string, opts?: TinyNotifyOptions) → Promise<boolean>tiny.notify(title: string, body?: string, opts?: TinyNotifyOptions) → Promise<boolean>same
Desktop notification.

App ​

backend apppage tinynotes
app.attention(opts?: { critical?: boolean; }) → booleantiny.app.attention(opts?: { critical?: boolean; }) → Promise<void>same
ask for the user's attention: macOS bounces the Dock icon once (critical: until the app is activated), Windows flashes the taskbar button (critical: longer), Linux sets the urgency hint (X11 only; critical makes no diffe
app.authenticate(reason?: string) → Promise<boolean>tiny.app.authenticate(reason?: string) → Promise<boolean>same
Touch ID (or the account-password sheet); false covers cancel
app.badge(text: string) → booleantiny.app.badge(text: string) → Promise<void>same
'' clears the badge
app.beep() → Promise<boolean>tiny.app.beep() → Promise<boolean>same
the system alert beep — the one portable sound
app.captureScreen(screenId?: number) → Promise<TinyCapture>tiny.app.captureScreen(screenId?: number) → Promise<TinyCapture>same
screenshot a display (id from screens(); default: the first display the OS lists, usually the main one — Linux always captures the whole desktop and ignores the id) — png in the temp dir, caller owns the file; needs the
app.cookies.get(filter?: { url?: string; name?: string; domain?: string; path?: string; }) → Promise<TinyCookie[]>—backend only
url keeps what a request to it would carry (domain, path, secure).
app.cookies.remove(target: { name: string; domain: string; path?: string; } | { url: string; name?: string; }) → Promise<number>—backend only
one cookie by name + domain (+ path, default '/') — e.g.
app.cookies.set(cookie: TinyCookieInit) → Promise<true>—backend only
replaces any cookie with the same name/domain/path
app.foregroundScreen() → Promise<TinyScreen | null>tiny.app.foregroundScreen() → Promise<TinyScreen | null>same
the screen of the focused window of ANY app (no permission needed); the cursor's screen when that app shows no window; null on Wayland
app.frontmostApp() → Promise<TinyFrontmostApp | null>tiny.app.frontmostApp() → Promise<TinyFrontmostApp | null>same
the active app right now (who focus returns to after win.hide())
app.icon(path: string) → booleantiny.app.icon(path: string) → Promise<void>same
replace the app icon from a png ('' resets to the bundle icon)
app.info() → Promise<TinyAppInfo>tiny.app.info() → Promise<TinyAppInfo>same
like tiny.app.info() (reading app.info.version as an object still works but is deprecated)
app.keystroke(combo: string) → Promise<TinyKeystrokeResult>tiny.app.keystroke(combo: string) → Promise<TinyKeystrokeResult>same
post a native keystroke, combo like 'cmd+v' (needs Accessibility)
app.launchAtLogin.get() → Promise<TinyLoginStatus>tiny.app.launchAtLogin.get() → Promise<TinyLoginStatus>same
app.launchAtLogin.set(enabled: boolean) → Promise<TinyLoginStatus>tiny.app.launchAtLogin.set(enabled: boolean) → Promise<TinyLoginStatus>same
returns the resulting status
app.matchScreen(saved: Partial<TinyScreen> | TinyScreenSnapshot) → Promise<TinyScreen | null>tiny.app.matchScreen(saved: Partial<TinyScreen> | TinyScreenSnapshot) → Promise<TinyScreen | null>same
a saved TinyScreen / TinyScreenSnapshot -> the connected screen it most likely is now (ids don't survive replugs/reboots), or null
app.mousePosition() → Promise<TinyMousePosition>tiny.app.mousePosition() → Promise<TinyMousePosition>same
global cursor position + the screen it's on
app.mouseTracking.start() → Promise<{ ok: true; }>tiny.app.mouseTracking.start() → Promise<{ ok: true; }>same
app.mouseTracking.stop() → booleantiny.app.mouseTracking.stop() → Promise<boolean>same
app.nowPlaying.clear() → booleantiny.app.nowPlaying.clear() → Promise<void>same
app.nowPlaying.set(info: TinyNowPlaying) → booleantiny.app.nowPlaying.set(info: TinyNowPlaying) → Promise<void>same
also arms the media keys
—tiny.app.onMediaKey(fn: (info: TinyMediaKey) => void) → () => voidpage only
a hardware media key / Control Center transport fired
—tiny.app.onNotificationAction(fn: (info: TinyNotificationAction) => void) → () => voidpage only
action button / reply field on a notification was used
—tiny.app.onNotificationClick(fn: (id: string) => void) → () => voidpage only
—tiny.app.onOpenFiles(fn: (paths: string[]) => void) → () => voidpage only
—tiny.app.onOpenUrl(fn: (url: string) => void) → () => voidpage only
—tiny.app.onScreensChanged(fn: (screens: TinyScreen[]) => void) → () => voidpage only
screens plugged/unplugged/rearranged/rescaled; returns unsubscribe
app.paste() → Promise<TinyKeystrokeResult>tiny.app.paste() → Promise<TinyKeystrokeResult>same
keystroke('cmd+v'): paste into the frontmost app (hide first)
app.paths() → Promise<TinyPaths>tiny.app.paths() → Promise<TinyPaths>same
standard per-app directories
app.permissions.check(name: TinyPermissionName) → Promise<TinyPermissionStatus>tiny.app.permissions.check(name: TinyPermissionName) → Promise<TinyPermissionStatus>same
app.permissions.request(name: TinyPermissionName) → Promise<TinyPermissionStatus>tiny.app.permissions.request(name: TinyPermissionName) → Promise<TinyPermissionStatus>same
also prompts (accessibility opens System Settings at your app)
app.pickColor() → Promise<string | null>tiny.app.pickColor() → Promise<string | null>same
system eyedropper — NO screen-recording permission needed; '#rrggbb', or null if the user cancels
app.playSound(target?: TinySoundName | (string & {})) → Promise<boolean>tiny.app.playSound(target?: TinySoundName | (string & {})) → Promise<boolean>same
'info' | 'success' | 'alert' | 'error' (portable — mapped to each OS's nearest sound), a platform sound name ('Glass' macOS, 'SystemHand' Windows, 'complete' Linux — these do NOT port), or an audio file path.
app.power.allowSleep() → Promise<boolean>tiny.app.power.allowSleep() → Promise<boolean>same
app.power.preventSleep(reason?: string, opts?: { display?: boolean; }) → Promise<boolean>tiny.app.power.preventSleep(reason?: string, opts?: { display?: boolean; }) → Promise<boolean>same
reason shows in `pmset -g assertions`; display: true also keeps the screen on
app.presence(mode: "normal" | "menubar") → voidtiny.app.presence(mode: "normal" | "menubar") → Promise<void>same
'menubar': no Dock icon / taskbar button / app switcher entry
app.progress(value: number | null) → booleantiny.app.progress(value: number | null) → Promise<void>same
progress bar on the app icon / taskbar button: 0..1, null clears
app.quit() → voidtiny.quit() → Promise<void>same
app.say(text: string, opts?: TinySayOptions) → Promise<boolean>tiny.app.say(text: string, opts?: TinySayOptions) → Promise<boolean>same
speak text; resolves when playback finishes (false if interrupted)
app.screenAt(x: number, y: number) → Promise<TinyScreen | null>tiny.app.screenAt(x: number, y: number) → Promise<TinyScreen | null>same
the screen containing a global point; null if none
app.screenFor(rect: TinyRect) → Promise<TinyScreen | null>tiny.app.screenFor(rect: TinyRect) → Promise<TinyScreen | null>same
the screen holding most of a global rect; null if it touches none
app.screens() → Promise<TinyScreen[]>tiny.app.screens() → Promise<TinyScreen[]>same
every display, same top-left coords as win.setPosition
app.secrets.delete(key: string) → Promise<boolean>tiny.app.secrets.delete(key: string) → Promise<boolean>same
app.secrets.get(key: string) → Promise<string | null>tiny.app.secrets.get(key: string) → Promise<string | null>same
app.secrets.set(key: string, value: string) → Promise<boolean>tiny.app.secrets.set(key: string, value: string) → Promise<boolean>same
app.setAsDefaultHandler(ext: string) → Promise<"unsupported" | "ok" | "failed">tiny.app.setAsDefaultHandler(ext: string) → Promise<"unsupported" | "ok" | "failed">same
become the default opener for a file extension, or 'folder'.
app.shell.open(target: string) → Promise<true>tiny.app.shell.open(target: string) → Promise<true>same
open a URL (any scheme) or file path in the default app
app.shell.reveal(path: string) → Promise<true>tiny.app.shell.reveal(path: string) → Promise<true>same
show the file in Finder
app.shell.trash(path: string) → Promise<true>tiny.app.shell.trash(path: string) → Promise<true>same
move to the Trash (recoverable — prefer over deleting user files)
app.spotlight(query: string) → Promise<string[]>tiny.app.spotlight(query: string) → Promise<string[]>same
find files — up to 100 paths.
app.stopSpeaking() → booleantiny.app.stopSpeaking() → Promise<void>same
app.thumbnail(path: string, size?: number) → Promise<TinyThumbnail>tiny.app.thumbnail(path: string, size?: number) → Promise<TinyThumbnail>same
thumbnail png for ANY path — a content preview where Quick Look has a renderer (images, video, PDF, source files), the document/app/folder ICON otherwise, so this never fails on file type alone (macOS and Windows; Linux
app.update.check() → Promise<{ available: boolean; current: string; latest: string | null; notes: string | null; }>tiny.app.update.check() → Promise<{ available: boolean; current: string; latest: string | null; notes: string | null; }>same
notes = release notes from the manifest ("tinyjs publish --notes")
app.update.install() → Promise<boolean>tiny.app.update.install() → Promise<true>same
downloads, verifies, swaps the bundle and relaunches
app.voices() → Promise<TinyVoice[]>tiny.app.voices() → Promise<TinyVoice[]>same

System ​

backend apppage tinynotes
—tiny.capabilities.can(path: string) → booleanpage only
true when the call works here.
—tiny.capabilities.get(path: string) → TinyCapabilitypage only
why not, when it doesn't
—tiny.capabilities.list() → string[]page only
every path that works here, sorted
—tiny.capabilities.onChange(fn: (change: { added: string[]; removed: string[]; }) => void) → () => voidpage only
fires when the answer changes, including when the first one lands
—tiny.capabilities.ready: Promise<void>page only
resolves once the answer has arrived, or after 3s without one — it never hangs; a late answer fires onChange.
—tiny.capabilities.refresh() → Promise<void>page only
ask the backend again; fires onChange if anything differs
app.system.architecture() → Promise<string>tiny.system.architecture() → Promise<string>same
app.system.battery() → Promise<TinyBattery | null>tiny.system.battery() → Promise<TinyBattery | null>same
live machine state
app.system.capabilities() → Promise<Record<string, string | boolean>>tiny.system.capabilities() → Promise<Record<string, string | boolean> & { api?: { gated: boolean; denied: string[]; }; }>returns differ
What this machine can actually do — anything ABSENT is supported.
app.system.idleTime() → Promise<number>tiny.system.idleTime() → Promise<number>same
seconds since the user's last input, session-wide
app.system.info() → Promise<TinySystemInfo>tiny.system.info() → Promise<TinySystemInfo>same
app.system.isLinux() → booleantiny.system.isLinux() → booleansame
app.system.isMacOS() → booleantiny.system.isMacOS() → booleansame
app.system.isWindows() → booleantiny.system.isWindows() → booleansame
app.system.locale() → Promise<TinyLocale | null>tiny.system.locale() → Promise<TinyLocale | null>same
null where the launcher has no locale reader yet (Windows, Linux)
app.system.missing(ids?: string[] | null) → Promise<TinyRequirement[]>tiny.system.missing(ids?: string[] | null) → Promise<TinyRequirement[]>same
app.system.os() → "macos" | "windows" | "linux"tiny.system.os() → "macos" | "windows" | "linux"same
synchronous and safe during page setup (the webview's UA is decisive)
—tiny.system.promptMissing(ids?: string[] | null, opts?: { title?: string; ok?: string; cancel?: string; }) → Promise<{ missing: TinyRequirement[]; copied: boolean; }>page only
app.system.requirements(ids?: string[] | null, opts?: { refresh?: boolean; }) → Promise<TinyRequirement[]>tiny.system.requirements(ids?: string[] | null, opts?: { refresh?: boolean; }) → Promise<TinyRequirement[]>same
app.system.wifi() → Promise<TinyWifi | null>tiny.system.wifi() → Promise<TinyWifi | null>same

Theme ​

backend apppage tinynotes
app.theme.get() → Promise<{ dark: boolean; } | null>tiny.theme.get() → Promise<{ dark: boolean; } | null>same
—tiny.theme.on(fn: (dark: boolean) => void) → () => voidpage only

Clipboard ​

backend apppage tinynotes
app.clipboard.changeCount() → Promise<number>tiny.clipboard.changeCount() → Promise<number>same
—tiny.clipboard.onChange(fn: (info: { changeCount: number; self: boolean; }) => void) → () => voidpage only
after watch(); self = our own write() caused the change
app.clipboard.read() → Promise<TinyClipboardData>tiny.clipboard.read() → Promise<TinyClipboardData>same
app.clipboard.unwatch() → truetiny.clipboard.unwatch() → Promise<void>same
app.clipboard.watch(intervalMs?: number) → truetiny.clipboard.watch(intervalMs?: number) → Promise<void>same
poll for changes every intervalMs (default 500)
app.clipboard.write(data: TinyClipboardWrite) → booleantiny.clipboard.write(data: TinyClipboardWrite) → Promise<void>same

Store ​

backend apppage tinynotes
app.store.all() → Promise<Record<string, any>>tiny.store.all() → Promise<Record<string, any>>same
app.store.delete(key: string) → Promise<boolean>tiny.store.delete(key: string) → Promise<boolean>same
Same result and failure rules as set().
app.store.get(key: string) → Promise<any>tiny.store.get(key: string) → Promise<any>same
app.store.set(key: string, value: unknown) → Promise<boolean>tiny.store.set(key: string, value: unknown) → Promise<boolean>same
Resolves true once on disk.

Audio ​

backend apppage tinynotes
app.audio.balance(v: number) → voidtiny.audio.balance(v: number) → Promise<void>same
Stereo balance -1 (left) ..
app.audio.clear() → voidtiny.audio.clear() → Promise<void>same
no filters, balance back to centre
app.audio.filter(index: number, patch: Partial<TinyAudioFilter>) → voidtiny.audio.filter(index: number, patch: Partial<TinyAudioFilter>) → Promise<void>same
Retune ONE filter in place — no rebuild, no gap; what a slider drag should call
app.audio.filters(list: TinyAudioFilter[]) → voidtiny.audio.filters(list: TinyAudioFilter[]) → Promise<void>same
Replace the whole chain.
—tiny.audio.pageChain(ctx: BaseAudioContext) → TinyPageChainpage only
The same chain as Web Audio nodes IN THE PAGE — the fallback where the native chain doesn't exist (Windows).
app.audio.sampler.load(name: string, source: string | ArrayBuffer | ArrayBufferView) → Promise<true>tiny.audio.sampler.load(name: string, source: string | ArrayBuffer | ArrayBufferView | Blob) → Promise<true>args differ
Decode a sound into the bank.
app.audio.sampler.master(v: number) → truetiny.audio.sampler.master(v: number) → Promise<void>same
One master gain over the whole mixer (linear, default 1).
app.audio.sampler.play(name: string, opts?: { vol?: number; pan?: number; rate?: number; loop?: boolean; }) → Promise<{ id: number; set(patch: { vol?: number; pan?: number; rate?: number; }): true; stop(): true; }>tiny.audio.sampler.play(name: string, opts?: { vol?: number; pan?: number; rate?: number; loop?: boolean; }) → Promise<TinySamplerVoice>returns differ
Fire a voice.
app.audio.sampler.stop(id: number) → true—backend only
stop a voice by id (same as voice.stop())
app.audio.sampler.stopAll() → truetiny.audio.sampler.stopAll() → Promise<void>same
app.audio.sampler.unload(name: string) → truetiny.audio.sampler.unload(name: string) → Promise<void>same
Drop a sound and free its decoded PCM.
—tiny.audioTap.on(fn: (chunk: { pcm: string; sampleRate: number; channels: number; frames: number; t: number; }) => void) → () => voidpage only
Register a chunk handler.
—tiny.audioTap.start(opts?: { scope?: "app" | "system"; excludeSelf?: boolean; interval?: number; }) → Promise<true>page only
Start tapping.
—tiny.audioTap.stop() → Promise<void>page only

macOS only ​

backend apppage tinynotes
app.macos.ai.availability() → Promise<TinyAiAvailability>tiny.macos.ai.availability() → Promise<TinyAiAvailability>same
app.macos.ai.generate(prompt: string, opts?: { instructions?: string; }) → Promise<string>app.macos.ai.generate(prompt: string, opts: { instructions?: string; tools: TinyAiTool[]; }) → Promise<{ text: string; calls: TinyAiCall[]; }>tiny.macos.ai.generate(prompt: string, opts?: { instructions?: string; }) → Promise<string>args differ
offline, no API key.
app.macos.applescript(source: string) → Promise<string | null>tiny.macos.applescript(source: string) → Promise<string | null>same
run AppleScript in-process (no osascript spawn; 'automation' TCC); resolves the result as a string, null if it isn't text; rejects with the script error message
app.macos.moveWindow(pid: number, rect: { x: number; y: number; width: number; height: number; }) → Promise<true>tiny.macos.moveWindow(pid: number, rect: { x: number; y: number; width: number; height: number; }) → Promise<true>same
move/resize another app's frontmost window (pid from otherWindows)
app.macos.ocr(path: string) → Promise<TinyOcrResult>tiny.macos.ocr(path: string) → Promise<TinyOcrResult>same
on-device OCR via Vision (accurate mode); box normalized 0..1
app.macos.otherWindows() → Promise<TinyOtherWindow[] | null>tiny.macos.otherWindows() → Promise<TinyOtherWindow[] | null>same
other apps' on-screen windows (Accessibility); null if not granted
app.macos.quickLook(paths?: string | string[] | null) → booleantiny.macos.quickLook(paths?: string | string[] | null) → Promise<void>same
Quick Look panel for the path(s); no args closes it
app.macos.recorder.start(opts: { path: string; screenId?: number; }) → Promise<true>tiny.macos.recorder.start(opts: { path: string; screenId?: number; }) → Promise<true>same
resolves once capture is running; needs the 'screen' permission + macOS 14, rejects with the reason otherwise
app.macos.recorder.stop() → Promise<TinyRecording>tiny.macos.recorder.stop() → Promise<TinyRecording>same
app.macos.selectedText() → Promise<string | null>tiny.macos.selectedText() → Promise<string | null>same
text selected in the frontmost app (Accessibility); null if none

Events ​

The backend hooks are exports of your backend module, wired once at startup; the page subscribes at runtime and gets back an unsubscribe function.

backend apppage tinynotes
export function onMenu(id, app)tiny.menu.on(fn)menu bar click
export function onContextMenu(id, app)tiny.menu.onContext(fn)custom right-click menu click
export function onTray(id | null, app)tiny.tray.on(fn) / tiny.tray.onClick(fn)tray menu item / bare icon click (one hook on the backend, two on the page)
export function onHotkey(id, app)tiny.hotkey.on(fn)global hotkey pressed
export function onSystem(kind, value, app)tiny.theme.on(fn(dark))theme / sleep / wake — the page has sugar for theme only; sleep/wake via tiny.api.on
export function onLocale(info, app)tiny.api.on('locale', fn)no page sugar; macOS only for now (no locale reader on Windows/Linux)
export function onOpenUrl(url, app)tiny.app.onOpenUrl(fn)
export function onOpenFiles(paths, app)tiny.app.onOpenFiles(fn)
export function onNotificationClick(id, app)tiny.app.onNotificationClick(fn)
export function onNotificationAction(info, app)tiny.app.onNotificationAction(fn)
export function onMediaKey(info, app)tiny.app.onMediaKey(fn)
export function onWindowState(info, app)tiny.win.onState(fn)broadcast to every window
export function onWindowClosed(id, app)tiny.api.on('window-closed', fn)no page sugar; the page gets { id }, the hook a bare id
export function onClipboardChange(info, app)tiny.clipboard.onChange(fn)both start a watch
export function onAudioTap(chunk, app)tiny.audioTap.on(fn)only a page can start the tap
export function onUpdateAvailable(info, app)tiny.api.on('update-available', fn)no page sugar
—tiny.win.onDrop(fn)page only; the launcher's drop carries no window id, so every window hears it
export function onNavigate(info, app)tiny.api.on('navigate', fn)pages hear the lifecycle (start/commit/finish/fail/crash); only the backend answers the policy ask
export function onDownload(info, app)tiny.api.on('download', fn)pages hear progress; only the backend answers the policy ask
export function onWindowOpen(info, app)tiny.api.on('popup', fn)backend decides; the page hears 'popup' (no kind field)

Deprecated backend names ​

Still work, log a one-line warning the first time each is used, and will be removed in a future release.

old backend nameuse instead
app.getMenuItem(id: string) → Promise<TinyMenuItemState>use app.menu.get()
app.getWinState() → Promise<TinyWinState | null>use app.win.getState()
app.openWindow(id: string, opts?: TinyOpenWindowOptions) → voiduse app.win.open()
app.setAudioBalance(v: number) → voiduse app.audio.balance()
app.setAudioFilter(index: number, patch: Partial<TinyAudioFilter>) → voiduse app.audio.filter()
app.setAudioFilters(list: TinyAudioFilter[]) → voiduse app.audio.filters()
app.setContextMenu(items: TinyMenuItem[] | null) → voiduse app.menu.setContext()
app.setMenu(menus: TinyMenu[]) → voiduse app.menu.set()
app.updateMenuItem(id: string, patch?: { label?: string; checked?: boolean; enabled?: boolean; }) → voiduse app.menu.update()
app.win.getMenuItem(id: string) → Promise<TinyMenuItemState>use menu.get()
app.win.resetMenu() → voiduse menu.reset()
app.win.setMenu(menus: TinyMenu[]) → voiduse menu.set()
app.win.updateMenuItem(id: string, patch?: { label?: string; checked?: boolean; enabled?: boolean; }) → voiduse menu.update()
app.notify({ title, body, …opts })app.notify(title, body, opts)
app.info.version, app.paths.data, …(await app.info()).version, (await app.paths()).data
app.presence(anything but 'normal' | 'menubar')will throw, as the page call does