Compare commits

...

4 commits
1.2.0 ... main

Author SHA1 Message Date
Claude
0c25564337
Normalize redirect URI to fix OAuth invalid_grant (1.2.3)
TickTick's OAuth server requires byte-exact match between the redirect_uri
the plugin sends and the value registered in the developer portal. Users
who register the URI with a trailing slash (common on iOS paste, or by
hand) get rejected with:

  error="invalid_grant"
  error_description="Invalid redirect: ...vercel.app does not match one
  of the registered values: [...vercel.app/]"

(Reported in issue #2.)

Normalize the redirect URI by stripping trailing slashes and whitespace at
all four use/save sites:

- main.ts: startAuthFlow() and exchangeAuthCodeForToken() clean the URI
  before sending — protects existing users with a slash already saved
- settings.ts: both Redirect URI inputs strip on save so the persisted
  value matches what's displayed
- settings.ts: both descriptions now warn against trailing slashes
- README: new Troubleshooting entry for the invalid_grant error

https://claude.ai/code/session_01V2fsiatACzjUCNwSEhwER9
2026-06-05 16:16:26 +00:00
Claude
c036f5ab67
Strip Markdown from TickTick task titles (1.2.2)
The task title was built verbatim from the source line, so list/checkbox
markers (- [ ]), bold/italic, links, headings, etc. leaked into TickTick.
Add a stripMarkdown() helper that cleans the title to plain text before
truncation:

- Removes leading list/checkbox/heading/blockquote/ordered markers
- Unwraps links and wiki links to their text
- Strips asterisk emphasis, ~~strike~~, ==highlight==, `code` (matched or
  dangling, e.g. a leading ** with no closing pair)
- Leaves single/snake_case underscores intact

The task description still includes the original text and the Open in
Obsidian link unchanged.

https://claude.ai/code/session_01V2fsiatACzjUCNwSEhwER9
2026-06-04 20:48:21 +00:00
Claude
0f98a56552
Release 1.2.1: address Obsidian directory review warnings
- manifest: drop "Obsidian" from description (directory rule), remove unknown
  `main` field, bump to 1.2.1
- README: title now matches plugin name in manifest
- Remove unused base64UrlEncode helper
- Remove dead express dependency and server.js (clears qs / path-to-regexp
  vulnerability warnings)
- package.json: real name + author + description, drop sample-plugin template
  metadata
- versions.json: add 1.2.1 → 1.4.0

https://claude.ai/code/session_01V2fsiatACzjUCNwSEhwER9
2026-06-04 20:30:07 +00:00
Claude
94953521fc
Lead with Community Plugins directory in README install section
Position BRAT as a beta/pre-release fallback rather than the primary
mobile path, now that the plugin is available in the directory.
2026-05-11 14:18:11 +00:00
9 changed files with 68 additions and 471 deletions

View file

@ -1,4 +1,4 @@
# TickTick Quick Add for Obsidian
# TickTick Quick Add Task
Send the line or paragraph at your cursor straight to TickTick as a new task — with a one-tap link back to the exact spot in your note. Works on desktop and on mobile (iOS and Android).
@ -14,15 +14,20 @@ When you trigger the command, the plugin:
## Installation
### Mobile (recommended path: BRAT)
### Recommended (mobile or desktop)
The easiest way to install on iOS or Android is via [BRAT](https://github.com/TfTHacker/obsidian42-brat), which sideloads plugins from GitHub.
Install directly from Obsidian's Community Plugins directory:
1. In Obsidian: Settings → Community plugins → turn off **Restricted Mode** if it's on → Browse → install and enable **Obsidian42 - BRAT**.
1. Settings → Community plugins → turn off **Restricted Mode** if it's on.
2. Browse → search "TickTick Quick Add Task" → Install → Enable.
### Beta / pre-release via BRAT
If you want a version newer than what's in the Community Plugins directory, use [BRAT](https://github.com/TfTHacker/obsidian42-brat) to sideload it from GitHub:
1. Install **Obsidian42 - BRAT** from Community plugins.
2. Settings → BRAT → "Add beta plugin" → paste: `heymoosh/ticktick-quick-add-obsidian`.
3. BRAT downloads the plugin. Go back to Community plugins and enable **TickTick Quick Add Task**.
> Note: BRAT pulls from the latest GitHub release. If no release exists yet, ask the maintainer to publish one, or use the manual path below.
3. Go back to Community plugins and enable **TickTick Quick Add Task**.
### Mobile (manual)
@ -36,9 +41,9 @@ The easiest way to install on iOS or Android is via [BRAT](https://github.com/Tf
> Why not just create `.obsidian` on iOS? iOS's Files app refuses to create folders whose names start with a dot. The folder already exists if Obsidian has ever opened the vault — but it's hidden from iOS Files. The desktop path above sidesteps this.
### Desktop (manual)
### Desktop (manual / for developers)
Either install via BRAT (steps above), or:
If you want to build from source instead of using the directory:
1. Clone the repo and build:
```bash
@ -109,6 +114,7 @@ After triggering, you'll see a notice confirming the task was created.
- **"TickTick auth failed: state mismatch"** — the OAuth flow expired or was started in a different session. Tap Connect again and complete the flow without delays.
- **"Failed to obtain access token"** — most often a bad Client ID or Secret, or the Redirect URI you set in the TickTick developer portal doesn't exactly match the one in the plugin. Copy/paste both rather than typing.
- **`"invalid_grant"` / `"Invalid redirect: ... does not match one of the registered values"`** — the URI registered in the TickTick Developer Portal isn't byte-equal to the one the plugin sends. The most common cause is a trailing `/` in the portal entry. Edit your TickTick app and remove any trailing slash so it matches the plugin's Redirect URI field exactly.
- **The Connect popup link does nothing** — make sure your default browser is set and you've allowed Obsidian to open external links. Try long-pressing the link to copy it, then paste into Safari/Chrome.
- **Callback page shows the code as text instead of returning to Obsidian** — that's the manual-fallback case. Paste the code into the "Authorization code" field; the plugin will exchange it for a token. (This happens if the callback page hasn't been deployed with the deep-link redirect.)
- **The "Open in Obsidian" link in TickTick does nothing** — confirm the Advanced URI plugin is installed and enabled in the same vault.

File diff suppressed because one or more lines are too long

41
main.ts
View file

@ -37,15 +37,31 @@ function getParagraph(editor: Editor, currentLine: number): { text: string, star
return { text: paragraphText.trim(), start, end };
}
// Helper function to base64url-encode an ArrayBuffer
function base64UrlEncode(buffer: ArrayBuffer): string {
const bytes = new Uint8Array(buffer);
let binary = '';
bytes.forEach(b => (binary += String.fromCharCode(b)));
return btoa(binary)
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
// Strip Markdown formatting so the TickTick task title is plain text.
// Removes leading list/checkbox/heading/quote markers and inline emphasis,
// keeping the inner text. Leaves single underscores alone to preserve
// snake_case identifiers.
function stripMarkdown(text: string): string {
return text
// Images: ![alt](url) -> alt
.replace(/!\[([^\]]*)\]\([^)]*\)/g, '$1')
// Markdown links: [text](url) -> text
.replace(/\[([^\]]+)\]\([^)]*\)/g, '$1')
// Wiki links: [[page|alias]] -> alias, [[page]] -> page
.replace(/\[\[([^\]|]+)\|([^\]]+)\]\]/g, '$2')
.replace(/\[\[([^\]]+)\]\]/g, '$1')
// Leading blockquote / heading / list / checkbox / ordered-list markers
.replace(/^\s*(?:>\s*|#{1,6}\s+|[-*+]\s+\[[ xX]\]\s+|[-*+]\s+|\d+\.\s+)+/, '')
// Bold/italic via underscores: only strip matched pairs, so
// snake_case identifiers are left intact.
.replace(/__([^_]+)__/g, '$1')
// Asterisk emphasis, highlight, strikethrough, inline code:
// remove the markers whether or not they're balanced (a dangling
// "**" at the start of a line should still be stripped).
.replace(/\*\*?|~~|==|`/g, '')
// Collapse remaining whitespace/newlines
.replace(/\s+/g, ' ')
.trim();
}
// Helper function to generate PKCE codes: codeVerifier and corresponding codeChallenge
@ -188,7 +204,8 @@ export default class TickTickPlugin extends Plugin {
const filePath = view.file.path;
const advancedUri = `obsidian://advanced-uri?vault=${encodeURIComponent(vaultName)}&filepath=${encodeURIComponent(filePath)}&block=${encodeURIComponent(blockId)}`;
const taskDescription = `${taskText}\n\n[Open in Obsidian](${advancedUri})`;
const taskTitle = taskText.length > 50 ? taskText.substring(0, 50) + "..." : taskText;
const cleanTitle = stripMarkdown(taskText);
const taskTitle = cleanTitle.length > 50 ? cleanTitle.substring(0, 50) + "..." : cleanTitle;
await this.ensureFreshToken();
@ -219,7 +236,7 @@ export default class TickTickPlugin extends Plugin {
new Notice('Please enter your Client ID in the settings.');
return;
}
const redirectUri = this.settings.redirectUri || 'https://ticktick-quick-add-obsidian-6yawfmvnj-mooshs-projects-0635287d.vercel.app';
const redirectUri = (this.settings.redirectUri || 'https://ticktick-quick-add-obsidian-6yawfmvnj-mooshs-projects-0635287d.vercel.app').trim().replace(/\/+$/, '');
const scope = encodeURIComponent('tasks:read tasks:write');
const { codeVerifier, codeChallenge } = await generatePKCECodes();
const state = generateRandomString(32);
@ -236,7 +253,7 @@ export default class TickTickPlugin extends Plugin {
*/
async exchangeAuthCodeForToken(code: string): Promise<void> {
const tokenEndpoint = 'https://ticktick.com/oauth/token';
const redirectUri = this.settings.redirectUri || 'https://ticktick-quick-add-obsidian-6yawfmvnj-mooshs-projects-0635287d.vercel.app';
const redirectUri = (this.settings.redirectUri || 'https://ticktick-quick-add-obsidian-6yawfmvnj-mooshs-projects-0635287d.vercel.app').trim().replace(/\/+$/, '');
const clientId = this.settings.clientId;
const clientSecret = this.settings.clientSecret;
const codeVerifier = this.settings.tempCodeVerifier;

View file

@ -1,11 +1,10 @@
{
"id": "ticktick-quickadd-task",
"name": "TickTick Quick Add Task",
"version": "1.2.0",
"version": "1.2.3",
"minAppVersion": "1.4.0",
"description": "Create TickTick tasks from text blocks with automatic Obsidian URI links. Requires Advanced URI plugin.",
"description": "Create TickTick tasks from text at your cursor with automatic deep links back to your notes. Requires the Advanced URI plugin.",
"author": "Muxin Li",
"authorUrl": "https://github.com/heymoosh",
"isDesktopOnly": false,
"main": "main.js"
}
"isDesktopOnly": false
}

419
package-lock.json generated
View file

@ -1,16 +1,13 @@
{
"name": "obsidian-sample-plugin",
"version": "1.1.0",
"name": "ticktick-quickadd-task",
"version": "1.2.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "obsidian-sample-plugin",
"version": "1.1.0",
"name": "ticktick-quickadd-task",
"version": "1.2.1",
"license": "MIT",
"dependencies": {
"express": "^4.21.2"
},
"devDependencies": {
"@types/node": "^16.11.6",
"@typescript-eslint/eslint-plugin": "5.29.0",
@ -46,278 +43,6 @@
"w3c-keyname": "^2.2.4"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz",
"integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz",
"integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz",
"integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz",
"integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz",
"integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz",
"integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz",
"integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz",
"integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz",
"integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz",
"integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz",
"integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz",
"integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz",
"integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz",
"integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz",
"integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz",
"integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz",
@ -335,142 +60,6 @@
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz",
"integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz",
"integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz",
"integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz",
"integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz",
"integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz",
"integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz",
"integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz",
"integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.5.1",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz",

View file

@ -1,7 +1,7 @@
{
"name": "obsidian-sample-plugin",
"version": "1.2.0",
"description": "This is a sample plugin for Obsidian (https://obsidian.md)",
"name": "ticktick-quickadd-task",
"version": "1.2.3",
"description": "Create TickTick tasks from text at your cursor with automatic deep links back to your notes. Requires the Advanced URI plugin.",
"main": "main.js",
"scripts": {
"dev": "node esbuild.config.mjs",
@ -9,7 +9,7 @@
"version": "node version-bump.mjs && git add manifest.json versions.json"
},
"keywords": [],
"author": "",
"author": "Muxin Li",
"license": "MIT",
"devDependencies": {
"@types/node": "^16.11.6",
@ -20,8 +20,5 @@
"obsidian": "latest",
"tslib": "2.4.0",
"typescript": "4.7.4"
},
"dependencies": {
"express": "^4.21.2"
}
}

View file

@ -1,15 +0,0 @@
const express = require('express');
const app = express();
const port = 3000;
app.get('/callback', (req, res) => {
const { code, state } = req.query;
// Here, you can just display the code and state
res.send(`Authorization code received: ${code}<br>State: ${state}<br><br>Copy this code into Obsidian!`);
console.log('Received code:', code);
console.log('Received state:', state);
});
app.listen(port, () => {
console.log(`Server listening at http://127.0.0.1:${port}`);
});

View file

@ -89,13 +89,13 @@ export class TickTickSettingTab extends PluginSettingTab {
new Setting(containerEl)
.setName('Redirect URI')
.setDesc('Copy this exact value into your TickTick app\'s Redirect URI field in the developer portal. Only change it here if you self-host the callback page.')
.setDesc('Copy this exact value into your TickTick app\'s Redirect URI field in the developer portal. Do not add a trailing slash — the URIs must match exactly. Only change it here if you self-host the callback page.')
.addText(text =>
text
.setPlaceholder(DEFAULT_SETTINGS.redirectUri!)
.setValue(this.plugin.settings.redirectUri || '')
.onChange(async (value) => {
this.plugin.settings.redirectUri = value.trim();
this.plugin.settings.redirectUri = value.trim().replace(/\/+$/, '');
await this.plugin.saveSettings();
})
);
@ -241,11 +241,12 @@ export class TickTickSettingTab extends PluginSettingTab {
new Setting(details)
.setName('Redirect URI')
.setDesc('Must match the value registered in your TickTick app exactly, with no trailing slash.')
.addText(text =>
text
.setValue(this.plugin.settings.redirectUri || '')
.onChange(async (value) => {
this.plugin.settings.redirectUri = value.trim();
this.plugin.settings.redirectUri = value.trim().replace(/\/+$/, '');
await this.plugin.saveSettings();
})
);

View file

@ -1,5 +1,8 @@
{
"1.0.0": "0.15.0",
"1.1.0": "1.4.0",
"1.2.0": "1.4.0"
"1.2.0": "1.4.0",
"1.2.1": "1.4.0",
"1.2.2": "1.4.0",
"1.2.3": "1.4.0"
}