Space API Reference
The eidos.space object provides access to all data space functionality including navigation, document management, and extension node operations.
Common Methods
Section titled “Common Methods”navigate(path: string, options?)
Section titled “navigate(path: string, options?)”Navigate to a node within the current space.
navigate(path: string, options?: { target?: "_blank" | "_self" }): voidParameters:
path(string): The path to navigate to, relative to the current spaceoptions(object, optional): Navigation optionstarget(string, optional): Where to open the navigation target"_self"(default): Open in the current tab"_blank": Open in a new tab
Supported Path Formats:
"/<nodeId>"- Navigate to a specific node by ID"/<tableId>"- Navigate to a table view"/<docId>#<hash>"- Navigate to a document (supports hash anchors, e.g.,#title)"/2025-09-30"- Navigate to a date-based node"/extensions/<extensionId>"- Navigate to an extension"/blocks/<blockId>"- Navigate to a block"/file-handler/#<filePath>"- Navigate to a file handler
Example:
// Navigate to a specific tableeidos.space.navigate("/table_123")
// Navigate to a documenteidos.space.navigate("/doc_456")
// Navigate to a specific title in a documenteidos.space.navigate("/doc_456#my-title")
// Navigate to today's pageconst today = new Date().toISOString().split("T")[0]eidos.space.navigate(`/${today}`)
// Navigate to an extensioneidos.space.navigate("/extensions/my-extension")
// Navigate to a blockeidos.space.navigate("/blocks/block_789")
// Navigate to a file handler (open a file in the project folder)eidos.space.navigate("/file-handler/#~/readme.md")
// Navigate to a file handler (open a file in a mounted folder)eidos.space.navigate("/file-handler/#@/music/song.mp3")
// Open in a new tabeidos.space.navigate("/doc_456", { target: "_blank" })notify(msg: string)
Section titled “notify(msg: string)”Show a notification to the user with markdown support. Supports advanced interactions via buttons.
// Simple mode: pass a string as notification contentnotify(msg: string): void
// Full mode: pass an object to customize title and contentnotify(msg: { title: string description: string actions?: Array<{ label: string action: "reload" | "dismiss" variant?: "primary" | "secondary" }>}): voidParameters:
msg(string | object): Notification message- Simple mode: Pass a string, which will be displayed as notification content with default title “Notification”
- Full mode: Pass an object containing:
title(string): The notification titledescription(string): The notification description (supports markdown)actions(Array): Optional interactive buttonslabel(string): Button textaction(string): Action to perform:"reload"(refresh page) or"dismiss"(close notification)variant(string): Button style:"primary"(solid) or"secondary"(outline)
Examples:
// Simple mode - quick notificationeidos.space.notify("Operation completed")
// Full mode - custom title and contenteidos.space.notify({ title: "Task Completed", description: "Successfully processed **100 records** and updated the database.",})
// With interactive actionseidos.space.notify({ title: "Update Available", description: "A new version is available. Would you like to refresh the page?", actions: [ { label: "Later", action: "dismiss", variant: "secondary" }, { label: "Refresh Now", action: "reload", variant: "primary" }, ],})Node API
Section titled “Node API”The eidos.space.node object provides a unified interface for managing all node types (documents, tables, folders, dataviews, and extension nodes) with path-based addressing.
See Node API Reference for complete documentation.
Quick Examples:
// Get node by pathconst node = await eidos.space.node.get("projects/roadmap")
// Create a documentawait eidos.space.node.create("notes/idea", "doc", { content: "# My Idea",})
// Move or renameawait eidos.space.node.move("drafts/article", "published/article")
// Deleteawait eidos.space.node.delete("old-document")Table API
Section titled “Table API”Table operations have been moved to their own focused pages.
- Table SDK (CRUD): findMany, create, update, delete, etc.
- Schema Management: createTable, addField, createView, etc.
- Field Objects: Field type references and properties.
- View Objects: View type references and properties.
Document API
Section titled “Document API”The eidos.space.doc object provides document content management functionality.
Content Operations (Path-based)
Section titled “Content Operations (Path-based)”read(path: string)
Section titled “read(path: string)”Read document content by path. Returns markdown.
async read(path: string): Promise<string>Example:
// Read document contentconst content = await eidos.space.doc.read("notes/ideas")console.log(content)write(path: string, markdown: string)
Section titled “write(path: string, markdown: string)”Write document content by path (overwrites existing content).
async write(path: string, markdown: string): Promise<void>Example:
// Write content to documentawait eidos.space.doc.write("notes/ideas", "# My Ideas\n\n- Idea 1")
// Create with content via node.createawait eidos.space.node.create("notes/new-doc", "doc", { content: "# Initial content",})append(path: string, markdown: string)
Section titled “append(path: string, markdown: string)”Append content to document by path.
async append(path: string, markdown: string): Promise<void>Example:
// Append to daily logawait eidos.space.doc.append("journal/daily", "\n## Evening\nWent for a walk.")
// Append command outputconst output = await eidos.space.exec("some command")await eidos.space.doc.append("logs/output", output)prepend(path: string, markdown: string)
Section titled “prepend(path: string, markdown: string)”Prepend content to document by path.
async prepend(path: string, markdown: string): Promise<void>Example:
// Add header to existing documentawait eidos.space.doc.prepend("notes/ideas", "# Ideas Collection\n\n")
// Add timestamp to logawait eidos.space.doc.prepend( "logs/activity", `[${new Date().toISOString()}] Started\n`)Content Operations (ID-based)
Section titled “Content Operations (ID-based)”getMarkdown(id: string)
Section titled “getMarkdown(id: string)”Get the Markdown content of a document by ID.
async getMarkdown(id: string): Promise<string>Example:
const markdown = await eidos.space.doc.getMarkdown("doc_123")console.log("Markdown content:", markdown)Document Properties
Section titled “Document Properties”getProperties(id: string)
Section titled “getProperties(id: string)”Get all properties of a document (including system properties and custom properties).
async getProperties(id: string): Promise<Record<string, any>>Example:
const allProps = await eidos.space.doc.getProperties("doc_123")console.log("All properties:", allProps)setProperties(id: string, properties: Record<string, any>)
Section titled “setProperties(id: string, properties: Record<string, any>)”Set properties of a document.
async setProperties(id: string, properties: Record<string, any>): Promise<{ success: boolean; message?: string; updatedProperties?: string[] }>Example:
const result = await eidos.space.doc.setProperties("doc_123", { title: "My Document", author: "John Doe", tags: "important,work",})
if (result.success) { console.log("Properties set successfully:", result.updatedProperties)}deleteProperty(propertyName: string)
Section titled “deleteProperty(propertyName: string)”Delete the specified property column.
async deleteProperty(propertyName: string): Promise<void>Example:
await eidos.space.doc.deleteProperty("old_property")console.log("Property deleted")Theme API
Section titled “Theme API”The eidos.space.theme object provides theme management functionality for customizing the appearance of your space.
Themes are stored as CSS files in <space>/.eidos/themes/<name>/theme.css.
Theme CSS Example:
/* Define CSS variables for light mode */:root { --background: hsl(0 0% 100%); --foreground: hsl(222.2 84% 4.9%); --primary: hsl(222.2 47.4% 11.2%); --primary-foreground: hsl(210 40% 98%); /* ... more variables */}
/* Define CSS variables for dark mode */.dark { --background: hsl(222.2 84% 4.9%); --foreground: hsl(210 40% 98%); --primary: hsl(210 40% 98%); --primary-foreground: hsl(222.2 47.4% 11.2%); /* ... more variables */}list()
Section titled “list()”List all available theme names.
async list(): Promise<string[]>Returns:
- Array of theme names
Example:
const themes = await eidos.space.theme.list()console.log(themes) // ["dark-pro", "minimal", "retro"]get(name: string)
Section titled “get(name: string)”Get theme CSS content.
async get(name: string): Promise<string | null>Parameters:
name(string): Theme name
Returns:
- CSS content as string, or
nullif theme not found
Example:
const css = await eidos.space.theme.get("dark-pro")if (css) { console.log("Theme loaded:", css.length, "characters")}install(name: string, css: string)
Section titled “install(name: string, css: string)”Install or update a theme.
async install(name: string, css: string): Promise<void>Parameters:
name(string): Theme namecss(string): Theme CSS content
Example:
const css = `:root { --primary: hsl(222.2 47.4% 11.2%);}`await eidos.space.theme.install("my-theme", css)uninstall(name: string)
Section titled “uninstall(name: string)”Delete a theme.
async uninstall(name: string): Promise<void>Parameters:
name(string): Theme name to delete
Example:
await eidos.space.theme.uninstall("old-theme")getCurrent()
Section titled “getCurrent()”Get the currently active theme name.
async getCurrent(): Promise<string | null>Returns:
- Current theme name, or
nullif using default theme
Example:
const current = await eidos.space.theme.getCurrent()if (current) { console.log(`Current theme: ${current}`)} else { console.log("Using default theme")}setCurrent(name: string | null)
Section titled “setCurrent(name: string | null)”Set the active theme.
async setCurrent(name: string | null): Promise<void>Parameters:
name(string | null): Theme name to activate, ornullto reset to default
Example:
// Apply a themeawait eidos.space.theme.setCurrent("dark-pro")
// Reset to defaultawait eidos.space.theme.setCurrent(null)File System API
Section titled “File System API”Eidos provides a restricted external file API that enables access to the native file system. This is a restricted mechanism that provides secure file system access capabilities.
Supported paths:
- Project folder (
~/) - The project directory where.eidosis located - Mounted folders (
@/) - Externally mounted directories
Path Format
Section titled “Path Format”| Path Format | Description |
|---|---|
~/src/main.js | Project folder (where .eidos is located) |
@/music/song.mp3 | Mounted folder |
readdir(path, options?)
Section titled “readdir(path, options?)”List directory contents (like Node.js fs.readdir).
readdir(path: string): Promise<string[]>readdir(path: string, options: { withFileTypes: true }): Promise<IDirectoryEntry[]>readdir(path: string, options?: { withFileTypes?: boolean recursive?: boolean}): Promise<string[] | IDirectoryEntry[]>Parameters:
path(string): Directory path, supports~/or@/prefixoptions.withFileTypes(boolean): Optional, returnsIDirectoryEntryobjects with type informationoptions.recursive(boolean): Optional, recursively list all subdirectories
Returns:
- By default, returns an array of file names
- With
withFileTypes: true, returns an array ofIDirectoryEntryobjects withname,path,parentPath, andkindproperties - With
recursive: true, recursively lists all subdirectories
Examples:
// List project root directoryconst files = await eidos.space.fs.readdir("~/")console.log(files)// ["package.json", "src", "README.md"]
// List project subdirectoryconst srcFiles = await eidos.space.fs.readdir("~/src")
// Get entries with type informationconst entries = await eidos.space.fs.readdir("~/", { withFileTypes: true,})entries.forEach((entry) => { console.log( `${entry.name}: ${entry.kind === "directory" ? "directory" : "file"}` )})// package.json: file// src: directory// README.md: file
// Recursively list all files (including subdirectories)const allFiles = await eidos.space.fs.readdir("~/", { recursive: true })console.log(allFiles)// ["package.json", "src", "src/index.js", "src/utils.js", "README.md"]
// Recursively list with type informationconst allEntries = await eidos.space.fs.readdir("~/", { withFileTypes: true, recursive: true,})
// List mounted folderconst musicFiles = await eidos.space.fs.readdir("@/music")
// Recursively list all files in mounted folderconst allMusicFiles = await eidos.space.fs.readdir("@/music", { recursive: true,})
// Access .eidos/files directory (naturally available through ~/ access)const eidosFiles = await eidos.space.fs.readdir("~/.eidos/files")console.log(eidosFiles)// ["photo.jpg", "document.pdf", "data.json"]
// Recursively list all files in .eidos/filesconst allEidosFiles = await eidos.space.fs.readdir("~/.eidos/files", { recursive: true,})Supported paths:
~/- Project root~/src- Project subdirectory~/.eidos/files/- .eidos subdirectory within project folder@/music- Mounted folder root@/music/albums- Mounted folder subdirectory
mkdir(path, options?)
Section titled “mkdir(path, options?)”Create directory (like Node.js fs.mkdir).
mkdir(path: string, options?: { recursive?: boolean }): Promise<string | undefined>Parameters:
path(string): Directory path to createoptions.recursive(boolean): Optional, whether to create parent directories
Returns:
- Returns the created directory path, or
undefinedif directory already exists
Examples:
// Create directory in mounted folderawait eidos.space.fs.mkdir("@/work/projects")
// Recursively create nested directoriesawait eidos.space.fs.mkdir("@/work/2024/Q1", { recursive: true })Common use cases:
// Organize files by year and monthconst today = new Date()const year = today.getFullYear()const month = String(today.getMonth() + 1).padStart(2, "0")await eidos.space.fs.mkdir(`@/archive/${year}/${month}`, { recursive: true,})
// Check if directory exists, create if nottry { await eidos.space.fs.readdir("@/work/temp")} catch { await eidos.space.fs.mkdir("@/work/temp")}readFile(path, options?)
Section titled “readFile(path, options?)”Read file contents (like Node.js fs.readFile).
readFile(path: string): Promise<Uint8Array>readFile(path: string, options: { encoding: BufferEncoding; flag?: string } | BufferEncoding): Promise<string>readFile(path: string, options?: { encoding?: BufferEncoding | null flag?: string}): Promise<string | Uint8Array>Parameters:
path(string): File path, supports~/or@/prefixoptions(optional): Read optionsencoding(BufferEncoding | null): File encoding, e.g.,'utf8','utf-8','base64', etc.flag(string): File system flag, e.g.,'r'(default)
Returns:
- Returns
Uint8Array(binary data) when noencodingis specified - Returns
string(text content) whenencodingis specified
Examples:
// Read text fileconst text = await eidos.space.fs.readFile("~/readme.md", "utf8")console.log(text) // "# My Project\nThis is a sample project..."
// Read JSON fileconst configText = await eidos.space.fs.readFile("~/config.json", "utf8")const config = JSON.parse(configText)
// Read using options objectconst content = await eidos.space.fs.readFile("~/data.txt", { encoding: "utf8",})
// Read binary file (images, videos, etc.)const imageData = await eidos.space.fs.readFile("~/image.png")console.log(imageData) // Uint8Array(1234) [137, 80, 78, 71, ...]
// Read file from mounted folderconst musicData = await eidos.space.fs.readFile("@/music/song.mp3")Common use cases:
// Read and parse JSON config fileasync function loadConfig(path: string) { const content = await eidos.space.fs.readFile(path, "utf8") return JSON.parse(content)}
// Read image and convert to base64async function imageToBase64(path: string) { const data = await eidos.space.fs.readFile(path) const base64 = btoa(String.fromCharCode(...data)) return `data:image/png;base64,${base64}`}
// Read text file and process line by lineasync function processTextFile(path: string) { const content = await eidos.space.fs.readFile(path, "utf8") const lines = content.split("\n") return lines.filter((line) => line.trim().length > 0)}writeFile(path, data, options?)
Section titled “writeFile(path, data, options?)”Write file contents (like Node.js fs.writeFile).
writeFile( path: string, data: string | Uint8Array, options?: { encoding?: BufferEncoding | null mode?: number flag?: string } | BufferEncoding): Promise<void>Parameters:
path(string): File path, supports~/or@/prefixdata(string | Uint8Array): Content to writestring: Text contentUint8Array: Binary data
options(optional): Write optionsencoding(BufferEncoding | null): File encoding, default'utf8'mode(number): File permission mode, default0o666flag(string): File system flag, default'w'(overwrite)
Examples:
// Write text fileawait eidos.space.fs.writeFile("~/hello.txt", "Hello, World!")
// Write JSON dataconst config = { theme: "dark", language: "en-US" }await eidos.space.fs.writeFile( "~/config.json", JSON.stringify(config, null, 2), "utf8")
// Write binary dataconst imageData = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10])await eidos.space.fs.writeFile("~/image.png", imageData)
// Write with options objectawait eidos.space.fs.writeFile("~/data.txt", "content", { encoding: "utf8", mode: 0o644,})
// Write to mounted folderawait eidos.space.fs.writeFile("@/backup/data.json", JSON.stringify(data))Common use cases:
// Save user configurationasync function saveConfig(config: object) { const content = JSON.stringify(config, null, 2) await eidos.space.fs.writeFile("~/config.json", content, "utf8") eidos.space.notify("Configuration saved")}
// Export data to fileasync function exportData(data: any[], filename: string) { const csv = data.map((row) => Object.values(row).join(",")).join("\n") await eidos.space.fs.writeFile(`@/exports/${filename}`, csv, "utf8")}
// Save Canvas screenshotasync function saveCanvasToFile(canvas: HTMLCanvasElement, path: string) { const blob = await new Promise<Blob>((resolve) => canvas.toBlob(resolve as any, "image/png") ) const arrayBuffer = await blob!.arrayBuffer() const data = new Uint8Array(arrayBuffer) await eidos.space.fs.writeFile(path, data)}
// Create log file (append mode)async function appendLog(message: string) { const timestamp = new Date().toISOString() const logEntry = `[${timestamp}] ${message}\n` try { const existing = await eidos.space.fs.readFile("~/app.log", "utf8") await eidos.space.fs.writeFile("~/app.log", existing + logEntry) } catch { await eidos.space.fs.writeFile("~/app.log", logEntry) }}stat(path)
Section titled “stat(path)”Get file or directory statistics (like Node.js fs.stat).
stat(path: string): Promise<IStats>
interface IStats { size: number // File size in bytes mtimeMs: number // Last modified time (milliseconds timestamp) atimeMs: number // Last accessed time (milliseconds timestamp) ctimeMs: number // Status change time (milliseconds timestamp) birthtimeMs: number // Creation time (milliseconds timestamp) isFile: boolean // Whether it's a file isDirectory: boolean // Whether it's a directory isSymbolicLink: boolean // Whether it's a symbolic link isBlockDevice: boolean // Whether it's a block device isCharacterDevice: boolean // Whether it's a character device isFIFO: boolean // Whether it's a FIFO pipe isSocket: boolean // Whether it's a socket mode: number // File permission mode uid: number // User ID gid: number // Group ID}Parameters:
path(string): File or directory path, supports~/or@/prefix
Returns:
IStatsobject containing detailed file or directory information
Examples:
// Get file informationconst stats = await eidos.space.fs.stat("~/readme.md")console.log(`File size: ${stats.size} bytes`)console.log(`Is file: ${stats.isFile}`)console.log(`Last modified: ${new Date(stats.mtimeMs)}`)
// Check if it's a file or directoryconst stats = await eidos.space.fs.stat("~/src")if (stats.isDirectory) { console.log("This is a directory")} else if (stats.isFile) { console.log("This is a file")}
// Get file info from mounted folderconst musicStats = await eidos.space.fs.stat("@/music/song.mp3")console.log(`Song size: ${(musicStats.size / 1024 / 1024).toFixed(2)} MB`)Common use cases:
// Check if file existsasync function fileExists(path: string): Promise<boolean> { try { await eidos.space.fs.stat(path) return true } catch { return false }}
// Get human-readable file sizeasync function getFileSize(path: string): Promise<string> { const stats = await eidos.space.fs.stat(path) const bytes = stats.size if (bytes < 1024) return `${bytes} B` if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB` if (bytes < 1024 * 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(2)} MB` return `${(bytes / 1024 / 1024 / 1024).toFixed(2)} GB`}
// List files in directory with their sizesasync function listFilesWithSize(dirPath: string) { const files = await eidos.space.fs.readdir(dirPath) const filesWithSize = await Promise.all( files.map(async (file) => { const filePath = `${dirPath}/${file}` const stats = await eidos.space.fs.stat(filePath) return { name: file, size: stats.size, isDirectory: stats.isDirectory, modified: new Date(stats.mtimeMs), } }) ) return filesWithSize}
// Find recently modified filesasync function findRecentlyModified(dirPath: string, days: number = 7) { const files = await eidos.space.fs.readdir(dirPath) const now = Date.now() const cutoff = now - days * 24 * 60 * 60 * 1000
const recentFiles = [] for (const file of files) { const stats = await eidos.space.fs.stat(`${dirPath}/${file}`) if (stats.isFile && stats.mtimeMs > cutoff) { recentFiles.push({ name: file, modified: new Date(stats.mtimeMs), }) } } return recentFiles.sort((a, b) => b.modified.getTime() - a.modified.getTime())}
// Compare modification times of two filesasync function isNewer(file1: string, file2: string): Promise<boolean> { const stats1 = await eidos.space.fs.stat(file1) const stats2 = await eidos.space.fs.stat(file2) return stats1.mtimeMs > stats2.mtimeMs}Supported paths:
~/- Project root~/src/index.js- Project file@/music- Mounted folder root@/music/albums/song.mp3- File in mounted folder
rename(oldPath, newPath)
Section titled “rename(oldPath, newPath)”Rename a file or directory (like Node.js fs.rename).
rename(oldPath: string, newPath: string): Promise<void>Parameters:
oldPath(string): Current file or directory path, supports~/or@/prefixnewPath(string): New file or directory path, supports~/or@/prefix
Important Notes:
- Both paths must be either virtual paths or real paths, cannot mix them
- For virtual paths (e.g., nodes under
~/.eidos/__NODES__/), renaming updates the database records - For real paths, renaming modifies files or directories in the file system
- Renaming can also be used to move files or directories to different locations
Examples:
// Rename a fileawait eidos.space.fs.rename("~/old-name.md", "~/new-name.md")
// Rename a directoryawait eidos.space.fs.rename("~/old-folder", "~/new-folder")
// Move file to different directoryawait eidos.space.fs.rename("~/src/old.js", "~/lib/new.js")
// Rename file in mounted folderawait eidos.space.fs.rename("@/music/old-song.mp3", "@/music/new-song.mp3")
// Rename a node (virtual path)await eidos.space.fs.rename( "~/.eidos/__NODES__/node-id", "~/.eidos/__NODES__/New Name")
// Rename an extension (virtual path)await eidos.space.fs.rename( "~/.eidos/__EXTENSIONS__/ext-id", "~/.eidos/__EXTENSIONS__/new-slug.ts")Common use cases:
// Batch rename filesasync function renameFiles(files: string[], prefix: string) { for (const file of files) { const dir = file.substring(0, file.lastIndexOf("/")) const name = file.substring(file.lastIndexOf("/") + 1) const newName = `${prefix}-${name}` await eidos.space.fs.rename(file, `${dir}/${newName}`) }}
// Organize files by dateasync function organizeByDate(filePath: string) { const stats = await eidos.space.fs.stat(filePath) const date = new Date(stats.mtimeMs) const year = date.getFullYear() const month = String(date.getMonth() + 1).padStart(2, "0") const dir = `@/archive/${year}/${month}`
// Ensure directory exists await eidos.space.fs.mkdir(dir, { recursive: true })
// Move file const fileName = filePath.substring(filePath.lastIndexOf("/") + 1) await eidos.space.fs.rename(filePath, `${dir}/${fileName}`)}
// Rename with backupasync function renameWithBackup(oldPath: string, newPath: string) { const backupPath = `${oldPath}.backup` // First copy the file (by reading and writing) const content = await eidos.space.fs.readFile(oldPath) await eidos.space.fs.writeFile(backupPath, content) // Then rename the original file await eidos.space.fs.rename(oldPath, newPath)}watch(path, options?)
Section titled “watch(path, options?)”Watch for changes on a file or directory (like Node.js fs.watch).
watch(path: string, options?: IWatchOptions): AsyncIterable<IWatchEvent>
interface IWatchOptions { encoding?: BufferEncoding // Encoding format, default 'utf8' persistent?: boolean // Whether to persist watching, default true recursive?: boolean // Whether to recursively watch subdirectories, default false signal?: AbortSignal // Signal to cancel watching}
interface IWatchEvent { eventType: 'rename' | 'change' // Event type: 'rename' means file/directory created or deleted, 'change' means file content changed filename: string // Name or path of the changed file}Parameters:
path(string): File or directory path to watch, supports~/or@/prefixoptions(IWatchOptions, optional): Watch options
Returns:
- Returns an
AsyncIterable<IWatchEvent>that can be used withfor await...ofloop to watch for changes
Important Notes:
- For virtual paths (e.g.,
~/.eidos/__NODES__/), only root virtual directories can be watched - Use
AbortSignalto gracefully stop watching eventTypeof'rename'indicates file/directory creation or deletioneventTypeof'change'indicates file content changes
Examples:
// Watch for changes in nodes directoryfor await (const event of eidos.space.fs.watch("~/.eidos/__NODES__/")) { console.log( `Node ${event.filename} ${event.eventType === "rename" ? "created/deleted" : "content changed"}` )}
// Watch for changes in extensions directoryfor await (const event of eidos.space.fs.watch("~/.eidos/__EXTENSIONS__/")) { if (event.eventType === "rename") { console.log(`Extension ${event.filename} created or deleted`) } else { console.log(`Extension ${event.filename} content updated`) }}
// Recursively watch directory and subdirectoriesfor await (const event of eidos.space.fs.watch("~/src", { recursive: true,})) { console.log(`File ${event.filename} changed`)}
// Use AbortSignal to control watch durationconst controller = new AbortController()const { signal } = controller
// Automatically stop watching after 5 secondssetTimeout(() => controller.abort(), 5000)
for await (const event of eidos.space.fs.watch("~/", { recursive: true, signal,})) { console.log(`Change: ${event.filename}`)}
// Watch mounted folderfor await (const event of eidos.space.fs.watch("@/music", { recursive: true,})) { console.log(`Music file ${event.filename} changed`)}Common use cases:
// Watch file changes and auto-reloadasync function watchAndReload(filePath: string, callback: () => void) { for await (const event of eidos.space.fs.watch(filePath)) { if (event.eventType === "change") { console.log(`File ${filePath} updated, reloading...`) callback() } }}
// Watch directory changes and sync to databaseasync function syncDirectoryChanges(dirPath: string) { for await (const event of eidos.space.fs.watch(dirPath, { recursive: true, })) { if (event.eventType === "rename") { // File created or deleted const fullPath = `${dirPath}/${event.filename}` try { await eidos.space.fs.stat(fullPath) // File exists, it's a creation console.log(`New file: ${fullPath}`) // Sync to database... } catch { // File doesn't exist, it's a deletion console.log(`File deleted: ${fullPath}`) // Delete from database... } } else { // File content changed console.log(`File updated: ${event.filename}`) // Update database... } }}
// Watch with timeoutasync function watchWithTimeout(path: string, timeoutMs: number) { const controller = new AbortController() const timeout = setTimeout(() => controller.abort(), timeoutMs)
try { for await (const event of eidos.space.fs.watch(path, { signal: controller.signal, })) { console.log(`Change: ${event.filename}`) } } catch (error) { if (error.name === "AbortError") { console.log("Watch timed out") } else { throw error } } finally { clearTimeout(timeout) }}
// Watch multiple directoriesasync function watchMultipleDirs(paths: string[]) { const watchers = paths.map((path) => eidos.space.fs.watch(path, { recursive: true }) )
// Use Promise.race to watch all directories const events = watchers.map(async function* (watcher) { for await (const event of watcher) { yield event } })
// Merge all event streams for await (const event of mergeAsyncIterables(...events)) { console.log(`Change: ${event.filename}`) }}
// Helper function: merge multiple AsyncIterablesasync function* mergeAsyncIterables<T>( ...iterables: AsyncIterable<T>[]): AsyncIterable<T> { const iterators = iterables.map((it) => it[Symbol.asyncIterator]()) const nextPromises = iterators.map((it) => it.next())
while (nextPromises.length > 0) { const { value, done } = await Promise.race( nextPromises.map((p, i) => p.then((result) => ({ ...result, index: i }))) )
if (done) { nextPromises.splice(value.index, 1) iterators.splice(value.index, 1) } else { yield value.value nextPromises[value.index] = iterators[value.index].next() } }}Supported paths:
~/- Project root~/src- Project subdirectory~/.eidos/__NODES__/- Nodes directory (virtual path, root only)~/.eidos/__EXTENSIONS__/- Extensions directory (virtual path, root only)@/music- Mounted folder root@/music/albums- Mounted folder subdirectory
Graft (Version Control) API
Section titled “Graft (Version Control) API”The eidos.space.graft object provides access to Graft, a distributed version control system for SQLite databases. Think of it as Git for your database: it allows you to track changes, synchronize with remote repositories, and manage different versions of your data space.
status()
Section titled “status()”Get the current synchronization status, including ahead/behind commit counts.
async status(): Promise<{ ahead: number // Number of local commits not yet pushed behind: number // Number of remote commits not yet pulled last_pushed_at: string last_pulled_at: string}>Example:
const status = await eidos.space.graft.status()if (status.behind > 0) { console.log(`You are ${status.behind} commits behind. pulling...`) await eidos.space.graft.pull()}pull()
Section titled “pull()”Pull the latest changes from the remote repository.
async pull(): Promise<void>Example:
await eidos.space.graft.pull()console.log("Pull completed successfully")push()
Section titled “push()”Push local commits to the remote repository.
async push(): Promise<void>Example:
await eidos.space.graft.push()console.log("Push completed successfully")fetch()
Section titled “fetch()”Fetch the latest changes from the remote repository without merging them.
async fetch(): Promise<void>Example:
await eidos.space.graft.fetch()const status = await eidos.space.graft.status()console.log(`Behind by ${status.behind} commits after fetch`)clone(remoteLogId?: string)
Section titled “clone(remoteLogId?: string)”Clone a remote repository into the current space.
async clone(remoteLogId?: string): Promise<void>Parameters:
remoteLogId(string, optional): The ID of the remote log to clone. If not provided, uses the default remote.
Example:
// Clone the default remoteawait eidos.space.graft.clone()
// Clone a specific remoteawait eidos.space.graft.clone("https://sync.eidos.space/logs/abc123")info()
Section titled “info()”Get information about the current Graft repository.
async info(): Promise<any>tags()
Section titled “tags()”List all tags in the repository.
async tags(): Promise<any[]>audit()
Section titled “audit()”Audit the local database against the remote state to check for consistency and integrity issues.
async audit(): Promise<any>volumes()
Section titled “volumes()”List the volumes associated with this space. A volume represents a distinct storage unit or branch in Graft.
async volumes(): Promise<any[]>version()
Section titled “version()”Get the version of the Graft extension and protocol being used.
async version(): Promise<{ graft_version: string }>