@parall/sdk 1.45.0 → 1.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.
package/src/client.ts CHANGED
@@ -94,6 +94,15 @@ import type {
94
94
  ChannelProvisioningSession,
95
95
  CreateChannelConnectionInput,
96
96
  InitiateChannelProvisioningInput,
97
+ SendChannelMessageInput,
98
+ SlackChannelsPage,
99
+ SlackHistoryPage,
100
+ SlackManifestLinkResult,
101
+ SlackMembersPage,
102
+ SlackReadPageQuery,
103
+ SlackStatusInput,
104
+ SlackUsersPage,
105
+ SentChannelMessage,
97
106
  UpdateChannelConnectionInput,
98
107
  ExternalIngressEvent,
99
108
  ExternalIngressEventFilters,
@@ -133,6 +142,8 @@ import type {
133
142
  WikiRefsCheckResponse,
134
143
  WikiAnchorStatusRequest,
135
144
  WikiAnchorStatusResponse,
145
+ WikiAnchorResolveRequest,
146
+ WikiAnchorResolveResponse,
136
147
  WikiDiff,
137
148
  WikiPathScope,
138
149
  WikiAccessStatus,
@@ -212,6 +223,7 @@ import type {
212
223
  BrowserViewerCommandResponse,
213
224
  GrantBrowserProfileConsentRequest,
214
225
  EdgeDevice,
226
+ EdgePlacement,
215
227
  EdgeBrowserProfile,
216
228
  ClipConnection,
217
229
  EdgeOnboardingStatus,
@@ -259,6 +271,7 @@ export class ParallClient {
259
271
  '/auth/check-email',
260
272
  '/auth/forgot-password',
261
273
  '/auth/reset-password',
274
+ '/auth/oauth/exchange',
262
275
  ]);
263
276
 
264
277
  /** Proactive refresh when token expires within this window (seconds). */
@@ -585,6 +598,15 @@ export class ParallClient {
585
598
  });
586
599
  }
587
600
 
601
+ /**
602
+ * Redeem a one-time OAuth code (from the `?code=` param the backend puts on
603
+ * the /auth/callback redirect) for the access/refresh tokens + user. The
604
+ * code is single-use and short-lived — call this once, immediately.
605
+ */
606
+ async oauthExchange(code: string): Promise<AuthTokens> {
607
+ return this.request('POST', ENDPOINTS.AUTH_OAUTH_EXCHANGE, { code });
608
+ }
609
+
588
610
  // ---- WebSocket ----
589
611
 
590
612
  async getWsTicket(): Promise<WsTicketResponse> {
@@ -1739,11 +1761,17 @@ export class ParallClient {
1739
1761
  return this.request('PATCH', ENDPOINTS.MACHINE_SPEC(orgId, machineId), spec);
1740
1762
  }
1741
1763
 
1742
- /** Signal a local daemon-mode Machine to check for and apply an update. */
1764
+ /** @deprecated Retired server-side (daemon-control-authorization §4.2):
1765
+ * daemons update autonomously (CDN poll + platform release signal). The
1766
+ * endpoint now answers 409 LOCAL_UPDATE_NOT_SUPPORTED unconditionally. */
1743
1767
  async requestMachineUpdate(orgId: string, machineId: string, mandatory = false): Promise<void> {
1744
1768
  await this.request('POST', ENDPOINTS.MACHINE_REQUEST_UPDATE(orgId, machineId), { mandatory });
1745
1769
  }
1746
1770
 
1771
+ /** @deprecated Retired server-side (daemon-control-authorization §4.2):
1772
+ * remote filesystem browse of a member's machine was remote device access.
1773
+ * The endpoint now answers 409 LOCAL_BROWSE_NOT_SUPPORTED unconditionally;
1774
+ * workspace paths are typed in (or picked on the machine's own Desktop). */
1747
1775
  async browseMachineFilesystem(
1748
1776
  orgId: string,
1749
1777
  machineId: string,
@@ -1799,6 +1827,20 @@ export class ParallClient {
1799
1827
  return this.request('GET', ENDPOINTS.THREAD_UNREAD(orgId, chatId, threadRootId));
1800
1828
  }
1801
1829
 
1830
+ /** Advance the per-thread read cursor (forward-only). The server auto-clears
1831
+ * thread-scoped inbox items (thread_reply + in-thread mentions) the cursor
1832
+ * now covers. */
1833
+ async markThreadRead(
1834
+ orgId: string,
1835
+ chatId: string,
1836
+ threadRootId: string,
1837
+ messageId: string,
1838
+ ): Promise<void> {
1839
+ return this.request('POST', ENDPOINTS.THREAD_READ(orgId, chatId, threadRootId), {
1840
+ message_id: messageId,
1841
+ });
1842
+ }
1843
+
1802
1844
  // ---- Inbox ----
1803
1845
 
1804
1846
  async getInbox(
@@ -1839,9 +1881,15 @@ export class ParallClient {
1839
1881
  return this.request('POST', ENDPOINTS.INBOX_ARCHIVE_ALL(orgId));
1840
1882
  }
1841
1883
 
1842
- /** Mark an inbox item as read by its source (source_type + source_id) rather than inbox item ID. */
1843
- async ackInbox(orgId: string, source: { source_type: string; source_id: string }): Promise<void> {
1844
- return this.request('POST', ENDPOINTS.INBOX_ACK(orgId), source);
1884
+ /** Mark inbox items as read by their source (source_type + source_id) or by
1885
+ * group_key, rather than by inbox item ID. The group_key form clears a whole
1886
+ * group at once (e.g. `task:{taskId}` — task_assign/task_update/task_comment
1887
+ * share it), used by the task detail view's auto-ack on open. */
1888
+ async ackInbox(
1889
+ orgId: string,
1890
+ target: { source_type: string; source_id: string } | { group_key: string },
1891
+ ): Promise<void> {
1892
+ return this.request('POST', ENDPOINTS.INBOX_ACK(orgId), target);
1845
1893
  }
1846
1894
 
1847
1895
  async deleteInboxItem(orgId: string, id: string): Promise<void> {
@@ -2405,6 +2453,19 @@ export class ParallClient {
2405
2453
  return this.request('POST', ENDPOINTS.CHANNEL_PROVISIONING(orgId), input);
2406
2454
  }
2407
2455
 
2456
+ /**
2457
+ * Mint a pending slack connection + api.slack.com manifest-prefill link
2458
+ * (guided manual path). Activate the returned connection_id with
2459
+ * deliverChannelCredentials once the user brings back the bot token +
2460
+ * signing secret.
2461
+ */
2462
+ async createSlackManifestLink(
2463
+ orgId: string,
2464
+ input: { agent_id: string },
2465
+ ): Promise<SlackManifestLinkResult> {
2466
+ return this.request('POST', ENDPOINTS.CHANNEL_SLACK_MANIFEST_LINK(orgId), input);
2467
+ }
2468
+
2408
2469
  /**
2409
2470
  * Lazy status poll — server-side this may forward one provider poll, so
2410
2471
  * call it at the session's `poll_interval_seconds` cadence, not faster.
@@ -2423,6 +2484,67 @@ export class ParallClient {
2423
2484
  return this.request('POST', ENDPOINTS.CHANNEL_PROVISIONING_CANCEL(orgId, sessionId));
2424
2485
  }
2425
2486
 
2487
+ /**
2488
+ * Tier-B platform verb (agent-only): send one message as the calling
2489
+ * agent's bound bot identity. Credentials never leave the platform —
2490
+ * api-server performs the vendor call in-process.
2491
+ */
2492
+ async sendChannelMessage(
2493
+ orgId: string,
2494
+ input: SendChannelMessageInput,
2495
+ ): Promise<SentChannelMessage> {
2496
+ return this.request('POST', ENDPOINTS.CHANNEL_SEND(orgId), input);
2497
+ }
2498
+
2499
+ private slackReadQuery(base: string, query?: SlackReadPageQuery, extra?: Record<string, string>) {
2500
+ const params = new URLSearchParams();
2501
+ if (query?.cursor) params.set('cursor', query.cursor);
2502
+ if (query?.limit) params.set('limit', String(query.limit));
2503
+ for (const [k, v] of Object.entries(extra ?? {})) params.set(k, v);
2504
+ const qs = params.toString();
2505
+ return qs ? `${base}?${qs}` : base;
2506
+ }
2507
+
2508
+ /**
2509
+ * Tier-B read verbs (agent-only): workspace visibility as the bot sees
2510
+ * it. Same live gate as the send verb; authorization beyond it is the
2511
+ * bot's own Slack permissions.
2512
+ */
2513
+ async listSlackChannels(orgId: string, query?: SlackReadPageQuery): Promise<SlackChannelsPage> {
2514
+ return this.request('GET', this.slackReadQuery(ENDPOINTS.SLACK_CHANNELS(orgId), query));
2515
+ }
2516
+
2517
+ async listSlackUsers(orgId: string, query?: SlackReadPageQuery): Promise<SlackUsersPage> {
2518
+ return this.request('GET', this.slackReadQuery(ENDPOINTS.SLACK_USERS(orgId), query));
2519
+ }
2520
+
2521
+ async slackHistory(
2522
+ orgId: string,
2523
+ conversationId: string,
2524
+ query?: SlackReadPageQuery,
2525
+ ): Promise<SlackHistoryPage> {
2526
+ return this.request(
2527
+ 'GET',
2528
+ this.slackReadQuery(ENDPOINTS.SLACK_HISTORY(orgId), query, { conversation: conversationId }),
2529
+ );
2530
+ }
2531
+
2532
+ async slackMembers(
2533
+ orgId: string,
2534
+ conversationId: string,
2535
+ query?: SlackReadPageQuery,
2536
+ ): Promise<SlackMembersPage> {
2537
+ return this.request(
2538
+ 'GET',
2539
+ this.slackReadQuery(ENDPOINTS.SLACK_MEMBERS(orgId), query, { conversation: conversationId }),
2540
+ );
2541
+ }
2542
+
2543
+ /** Set/clear the Agents-pane "typing…" indicator (best-effort cosmetic). */
2544
+ async setSlackStatus(orgId: string, input: SlackStatusInput): Promise<void> {
2545
+ await this.request('POST', ENDPOINTS.SLACK_STATUS(orgId), input);
2546
+ }
2547
+
2426
2548
  async listChannelConversations(
2427
2549
  orgId: string,
2428
2550
  connectionId: string,
@@ -2693,6 +2815,14 @@ export class ParallClient {
2693
2815
  return this.request('POST', ENDPOINTS.WIKI_ANCHOR_STATUS(orgId, wikiId), body);
2694
2816
  }
2695
2817
 
2818
+ async resolveWikiAnchors(
2819
+ orgId: string,
2820
+ wikiId: string,
2821
+ body: WikiAnchorResolveRequest,
2822
+ ): Promise<WikiAnchorResolveResponse> {
2823
+ return this.request('POST', ENDPOINTS.WIKI_ANCHOR_RESOLVE(orgId, wikiId), body);
2824
+ }
2825
+
2696
2826
  async createWikiChangeset(
2697
2827
  orgId: string,
2698
2828
  wikiId: string,
@@ -2964,6 +3094,7 @@ export class ParallClient {
2964
3094
  limit?: number;
2965
3095
  cursor?: string;
2966
3096
  order?: string;
3097
+ resolution?: 'active' | 'resolved' | 'all';
2967
3098
  }
2968
3099
  | {
2969
3100
  target_prefix: string;
@@ -2971,6 +3102,7 @@ export class ParallClient {
2971
3102
  limit?: number;
2972
3103
  cursor?: string;
2973
3104
  order?: string;
3105
+ resolution?: 'active' | 'resolved' | 'all';
2974
3106
  },
2975
3107
  ): Promise<PaginatedResponse<Comment>> {
2976
3108
  return this.request('GET', ENDPOINTS.COMMENTS(orgId), undefined, params);
@@ -2996,6 +3128,14 @@ export class ParallClient {
2996
3128
  return this.request('DELETE', ENDPOINTS.COMMENT(orgId, commentId));
2997
3129
  }
2998
3130
 
3131
+ async resolveComment(orgId: string, commentId: string): Promise<Comment> {
3132
+ return this.request('POST', ENDPOINTS.COMMENT_RESOLVE(orgId, commentId));
3133
+ }
3134
+
3135
+ async reopenComment(orgId: string, commentId: string): Promise<Comment> {
3136
+ return this.request('POST', ENDPOINTS.COMMENT_REOPEN(orgId, commentId));
3137
+ }
3138
+
2999
3139
  // ---- References ----
3000
3140
 
3001
3141
  async resolveRefs(
@@ -3338,6 +3478,35 @@ export class ParallClient {
3338
3478
  return this.request('GET', ENDPOINTS.ORG_EDGE_DEVICES(orgId));
3339
3479
  }
3340
3480
 
3481
+ /**
3482
+ * Register an Edge device. `placement` defaults to `byoc`.
3483
+ *
3484
+ * `placement: 'hosted'` creates a Cloud Profile: an ORG-SHARED browser that other
3485
+ * members and agents can run clips through once you bind a clip to it. Only a human
3486
+ * can create one (an agent gets `403 HOSTED_HUMAN_ONLY`), and only sign into it with
3487
+ * an account you are authorized and willing to share with the whole organization.
3488
+ * Creating one starts no pod and costs nothing.
3489
+ */
3490
+ async registerEdgeDevice(
3491
+ orgId: string,
3492
+ input: { name: string; placement?: EdgePlacement },
3493
+ ): Promise<EdgeDevice> {
3494
+ return this.request('POST', ENDPOINTS.ORG_EDGE(orgId), input);
3495
+ }
3496
+
3497
+ /**
3498
+ * Delete a hosted Cloud Profile. Hosted only — a BYOC device is removed by
3499
+ * uninstalling Parall Clip on that machine (`400 EDGE_PLACEMENT_UNSUPPORTED`).
3500
+ *
3501
+ * Idempotent and ASYNC: returns `202` with `hosted_state: 'deleting'` on the first
3502
+ * call and on every repeat. The device stops being usable immediately (no exec, no
3503
+ * new bindings), but it remains listed as `deleting` until the platform has drained
3504
+ * its pod and purged its stored browser state — which can take several minutes.
3505
+ */
3506
+ async deleteEdgeDevice(orgId: string, edgeId: string): Promise<EdgeDevice> {
3507
+ return this.request('DELETE', ENDPOINTS.ORG_EDGE_DEVICE(orgId, edgeId));
3508
+ }
3509
+
3341
3510
  async getEdgeOnboarding(orgId: string): Promise<EdgeOnboardingStatus> {
3342
3511
  return this.request('GET', ENDPOINTS.ORG_EDGE_ONBOARDING(orgId));
3343
3512
  }
package/src/constants.ts CHANGED
@@ -354,6 +354,7 @@ export const ENDPOINTS = {
354
354
  AUTH_RESEND_CODE: `${API_BASE}/auth/resend-code`,
355
355
  AUTH_FORGOT_PASSWORD: `${API_BASE}/auth/forgot-password`,
356
356
  AUTH_RESET_PASSWORD: `${API_BASE}/auth/reset-password`,
357
+ AUTH_OAUTH_EXCHANGE: `${API_BASE}/auth/oauth/exchange`,
357
358
 
358
359
  // Users
359
360
  USERS_ME: `${API_BASE}/users/me`,
@@ -627,10 +628,20 @@ export const ENDPOINTS = {
627
628
  CHANNEL_MESSAGE: (orgId: string, messageId: string) =>
628
629
  `${API_BASE}/orgs/${orgId}/channel-messages/${messageId}`,
629
630
  CHANNEL_PROVISIONING: (orgId: string) => `${API_BASE}/orgs/${orgId}/channel-provisioning`,
631
+ CHANNEL_SLACK_MANIFEST_LINK: (orgId: string) =>
632
+ `${API_BASE}/orgs/${orgId}/channel-provisioning/slack/manifest-link`,
630
633
  CHANNEL_PROVISIONING_SESSION: (orgId: string, sessionId: string) =>
631
634
  `${API_BASE}/orgs/${orgId}/channel-provisioning/${sessionId}`,
632
635
  CHANNEL_PROVISIONING_CANCEL: (orgId: string, sessionId: string) =>
633
636
  `${API_BASE}/orgs/${orgId}/channel-provisioning/${sessionId}/cancel`,
637
+ // Tier-B platform verb (agent-only): send one message as the bound bot.
638
+ CHANNEL_SEND: (orgId: string) => `${API_BASE}/orgs/${orgId}/agents/me/channel-send`,
639
+ // Tier-B read verbs (agent-only): workspace visibility as the bot sees it.
640
+ SLACK_CHANNELS: (orgId: string) => `${API_BASE}/orgs/${orgId}/agents/me/slack/channels`,
641
+ SLACK_USERS: (orgId: string) => `${API_BASE}/orgs/${orgId}/agents/me/slack/users`,
642
+ SLACK_HISTORY: (orgId: string) => `${API_BASE}/orgs/${orgId}/agents/me/slack/history`,
643
+ SLACK_MEMBERS: (orgId: string) => `${API_BASE}/orgs/${orgId}/agents/me/slack/members`,
644
+ SLACK_STATUS: (orgId: string) => `${API_BASE}/orgs/${orgId}/agents/me/slack/status`,
634
645
 
635
646
  // Invitations (org-scoped, admin)
636
647
  ORG_INVITATIONS: (orgId: string) => `${API_BASE}/orgs/${orgId}/invitations`,
@@ -678,6 +689,8 @@ export const ENDPOINTS = {
678
689
  `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/refs/check`,
679
690
  WIKI_ANCHOR_STATUS: (orgId: string, wikiId: string) =>
680
691
  `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/anchor-status`,
692
+ WIKI_ANCHOR_RESOLVE: (orgId: string, wikiId: string) =>
693
+ `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/anchor-resolve`,
681
694
  WIKI_CHANGESETS: (orgId: string, wikiId: string) =>
682
695
  `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/changesets`,
683
696
  WIKI_CHANGESET: (orgId: string, wikiId: string, changesetId: string) =>
@@ -729,6 +742,10 @@ export const ENDPOINTS = {
729
742
  // Unified Comments (org-scoped, api-server)
730
743
  COMMENTS: (orgId: string) => `${API_BASE}/orgs/${orgId}/comments`,
731
744
  COMMENT: (orgId: string, commentId: string) => `${API_BASE}/orgs/${orgId}/comments/${commentId}`,
745
+ COMMENT_RESOLVE: (orgId: string, commentId: string) =>
746
+ `${API_BASE}/orgs/${orgId}/comments/${commentId}:resolve`,
747
+ COMMENT_REOPEN: (orgId: string, commentId: string) =>
748
+ `${API_BASE}/orgs/${orgId}/comments/${commentId}:reopen`,
732
749
 
733
750
  // Inbox (org-scoped)
734
751
  INBOX: (orgId: string) => `${API_BASE}/orgs/${orgId}/inbox`,
@@ -765,6 +782,8 @@ export const ENDPOINTS = {
765
782
  CHAT_READ: (orgId: string, chatId: string) => `${API_BASE}/orgs/${orgId}/chats/${chatId}/read`,
766
783
  THREAD_UNREAD: (orgId: string, chatId: string, threadRootId: string) =>
767
784
  `${API_BASE}/orgs/${orgId}/chats/${chatId}/threads/${threadRootId}/unread`,
785
+ THREAD_READ: (orgId: string, chatId: string, threadRootId: string) =>
786
+ `${API_BASE}/orgs/${orgId}/chats/${chatId}/threads/${threadRootId}/read`,
768
787
 
769
788
  // References (org-scoped)
770
789
  REFS_RESOLVE: (orgId: string) => `${API_BASE}/orgs/${orgId}/refs/resolve`,
@@ -849,7 +868,9 @@ export const ENDPOINTS = {
849
868
  CLIP_REGISTRY: () => `${CLIP_BASE}/registry/clips`,
850
869
 
851
870
  // Edge device endpoints
871
+ ORG_EDGE: (orgId: string) => `/api/v1/orgs/${orgId}/edge`,
852
872
  ORG_EDGE_DEVICES: (orgId: string) => `/api/v1/orgs/${orgId}/edge/devices`,
873
+ ORG_EDGE_DEVICE: (orgId: string, edgeId: string) => `/api/v1/orgs/${orgId}/edge/${edgeId}`,
853
874
  ORG_EDGE_ONBOARDING: (orgId: string) => `/api/v1/orgs/${orgId}/edge/onboarding`,
854
875
  ORG_EDGE_PROFILES: (orgId: string, edgeId: string) =>
855
876
  `/api/v1/orgs/${orgId}/edge/${edgeId}/profiles`,
@@ -1060,4 +1081,6 @@ export const COMMENT_TARGET = {
1060
1081
  const frag = lineStart === lineEnd ? `l=${lineStart}` : `l=${lineStart}-${lineEnd}`;
1061
1082
  return `prll://${wikiId}/${encodeWikiPath(path)}?rev=${rev}#${frag}`;
1062
1083
  },
1084
+ wikiTextRange: (wikiId: string, path: string, rev: string, start: number, end: number) =>
1085
+ `prll://${wikiId}/${encodeWikiPath(path)}?rev=${rev}#t=${start}-${end}`,
1063
1086
  } as const;