@parall/sdk 1.45.0 → 1.46.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,8 @@ import type {
94
94
  ChannelProvisioningSession,
95
95
  CreateChannelConnectionInput,
96
96
  InitiateChannelProvisioningInput,
97
+ SendChannelMessageInput,
98
+ SentChannelMessage,
97
99
  UpdateChannelConnectionInput,
98
100
  ExternalIngressEvent,
99
101
  ExternalIngressEventFilters,
@@ -133,6 +135,8 @@ import type {
133
135
  WikiRefsCheckResponse,
134
136
  WikiAnchorStatusRequest,
135
137
  WikiAnchorStatusResponse,
138
+ WikiAnchorResolveRequest,
139
+ WikiAnchorResolveResponse,
136
140
  WikiDiff,
137
141
  WikiPathScope,
138
142
  WikiAccessStatus,
@@ -212,6 +216,7 @@ import type {
212
216
  BrowserViewerCommandResponse,
213
217
  GrantBrowserProfileConsentRequest,
214
218
  EdgeDevice,
219
+ EdgePlacement,
215
220
  EdgeBrowserProfile,
216
221
  ClipConnection,
217
222
  EdgeOnboardingStatus,
@@ -259,6 +264,7 @@ export class ParallClient {
259
264
  '/auth/check-email',
260
265
  '/auth/forgot-password',
261
266
  '/auth/reset-password',
267
+ '/auth/oauth/exchange',
262
268
  ]);
263
269
 
264
270
  /** Proactive refresh when token expires within this window (seconds). */
@@ -585,6 +591,15 @@ export class ParallClient {
585
591
  });
586
592
  }
587
593
 
594
+ /**
595
+ * Redeem a one-time OAuth code (from the `?code=` param the backend puts on
596
+ * the /auth/callback redirect) for the access/refresh tokens + user. The
597
+ * code is single-use and short-lived — call this once, immediately.
598
+ */
599
+ async oauthExchange(code: string): Promise<AuthTokens> {
600
+ return this.request('POST', ENDPOINTS.AUTH_OAUTH_EXCHANGE, { code });
601
+ }
602
+
588
603
  // ---- WebSocket ----
589
604
 
590
605
  async getWsTicket(): Promise<WsTicketResponse> {
@@ -2423,6 +2438,18 @@ export class ParallClient {
2423
2438
  return this.request('POST', ENDPOINTS.CHANNEL_PROVISIONING_CANCEL(orgId, sessionId));
2424
2439
  }
2425
2440
 
2441
+ /**
2442
+ * Tier-B platform verb (agent-only): send one message as the calling
2443
+ * agent's bound bot identity. Credentials never leave the platform —
2444
+ * api-server performs the vendor call in-process.
2445
+ */
2446
+ async sendChannelMessage(
2447
+ orgId: string,
2448
+ input: SendChannelMessageInput,
2449
+ ): Promise<SentChannelMessage> {
2450
+ return this.request('POST', ENDPOINTS.CHANNEL_SEND(orgId), input);
2451
+ }
2452
+
2426
2453
  async listChannelConversations(
2427
2454
  orgId: string,
2428
2455
  connectionId: string,
@@ -2693,6 +2720,14 @@ export class ParallClient {
2693
2720
  return this.request('POST', ENDPOINTS.WIKI_ANCHOR_STATUS(orgId, wikiId), body);
2694
2721
  }
2695
2722
 
2723
+ async resolveWikiAnchors(
2724
+ orgId: string,
2725
+ wikiId: string,
2726
+ body: WikiAnchorResolveRequest,
2727
+ ): Promise<WikiAnchorResolveResponse> {
2728
+ return this.request('POST', ENDPOINTS.WIKI_ANCHOR_RESOLVE(orgId, wikiId), body);
2729
+ }
2730
+
2696
2731
  async createWikiChangeset(
2697
2732
  orgId: string,
2698
2733
  wikiId: string,
@@ -2964,6 +2999,7 @@ export class ParallClient {
2964
2999
  limit?: number;
2965
3000
  cursor?: string;
2966
3001
  order?: string;
3002
+ resolution?: 'active' | 'resolved' | 'all';
2967
3003
  }
2968
3004
  | {
2969
3005
  target_prefix: string;
@@ -2971,6 +3007,7 @@ export class ParallClient {
2971
3007
  limit?: number;
2972
3008
  cursor?: string;
2973
3009
  order?: string;
3010
+ resolution?: 'active' | 'resolved' | 'all';
2974
3011
  },
2975
3012
  ): Promise<PaginatedResponse<Comment>> {
2976
3013
  return this.request('GET', ENDPOINTS.COMMENTS(orgId), undefined, params);
@@ -2996,6 +3033,14 @@ export class ParallClient {
2996
3033
  return this.request('DELETE', ENDPOINTS.COMMENT(orgId, commentId));
2997
3034
  }
2998
3035
 
3036
+ async resolveComment(orgId: string, commentId: string): Promise<Comment> {
3037
+ return this.request('POST', ENDPOINTS.COMMENT_RESOLVE(orgId, commentId));
3038
+ }
3039
+
3040
+ async reopenComment(orgId: string, commentId: string): Promise<Comment> {
3041
+ return this.request('POST', ENDPOINTS.COMMENT_REOPEN(orgId, commentId));
3042
+ }
3043
+
2999
3044
  // ---- References ----
3000
3045
 
3001
3046
  async resolveRefs(
@@ -3338,6 +3383,35 @@ export class ParallClient {
3338
3383
  return this.request('GET', ENDPOINTS.ORG_EDGE_DEVICES(orgId));
3339
3384
  }
3340
3385
 
3386
+ /**
3387
+ * Register an Edge device. `placement` defaults to `byoc`.
3388
+ *
3389
+ * `placement: 'hosted'` creates a Cloud Profile: an ORG-SHARED browser that other
3390
+ * members and agents can run clips through once you bind a clip to it. Only a human
3391
+ * can create one (an agent gets `403 HOSTED_HUMAN_ONLY`), and only sign into it with
3392
+ * an account you are authorized and willing to share with the whole organization.
3393
+ * Creating one starts no pod and costs nothing.
3394
+ */
3395
+ async registerEdgeDevice(
3396
+ orgId: string,
3397
+ input: { name: string; placement?: EdgePlacement },
3398
+ ): Promise<EdgeDevice> {
3399
+ return this.request('POST', ENDPOINTS.ORG_EDGE(orgId), input);
3400
+ }
3401
+
3402
+ /**
3403
+ * Delete a hosted Cloud Profile. Hosted only — a BYOC device is removed by
3404
+ * uninstalling Parall Clip on that machine (`400 EDGE_PLACEMENT_UNSUPPORTED`).
3405
+ *
3406
+ * Idempotent and ASYNC: returns `202` with `hosted_state: 'deleting'` on the first
3407
+ * call and on every repeat. The device stops being usable immediately (no exec, no
3408
+ * new bindings), but it remains listed as `deleting` until the platform has drained
3409
+ * its pod and purged its stored browser state — which can take several minutes.
3410
+ */
3411
+ async deleteEdgeDevice(orgId: string, edgeId: string): Promise<EdgeDevice> {
3412
+ return this.request('DELETE', ENDPOINTS.ORG_EDGE_DEVICE(orgId, edgeId));
3413
+ }
3414
+
3341
3415
  async getEdgeOnboarding(orgId: string): Promise<EdgeOnboardingStatus> {
3342
3416
  return this.request('GET', ENDPOINTS.ORG_EDGE_ONBOARDING(orgId));
3343
3417
  }
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`,
@@ -631,6 +632,8 @@ export const ENDPOINTS = {
631
632
  `${API_BASE}/orgs/${orgId}/channel-provisioning/${sessionId}`,
632
633
  CHANNEL_PROVISIONING_CANCEL: (orgId: string, sessionId: string) =>
633
634
  `${API_BASE}/orgs/${orgId}/channel-provisioning/${sessionId}/cancel`,
635
+ // Tier-B platform verb (agent-only): send one message as the bound bot.
636
+ CHANNEL_SEND: (orgId: string) => `${API_BASE}/orgs/${orgId}/agents/me/channel-send`,
634
637
 
635
638
  // Invitations (org-scoped, admin)
636
639
  ORG_INVITATIONS: (orgId: string) => `${API_BASE}/orgs/${orgId}/invitations`,
@@ -678,6 +681,8 @@ export const ENDPOINTS = {
678
681
  `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/refs/check`,
679
682
  WIKI_ANCHOR_STATUS: (orgId: string, wikiId: string) =>
680
683
  `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/anchor-status`,
684
+ WIKI_ANCHOR_RESOLVE: (orgId: string, wikiId: string) =>
685
+ `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/anchor-resolve`,
681
686
  WIKI_CHANGESETS: (orgId: string, wikiId: string) =>
682
687
  `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/changesets`,
683
688
  WIKI_CHANGESET: (orgId: string, wikiId: string, changesetId: string) =>
@@ -729,6 +734,10 @@ export const ENDPOINTS = {
729
734
  // Unified Comments (org-scoped, api-server)
730
735
  COMMENTS: (orgId: string) => `${API_BASE}/orgs/${orgId}/comments`,
731
736
  COMMENT: (orgId: string, commentId: string) => `${API_BASE}/orgs/${orgId}/comments/${commentId}`,
737
+ COMMENT_RESOLVE: (orgId: string, commentId: string) =>
738
+ `${API_BASE}/orgs/${orgId}/comments/${commentId}:resolve`,
739
+ COMMENT_REOPEN: (orgId: string, commentId: string) =>
740
+ `${API_BASE}/orgs/${orgId}/comments/${commentId}:reopen`,
732
741
 
733
742
  // Inbox (org-scoped)
734
743
  INBOX: (orgId: string) => `${API_BASE}/orgs/${orgId}/inbox`,
@@ -849,7 +858,9 @@ export const ENDPOINTS = {
849
858
  CLIP_REGISTRY: () => `${CLIP_BASE}/registry/clips`,
850
859
 
851
860
  // Edge device endpoints
861
+ ORG_EDGE: (orgId: string) => `/api/v1/orgs/${orgId}/edge`,
852
862
  ORG_EDGE_DEVICES: (orgId: string) => `/api/v1/orgs/${orgId}/edge/devices`,
863
+ ORG_EDGE_DEVICE: (orgId: string, edgeId: string) => `/api/v1/orgs/${orgId}/edge/${edgeId}`,
853
864
  ORG_EDGE_ONBOARDING: (orgId: string) => `/api/v1/orgs/${orgId}/edge/onboarding`,
854
865
  ORG_EDGE_PROFILES: (orgId: string, edgeId: string) =>
855
866
  `/api/v1/orgs/${orgId}/edge/${edgeId}/profiles`,
@@ -1060,4 +1071,6 @@ export const COMMENT_TARGET = {
1060
1071
  const frag = lineStart === lineEnd ? `l=${lineStart}` : `l=${lineStart}-${lineEnd}`;
1061
1072
  return `prll://${wikiId}/${encodeWikiPath(path)}?rev=${rev}#${frag}`;
1062
1073
  },
1074
+ wikiTextRange: (wikiId: string, path: string, rev: string, start: number, end: number) =>
1075
+ `prll://${wikiId}/${encodeWikiPath(path)}?rev=${rev}#t=${start}-${end}`,
1063
1076
  } as const;
package/src/types.ts CHANGED
@@ -1861,6 +1861,29 @@ export interface WikiAnchorStatusResponse {
1861
1861
  results: WikiAnchorStatus[];
1862
1862
  }
1863
1863
 
1864
+ export interface WikiAnchorResolveRequest {
1865
+ targets: string[];
1866
+ }
1867
+
1868
+ export type WikiAnchorResolveState = 'attached' | 'detached' | 'file_missing' | 'unknown';
1869
+
1870
+ export interface WikiAnchorResolveRange {
1871
+ start: number;
1872
+ end: number;
1873
+ }
1874
+
1875
+ export interface WikiAnchorResolveResult {
1876
+ target_uri: string;
1877
+ state: WikiAnchorResolveState;
1878
+ current?: WikiAnchorResolveRange;
1879
+ origin_quote?: string;
1880
+ }
1881
+
1882
+ export interface WikiAnchorResolveResponse {
1883
+ head_rev: string;
1884
+ results: WikiAnchorResolveResult[];
1885
+ }
1886
+
1864
1887
  export interface WikiRefsCheckResponse {
1865
1888
  wiki_id: string;
1866
1889
  wiki_slug: string;
@@ -2408,12 +2431,15 @@ export interface Comment {
2408
2431
  id: string;
2409
2432
  org_id: string;
2410
2433
  target_uri: string;
2434
+ target_quote?: string | null;
2411
2435
  parent_id?: string | null;
2412
2436
  author_id: string;
2413
2437
  body: string;
2414
2438
  mentions?: Mention[];
2415
2439
  hints?: MessageHints | null;
2416
2440
  agent_step_id?: string | null;
2441
+ resolved_at?: string | null;
2442
+ resolved_by_id?: string | null;
2417
2443
  created_at: string;
2418
2444
  updated_at: string;
2419
2445
  author?: User;
@@ -2421,6 +2447,7 @@ export interface Comment {
2421
2447
 
2422
2448
  export interface CreateCommentRequest {
2423
2449
  target_uri: string;
2450
+ target_quote?: string;
2424
2451
  body: string;
2425
2452
  parent_id?: string;
2426
2453
  }
@@ -2513,10 +2540,14 @@ export interface ChannelConnection {
2513
2540
  }
2514
2541
 
2515
2542
  export interface ChannelCredentialsInput {
2516
- app_id: string;
2517
- app_secret: string;
2543
+ /** Feishu fields. */
2544
+ app_id?: string;
2545
+ app_secret?: string;
2518
2546
  verification_token?: string;
2519
2547
  encrypt_key?: string;
2548
+ /** Slack fields (webhook-only: the signing secret is the verifier). */
2549
+ bot_token?: string;
2550
+ signing_secret?: string;
2520
2551
  team_id?: string;
2521
2552
  }
2522
2553
 
@@ -2566,10 +2597,13 @@ export interface ChannelMessage {
2566
2597
  }
2567
2598
 
2568
2599
  /**
2569
- * Feishu one-click provisioning session (OAuth device flow). The client
2570
- * renders `verification_url` as a QR code and lazily polls the status
2571
- * endpoint every `poll_interval_seconds` each poll may forward one
2572
- * provider poll server-side, so respect the interval.
2600
+ * One-click provisioning session. Provider-specific shape:
2601
+ * - feishu (OAuth device flow): render `verification_url` as a QR code;
2602
+ * each status poll may forward one provider poll server-side, so respect
2603
+ * `poll_interval_seconds`.
2604
+ * - slack (manifest + OAuth install): `verification_url` is the authorize
2605
+ * link to open; status polls are pure state reads (completion is pushed
2606
+ * by the OAuth callback).
2573
2607
  */
2574
2608
  export type ChannelProvisioningStatus =
2575
2609
  | 'pending'
@@ -2595,14 +2629,62 @@ export interface ChannelProvisioningSession {
2595
2629
  expires_at: string;
2596
2630
  created_at: string;
2597
2631
  updated_at: string;
2598
- /** QR target — present on live (pending/polling) sessions only. */
2632
+ /**
2633
+ * Provisioning target — present on live (pending/polling) sessions only.
2634
+ * feishu: the QR-code content; slack: the OAuth authorize link.
2635
+ */
2599
2636
  verification_url?: string;
2637
+ /** feishu only. */
2600
2638
  user_code?: string;
2601
2639
  }
2602
2640
 
2603
- export interface InitiateChannelProvisioningInput {
2604
- agent_id: string;
2605
- provider: ChannelProvider;
2641
+ /**
2642
+ * Discriminated on `provider`: slack REQUIRES the config token (the server
2643
+ * 400s without it), other providers have no such field — the union makes a
2644
+ * token-less slack initiate unrepresentable at compile time.
2645
+ */
2646
+ export type InitiateChannelProvisioningInput =
2647
+ | {
2648
+ agent_id: string;
2649
+ provider: 'slack';
2650
+ /**
2651
+ * The short-lived app-configuration token (12h, generated at
2652
+ * api.slack.com/apps). Transits once into apps.manifest.create and is
2653
+ * never stored.
2654
+ */
2655
+ config_token: string;
2656
+ }
2657
+ | {
2658
+ agent_id: string;
2659
+ provider: Exclude<ChannelProvider, 'slack'>;
2660
+ };
2661
+
2662
+ /**
2663
+ * Tier-B platform verb request (agent-only): send as the bound bot.
2664
+ * Deliberately narrowed to 'slack' — the verb surface is per-vendor
2665
+ * (feishu outbound is the lark-cli broker, not this endpoint), so a
2666
+ * generic ChannelProvider here would compile call sites that always 400.
2667
+ */
2668
+ export interface SendChannelMessageInput {
2669
+ channel_type: 'slack';
2670
+ /** Vendor-native conversation id from the inbound event (e.g. C…/D…). */
2671
+ conversation_id: string;
2672
+ /**
2673
+ * External message id being answered (channel-domain format). REQUIRED
2674
+ * for channel conversations (the reply lands in that message's thread);
2675
+ * optional for DMs (always linear).
2676
+ */
2677
+ reply_to?: string;
2678
+ text: string;
2679
+ }
2680
+
2681
+ export interface SentChannelMessage {
2682
+ channel_type: 'slack';
2683
+ conversation_id: string;
2684
+ /** Channel-domain external id ({channel}:{ts}) — usable as a reply_to. */
2685
+ message_id: string;
2686
+ thread_anchor?: string;
2687
+ sent_at: string;
2606
2688
  }
2607
2689
 
2608
2690
  // ============================================================
@@ -3099,6 +3181,8 @@ export interface ResolvedRef {
3099
3181
  resolved_rev?: string;
3100
3182
  line_start?: number;
3101
3183
  line_end?: number;
3184
+ text_start?: number;
3185
+ text_end?: number;
3102
3186
  heading_path?: string[];
3103
3187
  symbol_name?: string;
3104
3188
 
@@ -3915,6 +3999,30 @@ export interface SearchResponse {
3915
3999
  // Edge Device Types
3916
4000
  // ============================================================
3917
4001
 
4002
+ /**
4003
+ * Where an Edge device runs — and, consequently, who it belongs to.
4004
+ *
4005
+ * - `byoc` — the user's own computer running Parall Clip. Owner-only in every
4006
+ * sense: only the owner connects it, manages it, or executes on it.
4007
+ * - `hosted` — a platform-managed Cloud Profile. The browser login it holds is an
4008
+ * ORG-SHARED credential maintained by its creator. Members and agents
4009
+ * execute against it ONLY through a clip connection its maintainer
4010
+ * bound; there is no implicit route to a hosted device.
4011
+ */
4012
+ export type EdgePlacement = 'byoc' | 'hosted';
4013
+
4014
+ /**
4015
+ * Lifecycle of a hosted Cloud Profile. Only the states the server can PROVE without
4016
+ * the runtime fence are emitted today; the fence-aware ones (`starting` / `online` /
4017
+ * `busy`) arrive with the controller.
4018
+ *
4019
+ * - `idle` — no pod running (and none requested). Creating a profile starts nothing.
4020
+ * - `deleting` — delete requested; the finalizer (pod drain, S3 state purge) is still
4021
+ * running. Deletion is async and idempotent, so this can persist for
4022
+ * several minutes.
4023
+ */
4024
+ export type EdgeHostedState = 'idle' | 'deleting';
4025
+
3918
4026
  export interface EdgeDevice {
3919
4027
  id: string;
3920
4028
  org_id: string;
@@ -3924,6 +4032,23 @@ export interface EdgeDevice {
3924
4032
  last_seen_at?: string;
3925
4033
  created_at: string;
3926
4034
  updated_at: string;
4035
+ /** Absent on responses from a pre-D1 server; treat a missing value as 'byoc'. */
4036
+ placement?: EdgePlacement;
4037
+ /** Hosted devices only. */
4038
+ hosted_state?: EdgeHostedState;
4039
+ /**
4040
+ * Whether THIS caller may sign into / rebind / delete this device
4041
+ * (hosted: human maintainer ∨ human org admin; byoc: owner). Server-computed, so a
4042
+ * client can render management affordances without reimplementing the rule and
4043
+ * drifting from it.
4044
+ */
4045
+ can_manage?: boolean;
4046
+ /**
4047
+ * True for hosted devices: clips bound to it by its maintainer may be run by other
4048
+ * org members and agents. Surface this before anyone signs in — the login being
4049
+ * shared with the whole org is the product contract, not a footnote.
4050
+ */
4051
+ shared?: boolean;
3927
4052
  }
3928
4053
 
3929
4054
  export interface EdgeBrowserProfile {
@@ -3948,10 +4073,22 @@ export interface ClipConnection {
3948
4073
  updated_at: string;
3949
4074
  }
3950
4075
 
4076
+ /**
4077
+ * Two INDEPENDENT onboarding journeys. The original fields mean what they always
4078
+ * meant — "has this org set up the desktop journey?" — and hosted-backed state
4079
+ * never counts toward them, so a Cloud Profile cannot make desktop onboarding look
4080
+ * finished and tell the user to skip installing the app they still need. Precisely:
4081
+ * device-backed fields are scoped to live `placement='byoc'` edges;
4082
+ * `connection_created` additionally counts device-less MCP bindings (MCP has no
4083
+ * device and predates hosted). The `hosted_*` fields are the second journey;
4084
+ * neither impersonates the other.
4085
+ */
3951
4086
  export interface EdgeOnboardingStatus {
3952
4087
  device_registered: boolean;
3953
4088
  device_online: boolean;
3954
4089
  clip_installed: boolean;
3955
4090
  connection_created: boolean;
3956
4091
  profile_created: boolean;
4092
+ hosted_profile_created?: boolean;
4093
+ hosted_connection_created?: boolean;
3957
4094
  }