@plotday/tool-asana 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Plot Technologies Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,89 @@
1
+ import { type ActivityLink, type NewActivityWithNotes } from "@plotday/twister";
2
+ import type { Project, ProjectAuth, ProjectSyncOptions, ProjectTool } from "@plotday/twister/common/projects";
3
+ import { Tool, type ToolBuilder } from "@plotday/twister/tool";
4
+ import { Callbacks } from "@plotday/twister/tools/callbacks";
5
+ import { Integrations } from "@plotday/twister/tools/integrations";
6
+ import { Network } from "@plotday/twister/tools/network";
7
+ import { Plot } from "@plotday/twister/tools/plot";
8
+ import { Tasks } from "@plotday/twister/tools/tasks";
9
+ /**
10
+ * Asana project management tool
11
+ *
12
+ * Implements the ProjectTool interface for syncing Asana projects and tasks
13
+ * with Plot activities.
14
+ */
15
+ export declare class Asana extends Tool<Asana> implements ProjectTool {
16
+ build(build: ToolBuilder): {
17
+ integrations: Promise<Integrations>;
18
+ network: Promise<Network>;
19
+ callbacks: Promise<Callbacks>;
20
+ tasks: Promise<Tasks>;
21
+ plot: Promise<Plot>;
22
+ };
23
+ /**
24
+ * Create Asana API client with auth token
25
+ */
26
+ private getClient;
27
+ /**
28
+ * Request Asana OAuth authorization
29
+ */
30
+ requestAuth<TCallback extends (auth: ProjectAuth, ...args: any[]) => any>(callback: TCallback, ...extraArgs: TCallback extends (auth: any, ...rest: infer R) => any ? R : []): Promise<ActivityLink>;
31
+ /**
32
+ * Handle successful OAuth authorization
33
+ */
34
+ private onAuthSuccess;
35
+ /**
36
+ * Get list of Asana projects
37
+ */
38
+ getProjects(authToken: string): Promise<Project[]>;
39
+ /**
40
+ * Start syncing tasks from an Asana project
41
+ */
42
+ startSync<TCallback extends (task: NewActivityWithNotes, ...args: any[]) => any>(authToken: string, projectId: string, callback: TCallback, options?: ProjectSyncOptions, ...extraArgs: TCallback extends (task: any, ...rest: infer R) => any ? R : []): Promise<void>;
43
+ /**
44
+ * Setup Asana webhook for real-time updates
45
+ * Note: Asana webhook API requires special permissions, so we skip for now
46
+ */
47
+ private setupAsanaWebhook;
48
+ /**
49
+ * Initialize batch sync process
50
+ */
51
+ private startBatchSync;
52
+ /**
53
+ * Process a batch of tasks
54
+ */
55
+ private syncBatch;
56
+ /**
57
+ * Convert an Asana task to a Plot Activity
58
+ */
59
+ private convertTaskToActivity;
60
+ /**
61
+ * Update task with new values
62
+ *
63
+ * @param authToken - Authorization token
64
+ * @param update - ActivityUpdate with changed fields
65
+ */
66
+ updateIssue(authToken: string, update: import("@plotday/twister").ActivityUpdate): Promise<void>;
67
+ /**
68
+ * Add a comment (story) to an Asana task
69
+ *
70
+ * @param authToken - Authorization token
71
+ * @param issueId - Asana task GID
72
+ * @param body - Comment text (markdown not directly supported, plain text)
73
+ */
74
+ addIssueComment(authToken: string, issueId: string, body: string): Promise<void>;
75
+ /**
76
+ * Verify Asana webhook signature
77
+ * Asana uses HMAC-SHA256 with a shared secret
78
+ */
79
+ private verifyAsanaSignature;
80
+ /**
81
+ * Handle incoming webhook events from Asana
82
+ */
83
+ private onWebhook;
84
+ /**
85
+ * Stop syncing an Asana project
86
+ */
87
+ stopSync(authToken: string, projectId: string): Promise<void>;
88
+ }
89
+ export default Asana;
package/dist/asana.js ADDED
@@ -0,0 +1,347 @@
1
+ import * as asana from "asana";
2
+ import { ActivityType, } from "@plotday/twister";
3
+ import { Tool } from "@plotday/twister/tool";
4
+ import { Callbacks } from "@plotday/twister/tools/callbacks";
5
+ import { AuthLevel, AuthProvider, Integrations, } from "@plotday/twister/tools/integrations";
6
+ import { Network } from "@plotday/twister/tools/network";
7
+ import { ContactAccess, Plot } from "@plotday/twister/tools/plot";
8
+ import { Tasks } from "@plotday/twister/tools/tasks";
9
+ /**
10
+ * Asana project management tool
11
+ *
12
+ * Implements the ProjectTool interface for syncing Asana projects and tasks
13
+ * with Plot activities.
14
+ */
15
+ export class Asana extends Tool {
16
+ build(build) {
17
+ return {
18
+ integrations: build(Integrations),
19
+ network: build(Network, { urls: ["https://app.asana.com/*"] }),
20
+ callbacks: build(Callbacks),
21
+ tasks: build(Tasks),
22
+ plot: build(Plot, { contact: { access: ContactAccess.Write } }),
23
+ };
24
+ }
25
+ /**
26
+ * Create Asana API client with auth token
27
+ */
28
+ async getClient(authToken) {
29
+ const authorization = await this.get(`authorization:${authToken}`);
30
+ if (!authorization) {
31
+ throw new Error("Authorization no longer available");
32
+ }
33
+ const token = await this.tools.integrations.get(authorization);
34
+ if (!token) {
35
+ throw new Error("Authorization no longer available");
36
+ }
37
+ return asana.Client.create().useAccessToken(token.token);
38
+ }
39
+ /**
40
+ * Request Asana OAuth authorization
41
+ */
42
+ async requestAuth(callback, ...extraArgs) {
43
+ const asanaScopes = ["default"];
44
+ // Generate opaque token for authorization
45
+ const authToken = crypto.randomUUID();
46
+ const callbackToken = await this.tools.callbacks.createFromParent(callback, ...extraArgs);
47
+ // Request auth and return the activity link
48
+ return await this.tools.integrations.request({
49
+ provider: AuthProvider.Asana,
50
+ level: AuthLevel.User,
51
+ scopes: asanaScopes,
52
+ }, this.onAuthSuccess, authToken, callbackToken);
53
+ }
54
+ /**
55
+ * Handle successful OAuth authorization
56
+ */
57
+ async onAuthSuccess(authorization, authToken, callbackToken) {
58
+ // Store authorization for later use
59
+ await this.set(`authorization:${authToken}`, authorization);
60
+ // Execute the callback with the auth token
61
+ await this.run(callbackToken, { authToken });
62
+ }
63
+ /**
64
+ * Get list of Asana projects
65
+ */
66
+ async getProjects(authToken) {
67
+ const client = await this.getClient(authToken);
68
+ // Get user's workspaces first
69
+ const workspaces = await client.workspaces.getWorkspaces();
70
+ const allProjects = [];
71
+ // Get projects from each workspace
72
+ for (const workspace of workspaces.data) {
73
+ const projects = await client.projects.findByWorkspace(workspace.gid, {
74
+ limit: 100,
75
+ });
76
+ for (const project of projects.data) {
77
+ allProjects.push({
78
+ id: project.gid,
79
+ name: project.name,
80
+ description: null, // Asana doesn't return description in list
81
+ key: null, // Asana doesn't have project keys
82
+ });
83
+ }
84
+ }
85
+ return allProjects;
86
+ }
87
+ /**
88
+ * Start syncing tasks from an Asana project
89
+ */
90
+ async startSync(authToken, projectId, callback, options, ...extraArgs) {
91
+ // Setup webhook for real-time updates
92
+ await this.setupAsanaWebhook(authToken, projectId);
93
+ // Store callback for webhook processing
94
+ const callbackToken = await this.tools.callbacks.createFromParent(callback, ...extraArgs);
95
+ await this.set(`callback_${projectId}`, callbackToken);
96
+ // Start initial batch sync
97
+ await this.startBatchSync(authToken, projectId, options);
98
+ }
99
+ /**
100
+ * Setup Asana webhook for real-time updates
101
+ * Note: Asana webhook API requires special permissions, so we skip for now
102
+ */
103
+ async setupAsanaWebhook(authToken, projectId) {
104
+ // TODO: Implement Asana webhooks once we confirm the correct API
105
+ // The asana SDK webhook API may require special app permissions
106
+ console.log(`Asana webhooks not yet implemented for project ${projectId}`);
107
+ }
108
+ /**
109
+ * Initialize batch sync process
110
+ */
111
+ async startBatchSync(authToken, projectId, options) {
112
+ // Initialize sync state
113
+ await this.set(`sync_state_${projectId}`, {
114
+ offset: 0,
115
+ batchNumber: 1,
116
+ tasksProcessed: 0,
117
+ initialSync: true,
118
+ });
119
+ // Queue first batch
120
+ const batchCallback = await this.callback(this.syncBatch, authToken, projectId, options);
121
+ await this.tools.tasks.runTask(batchCallback);
122
+ }
123
+ /**
124
+ * Process a batch of tasks
125
+ */
126
+ async syncBatch(authToken, projectId, options) {
127
+ const state = await this.get(`sync_state_${projectId}`);
128
+ if (!state) {
129
+ throw new Error(`Sync state not found for project ${projectId}`);
130
+ }
131
+ // Retrieve callback token from storage
132
+ const callbackToken = await this.get(`callback_${projectId}`);
133
+ if (!callbackToken) {
134
+ throw new Error(`Callback token not found for project ${projectId}`);
135
+ }
136
+ const client = await this.getClient(authToken);
137
+ // Build request params
138
+ const batchSize = 50;
139
+ const params = {
140
+ project: projectId,
141
+ limit: batchSize,
142
+ opt_fields: [
143
+ "name",
144
+ "notes",
145
+ "completed",
146
+ "completed_at",
147
+ "created_at",
148
+ "modified_at",
149
+ ].join(","),
150
+ };
151
+ if (state.offset > 0) {
152
+ params.offset = state.offset;
153
+ }
154
+ // Fetch batch of tasks using findAll
155
+ const tasksResult = await client.tasks.findAll(params);
156
+ // Process each task
157
+ for (const task of tasksResult.data) {
158
+ // Optionally filter by time
159
+ if (options?.timeMin) {
160
+ const createdAt = new Date(task.created_at);
161
+ if (createdAt < options.timeMin) {
162
+ continue;
163
+ }
164
+ }
165
+ const activityWithNotes = await this.convertTaskToActivity(task, projectId);
166
+ // Set unread based on sync type (false for initial sync to avoid notification overload)
167
+ activityWithNotes.unread = !state.initialSync;
168
+ // Execute the callback using the callback token
169
+ await this.tools.callbacks.run(callbackToken, activityWithNotes);
170
+ }
171
+ // Check if more pages by checking if we got a full batch
172
+ const hasMore = tasksResult.data.length === batchSize;
173
+ if (hasMore) {
174
+ await this.set(`sync_state_${projectId}`, {
175
+ offset: state.offset + batchSize,
176
+ batchNumber: state.batchNumber + 1,
177
+ tasksProcessed: state.tasksProcessed + tasksResult.data.length,
178
+ initialSync: state.initialSync,
179
+ });
180
+ // Queue next batch
181
+ const nextBatch = await this.callback(this.syncBatch, authToken, projectId, options);
182
+ await this.tools.tasks.runTask(nextBatch);
183
+ }
184
+ else {
185
+ // Initial sync is complete - cleanup sync state
186
+ await this.clear(`sync_state_${projectId}`);
187
+ }
188
+ }
189
+ /**
190
+ * Convert an Asana task to a Plot Activity
191
+ */
192
+ async convertTaskToActivity(task, projectId) {
193
+ // Build notes array: description
194
+ const notes = [];
195
+ if (task.notes) {
196
+ notes.push({ content: task.notes });
197
+ }
198
+ // Ensure at least one note exists
199
+ if (notes.length === 0) {
200
+ notes.push({ content: "" });
201
+ }
202
+ return {
203
+ type: ActivityType.Action,
204
+ title: task.name,
205
+ source: `asana:task:${projectId}:${task.gid}`,
206
+ doneAt: task.completed ? new Date(task.completed_at || Date.now()) : null,
207
+ notes,
208
+ };
209
+ }
210
+ /**
211
+ * Update task with new values
212
+ *
213
+ * @param authToken - Authorization token
214
+ * @param update - ActivityUpdate with changed fields
215
+ */
216
+ async updateIssue(authToken, update) {
217
+ // Extract Asana task GID from source
218
+ const taskGid = update.source?.split(":").pop();
219
+ if (!taskGid) {
220
+ throw new Error("Invalid source format for Asana task");
221
+ }
222
+ const client = await this.getClient(authToken);
223
+ const updateFields = {};
224
+ // Handle title
225
+ if (update.title !== undefined) {
226
+ updateFields.name = update.title;
227
+ }
228
+ // Handle assignee
229
+ if (update.assignee !== undefined) {
230
+ updateFields.assignee = update.assignee?.id || null;
231
+ }
232
+ // Handle completion status based on doneAt
233
+ // Asana only has completed boolean (no In Progress state)
234
+ if (update.doneAt !== undefined) {
235
+ updateFields.completed = update.doneAt !== null;
236
+ }
237
+ // Apply updates if any fields changed
238
+ if (Object.keys(updateFields).length > 0) {
239
+ await client.tasks.updateTask(taskGid, updateFields);
240
+ }
241
+ }
242
+ /**
243
+ * Add a comment (story) to an Asana task
244
+ *
245
+ * @param authToken - Authorization token
246
+ * @param issueId - Asana task GID
247
+ * @param body - Comment text (markdown not directly supported, plain text)
248
+ */
249
+ async addIssueComment(authToken, issueId, body) {
250
+ const client = await this.getClient(authToken);
251
+ await client.tasks.addComment(issueId, {
252
+ text: body,
253
+ });
254
+ }
255
+ /**
256
+ * Verify Asana webhook signature
257
+ * Asana uses HMAC-SHA256 with a shared secret
258
+ */
259
+ async verifyAsanaSignature(signature, rawBody, secret) {
260
+ if (!signature) {
261
+ console.warn("Asana webhook missing signature header");
262
+ return false;
263
+ }
264
+ // Compute HMAC-SHA256 signature
265
+ const encoder = new TextEncoder();
266
+ const key = await crypto.subtle.importKey("raw", encoder.encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
267
+ const signatureBytes = await crypto.subtle.sign("HMAC", key, encoder.encode(rawBody));
268
+ // Convert to hex string
269
+ const expectedSignature = Array.from(new Uint8Array(signatureBytes))
270
+ .map((b) => b.toString(16).padStart(2, "0"))
271
+ .join("");
272
+ // Constant-time comparison
273
+ return signature === expectedSignature;
274
+ }
275
+ /**
276
+ * Handle incoming webhook events from Asana
277
+ */
278
+ async onWebhook(request, projectId, authToken) {
279
+ const payload = request.body;
280
+ // Asana webhook handshake
281
+ if (request.headers["x-hook-secret"]) {
282
+ // This is the initial handshake, respond with the secret
283
+ // Note: The network tool should handle this automatically
284
+ return;
285
+ }
286
+ // Verify webhook signature
287
+ const webhookId = await this.get(`webhook_id_${projectId}`);
288
+ if (webhookId && request.rawBody) {
289
+ const signature = request.headers["x-hook-signature"];
290
+ // For Asana, the secret is the webhook ID itself
291
+ const isValid = await this.verifyAsanaSignature(signature, request.rawBody, webhookId);
292
+ if (!isValid) {
293
+ console.warn("Asana webhook signature verification failed");
294
+ return;
295
+ }
296
+ }
297
+ // Process events
298
+ if (payload.events && Array.isArray(payload.events)) {
299
+ const callbackToken = await this.get(`callback_${projectId}`);
300
+ if (!callbackToken)
301
+ return;
302
+ const client = await this.getClient(authToken);
303
+ for (const event of payload.events) {
304
+ if (event.resource?.resource_type === "task") {
305
+ try {
306
+ // Fetch full task details
307
+ const task = await client.tasks.getTask(event.resource.gid, {
308
+ opt_fields: [
309
+ "name",
310
+ "notes",
311
+ "completed",
312
+ "completed_at",
313
+ "created_at",
314
+ "modified_at",
315
+ ].join(","),
316
+ });
317
+ const activityWithNotes = await this.convertTaskToActivity(task, projectId);
318
+ // Webhooks are incremental updates - mark as unread
319
+ activityWithNotes.unread = true;
320
+ // Execute stored callback
321
+ await this.tools.callbacks.run(callbackToken, activityWithNotes);
322
+ }
323
+ catch (error) {
324
+ console.warn("Failed to process Asana task webhook:", error);
325
+ }
326
+ }
327
+ }
328
+ }
329
+ }
330
+ /**
331
+ * Stop syncing an Asana project
332
+ */
333
+ async stopSync(authToken, projectId) {
334
+ // TODO: Remove webhook when webhook support is implemented
335
+ await this.clear(`webhook_id_${projectId}`);
336
+ // Cleanup callback
337
+ const callbackToken = await this.get(`callback_${projectId}`);
338
+ if (callbackToken) {
339
+ await this.deleteCallback(callbackToken);
340
+ await this.clear(`callback_${projectId}`);
341
+ }
342
+ // Cleanup sync state
343
+ await this.clear(`sync_state_${projectId}`);
344
+ }
345
+ }
346
+ export default Asana;
347
+ //# sourceMappingURL=asana.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asana.js","sourceRoot":"","sources":["../src/asana.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { Asana } from "./asana";
2
+ export { default } from "./asana";
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { Asana } from "./asana";
2
+ export { default } from "./asana";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@plotday/tool-asana",
3
+ "displayName": "Asana",
4
+ "description": "Sync with Asana project management",
5
+ "author": "Plot <team@plot.day> (https://plot.day)",
6
+ "license": "MIT",
7
+ "version": "0.2.0",
8
+ "type": "module",
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "@plotday/source": "./src/index.ts",
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "README.md",
21
+ "LICENSE"
22
+ ],
23
+ "dependencies": {
24
+ "asana": "^3.0.10",
25
+ "@plotday/twister": "^0.26.0"
26
+ },
27
+ "devDependencies": {
28
+ "@types/asana": "^0.18.17",
29
+ "@types/node": "^25.0.3",
30
+ "typescript": "^5.9.3"
31
+ },
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/plotday/plot.git",
35
+ "directory": "tools/asana"
36
+ },
37
+ "homepage": "https://plot.day",
38
+ "bugs": {
39
+ "url": "https://github.com/plotday/plot/issues"
40
+ },
41
+ "keywords": [
42
+ "plot",
43
+ "tool",
44
+ "asana",
45
+ "project-management"
46
+ ],
47
+ "publishConfig": {
48
+ "access": "public"
49
+ },
50
+ "scripts": {
51
+ "build": "tsc",
52
+ "clean": "rm -rf dist"
53
+ }
54
+ }