Skip to content

Commit 0a6af39

Browse files
authored
feat(n8n): n8n-nodes-taskade node + provenance publish workflow (PR #16)
Self-contained package (packages/n8n-nodes-taskade, no workspace machinery): - Resources: Task (create/complete/uncomplete/update/delete/move/getMany), Project (create/createFromTemplate/getMany), AI Agent (prompt via v2) - TaskadeApi credential (PAT Bearer, test against /v1/workspaces) - 4 dynamic dropdowns (projects, folders, tasks, templates) - usableAsTool: n8n AI agents can call Taskade directly - zero runtime deps (n8n verified-node rule); MIT; npm name verified free - publish-n8n.yml: GitHub-Actions npm publish WITH provenance (mandatory for verified nodes since 2026-05-01); gated on NPM_TOKEN secret
1 parent 4b5d818 commit 0a6af39

10 files changed

Lines changed: 1907 additions & 0 deletions

File tree

.github/workflows/publish-n8n.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Publish n8n node
2+
3+
# n8n verified community nodes must be published from GitHub Actions with npm
4+
# provenance (mandatory since 2026-05-01). Requires the NPM_TOKEN repo secret.
5+
on:
6+
workflow_dispatch:
7+
push:
8+
tags: ['n8n-v*']
9+
10+
permissions:
11+
contents: read
12+
id-token: write # npm provenance (OIDC)
13+
14+
jobs:
15+
publish:
16+
runs-on: ubuntu-latest
17+
defaults:
18+
run:
19+
working-directory: packages/n8n-nodes-taskade
20+
steps:
21+
- uses: actions/checkout@v4
22+
- uses: actions/setup-node@v4
23+
with:
24+
node-version: 20
25+
registry-url: https://registry.npmjs.org
26+
- run: npm install
27+
- run: npm run build
28+
- run: npm publish --provenance --access public
29+
env:
30+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,6 @@ typings/
6262
.next
6363

6464
lib
65+
66+
# package build output
67+
dist/
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# n8n-nodes-taskade
2+
3+
Official [n8n](https://n8n.io) community node for [Taskade](https://www.taskade.com) — tasks, projects, and AI agents on the [Taskade public API](https://docs.taskade.com).
4+
5+
## Operations
6+
7+
| Resource | Operations |
8+
|---|---|
9+
| Task | Create, Complete, Uncomplete, Update, Delete, Move, Get Many |
10+
| Project | Create (Markdown), Create From Template, Get Many |
11+
| AI Agent | Prompt (synchronous response via the v2 Action API) |
12+
13+
The node is `usableAsTool`, so n8n AI agents can call Taskade directly.
14+
15+
## Credentials
16+
17+
Personal Access Token — create one at taskade.com → Settings → API (tokens start with `tskdp_`). The credential test calls `GET /api/v1/workspaces`.
18+
19+
## Installation
20+
21+
Self-hosted n8n: **Settings → Community Nodes → Install**`n8n-nodes-taskade`.
22+
23+
## Development
24+
25+
```bash
26+
npm install
27+
npm run build # tsc -> dist/ + icon copy
28+
```
29+
30+
Part of [taskade/integrations](https://github.com/taskade/integrations) — the public source-of-truth for Taskade integrations. MIT.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import type {
2+
IAuthenticateGeneric,
3+
ICredentialTestRequest,
4+
ICredentialType,
5+
INodeProperties,
6+
} from 'n8n-workflow';
7+
8+
export class TaskadeApi implements ICredentialType {
9+
name = 'taskadeApi';
10+
11+
displayName = 'Taskade API';
12+
13+
documentationUrl = 'https://docs.taskade.com';
14+
15+
properties: INodeProperties[] = [
16+
{
17+
displayName: 'Personal Access Token',
18+
name: 'accessToken',
19+
type: 'string',
20+
typeOptions: { password: true },
21+
default: '',
22+
description:
23+
'Create a token at taskade.com → Settings → API (tokens start with tskdp_)',
24+
},
25+
];
26+
27+
authenticate: IAuthenticateGeneric = {
28+
type: 'generic',
29+
properties: {
30+
headers: {
31+
Authorization: '=Bearer {{$credentials.accessToken}}',
32+
},
33+
},
34+
};
35+
36+
test: ICredentialTestRequest = {
37+
request: {
38+
baseURL: 'https://www.taskade.com/api/v1',
39+
url: '/workspaces',
40+
},
41+
};
42+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import type {
2+
IExecuteFunctions,
3+
IHttpRequestMethods,
4+
IHttpRequestOptions,
5+
ILoadOptionsFunctions,
6+
IDataObject,
7+
} from 'n8n-workflow';
8+
9+
const BASE_V1 = 'https://www.taskade.com/api/v1';
10+
const BASE_V2 = 'https://www.taskade.com/api/v2';
11+
12+
export async function taskadeApiRequest(
13+
this: IExecuteFunctions | ILoadOptionsFunctions,
14+
method: IHttpRequestMethods,
15+
path: string,
16+
body?: IDataObject,
17+
version: 'v1' | 'v2' = 'v1',
18+
qs?: IDataObject,
19+
): Promise<IDataObject> {
20+
const options: IHttpRequestOptions = {
21+
method,
22+
url: `${version === 'v2' ? BASE_V2 : BASE_V1}${path}`,
23+
headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
24+
body,
25+
qs,
26+
json: true,
27+
};
28+
if (body === undefined) {
29+
delete options.body;
30+
}
31+
return (await this.helpers.httpRequestWithAuthentication.call(
32+
this,
33+
'taskadeApi',
34+
options,
35+
)) as IDataObject;
36+
}
37+
38+
/** Returns `items` from a Taskade `{ ok, items }` response, tolerating absent fields. */
39+
export async function taskadeApiList(
40+
this: IExecuteFunctions | ILoadOptionsFunctions,
41+
path: string,
42+
qs?: IDataObject,
43+
): Promise<IDataObject[]> {
44+
const response = await taskadeApiRequest.call(this, 'GET', path, undefined, 'v1', qs);
45+
return (response.items as IDataObject[]) ?? [];
46+
}

0 commit comments

Comments
 (0)