@plotday/twister 0.48.0 → 0.50.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 (137) hide show
  1. package/bin/templates/AGENTS.template.md +8 -2
  2. package/cli/templates/AGENTS.template.md +8 -2
  3. package/dist/connector.d.ts +97 -10
  4. package/dist/connector.d.ts.map +1 -1
  5. package/dist/connector.js +15 -5
  6. package/dist/connector.js.map +1 -1
  7. package/dist/docs/assets/hierarchy.js +1 -1
  8. package/dist/docs/assets/navigation.js +1 -1
  9. package/dist/docs/assets/search.js +1 -1
  10. package/dist/docs/classes/index.Connector.html +84 -51
  11. package/dist/docs/classes/index.Imap.html +1 -1
  12. package/dist/docs/classes/index.Options.html +1 -1
  13. package/dist/docs/classes/index.Smtp.html +1 -1
  14. package/dist/docs/classes/tools_ai.AI.html +1 -1
  15. package/dist/docs/classes/tools_callbacks.Callbacks.html +1 -1
  16. package/dist/docs/classes/tools_integrations.Integrations.html +55 -9
  17. package/dist/docs/classes/tools_network.Network.html +1 -1
  18. package/dist/docs/classes/tools_plot.Plot.html +11 -19
  19. package/dist/docs/classes/tools_store.Store.html +25 -2
  20. package/dist/docs/classes/tools_tasks.Tasks.html +1 -1
  21. package/dist/docs/classes/tools_twists.Twists.html +1 -1
  22. package/dist/docs/classes/twist.Twist.html +28 -28
  23. package/dist/docs/documents/Building_Connectors.html +8 -1
  24. package/dist/docs/documents/Built-in_Tools.html +1 -1
  25. package/dist/docs/documents/Runtime_Environment.html +25 -1
  26. package/dist/docs/enums/plot.ActorType.html +4 -4
  27. package/dist/docs/enums/tag.Tag.html +11 -1
  28. package/dist/docs/enums/tools_integrations.AuthProvider.html +13 -13
  29. package/dist/docs/hierarchy.html +1 -1
  30. package/dist/docs/media/AGENTS.md +298 -775
  31. package/dist/docs/media/MULTI_USER_AUTH.md +6 -4
  32. package/dist/docs/media/SYNC_STRATEGIES.md +20 -14
  33. package/dist/docs/modules/index.html +1 -1
  34. package/dist/docs/types/index.CreateLinkDraft.html +7 -12
  35. package/dist/docs/types/index.NewScheduleOccurrence.html +15 -2
  36. package/dist/docs/types/index.NoteWriteBackResult.html +38 -0
  37. package/dist/docs/types/index.ScheduleOccurrence.html +2 -4
  38. package/dist/docs/types/index.ScheduleOccurrenceUpdate.html +1 -1
  39. package/dist/docs/types/plot.Actor.html +5 -5
  40. package/dist/docs/types/plot.Contact.html +4 -4
  41. package/dist/docs/types/plot.ContentType.html +1 -1
  42. package/dist/docs/types/plot.Link.html +15 -15
  43. package/dist/docs/types/plot.LinkUpdate.html +1 -1
  44. package/dist/docs/types/plot.NewActor.html +1 -1
  45. package/dist/docs/types/plot.NewContact.html +1 -1
  46. package/dist/docs/types/plot.NewLink.html +1 -1
  47. package/dist/docs/types/plot.NewLinkWithNotes.html +1 -1
  48. package/dist/docs/types/plot.NewNote.html +1 -1
  49. package/dist/docs/types/plot.Note.html +7 -1
  50. package/dist/docs/types/plot.NoteUpdate.html +1 -1
  51. package/dist/docs/types/plot.PlanOperation.html +1 -1
  52. package/dist/docs/types/tools_integrations.ArchiveLinkFilter.html +5 -5
  53. package/dist/docs/types/tools_integrations.AuthToken.html +4 -4
  54. package/dist/docs/types/tools_integrations.Authorization.html +4 -4
  55. package/dist/docs/types/tools_integrations.SyncContext.html +21 -2
  56. package/dist/llm-docs/connector.d.ts +1 -1
  57. package/dist/llm-docs/connector.d.ts.map +1 -1
  58. package/dist/llm-docs/connector.js +1 -1
  59. package/dist/llm-docs/connector.js.map +1 -1
  60. package/dist/llm-docs/plot.d.ts +1 -1
  61. package/dist/llm-docs/plot.d.ts.map +1 -1
  62. package/dist/llm-docs/plot.js +1 -1
  63. package/dist/llm-docs/plot.js.map +1 -1
  64. package/dist/llm-docs/schedule.d.ts +1 -1
  65. package/dist/llm-docs/schedule.d.ts.map +1 -1
  66. package/dist/llm-docs/schedule.js +1 -1
  67. package/dist/llm-docs/schedule.js.map +1 -1
  68. package/dist/llm-docs/tag.d.ts +1 -1
  69. package/dist/llm-docs/tag.d.ts.map +1 -1
  70. package/dist/llm-docs/tag.js +1 -1
  71. package/dist/llm-docs/tag.js.map +1 -1
  72. package/dist/llm-docs/tools/integrations.d.ts +1 -1
  73. package/dist/llm-docs/tools/integrations.d.ts.map +1 -1
  74. package/dist/llm-docs/tools/integrations.js +1 -1
  75. package/dist/llm-docs/tools/integrations.js.map +1 -1
  76. package/dist/llm-docs/tools/plot.d.ts +1 -1
  77. package/dist/llm-docs/tools/plot.d.ts.map +1 -1
  78. package/dist/llm-docs/tools/plot.js +1 -1
  79. package/dist/llm-docs/tools/plot.js.map +1 -1
  80. package/dist/llm-docs/tools/store.d.ts +1 -1
  81. package/dist/llm-docs/tools/store.d.ts.map +1 -1
  82. package/dist/llm-docs/tools/store.js +1 -1
  83. package/dist/llm-docs/tools/store.js.map +1 -1
  84. package/dist/llm-docs/twist-guide-template.d.ts +1 -1
  85. package/dist/llm-docs/twist-guide-template.d.ts.map +1 -1
  86. package/dist/llm-docs/twist-guide-template.js +1 -1
  87. package/dist/llm-docs/twist-guide-template.js.map +1 -1
  88. package/dist/llm-docs/twist.d.ts +1 -1
  89. package/dist/llm-docs/twist.d.ts.map +1 -1
  90. package/dist/llm-docs/twist.js +1 -1
  91. package/dist/llm-docs/twist.js.map +1 -1
  92. package/dist/plot.d.ts +8 -1
  93. package/dist/plot.d.ts.map +1 -1
  94. package/dist/plot.js.map +1 -1
  95. package/dist/schedule.d.ts +18 -2
  96. package/dist/schedule.d.ts.map +1 -1
  97. package/dist/tag.d.ts +11 -1
  98. package/dist/tag.d.ts.map +1 -1
  99. package/dist/tag.js +10 -0
  100. package/dist/tag.js.map +1 -1
  101. package/dist/tools/integrations.d.ts +86 -0
  102. package/dist/tools/integrations.d.ts.map +1 -1
  103. package/dist/tools/integrations.js.map +1 -1
  104. package/dist/tools/plot.d.ts +0 -11
  105. package/dist/tools/plot.d.ts.map +1 -1
  106. package/dist/tools/plot.js.map +1 -1
  107. package/dist/tools/store.d.ts +40 -0
  108. package/dist/tools/store.d.ts.map +1 -1
  109. package/dist/tools/store.js.map +1 -1
  110. package/dist/twist-guide.d.ts +1 -1
  111. package/dist/twist-guide.d.ts.map +1 -1
  112. package/dist/twist.d.ts +2 -1
  113. package/dist/twist.d.ts.map +1 -1
  114. package/dist/twist.js.map +1 -1
  115. package/dist/utils/markdown.d.ts +27 -0
  116. package/dist/utils/markdown.d.ts.map +1 -0
  117. package/dist/utils/markdown.js +82 -0
  118. package/dist/utils/markdown.js.map +1 -0
  119. package/package.json +6 -1
  120. package/src/connector.ts +98 -10
  121. package/src/llm-docs/connector.ts +1 -1
  122. package/src/llm-docs/plot.ts +1 -1
  123. package/src/llm-docs/schedule.ts +1 -1
  124. package/src/llm-docs/tag.ts +1 -1
  125. package/src/llm-docs/tools/integrations.ts +1 -1
  126. package/src/llm-docs/tools/plot.ts +1 -1
  127. package/src/llm-docs/tools/store.ts +1 -1
  128. package/src/llm-docs/twist-guide-template.ts +1 -1
  129. package/src/llm-docs/twist.ts +1 -1
  130. package/src/plot.ts +8 -1
  131. package/src/schedule.ts +19 -3
  132. package/src/tag.ts +10 -0
  133. package/src/tools/integrations.ts +93 -0
  134. package/src/tools/plot.ts +0 -12
  135. package/src/tools/store.ts +44 -0
  136. package/src/twist.ts +2 -1
  137. package/src/utils/markdown.ts +94 -0
@@ -7,6 +7,7 @@
7
7
  <li><a href="#batch-processing">Batch Processing</a></li>
8
8
  <li><a href="#complete-example">Complete Example</a></li>
9
9
  <li><a href="#creating-items-from-plot-oncreatelink">Creating Items from Plot (<code>onCreateLink</code>)</a></li>
10
+ <li><a href="#bidirectional-note-sync-comments-messages-replies">Bidirectional Note Sync (Comments, Messages, Replies)</a></li>
10
11
  <li><a href="#best-practices">Best Practices</a></li>
11
12
  </ul>
12
13
  <hr>
@@ -186,6 +187,12 @@ won't retrigger <code>onLinkUpdated</code> for the initial state.</li>
186
187
  <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
188
  user not authorized), return <code>null</code>. The Plot thread is still saved; no
188
189
  link is attached.</p>
190
+ <h2 id="bidirectional-note-sync-comments-messages-replies" class="tsd-anchor-link">Bidirectional Note Sync (Comments, Messages, Replies)<a href="#bidirectional-note-sync-comments-messages-replies" 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>When a user adds a note to a thread your connector created, the runtime dispatches <code>onNoteCreated</code> (and <code>onNoteUpdated</code> when the note is edited). Implement these to push the note to the external system as a comment/message/reply and return a <code>NoteWriteBackResult</code>:</p>
191
+ <pre><code class="typescript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-0">type</span><span class="hl-1"> { </span><span class="hl-2">NoteWriteBackResult</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&quot;@plotday/twister&quot;</span><span class="hl-1">;</span><br/><br/><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">onNoteCreated</span><span class="hl-1">(</span><span class="hl-2">note</span><span class="hl-1">: </span><span class="hl-2">Note</span><span class="hl-1">, </span><span class="hl-2">thread</span><span class="hl-1">: </span><span class="hl-2">Thread</span><span class="hl-1">): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-2">NoteWriteBackResult</span><span class="hl-1"> | </span><span class="hl-4">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-6">if</span><span class="hl-1"> (note.author.type === ActorType.Twist) return; </span><span class="hl-7">// Prevent loops</span><br/><span class="hl-1"> const </span><span class="hl-2">comment</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">createComment</span><span class="hl-1">(</span><span class="hl-2">thread</span><span class="hl-1">.</span><span class="hl-2">meta</span><span class="hl-1">.</span><span class="hl-2">externalId</span><span class="hl-1">, { </span><span class="hl-2">body:</span><span class="hl-1"> </span><span class="hl-2">note</span><span class="hl-1">.</span><span class="hl-2">content</span><span class="hl-1"> ?? </span><span class="hl-3">&quot;&quot;</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">comment</span><span class="hl-1">?.id) return;</span><br/><span class="hl-1"> return {</span><br/><span class="hl-1"> </span><span class="hl-15">key</span><span class="hl-1">: </span><span class="hl-3">`comment-</span><span class="hl-4">${</span><span class="hl-2">comment</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-7">// What the external system NOW STORES, byte-for-byte equal to what</span><br/><span class="hl-1"> </span><span class="hl-7">// your sync-in path will emit as NewNote.content on re-ingest.</span><br/><span class="hl-1"> </span><span class="hl-15">externalContent</span><span class="hl-1">: </span><span class="hl-2">comment</span><span class="hl-1">.</span><span class="hl-2">body</span><span class="hl-1">,</span><br/><span class="hl-1"> };</span><br/><span class="hl-1">}</span><br/><br/><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">onNoteUpdated</span><span class="hl-1">(</span><span class="hl-2">note</span><span class="hl-1">: </span><span class="hl-2">Note</span><span class="hl-1">, </span><span class="hl-2">thread</span><span class="hl-1">: </span><span class="hl-2">Thread</span><span class="hl-1">): </span><span class="hl-5">Promise</span><span class="hl-1">&lt;</span><span class="hl-2">NoteWriteBackResult</span><span class="hl-1"> | </span><span class="hl-4">void</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-6">if</span><span class="hl-1"> (!note.key?.startsWith(</span><span class="hl-3">&quot;comment-&quot;</span><span class="hl-1">)) return;</span><br/><span class="hl-1"> const </span><span class="hl-2">commentId</span><span class="hl-1"> = </span><span class="hl-2">note</span><span class="hl-1">.</span><span class="hl-2">key</span><span class="hl-1">.</span><span class="hl-6">slice</span><span class="hl-1">(</span><span class="hl-3">&quot;comment-&quot;</span><span class="hl-1">.</span><span class="hl-2">length</span><span class="hl-1">);</span><br/><span class="hl-1"> const </span><span class="hl-2">updated</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">updateComment</span><span class="hl-1">(</span><span class="hl-2">commentId</span><span class="hl-1">, { </span><span class="hl-2">body:</span><span class="hl-1"> </span><span class="hl-2">note</span><span class="hl-1">.</span><span class="hl-2">content</span><span class="hl-1"> ?? </span><span class="hl-3">&quot;&quot;</span><span class="hl-1"> });</span><br/><span class="hl-1"> return { </span><span class="hl-15">externalContent</span><span class="hl-1">: </span><span class="hl-2">updated</span><span class="hl-1">.</span><span class="hl-2">body</span><span class="hl-1"> };</span><br/><span class="hl-1">}</span>
192
+ </code><button type="button">Copy</button></pre>
193
+
194
+ <p>The <code>externalContent</code> field establishes a sync baseline: the runtime hashes it and stores it on <code>note.external_content_hash</code>. On the next sync-in, the incoming content is hashed the same way — if the hashes match, the external side hasn't changed since we wrote, so Plot's stored content (which may be richer markdown than what the external system round-tripped) is preserved. If the hashes differ, the external was edited and Plot is overwritten.</p>
195
+ <p><strong>Contract</strong>: <code>externalContent</code> must exactly equal the <code>NewNote.content</code> your sync-in's <code>build*Note</code> function emits for this note on re-ingest. If sync-in runs a transform (ADF extraction, mention translation, HTML sanitisation), apply the same transform to the write-back response before returning it. Bidirectional connectors must also set <code>static readonly handleReplies = true</code> so the dispatch reaches your hooks. See <strong><a href="../media/AGENTS.md">Connector Development Guide</a></strong> → &quot;Sync baseline preservation&quot; for the full contract and failure modes.</p>
189
196
  <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>
190
197
  <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>
191
198
  <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>
@@ -199,4 +206,4 @@ link is attached.</p>
199
206
  <li><strong><a href="Built-in_Tools.html">Built-in Tools Guide</a></strong> - Complete reference for Plot, Store, Integrations, and more</li>
200
207
  <li><strong><a href="../media/MULTI_USER_AUTH.md">Multi-User Auth</a></strong> - Per-user auth for write-backs</li>
201
208
  </ul>
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>
209
+ </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="#bidirectional-note-sync-comments-messages-replies"><span>Bidirectional <wbr/>Note <wbr/>Sync (<wbr/>Comments, <wbr/>Messages, <wbr/>Replies)</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>
@@ -10,7 +10,7 @@
10
10
  </ul>
11
11
  <hr>
12
12
  <h2 id="plot" class="tsd-anchor-link">Plot<a href="#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>The Plot tool is the core interface for creating and managing activities and priorities.</p>
13
- <h3 id="workspace-level-twists" class="tsd-anchor-link">Workspace-Level Twists<a href="#workspace-level-twists" 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>A twist is installed by a single user at the workspace level — it is <strong>not</strong> scoped to a particular priority. <code>this.userId</code> exposes the installing user's ID, and <code>plot.getUserId()</code> / <code>plot.getDefaultPriorityId()</code> are available if you need them explicitly.</p>
13
+ <h3 id="workspace-level-twists" class="tsd-anchor-link">Workspace-Level Twists<a href="#workspace-level-twists" 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>A twist is installed by a single user at the workspace level — it is <strong>not</strong> scoped to a particular priority. <code>this.userId</code> exposes the installing user's ID, and <code>plot.getUserId()</code> is available if you need it explicitly.</p>
14
14
  <p>When a twist creates a thread or link without specifying a priority, the server picks one automatically for the owner user via <code>match_priority_for_user</code>. You only need to provide a <code>priority</code> (or a <code>priorityId</code> filter) when you want to override that automatic routing.</p>
15
15
  <h3 id="understanding-activities-and-notes" class="tsd-anchor-link">Understanding Activities and Notes<a href="#understanding-activities-and-notes" 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><strong>Activity</strong> represents something done or to be done (a task, event, or conversation), while <strong>Notes</strong> represent the updates and details on that activity.</p>
16
16
  <p><strong>Think of an Activity as a thread</strong> on a messaging platform, and <strong>Notes as the messages in that thread</strong>. Always create activities with an initial note, and add notes to existing activities for updates rather than creating new activities.</p>
@@ -30,6 +30,30 @@
30
30
  <li><strong>CPU time limit</strong> - Limited execution time (typically ~60 seconds)</li>
31
31
  <li><strong>Memory limit</strong> - Limited memory allocation (typically 128MB)</li>
32
32
  </ul>
33
+ <h3 id="rate-limits-and-auto-suspension" class="tsd-anchor-link">Rate Limits and Auto-Suspension<a href="#rate-limits-and-auto-suspension" 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>In addition to per-execution limits, the platform enforces per-twist-instance rate limits to prevent a single misbehaving twist from starving the shared task queue:</p>
34
+ <ul>
35
+ <li><strong>Burst limit</strong> — at most <strong>200 worker invocations in any rolling 5-minute window</strong> per twist_instance. Designed to catch runaway loops within ~1 minute.</li>
36
+ <li><strong>Daily limit</strong> — at most <strong>500 worker invocations in any rolling 24-hour window</strong> per twist_instance (configurable per-twist). Catches slower runaway patterns.</li>
37
+ <li><strong>Cost limit</strong> — at most <strong>$5 in any rolling 4-hour window</strong> and <strong>$20 in any rolling 30-day window</strong> per twist_instance.</li>
38
+ </ul>
39
+ <p>When any of these limits is exceeded, the twist is <strong>auto-suspended</strong>:</p>
40
+ <ul>
41
+ <li>All callbacks (webhooks, runTask handlers, scheduled tasks) immediately stop executing.</li>
42
+ <li>A suspension log is written to the twist log stream (visible in the connector logs UI) and a note is posted to the workspace owner's Help &amp; Feedback thread.</li>
43
+ <li><strong>Suspension is lifted automatically on the next deploy of the twist.</strong> Each new version starts with a clean rate-limit budget. If the same pattern repeats, the twist will be re-suspended within minutes — fix the root cause before redeploying.</li>
44
+ </ul>
45
+ <p>Manual/operator suspensions (set directly in the database without a recorded version) are durable across deploys.</p>
46
+ <h4 id="avoiding-auto-suspension" class="tsd-anchor-link">Avoiding auto-suspension<a href="#avoiding-auto-suspension" 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></h4><p>The most common cause of auto-suspension is a callback that re-queues itself with no exit condition:</p>
47
+ <pre><code class="typescript"><span class="hl-7">// ❌ WRONG — unbounded self-chain. Each call queues another with no</span><br/><span class="hl-7">// completion check. Even with delays, this will exceed the burst</span><br/><span class="hl-7">// limit (200 / 5 min) in under a minute.</span><br/><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">reconcileComments</span><span class="hl-1">() {</span><br/><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">processOne</span><span class="hl-1">();</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">callback</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">callback</span><span class="hl-1">(</span><span class="hl-3">&quot;reconcileComments&quot;</span><span class="hl-1">);</span><br/><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">runTask</span><span class="hl-1">(</span><span class="hl-2">callback</span><span class="hl-1">); </span><span class="hl-7">// recurses forever</span><br/><span class="hl-1">}</span><br/><br/><span class="hl-7">// ✅ CORRECT — explicit exit condition based on remaining work</span><br/><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">reconcileComments</span><span class="hl-1">() {</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">state</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">get</span><span class="hl-1">&lt;{ </span><span class="hl-2">cursor</span><span class="hl-1">: </span><span class="hl-5">string</span><span class="hl-1"> | </span><span class="hl-5">null</span><span class="hl-1"> }&gt;(</span><span class="hl-3">&quot;reconcile_state&quot;</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">result</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">processOne</span><span class="hl-1">(</span><span class="hl-2">state</span><span class="hl-1">?.</span><span class="hl-2">cursor</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (</span><span class="hl-2">result</span><span class="hl-1">.</span><span class="hl-2">hasMore</span><span class="hl-1">) {</span><br/><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">set</span><span class="hl-1">(</span><span class="hl-3">&quot;reconcile_state&quot;</span><span class="hl-1">, { </span><span class="hl-2">cursor:</span><span class="hl-1"> </span><span class="hl-2">result</span><span class="hl-1">.</span><span class="hl-2">nextCursor</span><span class="hl-1"> });</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">callback</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">callback</span><span class="hl-1">(</span><span class="hl-3">&quot;reconcileComments&quot;</span><span class="hl-1">);</span><br/><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">runTask</span><span class="hl-1">(</span><span class="hl-2">callback</span><span class="hl-1">);</span><br/><span class="hl-1"> } </span><span class="hl-0">else</span><span class="hl-1"> {</span><br/><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">set</span><span class="hl-1">(</span><span class="hl-3">&quot;reconcile_state&quot;</span><span class="hl-1">, { </span><span class="hl-2">cursor:</span><span class="hl-1"> </span><span class="hl-4">null</span><span class="hl-1"> });</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span><br/><br/><span class="hl-7">// ✅ CORRECT — periodic background work uses runAt, not a self-chain</span><br/><span class="hl-2">async</span><span class="hl-1"> </span><span class="hl-6">pollForChanges</span><span class="hl-1">() {</span><br/><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">processBatch</span><span class="hl-1">();</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">callback</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">callback</span><span class="hl-1">(</span><span class="hl-3">&quot;pollForChanges&quot;</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-7">// Schedule the next run 5 minutes from now. Cloudflare&#39;s queue stays</span><br/><span class="hl-1"> </span><span class="hl-7">// out of the loop entirely between runs.</span><br/><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">runTask</span><span class="hl-1">(</span><span class="hl-2">callback</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-2">runAt:</span><span class="hl-1"> </span><span class="hl-4">new</span><span class="hl-1"> </span><span class="hl-6">Date</span><span class="hl-1">(</span><span class="hl-2">Date</span><span class="hl-1">.</span><span class="hl-6">now</span><span class="hl-1">() + </span><span class="hl-14">5</span><span class="hl-1"> * </span><span class="hl-14">60</span><span class="hl-1"> * </span><span class="hl-14">1000</span><span class="hl-1">),</span><br/><span class="hl-1"> });</span><br/><span class="hl-1">}</span>
48
+ </code><button type="button">Copy</button></pre>
49
+
50
+ <p><strong>Guidelines:</strong></p>
51
+ <ul>
52
+ <li>Every <code>runTask</code> self-chain must have an explicit exit condition (a cursor that ends, a counter that reaches a limit, a <code>hasMore</code> flag).</li>
53
+ <li>For periodic &quot;keep checking&quot; patterns, use <code>runTask({ runAt })</code> instead of an immediate self-chain — the queue stays free between runs.</li>
54
+ <li>Cap recursion depth: store a counter in <code>this.set</code> and stop after a sane bound (e.g., 100 batches).</li>
55
+ <li>For sync flows, paginate with <code>runTask</code> per page rather than fanning out hundreds of tasks at once.</li>
56
+ </ul>
33
57
  <hr>
34
58
  <h2 id="limitations" class="tsd-anchor-link">Limitations<a href="#limitations" 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-no-persistent-instance-state" class="tsd-anchor-link">1. No Persistent Instance State<a href="#1-no-persistent-instance-state" 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>Instance variables don't survive between invocations:</p>
35
59
  <pre><code class="typescript"><span class="hl-7">// ❌ WRONG - This doesn&#39;t work!</span><br/><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">MyTwist</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">Twist</span><span class="hl-1">&lt;</span><span class="hl-5">MyTwist</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-4">private</span><span class="hl-1"> </span><span class="hl-2">syncToken</span><span class="hl-1">: </span><span class="hl-5">string</span><span class="hl-1"> = </span><span class="hl-3">&quot;&quot;</span><span class="hl-1">; </span><span class="hl-7">// Lost after execution!</span><br/><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">activate</span><span class="hl-1">() {</span><br/><span class="hl-1"> </span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">syncToken</span><span class="hl-1"> = </span><span class="hl-3">&quot;abc123&quot;</span><span class="hl-1">; </span><span class="hl-7">// Saved to instance</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">someMethod</span><span class="hl-1">() {</span><br/><span class="hl-1"> </span><span class="hl-2">console</span><span class="hl-1">.</span><span class="hl-6">log</span><span class="hl-1">(</span><span class="hl-4">this</span><span class="hl-1">.</span><span class="hl-2">syncToken</span><span class="hl-1">); </span><span class="hl-7">// Undefined! Different execution context</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span><br/><br/><span class="hl-7">// ✅ CORRECT - Use Store</span><br/><span class="hl-4">class</span><span class="hl-1"> </span><span class="hl-5">MyTwist</span><span class="hl-1"> </span><span class="hl-4">extends</span><span class="hl-1"> </span><span class="hl-5">Twist</span><span class="hl-1">&lt;</span><span class="hl-5">MyTwist</span><span class="hl-1">&gt; {</span><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">activate</span><span class="hl-1">() {</span><br/><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">set</span><span class="hl-1">(</span><span class="hl-3">&quot;sync_token&quot;</span><span class="hl-1">, </span><span class="hl-3">&quot;abc123&quot;</span><span class="hl-1">); </span><span class="hl-7">// Persisted</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-4">async</span><span class="hl-1"> </span><span class="hl-6">someMethod</span><span class="hl-1">() {</span><br/><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-8">token</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">get</span><span class="hl-1">&lt;</span><span class="hl-5">string</span><span class="hl-1">&gt;(</span><span class="hl-3">&quot;sync_token&quot;</span><span class="hl-1">); </span><span class="hl-7">// Retrieved</span><br/><span class="hl-1"> </span><span class="hl-2">console</span><span class="hl-1">.</span><span class="hl-6">log</span><span class="hl-1">(</span><span class="hl-2">token</span><span class="hl-1">); </span><span class="hl-7">// &quot;abc123&quot;</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span>
@@ -137,4 +161,4 @@
137
161
  <li><strong><a href="Built-in_Tools.html">Built-in Tools Guide</a></strong> - Learn about Store and Tasks tools</li>
138
162
  <li><strong><a href="Core_Concepts.html">Core Concepts</a></strong> - Understanding the twist architecture</li>
139
163
  </ul>
140
- </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="#runtime-environment"><span>Runtime <wbr/>Environment</span></a><ul><li><a href="#table-of-contents"><span>Table of <wbr/>Contents</span></a></li><li><a href="#execution-model"><span>Execution <wbr/>Model</span></a></li><li><ul><li><a href="#ephemeral-execution"><span>Ephemeral <wbr/>Execution</span></a></li><li><a href="#event-driven"><span>Event-<wbr/>Driven</span></a></li><li><a href="#resource-limits"><span>Resource <wbr/>Limits</span></a></li></ul></li><li><a href="#limitations"><span>Limitations</span></a></li><li><ul><li><a href="#1-no-persistent-instance-state"><span>1. <wbr/>No <wbr/>Persistent <wbr/>Instance <wbr/>State</span></a></li><li><a href="#2-limited-requests-per-execution"><span>2. <wbr/>Limited <wbr/>Requests <wbr/>Per <wbr/>Execution</span></a></li><li><a href="#3-no-file-system-access"><span>3. <wbr/>No <wbr/>File <wbr/>System <wbr/>Access</span></a></li><li><a href="#4-limited-global-state"><span>4. <wbr/>Limited <wbr/>Global <wbr/>State</span></a></li></ul></li><li><a href="#state-management"><span>State <wbr/>Management</span></a></li><li><ul><li><a href="#store-tool"><span>Store <wbr/>Tool</span></a></li><li><a href="#state-organization"><span>State <wbr/>Organization</span></a></li><li><a href="#state-cleanup"><span>State <wbr/>Cleanup</span></a></li></ul></li><li><a href="#batching-long-operations"><span>Batching <wbr/>Long <wbr/>Operations</span></a></li><li><ul><li><a href="#pattern-1-page-based-batching"><span>Pattern 1: <wbr/>Page-<wbr/>Based <wbr/>Batching</span></a></li><li><a href="#pattern-2-token-based-batching"><span>Pattern 2: <wbr/>Token-<wbr/>Based <wbr/>Batching</span></a></li><li><a href="#pattern-3-item-based-batching"><span>Pattern 3: <wbr/>Item-<wbr/>Based <wbr/>Batching</span></a></li></ul></li><li><a href="#memory-considerations"><span>Memory <wbr/>Considerations</span></a></li><li><ul><li><a href="#avoid-large-data-structures"><span>Avoid <wbr/>Large <wbr/>Data <wbr/>Structures</span></a></li><li><a href="#efficient-data-storage"><span>Efficient <wbr/>Data <wbr/>Storage</span></a></li></ul></li><li><a href="#performance-optimization"><span>Performance <wbr/>Optimization</span></a></li><li><ul><li><a href="#1-minimize-api-calls"><span>1. <wbr/>Minimize <wbr/>API <wbr/>Calls</span></a></li><li><a href="#2-parallel-operations"><span>2. <wbr/>Parallel <wbr/>Operations</span></a></li><li><a href="#3-caching"><span>3. <wbr/>Caching</span></a></li><li><a href="#4-debouncing"><span>4. <wbr/>Debouncing</span></a></li></ul></li><li><a href="#request-limits-and-timeouts"><span>Request <wbr/>Limits and <wbr/>Timeouts</span></a></li><li><ul><li><a href="#understanding-execution-limits"><span>Understanding <wbr/>Execution <wbr/>Limits</span></a></li><li><a href="#prevention-strategies"><span>Prevention <wbr/>Strategies</span></a></li></ul></li><li><a href="#best-practices-summary"><span>Best <wbr/>Practices <wbr/>Summary</span></a></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>
164
+ </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="#runtime-environment"><span>Runtime <wbr/>Environment</span></a><ul><li><a href="#table-of-contents"><span>Table of <wbr/>Contents</span></a></li><li><a href="#execution-model"><span>Execution <wbr/>Model</span></a></li><li><ul><li><a href="#ephemeral-execution"><span>Ephemeral <wbr/>Execution</span></a></li><li><a href="#event-driven"><span>Event-<wbr/>Driven</span></a></li><li><a href="#resource-limits"><span>Resource <wbr/>Limits</span></a></li><li><a href="#rate-limits-and-auto-suspension"><span>Rate <wbr/>Limits and <wbr/>Auto-<wbr/>Suspension</span></a></li><li><ul><li><a href="#avoiding-auto-suspension"><span>Avoiding auto-<wbr/>suspension</span></a></li></ul></li></ul></li><li><a href="#limitations"><span>Limitations</span></a></li><li><ul><li><a href="#1-no-persistent-instance-state"><span>1. <wbr/>No <wbr/>Persistent <wbr/>Instance <wbr/>State</span></a></li><li><a href="#2-limited-requests-per-execution"><span>2. <wbr/>Limited <wbr/>Requests <wbr/>Per <wbr/>Execution</span></a></li><li><a href="#3-no-file-system-access"><span>3. <wbr/>No <wbr/>File <wbr/>System <wbr/>Access</span></a></li><li><a href="#4-limited-global-state"><span>4. <wbr/>Limited <wbr/>Global <wbr/>State</span></a></li></ul></li><li><a href="#state-management"><span>State <wbr/>Management</span></a></li><li><ul><li><a href="#store-tool"><span>Store <wbr/>Tool</span></a></li><li><a href="#state-organization"><span>State <wbr/>Organization</span></a></li><li><a href="#state-cleanup"><span>State <wbr/>Cleanup</span></a></li></ul></li><li><a href="#batching-long-operations"><span>Batching <wbr/>Long <wbr/>Operations</span></a></li><li><ul><li><a href="#pattern-1-page-based-batching"><span>Pattern 1: <wbr/>Page-<wbr/>Based <wbr/>Batching</span></a></li><li><a href="#pattern-2-token-based-batching"><span>Pattern 2: <wbr/>Token-<wbr/>Based <wbr/>Batching</span></a></li><li><a href="#pattern-3-item-based-batching"><span>Pattern 3: <wbr/>Item-<wbr/>Based <wbr/>Batching</span></a></li></ul></li><li><a href="#memory-considerations"><span>Memory <wbr/>Considerations</span></a></li><li><ul><li><a href="#avoid-large-data-structures"><span>Avoid <wbr/>Large <wbr/>Data <wbr/>Structures</span></a></li><li><a href="#efficient-data-storage"><span>Efficient <wbr/>Data <wbr/>Storage</span></a></li></ul></li><li><a href="#performance-optimization"><span>Performance <wbr/>Optimization</span></a></li><li><ul><li><a href="#1-minimize-api-calls"><span>1. <wbr/>Minimize <wbr/>API <wbr/>Calls</span></a></li><li><a href="#2-parallel-operations"><span>2. <wbr/>Parallel <wbr/>Operations</span></a></li><li><a href="#3-caching"><span>3. <wbr/>Caching</span></a></li><li><a href="#4-debouncing"><span>4. <wbr/>Debouncing</span></a></li></ul></li><li><a href="#request-limits-and-timeouts"><span>Request <wbr/>Limits and <wbr/>Timeouts</span></a></li><li><ul><li><a href="#understanding-execution-limits"><span>Understanding <wbr/>Execution <wbr/>Limits</span></a></li><li><a href="#prevention-strategies"><span>Prevention <wbr/>Strategies</span></a></li></ul></li><li><a href="#best-practices-summary"><span>Best <wbr/>Practices <wbr/>Summary</span></a></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,10 +1,10 @@
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>ActorType | 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/plot.html">plot</a></li><li><a href="" aria-current="page">ActorType</a></li></ul><h1>Enumeration ActorType</h1></div><section class="tsd-panel tsd-comment"><div class="tsd-comment tsd-typography"><p>Enumeration of author types that can create threads.</p>
2
2
  <p>The author type affects how threads are displayed and processed
3
3
  within the Plot system.</p>
4
- </div></section><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/plot.ts#L824">plot.ts:824</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="#user" 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>User</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/plot.ts#L831">plot.ts:831</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="#user" 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>User</span></a>
5
5
  <a href="#contact" 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>Contact</span></a>
6
6
  <a href="#twist" 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>Twist</span></a>
7
7
  </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="user"><span>User</span><a href="#user" 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">User</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">0</span></div><div class="tsd-comment tsd-typography"><p>Threads created by human users</p>
8
- </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/plot.ts#L826">plot.ts:826</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="contact"><span>Contact</span><a href="#contact" 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">Contact</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">1</span></div><div class="tsd-comment tsd-typography"><p>Threads created by external contacts</p>
9
- </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/plot.ts#L828">plot.ts:828</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="twist"><span>Twist</span><a href="#twist" 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">Twist</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">2</span></div><div class="tsd-comment tsd-typography"><p>Threads created by automated twists</p>
10
- </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/plot.ts#L830">plot.ts:830</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="#user"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>User</span></a><a href="#contact"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Contact</span></a><a href="#twist"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Twist</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>
8
+ </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/plot.ts#L833">plot.ts:833</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="contact"><span>Contact</span><a href="#contact" 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">Contact</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">1</span></div><div class="tsd-comment tsd-typography"><p>Threads created by external contacts</p>
9
+ </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/plot.ts#L835">plot.ts:835</a></li></ul></aside></section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="twist"><span>Twist</span><a href="#twist" 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">Twist</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">2</span></div><div class="tsd-comment tsd-typography"><p>Threads created by automated twists</p>
10
+ </div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/plotday/plot/blob/main/twist/twister/src/plot.ts#L837">plot.ts:837</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="#user"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>User</span></a><a href="#contact"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Contact</span></a><a href="#twist"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Enumeration Member"><use href="../assets/icons.svg#icon-16"></use></svg><span>Twist</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>