feat(uri): support x-callback-url for the QuickAdd URI (#1070)#1339
Conversation
Let external callers (e.g. Apple Shortcuts) trigger a Template or Capture choice via obsidian://quickadd and receive a callback when it finishes, following the x-callback-url convention (x-success / x-error / x-cancel, plus a legacy single-URL x-callback-url shorthand). - New default-off setting `enableUriCallbacks`; with it off, or when no x-* params are present, the URI handler runs the exact legacy path (no behaviour change). - x-success carries `status=success` and, for Template/Capture, the affected note's vault `path` and an `obsidian://open` `url`. x-error carries a stable `errorCode` (no raw message, so vault internals never leak). x-cancel carries `status=cancel`. - Outcome is surfaced via a new `ChoiceExecutor.executeWithOutcome()` returning a typed `ChoiceOutcome`; `IChoiceExecutor.execute()` is unchanged. Engines record success at the content-commit point so a later cosmetic failure can't downgrade the outcome (and make a caller retry / duplicate the capture). - New `UserCancelError` distinguishes a genuine user prompt-dismissal (x-cancel) from a script/config abort (x-error execution-aborted); `handleMacroAbort` classifies via instanceof with a message-string fallback for back-compat. - Editor-insertion helpers now report whether the insertion landed, so a capture with no active editor reports failure instead of a false success. - Security: callbacks are validated before anything runs (so a bad URL can't half-execute) and restricted to an allow-list of `shortcuts:` and `obsidian:` schemes. Macro and Multi choices are not supported and return `unsupported-choice-type`. Pure URL logic lives in src/uri/uriCallback.ts with unit tests. Docs added to docs/docs/Advanced/ObsidianUri.md. Closes #1070
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds opt-in Changesx-callback-url URI Support
Sequence Diagram(s)sequenceDiagram
rect rgba(173, 216, 230, 0.5)
Note over ExternalApp,Obsidian: Initiating callback
ExternalApp->>Obsidian: obsidian://quickadd?choice=Daily+Log&x-success=shortcuts%3A%2F%2F...
end
rect rgba(255, 228, 196, 0.5)
Note over Obsidian,isCallbackUrlAllowed: Validation
Obsidian->>parseCallbackTargets: resolve success/error/cancel targets
Obsidian->>isCallbackUrlAllowed: validate each callback URL (allow: shortcuts:, obsidian:)
isCallbackUrlAllowed-->>Obsidian: allowed / rejected
end
rect rgba(144, 238, 144, 0.5)
Note over Obsidian,ChoiceExecutor: Execution
Obsidian->>ChoiceExecutor: executeWithOutcome(TemplateChoice | CaptureChoice)
ChoiceExecutor->>Engine: execute(choice)
Engine->>ChoiceExecutor: recordExecutionResult({status:"success", file})
ChoiceExecutor-->>Obsidian: ChoiceOutcome
end
rect rgba(255, 182, 193, 0.5)
Note over Obsidian,ExternalApp: Callback dispatch
alt status = success
Obsidian->>ExternalApp: window.open(x-success?status=success&path=...&url=...)
else status = error
Obsidian->>ExternalApp: window.open(x-error?status=error&errorCode=...)
else status = cancelled
Obsidian->>ExternalApp: window.open(x-cancel?status=cancel)
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying quickadd with
|
| Latest commit: |
8673c76
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://2b89b193.quickadd.pages.dev |
| Branch Preview URL: | https://chhoumann-1070-uri-x-callbac.quickadd.pages.dev |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/main.ts (1)
35-44: ⚡ Quick winUse type-only imports per coding guidelines.
Lines 35-36 (
ITemplateChoice,ICaptureChoice) and line 43 (CallbackTargets) import types that are only used in type positions (line 254 cast and line 198/354/363/369 annotations). Per the coding guidelines, "Prefer type-only imports in TypeScript files."♻️ Proposed refactor to use type-only imports
-import type ITemplateChoice from "./types/choices/ITemplateChoice"; -import type ICaptureChoice from "./types/choices/ICaptureChoice"; +import type { type ITemplateChoice } from "./types/choices/ITemplateChoice"; +import type { type ICaptureChoice } from "./types/choices/ICaptureChoice"; import { buildCallbackUrl, buildObsidianOpenUrl, callbackUrls, isCallbackUrlAllowed, parseCallbackTargets, - type CallbackTargets, } from "./uri/uriCallback"; +import type { CallbackTargets } from "./uri/uriCallback";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main.ts` around lines 35 - 44, The imports in src/main.ts should follow the type-only import guideline: keep only runtime values in the normal import list from "./uri/uriCallback", and move ITemplateChoice, ICaptureChoice, and CallbackTargets to type-only imports because they are used only in annotations/casts. Update the existing import declarations near the top of main.ts so the type symbols are clearly separated from value imports, while preserving the current runtime imports like buildCallbackUrl, buildObsidianOpenUrl, callbackUrls, isCallbackUrlAllowed, and parseCallbackTargets.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/docs/Advanced/ObsidianUri.md`:
- Around line 91-93: The fenced code blocks in the document are missing language
identifiers (info strings) which causes markdownlint MD040 violations. Add a
language tag to each code block fence - the URI examples shown in the diff and
the other occurrences mentioned in the comment should use `text` or another
appropriate language identifier (such as `uri`, `bash`, etc. depending on the
actual content of each block) immediately after the opening triple backticks to
satisfy the markdownlint rule and improve readability.
---
Nitpick comments:
In `@src/main.ts`:
- Around line 35-44: The imports in src/main.ts should follow the type-only
import guideline: keep only runtime values in the normal import list from
"./uri/uriCallback", and move ITemplateChoice, ICaptureChoice, and
CallbackTargets to type-only imports because they are used only in
annotations/casts. Update the existing import declarations near the top of
main.ts so the type symbols are clearly separated from value imports, while
preserving the current runtime imports like buildCallbackUrl,
buildObsidianOpenUrl, callbackUrls, isCallbackUrlAllowed, and
parseCallbackTargets.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d2896de3-7510-40a3-8ee1-f0d0a79969b0
📒 Files selected for processing (23)
docs/docs/Advanced/ObsidianUri.mdsrc/IChoiceExecutor.tssrc/ai/AIAssistant.tssrc/choiceExecutor.tssrc/engine/CaptureChoiceEngine.notice.test.tssrc/engine/CaptureChoiceEngine.selection.test.tssrc/engine/CaptureChoiceEngine.tssrc/engine/MacroChoiceEngine.notice.test.tssrc/engine/MacroChoiceEngine.tssrc/engine/TemplateChoiceEngine.notice.test.tssrc/engine/TemplateChoiceEngine.tssrc/engine/TemplateEngine.tssrc/errors/UserCancelError.tssrc/formatters/completeFormatter.tssrc/main.tssrc/quickAddApi.tssrc/quickAddSettingsTab.tssrc/settings.tssrc/types/ChoiceOutcome.tssrc/uri/uriCallback.test.tssrc/uri/uriCallback.tssrc/utilityObsidian.tssrc/utils/macroAbortHandler.ts
Addresses CodeRabbit review feedback on PR #1339.
Closes #1070.
Lets external callers (e.g. Apple Shortcuts) trigger a Template or Capture choice via
obsidian://quickaddand receive a callback when it finishes — the x-callback-url convention.What it does
enableUriCallbacks). With it off, or when nox-*params are present, the handler runs the exact legacy path — no behaviour change.x-success/x-error/x-cancel(plus a legacy single-URLx-callback-urlshorthand that fires on success and cancel).x-success→status=success+ the affected note'spathand anobsidian://openurl.x-error→status=error+ a stableerrorCode(choice-not-found,unsupported-choice-type,execution-failed,execution-aborted,bad-callback-url) — never the raw message, so vault internals don't leak.x-cancel→status=cancel.x-errorunsupported-choice-type(full propagation needs a larger refactor — tracked as follow-up).How it works
ChoiceExecutor.executeWithOutcome()returns a typedChoiceOutcome;IChoiceExecutor.execute()is unchanged (no stub churn). Engines record success at the content-commit point (before cosmetic steps), so a later cosmetic failure can't downgrade the outcome and make a caller retry/duplicate.UserCancelErrordistinguishes a genuine user prompt-dismissal (x-cancel) from a script/config abort (x-error execution-aborted);handleMacroAbortclassifies viainstanceofwith a message-string fallback for back-compat.shortcuts:andobsidian:schemes.src/uri/uriCallback.ts(unit-tested).Verification
tsc,eslint, 1934 vitest tests, production build, and docs build all pass.path/url),unsupported-choice-type,choice-not-found, bad-scheme → no execution, gate-off / no-callback → legacy, and caller-suppliedstatuscorrectly overridden — all behave as designed.{{MACRO}}could leak its outcome into the outer choice) is fixed by scoping the result slot perexecute()frame.Docs
Full section added to
docs/docs/Advanced/ObsidianUri.md, including the double-encoding requirement (Obsidian's URI parser truncates an under-encoded callback value — the issue's own example is affected).Release / migration
feat:→ minor release. New setting defaults off;Object.assignsupplies it for existing users (no migration).obsidian://quickaddbehaviour is unchanged unless a user opts in.Summary by CodeRabbit
Allow URI x-callback-urlsetting enablingobsidian://quickaddresult callbacks for Template and Capture choices (success, error, cancel).