feat: resolve daily-note path from Obsidian config for scoped tokens
Build and Push Docker Container / build-and-push (push) Successful in 4m15s

- Add daily_note_path_for_vault to read .obsidian/daily-notes.json

- Honor configured folder and date format for daily commands

- Add moment_to_strftime to translate Obsidian date tokens

- Authorize pathless daily:* commands against the resolved path

- Pick vault root from token vault, cwd, or default vault

- Normalize n8n httpRequest response to avoid circular JSON output

- Force returnFullResponse false and parse body to plain result

- Bump n8n-nodes-obsidian-cli-api to 0.2.0

- Add tests for allowed and denied scoped daily commands
This commit is contained in:
2026-06-24 11:01:57 +02:00
parent e21760949a
commit be78e3aa00
5 changed files with 135 additions and 6 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "n8n-nodes-obsidian-cli-api",
"version": "0.1.1",
"version": "0.2.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "n8n-nodes-obsidian-cli-api",
"version": "0.1.1",
"version": "0.2.0",
"license": "MIT",
"devDependencies": {
"@types/node": "^24.0.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "n8n-nodes-obsidian-cli-api",
"version": "0.1.1",
"version": "0.2.0",
"description": "n8n community nodes for the Obsidian API Docker service backed by the official Obsidian CLI.",
"license": "MIT",
"homepage": "https://git.yiprawr.dev/Docker/obsidian-api",
@@ -61,9 +61,11 @@ export async function executeObsidianCommand(
timeout: options.timeout,
},
json: true,
returnFullResponse: false,
};
const result = await context.helpers.httpRequest(request) as ObsidianCommandResult;
const response = await context.helpers.httpRequest(request) as unknown;
const result = normalizeCommandResult(response);
if (result.exit_code !== 0) {
throw new NodeOperationError(
@@ -75,3 +77,38 @@ export async function executeObsidianCommand(
return result;
}
function normalizeCommandResult(response: unknown): ObsidianCommandResult {
const data = extractResponseBody(response);
const result = typeof data === 'string' ? JSON.parse(data) : data;
if (!isObject(result)) {
throw new Error('Obsidian API returned a non-object response');
}
return {
id: String(result.id ?? ''),
command: Array.isArray(result.command) ? result.command.map(String) : [],
cwd: String(result.cwd ?? ''),
exit_code: Number(result.exit_code ?? 0),
stdout: String(result.stdout ?? ''),
stderr: String(result.stderr ?? ''),
duration_ms: Number(result.duration_ms ?? 0),
timed_out: Boolean(result.timed_out),
};
}
function extractResponseBody(response: unknown): unknown {
if (!isObject(response)) return response;
// Some n8n versions/helpers can return a full response object. Never pass that
// through to node output because it contains circular fields like res.socket.
if ('body' in response) return response.body;
if ('data' in response) return response.data;
return response;
}
function isObject(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null;
}