@parall/sdk 1.55.5 → 1.56.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
@@ -41,6 +41,8 @@ import type {
41
41
  BrowserAliasExecutionReceipt,
42
42
  BrowserAliasGrantReplaceRequest,
43
43
  BrowserAliasGrantSet,
44
+ BrowserUseOperationRequest,
45
+ BrowserUseOperationReceipt,
44
46
  BrowserRuntimeStatus,
45
47
  BrowserViewerCommandRequest,
46
48
  BrowserViewerCommandResponse,
@@ -3091,6 +3093,19 @@ export class ParallClient extends AttachmentClient {
3091
3093
  await this.request('DELETE', ENDPOINTS.WIKI_MEMBERSHIP_SELF(orgId, wikiId));
3092
3094
  }
3093
3095
 
3096
+ /** Star a library for the caller (sidebar Starred group). Idempotent —
3097
+ * re-starring is a 204 no-op. Requires read access; hidden private
3098
+ * libraries answer 404 like absent IDs. */
3099
+ async starWiki(orgId: string, wikiId: string): Promise<void> {
3100
+ await this.request('POST', ENDPOINTS.WIKI_STARS_SELF(orgId, wikiId));
3101
+ }
3102
+
3103
+ /** Remove the caller's star. Idempotent — unstarring a never-starred
3104
+ * library is a 204 no-op. */
3105
+ async unstarWiki(orgId: string, wikiId: string): Promise<void> {
3106
+ await this.request('DELETE', ENDPOINTS.WIKI_STARS_SELF(orgId, wikiId));
3107
+ }
3108
+
3094
3109
  async getWikiMembers(orgId: string, wikiId: string): Promise<WikiAccessPolicyMember[]> {
3095
3110
  const res = await this.request<{ data: WikiAccessPolicyMember[] | null }>(
3096
3111
  'GET',
@@ -3674,8 +3689,12 @@ export class ParallClient extends AttachmentClient {
3674
3689
  * connections operate on.
3675
3690
  */
3676
3691
  async listOrgRegistryClips(orgId: string): Promise<ClipRegistryEntry[]> {
3677
- // Server default page is 50 (max 100); one max-size page covers today's
3678
- // catalogs revisit with real pagination if registries outgrow it.
3692
+ // ONE page (server max 100), name-ordered a browse surface, not a
3693
+ // resolution surface. The catalog includes every public+approved clip
3694
+ // platform-wide, so "fetch it all" cannot scale; anything that needs a
3695
+ // SPECIFIC clip must point-query instead: `resolveRegistryClip` for an
3696
+ // exact <publisher org, name>, `getRegistryClip` for a `crg_` id, and
3697
+ // `searchOrgRegistryClips` for discovery.
3679
3698
  const resp = await this.request<ClipRegistryEntry[] | null>(
3680
3699
  'GET',
3681
3700
  `${ENDPOINTS.ORG_CLIP_REGISTRY(orgId)}?limit=100`,
@@ -3683,6 +3702,42 @@ export class ParallClient extends AttachmentClient {
3683
3702
  return resp ?? [];
3684
3703
  }
3685
3704
 
3705
+ /**
3706
+ * Resolve an exact `<publisher org, name>` reference to its registry entry —
3707
+ * the npm-style point read. Deliberately independent of catalog size: no
3708
+ * Search, no pagination, same read-visibility boundary as `getRegistryClip`
3709
+ * (cross-org requires public + approved). 404 `NOT_FOUND` when the publisher
3710
+ * org has no visible clip of that exact name.
3711
+ */
3712
+ async resolveRegistryClip(
3713
+ orgId: string,
3714
+ publisherOrgId: string,
3715
+ name: string,
3716
+ ): Promise<ClipRegistryEntry> {
3717
+ const params = new URLSearchParams({ org_id: publisherOrgId, name });
3718
+ return this.request('GET', `${ENDPOINTS.ORG_CLIP_REGISTRY_RESOLVE(orgId)}?${params}`);
3719
+ }
3720
+
3721
+ /**
3722
+ * Server-side fuzzy discovery over the visible registry (name/description
3723
+ * substring match), paginated. The discovery verb: rows carry the `crg_` id
3724
+ * that {@link installRegistryClip} takes.
3725
+ */
3726
+ async searchOrgRegistryClips(
3727
+ orgId: string,
3728
+ query: string,
3729
+ opts?: { limit?: number; offset?: number },
3730
+ ): Promise<ClipRegistryEntry[]> {
3731
+ const params = new URLSearchParams({ q: query });
3732
+ if (opts?.limit !== undefined) params.set('limit', String(opts.limit));
3733
+ if (opts?.offset !== undefined) params.set('offset', String(opts.offset));
3734
+ const resp = await this.request<ClipRegistryEntry[] | null>(
3735
+ 'GET',
3736
+ `${ENDPOINTS.ORG_CLIP_REGISTRY_SEARCH(orgId)}?${params}`,
3737
+ );
3738
+ return resp ?? [];
3739
+ }
3740
+
3686
3741
  /**
3687
3742
  * Install a registry clip into the org (a reference in `clip_installs`, not a
3688
3743
  * copy). Idempotent: installing an already-installed clip returns the same
@@ -3990,6 +4045,24 @@ export class ParallClient extends AttachmentClient {
3990
4045
  return this.request('GET', ENDPOINTS.ORG_BROWSER_ALIAS_EXECUTION(orgId, requestId));
3991
4046
  }
3992
4047
 
4048
+ /** Accept one idempotent Browser Use operation for an explicit Profile.
4049
+ * The Server resolves Profile→Edge; callers never select an Edge directly. */
4050
+ async createBrowserUseOperation(
4051
+ orgId: string,
4052
+ request: BrowserUseOperationRequest,
4053
+ ): Promise<BrowserUseOperationReceipt> {
4054
+ return this.request('POST', ENDPOINTS.ORG_BROWSER_USE_OPERATIONS(orgId), request);
4055
+ }
4056
+
4057
+ /** Recover the durable receipt. Successful data is present only inside the
4058
+ * Server's short encrypted result TTL; terminal proof remains afterwards. */
4059
+ async getBrowserUseOperation(
4060
+ orgId: string,
4061
+ operationId: string,
4062
+ ): Promise<BrowserUseOperationReceipt> {
4063
+ return this.request('GET', ENDPOINTS.ORG_BROWSER_USE_OPERATION(orgId, operationId));
4064
+ }
4065
+
3993
4066
  /**
3994
4067
  * Read a hosted Cloud Profile's egress-proxy status (manager-only: hosted
3995
4068
  * human maintainer or org admin). Sanitized — the password never comes back.
package/src/constants.ts CHANGED
@@ -573,6 +573,7 @@ export const ENDPOINTS = {
573
573
  TASKS: (orgId: string) => `${API_BASE}/orgs/${orgId}/tasks`,
574
574
  TASK_SUBTASK_SUMMARY: (orgId: string) => `${API_BASE}/orgs/${orgId}/tasks/subtask-summary`,
575
575
  TASK: (orgId: string, taskId: string) => `${API_BASE}/orgs/${orgId}/tasks/${taskId}`,
576
+ TASK_MOVE: (orgId: string, taskId: string) => `${API_BASE}/orgs/${orgId}/tasks/${taskId}/move`,
576
577
  TASK_ARCHIVE: (orgId: string, taskId: string) =>
577
578
  `${API_BASE}/orgs/${orgId}/tasks/${taskId}/archive`,
578
579
  TASK_RESTORE: (orgId: string, taskId: string) =>
@@ -776,6 +777,9 @@ export const ENDPOINTS = {
776
777
  `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/access-policy/members`,
777
778
  WIKI_MEMBERSHIP_SELF: (orgId: string, wikiId: string) =>
778
779
  `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/membership/self`,
780
+ // Library-level star (self-scoped bookmark; POST = star, DELETE = unstar).
781
+ WIKI_STARS_SELF: (orgId: string, wikiId: string) =>
782
+ `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/stars/self`,
779
783
  WIKI_MEMBERS: (orgId: string, wikiId: string) =>
780
784
  `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/members`,
781
785
  WIKI_ACCESS_STATUS: (orgId: string, wikiId: string) =>
@@ -972,6 +976,9 @@ export const ENDPOINTS = {
972
976
  ORG_BROWSER_ALIAS_EXECUTIONS: (orgId: string) => `/api/v1/orgs/${orgId}/executions`,
973
977
  ORG_BROWSER_ALIAS_EXECUTION: (orgId: string, requestId: string) =>
974
978
  `/api/v1/orgs/${orgId}/executions/${encodeURIComponent(requestId)}`,
979
+ ORG_BROWSER_USE_OPERATIONS: (orgId: string) => `/api/v1/orgs/${orgId}/browser-use/operations`,
980
+ ORG_BROWSER_USE_OPERATION: (orgId: string, operationId: string) =>
981
+ `/api/v1/orgs/${orgId}/browser-use/operations/${encodeURIComponent(operationId)}`,
975
982
  // Per-profile egress proxy (hosted Cloud Profiles; manager-only, human-only).
976
983
  ORG_EDGE_PROFILE_PROXY: (orgId: string, edgeId: string, profileName: string) =>
977
984
  `/api/v1/orgs/${orgId}/edge/${edgeId}/profiles/${encodeURIComponent(profileName)}/proxy`,
@@ -992,6 +999,8 @@ export const ENDPOINTS = {
992
999
 
993
1000
  // Clip registry (v3, org-scoped, served by api-server — `crg_` entries)
994
1001
  ORG_CLIP_REGISTRY: (orgId: string) => `/api/v1/orgs/${orgId}/clip-registry`,
1002
+ ORG_CLIP_REGISTRY_RESOLVE: (orgId: string) => `/api/v1/orgs/${orgId}/clip-registry/resolve`,
1003
+ ORG_CLIP_REGISTRY_SEARCH: (orgId: string) => `/api/v1/orgs/${orgId}/clip-registry/search`,
995
1004
  ORG_CLIP_REGISTRY_CLIP: (orgId: string, clipId: string) =>
996
1005
  `/api/v1/orgs/${orgId}/clip-registry/${clipId}`,
997
1006
  ORG_CLIP_REGISTRY_PUBLISH: (orgId: string) => `/api/v1/orgs/${orgId}/clip-registry/publish`,
@@ -23,6 +23,7 @@ import type {
23
23
  UpdateProjectMemberRequest,
24
24
  UpdateProjectRequest,
25
25
  UpdateTaskCommentRequest,
26
+ MoveTaskRequest,
26
27
  UpdateTaskRequest,
27
28
  } from './types.js';
28
29
 
@@ -84,6 +85,16 @@ export abstract class ProjectTaskClient {
84
85
  );
85
86
  }
86
87
 
88
+ /**
89
+ * Moves a task and its whole subtree into another project (renumbering it
90
+ * there; old identifiers stay resolvable as aliases). The caller needs
91
+ * update access on the task (source project membership) and read access to
92
+ * the target project.
93
+ */
94
+ async moveTask(orgId: string, taskId: string, data: MoveTaskRequest): Promise<Task> {
95
+ return this.request('POST', ENDPOINTS.TASK_MOVE(orgId, taskId), data);
96
+ }
97
+
87
98
  async archiveTask(orgId: string, taskId: string): Promise<void> {
88
99
  return this.request('POST', ENDPOINTS.TASK_ARCHIVE(orgId, taskId));
89
100
  }
package/src/types.ts CHANGED
@@ -365,10 +365,18 @@ export interface Message {
365
365
  recent_repliers?: User[];
366
366
  /**
367
367
  * Per-viewer count of thread replies newer than the viewer's thread read
368
- * cursor, excluding the viewer's own replies (root only). Populated on
369
- * top-level list responses; omitted when zero.
368
+ * cursor, excluding the viewer's own replies (root only). Watcher-scoped:
369
+ * only threads the viewer watches accrue unread. Populated on top-level
370
+ * list responses; omitted when zero.
370
371
  */
371
372
  unread_reply_count?: number;
373
+ /**
374
+ * Per-viewer thread watch state (root only): true when the viewer watches
375
+ * this root's thread. Populated on top-level list responses for roots with
376
+ * replies; omitted means not watching. Seeds the client's live unread
377
+ * mirror.
378
+ */
379
+ watching?: boolean;
372
380
  edited_at: string | null;
373
381
  deleted_at: string | null;
374
382
  created_at: string;
@@ -1731,6 +1739,20 @@ export interface CreateTaskRequest {
1731
1739
  label_ids?: string[];
1732
1740
  }
1733
1741
 
1742
+ /**
1743
+ * Moves a task (and its whole subtree) into another project via
1744
+ * POST /tasks/{taskId}/move — the only path that changes the binding; PATCH
1745
+ * keeps refusing project_id changes. Every subtree node is renumbered from the
1746
+ * target project's counter and its old KEY-N identifier stays resolvable as a
1747
+ * permanent alias. parent_id (must belong to the target project) attaches the
1748
+ * moved root under a parent there; same-project calls with a parent degrade to
1749
+ * a reparent, without one they are an idempotent no-op.
1750
+ */
1751
+ export interface MoveTaskRequest {
1752
+ project_id: string;
1753
+ parent_id?: string;
1754
+ }
1755
+
1734
1756
  export interface UpdateTaskRequest {
1735
1757
  title?: string;
1736
1758
  description?: string;
@@ -1738,9 +1760,10 @@ export interface UpdateTaskRequest {
1738
1760
  priority?: TaskPriority;
1739
1761
  assignee_id?: string | null;
1740
1762
  parent_id?: string | null;
1741
- // project_id is deliberately absent: a Task's Project is immutable after
1742
- // creation (server answers 400 PROJECT_IMMUTABLE; resubmitting the current
1743
- // value is an idempotent no-op).
1763
+ // project_id is deliberately absent: PATCH cannot change a Task's Project
1764
+ // (server answers 400 PROJECT_IMMUTABLE; resubmitting the current value is
1765
+ // an idempotent no-op). Moving between projects is its own explicit
1766
+ // operation — see MoveTaskRequest / moveTask().
1744
1767
  sort_order?: number;
1745
1768
  /**
1746
1769
  * Ordering intent resolved server-side in the update transaction:
@@ -2338,11 +2361,19 @@ export interface Wiki {
2338
2361
  * access_tier are populated — enough to request to join, nothing else.
2339
2362
  * Degraded entries must not be mounted, synced or treated as content. */
2340
2363
  degraded?: boolean;
2364
+ /** Caller's library-level star (the sidebar Starred group). Carried on full
2365
+ * list/get projections only — degraded entries never have it. */
2366
+ starred?: boolean;
2341
2367
  }
2342
2368
 
2343
2369
  export interface WikiFileChange {
2344
2370
  path: string;
2345
- action: 'create' | 'update' | 'delete';
2371
+ action: 'create' | 'update' | 'delete' | 'rename';
2372
+ /**
2373
+ * Rename source; present only when action is "rename" (path is the rename
2374
+ * target). Additive key — older changesets never carry it.
2375
+ */
2376
+ from_path?: string;
2346
2377
  }
2347
2378
 
2348
2379
  export interface WikiChangeset {
@@ -2558,7 +2589,9 @@ export interface WikiRefsCheckResponse {
2558
2589
 
2559
2590
  export interface WikiDiffFile {
2560
2591
  path: string;
2561
- action?: string; // "create" | "update" | "delete"
2592
+ action?: string; // "create" | "update" | "delete" | "rename"
2593
+ /** Rename source when action is "rename" (path is the target). */
2594
+ from_path?: string;
2562
2595
  additions: number;
2563
2596
  deletions: number;
2564
2597
  }
@@ -2574,20 +2607,44 @@ export interface CreateWikiRequest {
2574
2607
  default_branch?: string;
2575
2608
  }
2576
2609
 
2577
- export interface WikiFileChangeInput {
2610
+ interface WikiFileChangeInputCommon {
2578
2611
  path: string;
2579
- action: 'create' | 'update' | 'delete';
2580
- content_base64?: string;
2581
2612
  base_version?: number;
2582
2613
  /**
2583
2614
  * Git blob SHA of the default-branch version this change was authored
2584
2615
  * against. When set on update/delete, the server rejects the changeset
2585
2616
  * with 409 STALE_BASE if the file has since changed on the default branch
2586
- * (prevents silently overwriting concurrent edits).
2617
+ * (prevents silently overwriting concurrent edits). For rename it guards
2618
+ * the from_path side.
2587
2619
  */
2588
2620
  base_sha?: string;
2589
2621
  }
2590
2622
 
2623
+ export interface WikiFileChangeWriteInput extends WikiFileChangeInputCommon {
2624
+ action: 'create' | 'update' | 'delete';
2625
+ content_base64?: string;
2626
+ /** Only valid with action "rename" — the server rejects it elsewhere. */
2627
+ from_path?: never;
2628
+ }
2629
+
2630
+ /**
2631
+ * Rename is a discriminated variant: `from_path` (the source; `path` is the
2632
+ * target) and `content_base64` are both REQUIRED. The content must be sent —
2633
+ * the server rejects a rename without the content_base64 key
2634
+ * (400 MISSING_FIELDS) because the single-commit move always writes content
2635
+ * and an omitted key would otherwise erase the file; an explicitly empty
2636
+ * string (an empty file) is legal. Requires the server capability
2637
+ * `cap:wiki-rename` — while it is off the server answers 422 RENAME_DISABLED
2638
+ * (older servers answer 400 INVALID_ACTION).
2639
+ */
2640
+ export interface WikiFileChangeRenameInput extends WikiFileChangeInputCommon {
2641
+ action: 'rename';
2642
+ from_path: string;
2643
+ content_base64: string;
2644
+ }
2645
+
2646
+ export type WikiFileChangeInput = WikiFileChangeWriteInput | WikiFileChangeRenameInput;
2647
+
2591
2648
  export interface CreateWikiChangesetRequest {
2592
2649
  title: string;
2593
2650
  message?: string;
@@ -5430,6 +5487,89 @@ export interface BrowserAliasExecutionReceipt {
5430
5487
  updated_at: string;
5431
5488
  }
5432
5489
 
5490
+ export type BrowserUseAction =
5491
+ | 'read'
5492
+ | 'tabs'
5493
+ | 'wait'
5494
+ | 'snapshot'
5495
+ | 'get'
5496
+ | 'screenshot'
5497
+ | 'open'
5498
+ | 'navigate'
5499
+ | 'viewport'
5500
+ | 'click'
5501
+ | 'fill'
5502
+ | 'type'
5503
+ | 'press'
5504
+ | 'scroll'
5505
+ | 'close'
5506
+ | 'recover'
5507
+ | 'eval';
5508
+
5509
+ export interface BrowserUseTarget {
5510
+ tab_id?: string;
5511
+ browser_generation?: number;
5512
+ document_generation?: number;
5513
+ snapshot_id?: string;
5514
+ ref?: string;
5515
+ }
5516
+
5517
+ export interface BrowserUseOperationRequest {
5518
+ contract_version: 'browser-use-operation-v1';
5519
+ request_id: string;
5520
+ profile_id: string;
5521
+ action: BrowserUseAction;
5522
+ target?: BrowserUseTarget;
5523
+ params: Record<string, unknown>;
5524
+ /** Canonical RFC3339 UTC instant, no more than two minutes in the future. */
5525
+ deadline: string;
5526
+ }
5527
+
5528
+ export type BrowserUseOperationPhase =
5529
+ | 'accepted'
5530
+ | 'started'
5531
+ | 'succeeded'
5532
+ | 'failed'
5533
+ | 'outcome_unknown';
5534
+
5535
+ export interface BrowserUseOperationError {
5536
+ code: string;
5537
+ message?: string;
5538
+ hint?: string;
5539
+ }
5540
+
5541
+ /** Durable Browser Use proof. `data` is encrypted/transient: it is present
5542
+ * only while result_available is true and disappears after result_expires_at;
5543
+ * the terminal receipt and result_digest remain durable. */
5544
+ export interface BrowserUseOperationReceipt {
5545
+ contract_version: 'browser-use-operation-v1';
5546
+ operation_id: string;
5547
+ request_id: string;
5548
+ profile_id: string;
5549
+ profile_version: number;
5550
+ profile_config_revision: number;
5551
+ action: BrowserUseAction;
5552
+ required_grant: 'browser.read' | 'browser.interact' | 'browser.advanced';
5553
+ phase: BrowserUseOperationPhase;
5554
+ dispatched?: boolean;
5555
+ receipt_id?: string;
5556
+ receipt_digest?: string;
5557
+ occurred_at?: string;
5558
+ tab_id?: string;
5559
+ browser_generation?: number;
5560
+ duration_ms?: number;
5561
+ result_digest?: string;
5562
+ result_available: boolean;
5563
+ result_expires_at?: string;
5564
+ data?: unknown;
5565
+ error?: BrowserUseOperationError;
5566
+ deadline: string;
5567
+ accepted_at: string;
5568
+ started_at?: string;
5569
+ terminal_at?: string;
5570
+ updated_at: string;
5571
+ }
5572
+
5433
5573
  /**
5434
5574
  * Sanitized per-profile egress proxy status (hosted Cloud Profiles) — the GET
5435
5575
  * response and the PUT/DELETE result. NEVER carries the password; `password_set`