Skip to content

Plugin API Reference

This document provides a comprehensive reference for @eidos.space/plugin-sdk types, interfaces, and host capabilities.

Install the TypeScript types in your plugin project:

Terminal window
pnpm add -D @eidos.space/plugin-sdk

Every plugin declares its metadata, permissions, and extension points in plugin.json (or exports a manifest object from a standalone .ts / .js file).

export interface PluginManifest {
apiVersion: 1
id: string
name: string
version: string
icon?: PluginIconDefinition
requires?: { pluginApi: string }
// Contribution declarations
views?: ViewDeclaration[]
actions?: ActionDeclaration[]
formatters?: FormatterDeclaration[]
placements?: Placement[]
// Background extension entry
extension?: string
// Permissions and resource configurations
workspace?: {
files?: boolean | { read?: boolean; write?: boolean }
}
settings?: Record<string, SettingDeclaration>
storage?: { maxBytes: number }
browser?: {
workers?: boolean
networkOrigins?: string[]
}
connections?: Record<
string,
{ title: string; url: string; configurable?: boolean }
>
// Standalone host theme
kind?: "theme"
theme?: ThemeDeclaration
}
Field Type Description
apiVersion 1 Plugin host API contract version (currently 1).
id string Unique identifier (recommended reverse domain notation, e.g. com.example.viewer).
name string Human-readable plugin display name.
version string Semantic version string (e.g. 0.1.0).
icon PluginIconDefinition Plugin brand icon (SVG paths object, relative file path, or Data URL).
requires.pluginApi string Minimum host API contract. Current Lite executable plugins require "2.0.0"; pure "1.6.0" themes remain supported.
extension string Background module entrypoint (e.g. "./src/extension.ts"). Required if actions or formatters are declared.
views ViewDeclaration[] User interface view contributions.
actions ActionDeclaration[] Command and shortcut contributions.
formatters FormatterDeclaration[] Document formatting provider contributions.
placements Placement[] UI entrypoint mappings for views and actions.
workspace.files boolean | { read?: boolean; write?: boolean } Permission grant for Space-wide filesystem read/write access.
settings Record<string, SettingDeclaration> Declarations for plugin settings rendered in the plugin configuration panel.
storage.maxBytes number Private persistent storage quota in bytes (up to 1 GiB).
browser.networkOrigins string[] Whitelisted HTTPS origins for anonymous network requests.
kind / theme "theme" / ThemeDeclaration Declares a standalone Eidos Lite host theme (contains no executable code).

export interface ViewDeclaration {
id: string
title: string
entry: string
context: "file" | "page" | "table" | "document" | "media" | "eidos"
access?: "read" | "write"
icon?: PluginIconDefinition
configuration?: ViewConfiguration
}
  • context: Physical entity target. Standard values are "file" (opened on workspace files) and "page" (standalone panel). "document", "media", and "eidos" are supported for compatibility.
  • access: File access level ("read" or "write", defaults to "read").
  • configuration: Used with context: "table", declaring view settings schema stored in view.properties.plugin.
export interface ActionDeclaration {
id: string
title: string
context: "workspace" | "file" | "document" | "table"
access?: "read" | "write"
extensions?: string[]
icon?: PluginIconDefinition
}
  • context: Target scope. "workspace" for global Space commands; "file" for file-targeted context actions.
  • extensions: File extensions filter when the action is targeted at specific formats.
export type Placement =
| { location: "command-palette"; action: string }
| { location: "file/open"; view: string; extensions: string[] }
| { location: "navigation"; view: string }
| { location: "table/view"; view: string }
| { location: "file/context"; action: string }
| { location: "table/context"; action: string }
| { location: "view/toolbar"; view: string; action: string }
| { location: "keybinding"; action: string; key: string; mac?: string; linux?: string }
| { location: "plugin/settings"; view: string }
Location Target Description
"command-palette" Action Injected into the global Command Palette (Cmd+K / Ctrl+K).
"file/open" View Injected into file right-click menu Open with, claiming matching extensions.
"navigation" View Mounted as a primary item in the Space left navigation sidebar.
"table/view" View Mounted in the table view switcher menu (New View).
"file/context" Action Injected into the file list right-click context menu.
"table/context" Action Injected into the table row/selection context menu (supports dynamic providers).
"view/toolbar" Action Displayed on the top toolbar of a specific view.
"keybinding" Action Binds a global or scoped keyboard shortcut (e.g. "Mod+Alt+F").
"plugin/settings" View Embedded inside the plugin’s configuration detail panel.

Both ViewContext and ActionContext inherit the complete set of first-class capabilities via CommonContext:

export interface CommonContext extends Lifetime {
readonly fs: PluginFileSystem
readonly storage: PluginStorage
readonly network: PluginNetwork
readonly settings: Settings
readonly ui: HostUI
}
export interface Lifetime {
readonly signal: AbortSignal
readonly subscriptions: { add<T extends Disposable>(value: T): T }
}

Plugins run locally in isolated sandboxes. ctx.fs provides complete local filesystem primitives:

export interface PluginFileSystem {
/** Reads the text content of a file (subject to a 2 MiB preview limit). */
readText(path: string): Promise<string>
/** Writes text to a file. Missing parent directories are created automatically. */
writeText(path: string, content: string): Promise<void>
/** Reads binary data from a file (supports up to 16 MiB images, media, models, etc.). */
readBinary(path: string): Promise<Uint8Array>
/** Writes binary data to a file (up to 16 MiB). Missing parent directories are created automatically. */
writeBinary(path: string, content: Uint8Array): Promise<void>
/** Deletes a file within the Space. */
delete(path: string): Promise<void>
/** Renames or moves a regular file within the Space; rejects existing targets with ALREADY_EXISTS. */
rename(oldPath: string, newPath: string): Promise<void>
/**
* Lists files in a directory.
* If folder is omitted in a file view, defaults to the directory of the opened file.
* Optionally filtered by options.extensions.
*/
list(folder?: string, options?: { extensions?: string[] }): Promise<FileStat[]>
/** Inspects file or directory metadata. Returns null if missing or inaccessible. */
stat(path: string): Promise<FileStat | null>
/**
* Returns a privileged native streaming protocol URL (eidos-space-media:).
* Supports HTTP Range requests and instantaneous seek. If path is omitted, defaults to the current file.
*/
getUrl(path?: string): Promise<string>
/** Watches a file or directory for live change events. Disposed automatically on unmount. */
watch(pathOrFolder: string, listener: () => void): Promise<Disposable>
}
  • Companion File Scope: In file views or actions without workspace.files: true, ctx.fs operations are strictly confined to the directory of the opened file and companion files (e.g. movie.srt next to movie.mp4).
  • Space-Wide Access: Declaring workspace.files: true grants permission to read and write anywhere within the active Space.
  • Sandbox Isolation: Traversal outside the Space (..) and access to internal directories (such as .graft) are strictly rejected.
export interface HostUI {
/** Displays a toast notification in the host interface. */
notify(message: string): Promise<void>
/** Displays a modal selection dialog. */
select(options: {
title: string
options: Array<{ id: string; label: string }>
}): Promise<{ status: "selected"; id: string } | { status: "cancelled" }>
/** Displays a modal confirmation dialog. */
confirm(options: {
title: string
message: string
}): Promise<{ status: "confirmed" | "cancelled" }>
/** Requests the host to open a relative file path in its default or associated editor. */
openFile(relativePath: string): Promise<void>
/** Navigates internally between declared page views of this plugin. */
navigate(viewId: string, route?: string): Promise<void>
}

Private binary key-value persistence on the local device, shared across Spaces for the same plugin:

export interface PluginStorage {
write(key: string, value: Uint8Array): Promise<void>
read(key: string): Promise<Uint8Array | null>
list(prefix?: string): Promise<Array<{ key: string; size: number }>>
remove(key: string): Promise<void>
}

Performs restricted HTTPS requests to whitelisted domains declared in browser.networkOrigins:

export interface PluginNetwork {
read(request: {
url: string
range?: { offset: number; length: number }
}): Promise<{ data: Uint8Array; status: number; etag?: string }>
}

Manages plugin settings declared in manifest.settings (persisted per Space):

export interface Settings {
get(key: string): Promise<SettingValue>
update(key: string, value: SettingValue): Promise<void>
reset(key: string): Promise<void>
observe(
listener: (values: Record<string, SettingValue>) => void,
onError?: ObserverErrorHandler
): Promise<{ values: Record<string, SettingValue>; subscription: Disposable }>
}

Each view entrypoint exports a default mount function:

import type { ViewContext, Disposable } from "@eidos.space/plugin-sdk"
export default function mount(
ctx: ViewContext,
root: HTMLElement
): void | Disposable | Promise<void | Disposable> {
root.textContent = "Hello View"
return {
dispose() {
root.replaceChildren()
},
}
}
export interface ViewContext extends CommonContext {
readonly binding: ViewBinding
// Available according to the opened file type:
readonly file?: FileContext // Available for all file views
readonly editor?: TextDocument // Available when viewing text files
readonly table?: TableContext // Available when viewing .eidos tables
readonly eidos?: EidosFileContext // Available when viewing .eidos files
}

Available in any view opened through file/open:

export interface FileContext {
readonly path: string // Space-relative path (e.g. "notes/todo.md")
readonly name: string // Full filename (e.g. "todo.md")
readonly baseName: string // Filename without extension (e.g. "todo")
readonly extension: string // Extension (e.g. ".md")
readonly size: number // File size in bytes
readonly mimeType?: string // Optional media MIME type
}

When viewing text files, ctx.editor provides working-copy coordination:

export interface TextDocument {
read(): Promise<TextSnapshot>
observe(listener: (state: TextSnapshot) => void): Promise<{ snapshot: TextSnapshot; subscription: Disposable }>
edit(change: { text: string; expectedVersion: string; label?: string }): Promise<{ status: "applied" | "stale"; snapshot: TextSnapshot }>
save(): Promise<{ status: "saved" | "conflict"; snapshot: TextSnapshot }>
undo(): Promise<TextSnapshot>
redo(): Promise<TextSnapshot>
}

Database Tables and .eidos Context (ctx.table & ctx.eidos)

Section titled “Database Tables and .eidos Context (ctx.table & ctx.eidos)”

Available when viewing .eidos SQLite database files or embedded table views:

export interface TableContext {
readonly tableId: string
readonly viewId: string
readonly pluginConfig: TablePluginConfig
read(): Promise<TableViewSnapshot>
getPage(options: { offset: number; limit: number }): Promise<EidosFileRowPage>
aggregate(options: TableAggregateOptions): Promise<TableAggregateResult>
updateProperties(properties: Record<string, unknown>): Promise<void>
openRecord(rowId: string): Promise<void>
observe(listener: () => void): Disposable
}
export interface EidosFileContext {
listTables(): Promise<Array<{ id: string; name: string }>>
readTable(tableId: string): Promise<{ fields: EidosFileFieldInfo[] }>
readPluginConfig(tableId: string): Promise<TablePluginConfigSnapshot>
writePluginConfig(tableId: string, input: { value: JsonObject | null; expectedVersion: string }): Promise<TablePluginConfigSnapshot>
}

Actions & Background Extension (activate & ActionContext)

Section titled “Actions & Background Extension (activate & ActionContext)”

Plugins with actions or formatters specify an extension entry in plugin.json:

import type { ExtensionContext } from "@eidos.space/plugin-sdk"
export default function activate(ctx: ExtensionContext) {
ctx.actions.register("format-markdown", async (actionCtx) => {
// actionCtx provides full CommonContext
})
}
export interface ExtensionContext extends Lifetime {
readonly actions: {
register(id: string, handler: (ctx: ActionContext) => void | Promise<void>): Disposable
registerTableProvider(id: string, provider: TableActionProvider): Disposable
}
readonly formatters: {
register(id: string, provider: FormatterProvider): Disposable
}
readonly settings: Settings
}
export interface ActionContext extends CommonContext {
readonly binding: ActionBinding
readonly file?: FileContext
readonly editor?: TextDocument
readonly table?: TableContext
}
export interface FormatterProvider {
format(input: { text: string; path: string; signal: AbortSignal }): { text: string } | Promise<{ text: string }>
}

Triggered automatically when the user invokes Format Document (Shift+Option+F / Shift+Alt+F).