Skip to content

Commit 9428f5b

Browse files
committed
Return only id on create for performance
1 parent 289cd83 commit 9428f5b

13 files changed

Lines changed: 61 additions & 111 deletions

File tree

.changeset/tangy-foxes-stand.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@plotday/twister": minor
3+
---
4+
5+
Changed: BREAKING: Return only the id when creating/upserting to increase performance

.changeset/tasty-kids-count.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@plotday/tool-linear": patch
3+
"@plotday/tool-gmail": patch
4+
"@plotday/tool-slack": patch
5+
---
6+
7+
Changed: Use new return values from create functions

tools/gmail/src/gmail.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {
22
type ActivityLink,
3+
type NewActivityWithNotes,
34
Serializable,
4-
type SyncUpdate,
55
Tool,
66
type ToolBuilder,
77
} from "@plotday/twister";
@@ -200,7 +200,7 @@ export class Gmail extends Tool<Gmail> implements MessagingTool {
200200

201201
async startSync<
202202
TArgs extends Serializable[],
203-
TCallback extends (syncUpdate: SyncUpdate, ...args: TArgs) => any
203+
TCallback extends (thread: NewActivityWithNotes, ...args: TArgs) => any
204204
>(
205205
options: {
206206
authToken: string;

tools/linear/src/linear.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
type NewActivityWithNotes,
99
type NewNote,
1010
Serializable,
11-
type SyncUpdate,
1211
} from "@plotday/twister";
1312
import type {
1413
Project,
@@ -277,15 +276,15 @@ export class Linear extends Tool<Linear> implements ProjectTool {
277276

278277
// Process each issue
279278
for (const issue of issuesConnection.nodes) {
280-
const syncUpdate = await this.convertIssueToSyncUpdate(
279+
const activity = await this.convertIssueToActivity(
281280
issue,
282281
projectId,
283282
state.initialSync
284283
);
285284

286-
if (syncUpdate) {
285+
if (activity) {
287286
// Execute the callback using the callback token
288-
await this.tools.callbacks.run(callbackToken, syncUpdate);
287+
await this.tools.callbacks.run(callbackToken, activity);
289288
}
290289
}
291290

@@ -313,13 +312,13 @@ export class Linear extends Tool<Linear> implements ProjectTool {
313312
}
314313

315314
/**
316-
* Convert a Linear issue to a SyncUpdate
315+
* Convert a Linear issue to a NewActivityWithNotes
317316
*/
318-
private async convertIssueToSyncUpdate(
317+
private async convertIssueToActivity(
319318
issue: Issue,
320319
projectId: string,
321320
initialSync: boolean
322-
): Promise<SyncUpdate | null> {
321+
): Promise<NewActivityWithNotes | null> {
323322
const creator = await issue.creator;
324323
const assignee = await issue.assignee;
325324
const comments = await issue.comments();
@@ -579,16 +578,16 @@ export class Linear extends Tool<Linear> implements ProjectTool {
579578
const client = await this.getClient(authToken);
580579
const issue = await client.issue(payload.data.id);
581580

582-
const syncUpdate = await this.convertIssueToSyncUpdate(
581+
const activity = await this.convertIssueToActivity(
583582
issue,
584583
projectId,
585584
false // incremental update, not initial sync
586585
);
587586

588-
if (!syncUpdate) return;
587+
if (!activity) return;
589588

590-
// Execute stored callback (unread flag already set by convertIssueToSyncUpdate)
591-
await this.tools.callbacks.run(callbackToken, syncUpdate);
589+
// Execute stored callback (unread flag already set by convertIssueToActivity)
590+
await this.tools.callbacks.run(callbackToken, activity);
592591
}
593592
}
594593

tools/slack/src/slack.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {
22
type ActivityLink,
3+
type NewActivityWithNotes,
34
Serializable,
4-
type SyncUpdate,
55
Tool,
66
type ToolBuilder,
77
} from "@plotday/twister";
@@ -202,7 +202,7 @@ export class Slack extends Tool<Slack> implements MessagingTool {
202202

203203
async startSync<
204204
TArgs extends Serializable[],
205-
TCallback extends (syncUpdate: SyncUpdate, ...args: TArgs) => any
205+
TCallback extends (thread: NewActivityWithNotes, ...args: TArgs) => any
206206
>(
207207
options: {
208208
authToken: string;

twister/src/common/calendar.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ActivityLink, Serializable, SyncUpdate } from "../index";
1+
import type { ActivityLink, NewActivityWithNotes, Serializable } from "../index";
22

33
/**
44
* Represents successful calendar authorization.
@@ -115,18 +115,12 @@ export type SyncOptions = {
115115
* }
116116
*
117117
* async onCalendarEvent(
118-
* syncUpdate: SyncUpdate,
118+
* activity: NewActivityWithNotes,
119119
* syncMeta: { initialSync: boolean }
120120
* ) {
121121
* // Step 4: Twist decides what to do with the data
122122
* // Tool built the NewActivity, twist saves it
123-
* if ("activityId" in syncUpdate) {
124-
* // Update existing activity
125-
* await this.plot.updateActivity(syncUpdate.activityId, syncUpdate.update);
126-
* } else {
127-
* // Create/upsert new activity using source/key pattern
128-
* await this.plot.createActivity(syncUpdate);
129-
* }
123+
* await this.plot.createActivity(activity);
130124
* }
131125
* }
132126
* ```
@@ -183,14 +177,14 @@ export type CalendarTool = {
183177
* @param options.calendarId - ID of the calendar to sync
184178
* @param options.timeMin - Earliest date to sync events from (inclusive)
185179
* @param options.timeMax - Latest date to sync events to (exclusive)
186-
* @param callback - Function receiving (syncUpdate, ...extraArgs) for each synced event
180+
* @param callback - Function receiving (activity, ...extraArgs) for each synced event
187181
* @param extraArgs - Additional arguments to pass to the callback (type-checked, no functions allowed)
188182
* @returns Promise that resolves when sync setup is complete
189183
* @throws When auth token is invalid or calendar doesn't exist
190184
*/
191185
startSync<
192186
TArgs extends Serializable[],
193-
TCallback extends (syncUpdate: SyncUpdate, ...args: TArgs) => any
187+
TCallback extends (activity: NewActivityWithNotes, ...args: TArgs) => any
194188
>(
195189
options: {
196190
authToken: string;

twister/src/common/messaging.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ActivityLink, Serializable, SyncUpdate } from "../index";
1+
import type { ActivityLink, NewActivityWithNotes, Serializable } from "../index";
22

33
/**
44
* Represents a successful messaging service authorization.
@@ -77,8 +77,7 @@ export type MessagingTool = {
7777
/**
7878
* Begins synchronizing messages from a specific channel.
7979
*
80-
* Email threads and chat conversations are converted to SyncUpdate objects,
81-
* which can be either new items or updates to existing items.
80+
* Email threads and chat conversations are converted to NewActivityWithNotes objects.
8281
*
8382
* **Recommended Implementation** (Strategy 2 - Upsert via Source/Key):
8483
* - Set Activity.source to the thread/conversation URL or stable ID (e.g., "slack:{channelId}:{threadTs}")
@@ -96,13 +95,13 @@ export type MessagingTool = {
9695
* @param options.authToken - Authorization token for access
9796
* @param options.channelId - ID of the channel (e.g., channel, inbox) to sync
9897
* @param options.timeMin - Earliest date to sync events from (inclusive)
99-
* @param callback - Function receiving (syncUpdate, ...extraArgs) for each synced conversation
98+
* @param callback - Function receiving (thread, ...extraArgs) for each synced conversation
10099
* @param extraArgs - Additional arguments to pass to the callback (type-checked, no functions allowed)
101100
* @returns Promise that resolves when sync setup is complete
102101
*/
103102
startSync<
104103
TArgs extends Serializable[],
105-
TCallback extends (syncUpdate: SyncUpdate, ...args: TArgs) => any
104+
TCallback extends (thread: NewActivityWithNotes, ...args: TArgs) => any
106105
>(
107106
options: {
108107
authToken: string;

twister/src/common/projects.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import type {
22
Activity,
33
ActivityLink,
44
ActivityMeta,
5+
NewActivityWithNotes,
56
Serializable,
6-
SyncUpdate,
77
} from "../index";
88

99
/**
@@ -83,8 +83,7 @@ export type ProjectTool = {
8383
/**
8484
* Begins synchronizing issues from a specific project.
8585
*
86-
* Issues and tasks are converted to SyncUpdate objects, which can be either
87-
* new items or updates to existing items.
86+
* Issues and tasks are converted to NewActivityWithNotes objects.
8887
*
8988
* **Recommended Implementation** (Strategy 2 - Upsert via Source/Key):
9089
* - Set Activity.source to the issue's canonical URL (e.g., Linear issue URL, Jira issue URL)
@@ -104,13 +103,13 @@ export type ProjectTool = {
104103
* @param options.authToken - Authorization token for access
105104
* @param options.projectId - ID of the project to sync
106105
* @param options.timeMin - Earliest date to sync issues from (inclusive)
107-
* @param callback - Function receiving (syncUpdate, ...extraArgs) for each synced issue
106+
* @param callback - Function receiving (activity, ...extraArgs) for each synced issue
108107
* @param extraArgs - Additional arguments to pass to the callback (type-checked, no functions allowed)
109108
* @returns Promise that resolves when sync setup is complete
110109
*/
111110
startSync<
112111
TArgs extends Serializable[],
113-
TCallback extends (syncUpdate: SyncUpdate, ...args: TArgs) => any
112+
TCallback extends (activity: NewActivityWithNotes, ...args: TArgs) => any
114113
>(
115114
options: {
116115
authToken: string;

twister/src/plot.ts

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,6 @@ export type ActivityOccurrence = {
506506
end: Date | string | null;
507507
done: Date | null;
508508
title: string;
509-
preview: string | null;
510509
/**
511510
* Meta is merged, with the occurrence's meta taking precedence.
512511
*/
@@ -868,45 +867,6 @@ export type ActivityUpdate = (
868867
occurrences?: (NewActivityOccurrence | ActivityOccurrenceUpdate)[];
869868
};
870869

871-
/**
872-
* Represents a sync update from a tool.
873-
*
874-
* Tools that sync from external sources can send either:
875-
* - A new activity with notes (for newly discovered items)
876-
* - An update to an existing activity with optional new notes (for changed items)
877-
*
878-
* This allows tools to manage their own update detection logic locally,
879-
* providing Plot with the appropriate operation to perform.
880-
*
881-
* @example
882-
* ```typescript
883-
* // Send a new activity
884-
* const newItem: SyncUpdate = {
885-
* type: ActivityType.Event,
886-
* title: "New Meeting",
887-
* id: Uuid.Generate(), // Tool-generated ID
888-
* notes: [{ id: Uuid.Generate(), content: "Description" }]
889-
* };
890-
*
891-
* // Send an update to existing activity
892-
* const update: SyncUpdate = {
893-
* activityId: existingActivityId,
894-
* update: { title: "Updated Meeting Title" },
895-
* notes: [{ id: Uuid.Generate(), content: "New comment" }]
896-
* };
897-
* ```
898-
*/
899-
export type SyncUpdate =
900-
| NewActivityWithNotes
901-
| {
902-
/** ID of the activity to update */
903-
activityId: string;
904-
/** Optional updates to the activity itself */
905-
update?: ActivityUpdate;
906-
/** Optional new notes to add to the activity */
907-
notes?: NewNote[];
908-
};
909-
910870
/**
911871
* Represents a note within an activity.
912872
*

twister/src/tools/plot.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -219,12 +219,12 @@ export abstract class Plot extends ITool {
219219
* will be preserved in the created activity.
220220
*
221221
* @param activity - The activity data to create
222-
* @returns Promise resolving to the complete created activity
222+
* @returns Promise resolving to the created activity's ID
223223
*/
224224
// eslint-disable-next-line @typescript-eslint/no-unused-vars
225225
abstract createActivity(
226226
activity: NewActivity | NewActivityWithNotes
227-
): Promise<Activity>;
227+
): Promise<Uuid>;
228228

229229
/**
230230
* Creates multiple activities in a single batch operation.
@@ -234,12 +234,12 @@ export abstract class Plot extends ITool {
234234
* All activities are created with the same author and access control rules.
235235
*
236236
* @param activities - Array of activity data to create
237-
* @returns Promise resolving to array of created activities
237+
* @returns Promise resolving to array of created activity IDs
238238
*/
239239
// eslint-disable-next-line @typescript-eslint/no-unused-vars
240240
abstract createActivities(
241241
activities: (NewActivity | NewActivityWithNotes)[]
242-
): Promise<Activity[]>;
242+
): Promise<Uuid[]>;
243243

244244
/**
245245
* Updates an existing activity in the Plot system.
@@ -321,7 +321,7 @@ export abstract class Plot extends ITool {
321321
* an ID and author information based on the current execution context.
322322
*
323323
* @param note - The note data to create
324-
* @returns Promise resolving to the complete created note
324+
* @returns Promise resolving to the created note's ID
325325
*
326326
* @example
327327
* ```typescript
@@ -345,7 +345,7 @@ export abstract class Plot extends ITool {
345345
* ```
346346
*/
347347
// eslint-disable-next-line @typescript-eslint/no-unused-vars
348-
abstract createNote(note: NewNote): Promise<Note>;
348+
abstract createNote(note: NewNote): Promise<Uuid>;
349349

350350
/**
351351
* Creates multiple notes in a single batch operation.
@@ -355,7 +355,7 @@ export abstract class Plot extends ITool {
355355
* All notes are created with the same author and access control rules.
356356
*
357357
* @param notes - Array of note data to create
358-
* @returns Promise resolving to array of created notes
358+
* @returns Promise resolving to array of created note IDs
359359
*
360360
* @example
361361
* ```typescript
@@ -373,7 +373,7 @@ export abstract class Plot extends ITool {
373373
* ```
374374
*/
375375
// eslint-disable-next-line @typescript-eslint/no-unused-vars
376-
abstract createNotes(notes: NewNote[]): Promise<Note[]>;
376+
abstract createNotes(notes: NewNote[]): Promise<Uuid[]>;
377377

378378
/**
379379
* Updates an existing note in the Plot system.

0 commit comments

Comments
 (0)