@plotday/twister 0.45.0 → 0.47.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.
Files changed (53) hide show
  1. package/dist/connector.d.ts +49 -1
  2. package/dist/connector.d.ts.map +1 -1
  3. package/dist/connector.js +24 -0
  4. package/dist/connector.js.map +1 -1
  5. package/dist/docs/assets/hierarchy.js +1 -1
  6. package/dist/docs/assets/navigation.js +1 -1
  7. package/dist/docs/assets/search.js +1 -1
  8. package/dist/docs/classes/index.Connector.html +65 -42
  9. package/dist/docs/classes/index.Imap.html +1 -1
  10. package/dist/docs/classes/index.Options.html +1 -1
  11. package/dist/docs/classes/index.Smtp.html +1 -1
  12. package/dist/docs/classes/tool.ITool.html +1 -1
  13. package/dist/docs/classes/tools_ai.AI.html +1 -1
  14. package/dist/docs/classes/tools_callbacks.Callbacks.html +1 -1
  15. package/dist/docs/classes/tools_integrations.Integrations.html +9 -9
  16. package/dist/docs/classes/tools_network.Network.html +1 -1
  17. package/dist/docs/classes/tools_plot.Plot.html +1 -1
  18. package/dist/docs/classes/tools_store.Store.html +1 -1
  19. package/dist/docs/classes/tools_tasks.Tasks.html +1 -1
  20. package/dist/docs/classes/tools_twists.Twists.html +1 -1
  21. package/dist/docs/classes/twist.Twist.html +34 -26
  22. package/dist/docs/documents/Building_Connectors.html +66 -1
  23. package/dist/docs/enums/tools_integrations.AuthProvider.html +12 -12
  24. package/dist/docs/hierarchy.html +1 -1
  25. package/dist/docs/media/AGENTS.md +90 -10
  26. package/dist/docs/media/SYNC_STRATEGIES.md +5 -1
  27. package/dist/docs/modules/index.html +1 -1
  28. package/dist/docs/types/index.CreateLinkDraft.html +21 -0
  29. package/dist/docs/types/tools_integrations.ArchiveLinkFilter.html +5 -5
  30. package/dist/docs/types/tools_integrations.AuthToken.html +4 -4
  31. package/dist/docs/types/tools_integrations.Authorization.html +4 -4
  32. package/dist/docs/types/tools_integrations.LinkTypeConfig.html +8 -4
  33. package/dist/docs/types/tools_integrations.SyncContext.html +2 -2
  34. package/dist/llm-docs/connector.d.ts +1 -1
  35. package/dist/llm-docs/connector.d.ts.map +1 -1
  36. package/dist/llm-docs/connector.js +1 -1
  37. package/dist/llm-docs/connector.js.map +1 -1
  38. package/dist/llm-docs/tools/integrations.d.ts +1 -1
  39. package/dist/llm-docs/tools/integrations.d.ts.map +1 -1
  40. package/dist/llm-docs/tools/integrations.js +1 -1
  41. package/dist/llm-docs/tools/integrations.js.map +1 -1
  42. package/dist/llm-docs/twist.d.ts +1 -1
  43. package/dist/llm-docs/twist.d.ts.map +1 -1
  44. package/dist/llm-docs/twist.js +1 -1
  45. package/dist/llm-docs/twist.js.map +1 -1
  46. package/dist/tools/integrations.d.ts +7 -0
  47. package/dist/tools/integrations.d.ts.map +1 -1
  48. package/dist/tools/integrations.js.map +1 -1
  49. package/dist/twist.d.ts +17 -1
  50. package/dist/twist.d.ts.map +1 -1
  51. package/dist/twist.js +17 -1
  52. package/dist/twist.js.map +1 -1
  53. package/package.json +1 -1
@@ -6,6 +6,7 @@
6
6
  <li><a href="#data-sync">Data Sync</a></li>
7
7
  <li><a href="#batch-processing">Batch Processing</a></li>
8
8
  <li><a href="#complete-example">Complete Example</a></li>
9
+ <li><a href="#creating-items-from-plot-oncreatelink">Creating Items from Plot (<code>onCreateLink</code>)</a></li>
9
10
  <li><a href="#best-practices">Best Practices</a></li>
10
11
  </ul>
11
12
  <hr>
@@ -121,6 +122,70 @@
121
122
  </code><button type="button">Copy</button></pre>
122
123
 
123
124
  <hr>
125
+ <h2 id="creating-items-from-plot-" class="tsd-anchor-link">Creating Items from Plot (<code>onCreateLink</code>)<a href="#creating-items-from-plot-" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Some connectors let users start a new thread that creates a brand-new
126
+ external item — a Linear issue, a Google Calendar event, a Slack DM. Opt
127
+ in per link type:</p>
128
+ <h3 id="1-mark-the-creation-default" class="tsd-anchor-link">1. Mark the creation default<a href="#1-mark-the-creation-default" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Declare one <code>statuses[]</code> entry with <code>createDefault: true</code> on the
129
+ <code>LinkTypeConfig</code> for that type. Either on the static <code>readonly linkTypes</code>
130
+ on the class or on the dynamic per-channel linkTypes returned by
131
+ <code>getChannels</code>:</p>
132
+ <pre><code class="typescript"><span class="hl-2">readonly</span><span class="hl-1"> </span><span class="hl-2">linkTypes</span><span class="hl-1"> = [{</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-3">&quot;issue&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">&quot;Issue&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">statuses:</span><span class="hl-1"> [</span><br/><span class="hl-1"> { </span><span class="hl-2">status:</span><span class="hl-1"> </span><span class="hl-3">&quot;backlog&quot;</span><span class="hl-1">, </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">&quot;Backlog&quot;</span><span class="hl-1"> },</span><br/><span class="hl-1"> { </span><span class="hl-2">status:</span><span class="hl-1"> </span><span class="hl-3">&quot;unstarted&quot;</span><span class="hl-1">, </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">&quot;To Do&quot;</span><span class="hl-1">, </span><span class="hl-2">todo:</span><span class="hl-1"> </span><span class="hl-4">true</span><span class="hl-1">, </span><span class="hl-2">createDefault:</span><span class="hl-1"> </span><span class="hl-4">true</span><span class="hl-1"> },</span><br/><span class="hl-1"> { </span><span class="hl-2">status:</span><span class="hl-1"> </span><span class="hl-3">&quot;completed&quot;</span><span class="hl-1">, </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">&quot;Done&quot;</span><span class="hl-1">, </span><span class="hl-2">tag:</span><span class="hl-1"> </span><span class="hl-2">Tag</span><span class="hl-1">.</span><span class="hl-2">Done</span><span class="hl-1">, </span><span class="hl-2">done:</span><span class="hl-1"> </span><span class="hl-4">true</span><span class="hl-1"> },</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1">}];</span>
133
+ </code><button type="button">Copy</button></pre>
134
+
135
+ <p>A link type opts in to Plot-initiated creation by having at least one
136
+ status with <code>createDefault: true</code>. The marker also tells the UI which
137
+ status to pre-select in the picker.</p>
138
+ <h3 id="2-implement" class="tsd-anchor-link">2. Implement <code>onCreateLink(draft)</code><a href="#2-implement" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="typescript"><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">onCreateLink</span><span class="hl-1">(</span><span class="hl-2">draft</span><span class="hl-1">: </span><span class="hl-2">CreateLinkDraft</span><span class="hl-1">): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-2">NewLinkWithNotes</span><span class="hl-1"> | </span><span class="hl-4">null</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> const </span><span class="hl-2">client</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">getClient</span><span class="hl-1">(</span><span class="hl-2">draft</span><span class="hl-1">.</span><span class="hl-2">channelId</span><span class="hl-1">);</span><br/><span class="hl-1"> const </span><span class="hl-2">payload</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-2">client</span><span class="hl-1">.</span><span class="hl-6">createIssue</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">teamId:</span><span class="hl-1"> </span><span class="hl-2">draft</span><span class="hl-1">.</span><span class="hl-2">channelId</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-2">draft</span><span class="hl-1">.</span><span class="hl-2">title</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">description:</span><span class="hl-1"> </span><span class="hl-2">draft</span><span class="hl-1">.</span><span class="hl-2">noteContent</span><span class="hl-1"> ?? </span><span class="hl-4">undefined</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">stateId:</span><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-6">resolveStateId</span><span class="hl-1">(</span><span class="hl-2">client</span><span class="hl-1">, </span><span class="hl-2">draft</span><span class="hl-1">.</span><span class="hl-2">channelId</span><span class="hl-1">, </span><span class="hl-2">draft</span><span class="hl-1">.</span><span class="hl-2">status</span><span class="hl-1">),</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> const </span><span class="hl-2">issue</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-2">payload</span><span class="hl-1">.</span><span class="hl-2">issue</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-6">if</span><span class="hl-1"> (!</span><span class="hl-2">issue</span><span class="hl-1">) return null;</span><br/><span class="hl-1"> return {</span><br/><span class="hl-1"> </span><span class="hl-15">source</span><span class="hl-1">: </span><span class="hl-3">`linear:issue:</span><span class="hl-4">${</span><span class="hl-2">issue</span><span class="hl-13">.</span><span class="hl-2">id</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-15">type</span><span class="hl-1">: </span><span class="hl-3">&quot;issue&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-15">title</span><span class="hl-1">: </span><span class="hl-2">issue</span><span class="hl-1">.</span><span class="hl-2">title</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-15">status</span><span class="hl-1">: </span><span class="hl-2">draft</span><span class="hl-1">.</span><span class="hl-2">status</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-15">created</span><span class="hl-1">: </span><span class="hl-2">issue</span><span class="hl-1">.</span><span class="hl-2">createdAt</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-15">sourceUrl</span><span class="hl-1">: </span><span class="hl-2">issue</span><span class="hl-1">.</span><span class="hl-2">url</span><span class="hl-1"> ?? </span><span class="hl-4">null</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-15">meta</span><span class="hl-1">: { </span><span class="hl-15">linearId</span><span class="hl-1">: </span><span class="hl-2">issue</span><span class="hl-1">.</span><span class="hl-2">id</span><span class="hl-1">, </span><span class="hl-15">projectId</span><span class="hl-1">: </span><span class="hl-2">draft</span><span class="hl-1">.</span><span class="hl-2">channelId</span><span class="hl-1"> },</span><br/><span class="hl-1"> };</span><br/><span class="hl-1">}</span>
139
+ </code><button type="button">Copy</button></pre>
140
+
141
+ <h3 id="" class="tsd-anchor-link"><code>CreateLinkDraft</code></h3><table>
142
+ <thead>
143
+ <tr>
144
+ <th>Field</th>
145
+ <th>Purpose</th>
146
+ </tr>
147
+ </thead>
148
+ <tbody>
149
+ <tr>
150
+ <td><code>channelId</code></td>
151
+ <td>Target channel (Linear team, Google calendar, Slack workspace).</td>
152
+ </tr>
153
+ <tr>
154
+ <td><code>type</code></td>
155
+ <td>Link type id matching a <code>LinkTypeConfig.type</code>.</td>
156
+ </tr>
157
+ <tr>
158
+ <td><code>status</code></td>
159
+ <td>Status the user selected; matches <code>statuses[].status</code>.</td>
160
+ </tr>
161
+ <tr>
162
+ <td><code>title</code></td>
163
+ <td>Thread title (post AI title generation).</td>
164
+ </tr>
165
+ <tr>
166
+ <td><code>noteContent</code></td>
167
+ <td>Markdown of the thread's first note, or <code>null</code>.</td>
168
+ </tr>
169
+ <tr>
170
+ <td><code>contacts</code></td>
171
+ <td>Thread's contacts, minus the creating user — use for email recipients, DM members, invitees.</td>
172
+ </tr>
173
+ </tbody>
174
+ </table>
175
+ <h3 id="platform-guarantees" class="tsd-anchor-link">Platform guarantees<a href="#platform-guarantees" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><ul>
176
+ <li>The returned link is attached to the originating Plot thread
177
+ automatically. <strong>Don't call <code>integrations.saveLink()</code> yourself</strong> — doing
178
+ so creates a duplicate thread.</li>
179
+ <li>The runtime fills <code>channelId</code> and <code>type</code> on the saved link from the
180
+ draft if you omit them, so status-label lookup and channel-scoped
181
+ rendering keep working.</li>
182
+ <li>Loop prevention is handled by the runtime: the link is written with
183
+ the twist as <code>updated_by</code>, so subsequent syncs of the same external id
184
+ won't retrigger <code>onLinkUpdated</code> for the initial state.</li>
185
+ </ul>
186
+ <h3 id="return-to-abort" class="tsd-anchor-link">Return <code>null</code> to abort<a href="#return-to-abort" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>If creation shouldn't proceed (wrong link type, external API refused,
187
+ user not authorized), return <code>null</code>. The Plot thread is still saved; no
188
+ link is attached.</p>
124
189
  <h2 id="best-practices" class="tsd-anchor-link">Best Practices<a href="#best-practices" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><h3 id="1-always-inject-sync-metadata" class="tsd-anchor-link">1. Always Inject Sync Metadata<a href="#1-always-inject-sync-metadata" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Every synced activity must include <code>syncProvider</code> and <code>channelId</code> in <code>meta</code> for bulk operations (e.g., archiving all activities when a channel is disabled).</p>
125
190
  <h3 id="2-use-canonical-source-urls" class="tsd-anchor-link">2. Use Canonical Source URLs<a href="#2-use-canonical-source-urls" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Use immutable IDs in <code>Activity.source</code> for deduplication. For services with mutable identifiers (like Jira issue keys), use the immutable ID in <code>source</code> and store the mutable key in <code>meta</code>.</p>
126
191
  <h3 id="3-handle-html-content-correctly" class="tsd-anchor-link">3. Handle HTML Content Correctly<a href="#3-handle-html-content-correctly" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Never strip HTML tags locally. Pass raw HTML with <code>contentType: &quot;html&quot;</code> for server-side markdown conversion.</p>
@@ -134,4 +199,4 @@
134
199
  <li><strong><a href="Built-in_Tools.html">Built-in Tools Guide</a></strong> - Complete reference for Plot, Store, Integrations, and more</li>
135
200
  <li><strong><a href="../media/MULTI_USER_AUTH.md">Multi-User Auth</a></strong> - Per-user auth for write-backs</li>
136
201
  </ul>
137
- </div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#building-connectors"><span>Building <wbr/>Connectors</span></a><ul><li><a href="#table-of-contents"><span>Table of <wbr/>Contents</span></a></li><li><a href="#connectors-vs-twists"><span>Connectors vs <wbr/>Twists</span></a></li><li><a href="#connector-structure"><span>Connector <wbr/>Structure</span></a></li><li><ul><li><a href="#package-structure"><span>Package <wbr/>Structure</span></a></li></ul></li><li><a href="#oauth-and-channel-lifecycle"><span>O<wbr/>Auth and <wbr/>Channel <wbr/>Lifecycle</span></a></li><li><ul><li><a href="#how-it-works"><span>How <wbr/>It <wbr/>Works</span></a></li><li><a href="#getchannels"><span>get<wbr/>Channels</span></a></li><li><a href="#onchannelenabled"><span>on<wbr/>Channel<wbr/>Enabled</span></a></li><li><a href="#onchanneldisabled"><span>on<wbr/>Channel<wbr/>Disabled</span></a></li><li><a href="#getting-auth-tokens"><span>Getting <wbr/>Auth <wbr/>Tokens</span></a></li></ul></li><li><a href="#data-sync"><span>Data <wbr/>Sync</span></a></li><li><ul><li><a href="#transforming-external-items"><span>Transforming <wbr/>External <wbr/>Items</span></a></li><li><a href="#initial-vs-incremental-sync"><span>Initial vs <wbr/>Incremental <wbr/>Sync</span></a></li></ul></li><li><a href="#batch-processing"><span>Batch <wbr/>Processing</span></a></li><li><a href="#complete-example"><span>Complete <wbr/>Example</span></a></li><li><a href="#best-practices"><span>Best <wbr/>Practices</span></a></li><li><ul><li><a href="#1-always-inject-sync-metadata"><span>1. <wbr/>Always <wbr/>Inject <wbr/>Sync <wbr/>Metadata</span></a></li><li><a href="#2-use-canonical-source-urls"><span>2. <wbr/>Use <wbr/>Canonical <wbr/>Source <wbr/>UR<wbr/>Ls</span></a></li><li><a href="#3-handle-html-content-correctly"><span>3. <wbr/>Handle <wbr/>HTML <wbr/>Content <wbr/>Correctly</span></a></li><li><a href="#4-add-localhost-guard-for-webhooks"><span>4. <wbr/>Add <wbr/>Localhost <wbr/>Guard for <wbr/>Webhooks</span></a></li><li><a href="#5-maintain-callback-backward-compatibility"><span>5. <wbr/>Maintain <wbr/>Callback <wbr/>Backward <wbr/>Compatibility</span></a></li><li><a href="#6-clean-up-on-disable"><span>6. <wbr/>Clean <wbr/>Up on <wbr/>Disable</span></a></li></ul></li><li><a href="#next-steps"><span>Next <wbr/>Steps</span></a></li></ul></div></details></div><div class="site-menu"><nav id="tsd-sidebar-links" class="tsd-navigation"><a href="https://plot.day" class="tsd-nav-link">Plot</a><a href="https://github.com/plotday/plot" class="tsd-nav-link">GitHub</a><a href="https://www.npmjs.com/package/@plotday/twister" class="tsd-nav-link">NPM</a></nav><nav class="tsd-navigation"><a href="../modules.html">Creating Plot Twists</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
202
+ </div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#building-connectors"><span>Building <wbr/>Connectors</span></a><ul><li><a href="#table-of-contents"><span>Table of <wbr/>Contents</span></a></li><li><a href="#connectors-vs-twists"><span>Connectors vs <wbr/>Twists</span></a></li><li><a href="#connector-structure"><span>Connector <wbr/>Structure</span></a></li><li><ul><li><a href="#package-structure"><span>Package <wbr/>Structure</span></a></li></ul></li><li><a href="#oauth-and-channel-lifecycle"><span>O<wbr/>Auth and <wbr/>Channel <wbr/>Lifecycle</span></a></li><li><ul><li><a href="#how-it-works"><span>How <wbr/>It <wbr/>Works</span></a></li><li><a href="#getchannels"><span>get<wbr/>Channels</span></a></li><li><a href="#onchannelenabled"><span>on<wbr/>Channel<wbr/>Enabled</span></a></li><li><a href="#onchanneldisabled"><span>on<wbr/>Channel<wbr/>Disabled</span></a></li><li><a href="#getting-auth-tokens"><span>Getting <wbr/>Auth <wbr/>Tokens</span></a></li></ul></li><li><a href="#data-sync"><span>Data <wbr/>Sync</span></a></li><li><ul><li><a href="#transforming-external-items"><span>Transforming <wbr/>External <wbr/>Items</span></a></li><li><a href="#initial-vs-incremental-sync"><span>Initial vs <wbr/>Incremental <wbr/>Sync</span></a></li></ul></li><li><a href="#batch-processing"><span>Batch <wbr/>Processing</span></a></li><li><a href="#complete-example"><span>Complete <wbr/>Example</span></a></li><li><a href="#creating-items-from-plot-"><span>Creating <wbr/>Items from <wbr/>Plot ()</span></a></li><li><ul><li><a href="#1-mark-the-creation-default"><span>1. <wbr/>Mark the creation default</span></a></li><li><a href="#2-implement"><span>2. <wbr/>Implement </span></a></li><li><a href="#"><span></span></a></li><li><a href="#platform-guarantees"><span>Platform guarantees</span></a></li><li><a href="#return-to-abort"><span>Return to abort</span></a></li></ul></li><li><a href="#best-practices"><span>Best <wbr/>Practices</span></a></li><li><ul><li><a href="#1-always-inject-sync-metadata"><span>1. <wbr/>Always <wbr/>Inject <wbr/>Sync <wbr/>Metadata</span></a></li><li><a href="#2-use-canonical-source-urls"><span>2. <wbr/>Use <wbr/>Canonical <wbr/>Source <wbr/>UR<wbr/>Ls</span></a></li><li><a href="#3-handle-html-content-correctly"><span>3. <wbr/>Handle <wbr/>HTML <wbr/>Content <wbr/>Correctly</span></a></li><li><a href="#4-add-localhost-guard-for-webhooks"><span>4. <wbr/>Add <wbr/>Localhost <wbr/>Guard for <wbr/>Webhooks</span></a></li><li><a href="#5-maintain-callback-backward-compatibility"><span>5. <wbr/>Maintain <wbr/>Callback <wbr/>Backward <wbr/>Compatibility</span></a></li><li><a href="#6-clean-up-on-disable"><span>6. <wbr/>Clean <wbr/>Up on <wbr/>Disable</span></a></li></ul></li><li><a href="#next-steps"><span>Next <wbr/>Steps</span></a></li></ul></div></details></div><div class="site-menu"><nav id="tsd-sidebar-links" class="tsd-navigation"><a href="https://plot.day" class="tsd-nav-link">Plot</a><a href="https://github.com/plotday/plot" class="tsd-nav-link">GitHub</a><a href="https://www.npmjs.com/package/@plotday/twister" class="tsd-nav-link">NPM</a></nav><nav class="tsd-navigation"><a href="../modules.html">Creating Plot Twists</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
@@ -1,7 +1,7 @@
1
1
  <!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>AuthProvider | Creating Plot Twists</title><link rel="icon" href="../assets/favicon.svg" type="image/svg+xml"/><meta name="description" content="Documentation for Creating Plot Twists"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script><script async src="../assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="/" class="title">Creating Plot Twists</a><div id="tsd-toolbar-links"><a href="https://plot.day">Plot</a><a href="https://github.com/plotday/plot">GitHub</a><a href="https://www.npmjs.com/package/@plotday/twister">NPM</a></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="../modules/tools_integrations.html">tools/integrations</a></li><li><a href="" aria-current="page">AuthProvider</a></li></ul><h1>Enumeration AuthProvider</h1></div><section class="tsd-panel tsd-comment"><div class="tsd-comment tsd-typography"><p>Enumeration of supported OAuth providers.</p>
2
2
  <p>Each provider has different OAuth endpoints, scopes, and token formats.
3
3
  The Integrations tool handles the provider-specific implementation details.</p>
4
- </div></section><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L259">tools/integrations.ts:259</a></li></ul></aside><section class="tsd-panel-group tsd-index-group"><section class="tsd-panel tsd-index-panel"><details class="tsd-index-content tsd-accordion" open><summary class="tsd-accordion-summary tsd-index-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h5 class="tsd-index-heading uppercase">Index</h5></summary><div class="tsd-accordion-details"><section class="tsd-index-section"><h3 class="tsd-index-heading">Enumeration Members</h3><div class="tsd-index-list"><a href="#google" class="tsd-index-link"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Google</span></a>
4
+ </div></section><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L266">tools/integrations.ts:266</a></li></ul></aside><section class="tsd-panel-group tsd-index-group"><section class="tsd-panel tsd-index-panel"><details class="tsd-index-content tsd-accordion" open><summary class="tsd-accordion-summary tsd-index-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h5 class="tsd-index-heading uppercase">Index</h5></summary><div class="tsd-accordion-details"><section class="tsd-index-section"><h3 class="tsd-index-heading">Enumeration Members</h3><div class="tsd-index-list"><a href="#google" class="tsd-index-link"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Google</span></a>
5
5
  <a href="#microsoft" class="tsd-index-link"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Microsoft</span></a>
6
6
  <a href="#notion" class="tsd-index-link"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Notion</span></a>
7
7
  <a href="#slack" class="tsd-index-link"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Slack</span></a>
@@ -13,14 +13,14 @@ The Integrations tool handles the provider-specific implementation details.</p>
13
13
  <a href="#hubspot" class="tsd-index-link"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Hub<wbr/>Spot</span></a>
14
14
  <a href="#todoist" class="tsd-index-link"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Todoist</span></a>
15
15
  </div></section></div></details></section></section><details class="tsd-panel-group tsd-member-group tsd-accordion" open><summary class="tsd-accordion-summary" data-key="section-Enumeration Members"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h2>Enumeration Members</h2></summary><section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="google"><span>Google</span><a href="#google" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">Google</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;google&quot;</span></div><div class="tsd-comment tsd-typography"><p>Google OAuth provider for Google Workspace services</p>
16
- </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L261">tools/integrations.ts:261</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="microsoft"><span>Microsoft</span><a href="#microsoft" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">Microsoft</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;microsoft&quot;</span></div><div class="tsd-comment tsd-typography"><p>Microsoft OAuth provider for Microsoft 365 services</p>
17
- </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L263">tools/integrations.ts:263</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="notion"><span>Notion</span><a href="#notion" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">Notion</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;notion&quot;</span></div><div class="tsd-comment tsd-typography"><p>Notion OAuth provider for Notion workspaces</p>
18
- </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L265">tools/integrations.ts:265</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="slack"><span>Slack</span><a href="#slack" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">Slack</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;slack&quot;</span></div><div class="tsd-comment tsd-typography"><p>Slack OAuth provider for Slack workspaces</p>
19
- </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L267">tools/integrations.ts:267</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="atlassian"><span>Atlassian</span><a href="#atlassian" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">Atlassian</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;atlassian&quot;</span></div><div class="tsd-comment tsd-typography"><p>Atlassian OAuth provider for Jira and Confluence</p>
20
- </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L269">tools/integrations.ts:269</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="linear"><span>Linear</span><a href="#linear" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">Linear</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;linear&quot;</span></div><div class="tsd-comment tsd-typography"><p>Linear OAuth provider for Linear workspaces</p>
21
- </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L271">tools/integrations.ts:271</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="monday"><span>Monday</span><a href="#monday" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">Monday</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;monday&quot;</span></div><div class="tsd-comment tsd-typography"><p><a href="http://Monday.com">Monday.com</a> OAuth provider</p>
22
- </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L273">tools/integrations.ts:273</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="github"><span>Git<wbr/>Hub</span><a href="#github" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">GitHub</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;github&quot;</span></div><div class="tsd-comment tsd-typography"><p>GitHub OAuth provider for GitHub repositories and organizations</p>
23
- </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L275">tools/integrations.ts:275</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="asana"><span>Asana</span><a href="#asana" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">Asana</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;asana&quot;</span></div><div class="tsd-comment tsd-typography"><p>Asana OAuth provider for Asana workspaces</p>
24
- </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L277">tools/integrations.ts:277</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="hubspot"><span>Hub<wbr/>Spot</span><a href="#hubspot" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">HubSpot</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;hubspot&quot;</span></div><div class="tsd-comment tsd-typography"><p>HubSpot OAuth provider for HubSpot CRM</p>
25
- </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L279">tools/integrations.ts:279</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="todoist"><span>Todoist</span><a href="#todoist" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">Todoist</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;todoist&quot;</span></div><div class="tsd-comment tsd-typography"><p>Todoist OAuth provider for Todoist task management</p>
26
- </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L281">tools/integrations.ts:281</a></li></ul></aside></section></section></details></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><details open class="tsd-accordion tsd-page-navigation-section"><summary class="tsd-accordion-summary" data-key="section-Enumeration Members"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>Enumeration Members</summary><div><a href="#google"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Google</span></a><a href="#microsoft"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Microsoft</span></a><a href="#notion"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Notion</span></a><a href="#slack"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Slack</span></a><a href="#atlassian"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Atlassian</span></a><a href="#linear"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Linear</span></a><a href="#monday"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Monday</span></a><a href="#github"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Git<wbr/>Hub</span></a><a href="#asana"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Asana</span></a><a href="#hubspot"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Hub<wbr/>Spot</span></a><a href="#todoist"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Todoist</span></a></div></details></div></details></div><div class="site-menu"><nav id="tsd-sidebar-links" class="tsd-navigation"><a href="https://plot.day" class="tsd-nav-link">Plot</a><a href="https://github.com/plotday/plot" class="tsd-nav-link">GitHub</a><a href="https://www.npmjs.com/package/@plotday/twister" class="tsd-nav-link">NPM</a></nav><nav class="tsd-navigation"><a href="../modules.html">Creating Plot Twists</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
16
+ </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L268">tools/integrations.ts:268</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="microsoft"><span>Microsoft</span><a href="#microsoft" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">Microsoft</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;microsoft&quot;</span></div><div class="tsd-comment tsd-typography"><p>Microsoft OAuth provider for Microsoft 365 services</p>
17
+ </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L270">tools/integrations.ts:270</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="notion"><span>Notion</span><a href="#notion" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">Notion</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;notion&quot;</span></div><div class="tsd-comment tsd-typography"><p>Notion OAuth provider for Notion workspaces</p>
18
+ </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L272">tools/integrations.ts:272</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="slack"><span>Slack</span><a href="#slack" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">Slack</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;slack&quot;</span></div><div class="tsd-comment tsd-typography"><p>Slack OAuth provider for Slack workspaces</p>
19
+ </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L274">tools/integrations.ts:274</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="atlassian"><span>Atlassian</span><a href="#atlassian" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">Atlassian</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;atlassian&quot;</span></div><div class="tsd-comment tsd-typography"><p>Atlassian OAuth provider for Jira and Confluence</p>
20
+ </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L276">tools/integrations.ts:276</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="linear"><span>Linear</span><a href="#linear" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">Linear</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;linear&quot;</span></div><div class="tsd-comment tsd-typography"><p>Linear OAuth provider for Linear workspaces</p>
21
+ </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L278">tools/integrations.ts:278</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="monday"><span>Monday</span><a href="#monday" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">Monday</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;monday&quot;</span></div><div class="tsd-comment tsd-typography"><p><a href="http://Monday.com">Monday.com</a> OAuth provider</p>
22
+ </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L280">tools/integrations.ts:280</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="github"><span>Git<wbr/>Hub</span><a href="#github" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">GitHub</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;github&quot;</span></div><div class="tsd-comment tsd-typography"><p>GitHub OAuth provider for GitHub repositories and organizations</p>
23
+ </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L282">tools/integrations.ts:282</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="asana"><span>Asana</span><a href="#asana" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">Asana</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;asana&quot;</span></div><div class="tsd-comment tsd-typography"><p>Asana OAuth provider for Asana workspaces</p>
24
+ </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L284">tools/integrations.ts:284</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="hubspot"><span>Hub<wbr/>Spot</span><a href="#hubspot" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">HubSpot</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;hubspot&quot;</span></div><div class="tsd-comment tsd-typography"><p>HubSpot OAuth provider for HubSpot CRM</p>
25
+ </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L286">tools/integrations.ts:286</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="todoist"><span>Todoist</span><a href="#todoist" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-enum-member">Todoist</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;todoist&quot;</span></div><div class="tsd-comment tsd-typography"><p>Todoist OAuth provider for Todoist task management</p>
26
+ </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/tools/integrations.ts#L288">tools/integrations.ts:288</a></li></ul></aside></section></section></details></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><details open class="tsd-accordion tsd-page-navigation-section"><summary class="tsd-accordion-summary" data-key="section-Enumeration Members"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>Enumeration Members</summary><div><a href="#google"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Google</span></a><a href="#microsoft"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Microsoft</span></a><a href="#notion"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Notion</span></a><a href="#slack"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Slack</span></a><a href="#atlassian"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Atlassian</span></a><a href="#linear"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Linear</span></a><a href="#monday"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Monday</span></a><a href="#github"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Git<wbr/>Hub</span></a><a href="#asana"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Asana</span></a><a href="#hubspot"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Hub<wbr/>Spot</span></a><a href="#todoist"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Todoist</span></a></div></details></div></details></div><div class="site-menu"><nav id="tsd-sidebar-links" class="tsd-navigation"><a href="https://plot.day" class="tsd-nav-link">Plot</a><a href="https://github.com/plotday/plot" class="tsd-nav-link">GitHub</a><a href="https://www.npmjs.com/package/@plotday/twister" class="tsd-nav-link">NPM</a></nav><nav class="tsd-navigation"><a href="../modules.html">Creating Plot Twists</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
@@ -1 +1 @@
1
- <!DOCTYPE html><html class="default" lang="en" data-base="./"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>Creating Plot Twists</title><link rel="icon" href="assets/favicon.svg" type="image/svg+xml"/><meta name="description" content="Documentation for Creating Plot Twists"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="assets/style.css"/><link rel="stylesheet" href="assets/highlight.css"/><script defer src="assets/main.js"></script><script async src="assets/icons.js" id="tsd-icons-script"></script><script async src="assets/search.js" id="tsd-search-script"></script><script async src="assets/navigation.js" id="tsd-nav-script"></script><script async src="assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="/" class="title">Creating Plot Twists</a><div id="tsd-toolbar-links"><a href="https://plot.day">Plot</a><a href="https://github.com/plotday/plot">GitHub</a><a href="https://www.npmjs.com/package/@plotday/twister">NPM</a></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><h1>Creating Plot Twists</h1></div><h2>Hierarchy Summary</h2><ul class="tsd-full-hierarchy"><li data-refl="125" id="tool.ITool"><a href="classes/tool.ITool.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>ITool</a><ul><li data-refl="128" id="tool.Tool"><a href="classes/tool.Tool.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Tool</a></li><li data-refl="544" id="tools/twists.Twists"><a href="classes/tools_twists.Twists.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Twists</a></li><li data-refl="574" id="tools/ai.AI"><a href="classes/tools_ai.AI.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>AI</a></li><li data-refl="765" id="tools/callbacks.Callbacks"><a href="classes/tools_callbacks.Callbacks.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Callbacks</a></li><li data-refl="840" id="tools/integrations.Integrations"><a href="classes/tools_integrations.Integrations.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Integrations</a></li><li data-refl="918" id="tools/network.Network"><a href="classes/tools_network.Network.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Network</a></li><li data-refl="990" id="tools/plot.Plot"><a href="classes/tools_plot.Plot.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Plot</a></li><li data-refl="1116" id="tools/store.Store"><a href="classes/tools_store.Store.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Store</a></li><li data-refl="1137" id="tools/tasks.Tasks"><a href="classes/tools_tasks.Tasks.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Tasks</a></li><li data-refl="1568" id="index.Imap"><a href="classes/index.Imap.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Imap</a></li><li data-refl="1633" id="index.Smtp"><a href="classes/index.Smtp.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Smtp</a></li><li data-refl="1687" id="index.Options"><a href="classes/index.Options.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Options</a></li></ul></li></ul><ul class="tsd-full-hierarchy"><li data-refl="9" id="twist.Twist"><a href="classes/twist.Twist.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Twist</a><ul><li data-refl="1203" id="index.Connector"><a href="classes/index.Connector.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Connector</a></li></ul></li></ul></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav id="tsd-sidebar-links" class="tsd-navigation"><a href="https://plot.day" class="tsd-nav-link">Plot</a><a href="https://github.com/plotday/plot" class="tsd-nav-link">GitHub</a><a href="https://www.npmjs.com/package/@plotday/twister" class="tsd-nav-link">NPM</a></nav><nav class="tsd-navigation"><a href="modules.html">Creating Plot Twists</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
1
+ <!DOCTYPE html><html class="default" lang="en" data-base="./"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>Creating Plot Twists</title><link rel="icon" href="assets/favicon.svg" type="image/svg+xml"/><meta name="description" content="Documentation for Creating Plot Twists"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="assets/style.css"/><link rel="stylesheet" href="assets/highlight.css"/><script defer src="assets/main.js"></script><script async src="assets/icons.js" id="tsd-icons-script"></script><script async src="assets/search.js" id="tsd-search-script"></script><script async src="assets/navigation.js" id="tsd-nav-script"></script><script async src="assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="/" class="title">Creating Plot Twists</a><div id="tsd-toolbar-links"><a href="https://plot.day">Plot</a><a href="https://github.com/plotday/plot">GitHub</a><a href="https://www.npmjs.com/package/@plotday/twister">NPM</a></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><h1>Creating Plot Twists</h1></div><h2>Hierarchy Summary</h2><ul class="tsd-full-hierarchy"><li data-refl="126" id="tool.ITool"><a href="classes/tool.ITool.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>ITool</a><ul><li data-refl="129" id="tool.Tool"><a href="classes/tool.Tool.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Tool</a></li><li data-refl="545" id="tools/twists.Twists"><a href="classes/tools_twists.Twists.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Twists</a></li><li data-refl="575" id="tools/ai.AI"><a href="classes/tools_ai.AI.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>AI</a></li><li data-refl="766" id="tools/callbacks.Callbacks"><a href="classes/tools_callbacks.Callbacks.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Callbacks</a></li><li data-refl="842" id="tools/integrations.Integrations"><a href="classes/tools_integrations.Integrations.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Integrations</a></li><li data-refl="920" id="tools/network.Network"><a href="classes/tools_network.Network.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Network</a></li><li data-refl="992" id="tools/plot.Plot"><a href="classes/tools_plot.Plot.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Plot</a></li><li data-refl="1118" id="tools/store.Store"><a href="classes/tools_store.Store.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Store</a></li><li data-refl="1139" id="tools/tasks.Tasks"><a href="classes/tools_tasks.Tasks.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Tasks</a></li><li data-refl="1582" id="index.Imap"><a href="classes/index.Imap.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Imap</a></li><li data-refl="1647" id="index.Smtp"><a href="classes/index.Smtp.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Smtp</a></li><li data-refl="1701" id="index.Options"><a href="classes/index.Options.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Options</a></li></ul></li></ul><ul class="tsd-full-hierarchy"><li data-refl="9" id="twist.Twist"><a href="classes/twist.Twist.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Twist</a><ul><li data-refl="1213" id="index.Connector"><a href="classes/index.Connector.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Class"><use href="assets/icons.svg#icon-128"></use></svg>Connector</a></li></ul></li></ul></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav id="tsd-sidebar-links" class="tsd-navigation"><a href="https://plot.day" class="tsd-nav-link">Plot</a><a href="https://github.com/plotday/plot" class="tsd-nav-link">GitHub</a><a href="https://www.npmjs.com/package/@plotday/twister" class="tsd-nav-link">NPM</a></nav><nav class="tsd-navigation"><a href="modules.html">Creating Plot Twists</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>
@@ -556,19 +556,39 @@ The `activity.source` field is the idempotency key for automatic upserts. Use a
556
556
  <provider>:<namespace>:<id> — When provider has multiple entity types
557
557
  ```
558
558
 
559
- Examples from existing connectors:
559
+ ### Source identifier uniqueness (CRITICAL)
560
+
561
+ `source` is the **cross-user deduplication key** for the Plot runtime. Two instances of the same connector that emit the same `source` string will **converge on a single shared thread** across users — that's how two users on the same Gmail message see one shared thread rather than two parallel ones.
562
+
563
+ This means your `source` must be globally unique for the logical external item — not merely unique within a single user's account. Before committing a source pattern, ask yourself: *"Could two different users' connector instances emit this exact string for different external items?"* If yes, you must include a qualifier (workspace, tenant, mailbox, project, …).
564
+
565
+ Safe patterns (globally unique external ids):
566
+ ```
567
+ linear:issue:<uuid> — Linear issue UUIDs are globally unique
568
+ github:<owner>/<repo>/issue:<number> — Scoped by owner+repo
569
+ google-chat:<spaceId>:thread:<threadKey> — Space id globally unique
570
+ ms-teams:channel:<channelId>:message:<id> — Teams channel id globally unique
571
+ ms-teams:dm:<chatId> — Chat ids globally unique
572
+ https://mail.google.com/mail/u/0/#inbox/<threadId> — Gmail thread id globally unique
573
+ ```
574
+
575
+ Patterns that need disambiguation:
560
576
  ```
561
- linear:issue:<issueId>
562
- asana:task:<taskGid>
563
- jira:<cloudId>:issue:<issueId> Uses immutable ID, NOT mutable key like "PROJ-123"
564
- google-calendar:<eventId>
565
- outlook-calendar:<eventId>
566
- google-drive:file:<fileId>
567
- https://mail.google.com/mail/u/0/#inbox/<threadId> — Gmail uses full URL
568
- https://slack.com/app_redirect?channel=<id>&message_ts=<ts> — Slack uses full URL
577
+ attio:<workspaceId>:<type>:<recordId> — Attio record ids are workspace-scoped
578
+ posthog:<projectId>:person:<distinctId> — distinct_id is project-scoped (often just an email)
579
+ outlook-calendar:<mailboxId>:<eventId> Graph event ids are mailbox-local
580
+ fellow:<tenantId>:note:<id> — Fellow ids are tenant-scoped
569
581
  ```
570
582
 
571
- **Critical:** For services with mutable identifiers (like Jira where issue keys change on project move), use the immutable ID in `source` and store the mutable key in `meta` only.
583
+ **If you're adding a new connector, pick a source format that encodes the tenant/workspace/mailbox upfront.** Retrofits are possible but require a backfill migration.
584
+
585
+ **Mutable IDs:** For services where identifiers can change (like Jira issue keys that change on project move), use the immutable ID in `source` and store the mutable key in `meta` only.
586
+
587
+ ### Attestation-based visibility for shared threads
588
+
589
+ When your connector populates `thread.contacts` from an external item's recipients, listing someone there does NOT automatically admit them to the thread. The runtime requires that each user's own connector instance independently sync the item (proof that it's in their authenticated account) before they gain a `thread_priority` row. Users whose own sync arrives before any other user has attested them land in `thread.pending_contacts` and are promoted to `thread.contacts` on the next attester's sync.
590
+
591
+ You don't need to do anything special for this — just continue to populate `contacts` with every recipient you see. The runtime's `upsert_thread` enforces attestation; connectors can treat visibility as a server-side concern.
572
592
 
573
593
  ## Note Key Conventions
574
594
 
@@ -811,6 +831,63 @@ export class MyConnector extends Connector<MyConnector> {
811
831
 
812
832
  Without this, the connector cannot be @-mentioned at all. Connectors that don't process replies (e.g., read-only calendar sync) should NOT set this flag.
813
833
 
834
+ ### Creating New Items from Plot (`onCreateLink`)
835
+
836
+ Plot users can start a new thread tied to a brand-new external item (e.g. create a Linear issue, a Google Calendar event, a Slack DM) via "Create new …" in the Add link modal. Connectors opt in per link type:
837
+
838
+ 1. **Mark a status as the creation default** on the `LinkTypeConfig` you expose for that type — either on the static `readonly linkTypes` on the class, or on the dynamic per-channel linkTypes returned by `getChannels`:
839
+
840
+ ```typescript
841
+ statuses: [
842
+ { status: "backlog", label: "Backlog" },
843
+ { status: "unstarted", label: "To Do", todo: true, createDefault: true },
844
+ { status: "completed", label: "Done", tag: Tag.Done, done: true },
845
+ ],
846
+ ```
847
+
848
+ A link type opts in to Plot-initiated creation by declaring at least one status with `createDefault: true`. The marked status is used as the default when the user selects "Create new X".
849
+
850
+ 2. **Implement `onCreateLink(draft)`** — called after the Plot thread is saved and titled. Create the external item and return a `NewLinkWithNotes` describing it. The platform attaches the link to the originating thread; do NOT call `integrations.saveLink()` yourself.
851
+
852
+ ```typescript
853
+ async onCreateLink(draft: CreateLinkDraft): Promise<NewLinkWithNotes | null> {
854
+ if (draft.type !== "issue") return null;
855
+ const client = await this.getClient(draft.channelId);
856
+ const payload = await client.createIssue({
857
+ teamId: draft.channelId,
858
+ title: draft.title,
859
+ description: draft.noteContent ?? undefined,
860
+ stateId: await this.resolveStateId(client, draft.channelId, draft.status),
861
+ });
862
+ const issue = await payload.issue;
863
+ if (!issue) return null;
864
+ return {
865
+ source: `linear:issue:${issue.id}`,
866
+ type: "issue",
867
+ title: issue.title,
868
+ status: draft.status,
869
+ created: issue.createdAt,
870
+ sourceUrl: issue.url ?? null,
871
+ meta: { linearId: issue.id, projectId: draft.channelId },
872
+ // channelId/type default to draft.channelId/draft.type if you omit them.
873
+ };
874
+ }
875
+ ```
876
+
877
+ **`CreateLinkDraft` shape** (see `twister/src/connector.ts`):
878
+ - `channelId`, `type`, `status` — identify the target channel + link type + status.
879
+ - `title` — Plot thread title (post AI title generation).
880
+ - `noteContent` — markdown of the thread's first note, or `null`.
881
+ - `contacts: Actor[]` — thread's contacts (excluding the creating user), for email recipients / DM members / invitees.
882
+
883
+ **Platform defaults**: the runtime fills in `channelId` and `type` on the returned link from the draft if the connector omits them. Status label resolution depends on `channel_id`, so this default keeps the UI rendering correct even if you forget to echo them.
884
+
885
+ **Do not**:
886
+ - Call `integrations.saveLink()` — the platform wires the returned link to the user's thread.
887
+ - Assume the draft's status matches an external state id verbatim. For dynamic-per-team statuses (Linear teams, Jira projects), the draft's status is whatever was shown in the picker — your connector is responsible for resolving categories like `"unstarted"` if your static `linkTypes` fallback was used.
888
+
889
+ **Loop prevention**: the link your `onCreateLink` returns is written with `updated_by` set to the twist, so subsequent syncs of the same external id won't retrigger `onCreateLink` or `onLinkUpdated` for the initial state.
890
+
814
891
  ## Contacts Pattern
815
892
 
816
893
  Connectors that sync user data should create contacts for authors and assignees:
@@ -887,6 +964,7 @@ After creating a new connector, add it to `pnpm-workspace.yaml` if not already c
887
964
  - [ ] Handle `initialSync` flag in **every sync entry point**: `onChannelEnabled`/`startSync` set `true`, webhooks/incremental set `false`, and the flag is propagated through all batch callbacks to where activities are created. Set `unread: false` and `archived: false` for initial, omit both for incremental
888
965
  - [ ] Create contacts for authors/assignees with `NewContact`
889
966
  - [ ] Clean up all stored state and callbacks in `stopSync()` and `onChannelDisabled()`
967
+ - [ ] **If the connector should let users create new items from Plot**: mark one status per opted-in `LinkTypeConfig` with `createDefault: true` and implement `onCreateLink(draft)`. Return a `NewLinkWithNotes` — never call `integrations.saveLink()` from `onCreateLink`
890
968
  - [ ] Add `package.json` with correct structure, `tsconfig.json`, and `src/index.ts` re-export
891
969
  - [ ] Verify the connector builds: `pnpm build`
892
970
 
@@ -909,6 +987,8 @@ After creating a new connector, add it to `pnpm-workspace.yaml` if not already c
909
987
  15. **❌ Using placeholder titles in comment/update webhooks** — `title` always overwrites on upsert. Always use the real entity title (fetch from API if not in the webhook payload). Never use IDs or keys as placeholder titles
910
988
  16. **❌ Not setting `created` on notes from external data** — Always pass the external system's timestamp (e.g., `internalDate` from Gmail, `created_at` from an API) as the note's `created` field. Omitting it defaults to sync time, making all notes appear to have been created "just now"
911
989
  17. **❌ Using `this.run()` in `onChannelEnabled` to start sync** — `onChannelEnabled` runs synchronously inside the API request handler. Using `this.run()` (which executes inline) blocks the HTTP response until the entire sync completes, causing client timeouts. Always use `this.runTask()` to queue the initial sync as a separate execution so `onChannelEnabled` returns quickly
990
+ 18. **❌ Calling `integrations.saveLink()` from `onCreateLink`** — The platform wires the returned link to the user's originating thread. Calling `saveLink` yourself creates a duplicate thread. Just return the `NewLinkWithNotes`
991
+ 19. **❌ Forgetting to mark a status with `createDefault: true`** — Without it, Plot has no idea the link type opts in to Plot-initiated creation, so the "Create new X" entry never appears in the Add link modal. Declaring the marker is what opts a link type in, not implementing `onCreateLink` alone
912
992
 
913
993
  ## Study These Examples
914
994
 
@@ -98,7 +98,11 @@ The `source` field should be:
98
98
 
99
99
  - A canonical URL from the external system (preferred)
100
100
  - A stable identifier in a namespaced format (e.g., `gmail:thread-id-123`)
101
- - Unique within the priority tree
101
+ - **Globally unique for the logical external item** — see "Source identifier uniqueness" below
102
+
103
+ > **Cross-user dedup:** Two instances of the same connector (run by two different Plot users) that emit the same `source` for the same external item will converge on a **single shared thread**. This is how two users on the same Gmail message, calendar event, or Linear issue see one thread rather than two.
104
+ >
105
+ > This means `source` must not merely be unique within one user's account — it must be globally unique for the item. If an external id is workspace- or tenant-scoped (Attio record ids, PostHog distinct_ids, Outlook event ids, Fellow note ids, etc.), include the workspace/tenant/mailbox id as a qualifier: `attio:<workspaceId>:person:<recordId>`, not `attio:person:<recordId>`. See `connectors/AGENTS.md` → "Source identifier uniqueness" for the full guidance.
102
106
 
103
107
  ```typescript
104
108
  // Activity.source field definition