902a3df8b5
Build and Push Docker Container / build-and-push (push) Successful in 4m26s
- Add Docker image for the official Obsidian desktop app and CLI. - Start Obsidian headlessly with Xvfb and DBus setup. - Expose a safe structured HTTP command API without shell execution. - Add JWT-based vault, path, and command authorization. - Support single-vault and multi-vault container mounts. - Add TypeScript SDK helpers for Obsidian CLI commands. - Add n8n community node package with Obsidian operations. - Add docs, compose config, tests, and production image workflow.
134 lines
3.6 KiB
Markdown
134 lines
3.6 KiB
Markdown
# n8n usage notes
|
|
Use the TypeScript SDK from an n8n **Code** node when n8n can import local or bundled npm packages. In self-hosted n8n this usually means installing the SDK where n8n can resolve it and allowing external modules, for example with `NODE_FUNCTION_ALLOW_EXTERNAL=@obsidian-api/sdk` or `NODE_FUNCTION_ALLOW_EXTERNAL=*`.
|
|
|
|
The SDK only sends structured `args` arrays to the HTTP API. It never sends shell command strings.
|
|
|
|
## Environment variables
|
|
Recommended n8n env vars:
|
|
|
|
```env
|
|
OBSIDIAN_API_URL=http://obsidian-api:8080
|
|
OBSIDIAN_API_JWT=<jwt-from-scripts/create_jwt.py>
|
|
OBSIDIAN_VAULT=work
|
|
```
|
|
|
|
Recommended: use a restricted JWT for n8n. Create it with:
|
|
```bash
|
|
OBSIDIAN_JWT_SECRET=change-this-long-random-secret \
|
|
python scripts/create_jwt.py \
|
|
--sub n8n \
|
|
--vault work \
|
|
--path Inbox/n8n/ \
|
|
--path Automation.md \
|
|
--command create \
|
|
--command read \
|
|
--command append \
|
|
--command search \
|
|
--command search:context \
|
|
--days 365
|
|
```
|
|
|
|
The JWT contains claims like:
|
|
```json
|
|
{
|
|
"sub": "n8n",
|
|
"vaults": ["work"],
|
|
"paths": ["Inbox/n8n/", "Automation.md"],
|
|
"commands": ["create", "read", "append", "search", "search:context"],
|
|
"exp": 1791536000
|
|
}
|
|
```
|
|
|
|
If n8n runs outside the Docker network, use the exposed host URL instead:
|
|
|
|
```env
|
|
OBSIDIAN_API_URL=http://localhost:8080
|
|
```
|
|
|
|
## Basic Code node
|
|
```ts
|
|
import { ObsidianCliClient } from '@obsidian-api/sdk';
|
|
|
|
const obsidian = new ObsidianCliClient({
|
|
baseUrl: process.env.OBSIDIAN_API_URL!,
|
|
token: process.env.OBSIDIAN_API_JWT!,
|
|
vault: process.env.OBSIDIAN_VAULT,
|
|
});
|
|
|
|
const title = $json.title ?? 'n8n note';
|
|
const content = `# ${title}\n\nCreated from n8n.\n`;
|
|
|
|
const result = await obsidian.create({
|
|
path: `Inbox/${title}.md`,
|
|
content,
|
|
overwrite: true,
|
|
});
|
|
|
|
return [{ json: result }];
|
|
```
|
|
|
|
## Append incoming webhook payload to a daily note
|
|
```ts
|
|
import { ObsidianCliClient } from '@obsidian-api/sdk';
|
|
|
|
const obsidian = new ObsidianCliClient({
|
|
baseUrl: process.env.OBSIDIAN_API_URL!,
|
|
token: process.env.OBSIDIAN_API_JWT!,
|
|
vault: process.env.OBSIDIAN_VAULT,
|
|
});
|
|
|
|
const payload = JSON.stringify($json, null, 2).replace(/```/g, '``\\`');
|
|
|
|
const result = await obsidian.dailyAppend(
|
|
`\n## n8n event\n\n\`\`\`json\n${payload}\n\`\`\`\n`,
|
|
);
|
|
|
|
return [{ json: result }];
|
|
```
|
|
|
|
## Search notes
|
|
```ts
|
|
import { ObsidianCliClient } from '@obsidian-api/sdk';
|
|
|
|
const obsidian = new ObsidianCliClient({
|
|
baseUrl: process.env.OBSIDIAN_API_URL!,
|
|
token: process.env.OBSIDIAN_API_JWT!,
|
|
vault: process.env.OBSIDIAN_VAULT,
|
|
});
|
|
|
|
const result = await obsidian.search($json.query, { format: 'json' });
|
|
return [{ json: { matches: JSON.parse(result.stdout) } }];
|
|
```
|
|
|
|
## Multi-vault usage
|
|
If the API container registers multiple vaults, use a scoped client per vault:
|
|
```ts
|
|
const base = new ObsidianCliClient({
|
|
baseUrl: process.env.OBSIDIAN_API_URL!,
|
|
token: process.env.OBSIDIAN_API_JWT!,
|
|
});
|
|
|
|
const work = base.inVault('work');
|
|
const personal = base.inVault('personal');
|
|
|
|
await work.create({ path: 'Inbox/Work.md', content: 'Work note', overwrite: true });
|
|
await personal.create({ path: 'Inbox/Personal.md', content: 'Personal note', overwrite: true });
|
|
```
|
|
|
|
## Without SDK
|
|
If package imports are not available in your n8n environment, call the HTTP API directly:
|
|
```ts
|
|
const response = await fetch(`${process.env.OBSIDIAN_API_URL}/commands`, {
|
|
method: 'POST',
|
|
headers: {
|
|
authorization: `Bearer ${process.env.OBSIDIAN_API_JWT}`,
|
|
'content-type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
args: ['vault=work', 'create', 'path=Inbox/n8n.md', 'content=Hello from n8n', 'overwrite'],
|
|
}),
|
|
});
|
|
|
|
return [{ json: await response.json() }];
|
|
```
|