commit 23bfd2e2e213da57e7789ab6ee18200aae9ee23c Author: hermes Date: Thu Apr 23 13:34:59 2026 +0000 feat: initial implementation of backlinks extension diff --git a/README.md b/README.md new file mode 100644 index 0000000..c8102c1 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# Obsidian Local REST API — Backlinks Extension + +This is an extension for the [Obsidian Local REST API](https://github.com/coddingtonbear/obsidian-local-rest-api) plugin. It adds a new endpoint to retrieve backlinks for a specific note. + +## Features +- **GET `/extensions/backlinks/{filepath}`**: Returns all notes that link to the specified file. + +## Installation +1. Install the [Obsidian Local REST API](https://github.com/coddingtonbear/obsidian-local-rest-api) plugin. +2. Download the `main.js` and `manifest.json` from the `/dist` folder of this repository. +3. Create a folder named `obsidian-local-rest-api-backlinks` in your vault's `.obsidian/plugins/` directory. +4. Place `main.js` and `manifest.json` into that folder. +5. Restart Obsidian or reload plugins. +6. Enable the plugin in **Settings > Community Plugins**. + +## Usage Example +```bash +curl -k -H "Authorization: Bearer YOUR_API_KEY" \ + "https://127.0.0.1:PORT/extensions/backlinks/MyNote.md" +``` + +## Development +```bash +npm install +npm run build +``` diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..4306cd7 --- /dev/null +++ b/manifest.json @@ -0,0 +1,9 @@ +{ + "id": "obsidian-local-rest-api-backlinks", + "name": "Local REST API — Backlinks Extension", + "version": "1.0.0", + "minAppVersion": "1.0.0", + "description": "Adds a /extensions/backlinks/ route to Obsidian Local REST API to retrieve backlinks for a specific note.", + "author": "Hermes", + "isDesktopOnly": false +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..b9e64a8 --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "obsidian-local-rest-api-backlinks", + "version": "1.0.0", + "description": "Obsidian Local REST API Backlinks Extension", + "main": "main.js", + "types": "main.d.ts", + "dependencies": { + "obsidian": "npm:obsidian@^1.0.0", + "obsidian-local-rest-api": "npm:obsidian-local-rest-api@^2.5.0" + }, + "devDependencies": { + "typescript": "^5.0.0", + "esbuild": "^0.19.0" + }, + "scripts": { + "build": "esbuild src/main.ts --bundle --outfile=dist/main.js --external:obsidian --platform=node --target=es2020" + } +} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..176e6b5 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,77 @@ +import { Plugin, TFile, normalizePath } from "obsidian"; +import { + LocalRestApiPublicApi, + Route, + Request, + Response, +} from "obsidian-local-rest-api"; + +interface LinkMetadata { + displayText: string; + link: string; + original: string; + position: { start: unknown; end: unknown }; +} + +interface BacklinksData { + data: Record; +} + +export default class BacklinksExtension extends Plugin { + async onload() { + console.log("Loading Local REST API Backlinks Extension..."); + + const api = (this.app as any).plugins.plugins[ + "obsidian-local-rest-api" + ]?.api as LocalRestApiPublicApi | undefined; + + if (!api) { + console.error("Local REST API plugin not found. Please ensure it is installed and enabled."); + return; + } + + const routes: Route[] = [ + { + path: "/extensions/backlinks/{*}", + method: "get", + handler: async (req: Request, res: Response) => { + const filePath = req.params["*"] ?? ""; + const path = normalizePath(filePath); + + const file = this.app.vault.getAbstractFileByPath(path); + if (!file) { + return res.status(404).json({ + errorCode: 40, + message: `File not found at path: ${filePath}`, + }); + } + if (!(file instanceof TFile)) { + return res.status(400).json({ + errorCode: 405, + message: `Path is a folder, not a file: ${path}`, + }); + } + + const backlinks: BacklinksData = + (this.app as any).metadataCache.getBacklinksForFile(file); + + const result: Record = {}; + if (backlinks && backlinks.data) { + for (const [sourcePath, links] of Object.entries(backlinks.data)) { + result[sourcePath] = links; + } + } + + return res.json({ + file: path, + backlinks: result, + count: Object.keys(result).length, + }); + }, + }, + ]; + + api.registerRoutes(routes); + console.log("Backlinks route registered: GET /extensions/backlinks/{*}"); + } +}