@parall/sdk 1.55.0 → 1.55.2
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/dist/client.d.ts +36 -7
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +44 -5
- package/dist/constants.d.ts +8 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +11 -0
- package/dist/project-task-client.d.ts +33 -1
- package/dist/project-task-client.d.ts.map +1 -1
- package/dist/project-task-client.js +56 -0
- package/dist/subject.d.ts +7 -10
- package/dist/subject.d.ts.map +1 -1
- package/dist/subject.js +22 -31
- package/dist/types.d.ts +231 -22
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +80 -6
- package/src/constants.ts +17 -0
- package/src/project-task-client.ts +93 -0
- package/src/subject.ts +23 -32
- package/src/types.ts +255 -24
package/src/constants.ts
CHANGED
|
@@ -604,6 +604,18 @@ export const ENDPOINTS = {
|
|
|
604
604
|
PROJECTS: (orgId: string) => `${API_BASE}/orgs/${orgId}/projects`,
|
|
605
605
|
PROJECT_TASK_SUMMARY: (orgId: string) => `${API_BASE}/orgs/${orgId}/projects/task-summary`,
|
|
606
606
|
PROJECT: (orgId: string, projectId: string) => `${API_BASE}/orgs/${orgId}/projects/${projectId}`,
|
|
607
|
+
PROJECT_MEMBERS: (orgId: string, projectId: string) =>
|
|
608
|
+
`${API_BASE}/orgs/${orgId}/projects/${projectId}/members`,
|
|
609
|
+
PROJECT_READERS: (orgId: string, projectId: string) =>
|
|
610
|
+
`${API_BASE}/orgs/${orgId}/projects/${projectId}/readers`,
|
|
611
|
+
PROJECT_LIBRARY: (orgId: string) => `${API_BASE}/orgs/${orgId}/projects/library`,
|
|
612
|
+
PROJECT_JOIN: (orgId: string, projectId: string) =>
|
|
613
|
+
`${API_BASE}/orgs/${orgId}/projects/${projectId}/join`,
|
|
614
|
+
PROJECT_JOIN_REQUESTS: (orgId: string, projectId: string) =>
|
|
615
|
+
`${API_BASE}/orgs/${orgId}/projects/${projectId}/join-requests`,
|
|
616
|
+
// subject is a bare user ID or a bare team ID; both are path-segment safe.
|
|
617
|
+
PROJECT_MEMBER: (orgId: string, projectId: string, subject: string) =>
|
|
618
|
+
`${API_BASE}/orgs/${orgId}/projects/${projectId}/members/${subject}`,
|
|
607
619
|
|
|
608
620
|
// Schedules (org-scoped, platform time trigger primitive)
|
|
609
621
|
SCHEDULES: (orgId: string) => `${API_BASE}/orgs/${orgId}/schedules`,
|
|
@@ -925,6 +937,10 @@ export const ENDPOINTS = {
|
|
|
925
937
|
// Per-profile egress proxy (hosted Cloud Profiles; manager-only, human-only).
|
|
926
938
|
ORG_EDGE_PROFILE_PROXY: (orgId: string, edgeId: string, profileName: string) =>
|
|
927
939
|
`/api/v1/orgs/${orgId}/edge/${edgeId}/profiles/${encodeURIComponent(profileName)}/proxy`,
|
|
940
|
+
// Per-profile one-shot cookie seed (hosted Cloud Profiles; manager-only,
|
|
941
|
+
// human-only, idle-only). Injected at the next cold start, then consumed.
|
|
942
|
+
ORG_EDGE_PROFILE_COOKIES: (orgId: string, edgeId: string, profileName: string) =>
|
|
943
|
+
`/api/v1/orgs/${orgId}/edge/${edgeId}/profiles/${encodeURIComponent(profileName)}/cookies`,
|
|
928
944
|
ORG_EDGE_EXEC: (orgId: string) => `/api/v1/orgs/${orgId}/edge/exec`,
|
|
929
945
|
// Cloud Edge live viewer command (V1b) — api-server, gated on cap:edge-viewer.
|
|
930
946
|
// Same request/reply shape as the v2 browser-profile viewer, on the v3 edge
|
|
@@ -1020,6 +1036,7 @@ export const WS_EVENTS = {
|
|
|
1020
1036
|
PONG: 'pong',
|
|
1021
1037
|
WATCHING: 'watching',
|
|
1022
1038
|
MESSAGE_NEW: 'message.new',
|
|
1039
|
+
/** @deprecated `message.patch` is retired and never published; kept for compile compatibility. */
|
|
1023
1040
|
MESSAGE_PATCH: 'message.patch',
|
|
1024
1041
|
MESSAGE_EDIT: 'message.edit',
|
|
1025
1042
|
MESSAGE_DELETE: 'message.delete',
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { ENDPOINTS } from './constants.js';
|
|
2
2
|
import type {
|
|
3
|
+
AddProjectMemberRequest,
|
|
4
|
+
Approval,
|
|
3
5
|
CreateProjectRequest,
|
|
4
6
|
CreateTaskCommentRequest,
|
|
5
7
|
CreateTaskRelationRequest,
|
|
6
8
|
CreateTaskRequest,
|
|
7
9
|
PaginatedResponse,
|
|
8
10
|
Project,
|
|
11
|
+
ProjectJoinRequest,
|
|
12
|
+
ProjectLibraryEntry,
|
|
13
|
+
ProjectMember,
|
|
9
14
|
ProjectTaskSummaryResponse,
|
|
10
15
|
Task,
|
|
11
16
|
TaskActivity,
|
|
@@ -15,6 +20,7 @@ import type {
|
|
|
15
20
|
TaskSubtaskSummaryResponse,
|
|
16
21
|
TaskWatcher,
|
|
17
22
|
ThreadWatcher,
|
|
23
|
+
UpdateProjectMemberRequest,
|
|
18
24
|
UpdateProjectRequest,
|
|
19
25
|
UpdateTaskCommentRequest,
|
|
20
26
|
UpdateTaskRequest,
|
|
@@ -246,4 +252,91 @@ export abstract class ProjectTaskClient {
|
|
|
246
252
|
async deleteProject(orgId: string, projectId: string): Promise<void> {
|
|
247
253
|
return this.request('DELETE', ENDPOINTS.PROJECT(orgId, projectId));
|
|
248
254
|
}
|
|
255
|
+
|
|
256
|
+
/** Roster with display info; readable by anyone who can read the project. */
|
|
257
|
+
async getProjectMembers(orgId: string, projectId: string): Promise<ProjectMember[]> {
|
|
258
|
+
const res = await this.request<{ data: ProjectMember[] }>(
|
|
259
|
+
'GET',
|
|
260
|
+
ENDPOINTS.PROJECT_MEMBERS(orgId, projectId),
|
|
261
|
+
);
|
|
262
|
+
return res.data;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* User IDs who may read the project — the assignee-eligibility set. Every
|
|
267
|
+
* tier answers the roster expansion (direct, team-reached, org
|
|
268
|
+
* owners/admins); visibility only shapes admission, never reach.
|
|
269
|
+
*/
|
|
270
|
+
async getProjectReaders(orgId: string, projectId: string): Promise<string[]> {
|
|
271
|
+
const res = await this.request<{ data: string[] }>(
|
|
272
|
+
'GET',
|
|
273
|
+
ENDPOINTS.PROJECT_READERS(orgId, projectId),
|
|
274
|
+
);
|
|
275
|
+
return res.data;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** The join library: every discoverable project (public + restricted, plus
|
|
279
|
+
* private for org owners/admins) with the caller's admission state. */
|
|
280
|
+
async getProjectLibrary(orgId: string): Promise<ProjectLibraryEntry[]> {
|
|
281
|
+
const res = await this.request<{ data: ProjectLibraryEntry[] }>(
|
|
282
|
+
'GET',
|
|
283
|
+
ENDPOINTS.PROJECT_LIBRARY(orgId),
|
|
284
|
+
);
|
|
285
|
+
return res.data;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/** Public-tier self-admission: writes the caller's own member row.
|
|
289
|
+
* Other tiers answer `404 PROJECT_NOT_FOUND`; a duplicate answers
|
|
290
|
+
* `409 MEMBER_EXISTS`. */
|
|
291
|
+
async joinProject(orgId: string, projectId: string): Promise<ProjectMember> {
|
|
292
|
+
return this.request('POST', ENDPOINTS.PROJECT_JOIN(orgId, projectId));
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** Restricted-tier admission petition. A pending duplicate answers
|
|
296
|
+
* `409 REQUEST_EXISTS`; membership answers `409 MEMBER_EXISTS`. */
|
|
297
|
+
async createProjectJoinRequest(orgId: string, projectId: string): Promise<Approval> {
|
|
298
|
+
return this.request('POST', ENDPOINTS.PROJECT_JOIN_REQUESTS(orgId, projectId));
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/** Pending petitions for one project — manager standing required. */
|
|
302
|
+
async listProjectJoinRequests(orgId: string, projectId: string): Promise<ProjectJoinRequest[]> {
|
|
303
|
+
const res = await this.request<{ data: ProjectJoinRequest[] }>(
|
|
304
|
+
'GET',
|
|
305
|
+
ENDPOINTS.PROJECT_JOIN_REQUESTS(orgId, projectId),
|
|
306
|
+
);
|
|
307
|
+
return res.data;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/** Withdraws the caller's own pending petition. */
|
|
311
|
+
async cancelProjectJoinRequest(orgId: string, projectId: string): Promise<void> {
|
|
312
|
+
return this.request('DELETE', ENDPOINTS.PROJECT_JOIN_REQUESTS(orgId, projectId));
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Adds one subject (user ID or team ID) to the roster. Manager-only,
|
|
317
|
+
* create-only: an existing row answers `409 MEMBER_EXISTS` — change roles
|
|
318
|
+
* through updateProjectMember instead.
|
|
319
|
+
*/
|
|
320
|
+
async addProjectMember(
|
|
321
|
+
orgId: string,
|
|
322
|
+
projectId: string,
|
|
323
|
+
req: AddProjectMemberRequest,
|
|
324
|
+
): Promise<ProjectMember> {
|
|
325
|
+
return this.request('POST', ENDPOINTS.PROJECT_MEMBERS(orgId, projectId), req);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/** Sets one roster entry's role. Demoting the last manager answers `400 LAST_MANAGER`. */
|
|
329
|
+
async updateProjectMember(
|
|
330
|
+
orgId: string,
|
|
331
|
+
projectId: string,
|
|
332
|
+
subject: string,
|
|
333
|
+
req: UpdateProjectMemberRequest,
|
|
334
|
+
): Promise<ProjectMember> {
|
|
335
|
+
return this.request('PATCH', ENDPOINTS.PROJECT_MEMBER(orgId, projectId, subject), req);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/** Removes one roster entry. Removing the last manager answers `400 LAST_MANAGER`. */
|
|
339
|
+
async removeProjectMember(orgId: string, projectId: string, subject: string): Promise<void> {
|
|
340
|
+
return this.request('DELETE', ENDPOINTS.PROJECT_MEMBER(orgId, projectId, subject));
|
|
341
|
+
}
|
|
249
342
|
}
|
package/src/subject.ts
CHANGED
|
@@ -4,37 +4,32 @@ export type SubjectKind = 'wildcard' | 'user' | 'team';
|
|
|
4
4
|
|
|
5
5
|
export interface ParsedSubject {
|
|
6
6
|
kind: SubjectKind;
|
|
7
|
-
/** Empty for wildcard, user ID for user, and
|
|
7
|
+
/** Empty for wildcard, user ID for user, and the full team ID for team. */
|
|
8
8
|
value: string;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Team subjects are stored as bare team IDs (`team_...`), mirroring the
|
|
13
|
+
* server's `pkg/subject`: the ID prefix is what makes a token a team
|
|
14
|
+
* reference, so no marker syntax exists and a rename never invalidates a
|
|
15
|
+
* stored reference.
|
|
16
|
+
*/
|
|
17
|
+
const TEAM_ID_PREFIX = 'team_';
|
|
12
18
|
|
|
13
|
-
export function
|
|
14
|
-
return
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function formatTeamSubject(slug: string): string {
|
|
18
|
-
if (!isValidTeamSlug(slug)) {
|
|
19
|
-
throw new Error(`Invalid team slug: ${slug}`);
|
|
20
|
-
}
|
|
21
|
-
return `@${slug}`;
|
|
19
|
+
export function isTeamSubject(token: string): boolean {
|
|
20
|
+
return token.startsWith(TEAM_ID_PREFIX);
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
export function parseSubjectToken(token: string): ParsedSubject {
|
|
25
24
|
if (token === '*') {
|
|
26
25
|
return { kind: 'wildcard', value: '' };
|
|
27
26
|
}
|
|
28
|
-
if (token.startsWith('@')) {
|
|
29
|
-
const slug = token.slice(1);
|
|
30
|
-
if (!isValidTeamSlug(slug)) {
|
|
31
|
-
throw new Error(`Invalid team subject: ${token}`);
|
|
32
|
-
}
|
|
33
|
-
return { kind: 'team', value: slug };
|
|
34
|
-
}
|
|
35
27
|
if (!token) {
|
|
36
28
|
throw new Error('Subject token is empty');
|
|
37
29
|
}
|
|
30
|
+
if (isTeamSubject(token)) {
|
|
31
|
+
return { kind: 'team', value: token };
|
|
32
|
+
}
|
|
38
33
|
return { kind: 'user', value: token };
|
|
39
34
|
}
|
|
40
35
|
|
|
@@ -45,22 +40,18 @@ export function parseSubjectToken(token: string): ParsedSubject {
|
|
|
45
40
|
export const MAX_TEAM_SUBJECTS_PER_WRITE = 200;
|
|
46
41
|
|
|
47
42
|
/**
|
|
48
|
-
* Returns unique team
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* check and be reported missing, so the write fails with a legible error
|
|
53
|
-
* instead of storing a token that matches nobody.
|
|
43
|
+
* Returns unique team IDs in first-seen order for batched write validation.
|
|
44
|
+
* An ID that names no team comes back from the server's existence check
|
|
45
|
+
* reported missing, so the write fails with a legible error instead of
|
|
46
|
+
* storing a token that matches nobody.
|
|
54
47
|
*/
|
|
55
|
-
export function
|
|
48
|
+
export function teamIdsFromSubjects(subjects: readonly string[]): string[] {
|
|
56
49
|
const seen = new Set<string>();
|
|
57
|
-
const
|
|
50
|
+
const ids: string[] = [];
|
|
58
51
|
for (const token of subjects) {
|
|
59
|
-
if (!token.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
seen.add(slug);
|
|
63
|
-
slugs.push(slug);
|
|
52
|
+
if (!isTeamSubject(token) || seen.has(token)) continue;
|
|
53
|
+
seen.add(token);
|
|
54
|
+
ids.push(token);
|
|
64
55
|
}
|
|
65
|
-
return
|
|
56
|
+
return ids;
|
|
66
57
|
}
|
package/src/types.ts
CHANGED
|
@@ -486,14 +486,15 @@ export interface UpdateAgentInstructionsRequest {
|
|
|
486
486
|
expected_version: number;
|
|
487
487
|
}
|
|
488
488
|
|
|
489
|
-
// Team — a named group of org members, referenced in
|
|
489
|
+
// Team — a named group of org members, referenced in ACL rosters by its ID.
|
|
490
490
|
export type TeamRole = 'member' | 'manager';
|
|
491
491
|
|
|
492
492
|
export interface Team {
|
|
493
493
|
id: string;
|
|
494
494
|
org_id: string;
|
|
495
495
|
name: string;
|
|
496
|
-
slug
|
|
496
|
+
/** @deprecated Removed since migration 176 — teams have no slug anymore. */
|
|
497
|
+
slug?: string;
|
|
497
498
|
created_by: string;
|
|
498
499
|
created_at: string;
|
|
499
500
|
updated_at: string;
|
|
@@ -526,13 +527,12 @@ export interface TeamMember {
|
|
|
526
527
|
|
|
527
528
|
export interface CreateTeamRequest {
|
|
528
529
|
name: string;
|
|
529
|
-
|
|
530
|
+
/** @deprecated Accepted and ignored by the server since migration 176. */
|
|
531
|
+
slug?: string;
|
|
530
532
|
}
|
|
531
533
|
|
|
532
534
|
export interface UpdateTeamRequest {
|
|
533
535
|
name: string;
|
|
534
|
-
/** Team slugs are immutable because wiki ACL rows store them as @slug. */
|
|
535
|
-
slug?: never;
|
|
536
536
|
}
|
|
537
537
|
|
|
538
538
|
export interface AddTeamMemberRequest {
|
|
@@ -1028,12 +1028,6 @@ export interface DirectMessageResponse {
|
|
|
1028
1028
|
message: Message;
|
|
1029
1029
|
}
|
|
1030
1030
|
|
|
1031
|
-
export interface JsonPatchOp {
|
|
1032
|
-
op: 'replace' | 'add';
|
|
1033
|
-
path: string;
|
|
1034
|
-
value: unknown;
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
1031
|
export interface CreateAgentRequest {
|
|
1038
1032
|
display_name: string;
|
|
1039
1033
|
agent_provider?: string;
|
|
@@ -1559,7 +1553,8 @@ export interface Task {
|
|
|
1559
1553
|
assignee_id: string | null;
|
|
1560
1554
|
creator_id: string;
|
|
1561
1555
|
parent_id: string | null;
|
|
1562
|
-
|
|
1556
|
+
/** Every Task belongs to exactly one Project; immutable after creation. */
|
|
1557
|
+
project_id: string;
|
|
1563
1558
|
seq_number: number | null;
|
|
1564
1559
|
identifier: string | null;
|
|
1565
1560
|
sort_order: number;
|
|
@@ -1583,7 +1578,7 @@ export interface Task {
|
|
|
1583
1578
|
deleted_at?: string | null;
|
|
1584
1579
|
/**
|
|
1585
1580
|
* Per-viewer: whether the requesting user may manage OTHER members' comment
|
|
1586
|
-
* subscriptions for this task (creator / assignee / project
|
|
1581
|
+
* subscriptions for this task (creator / assignee / project manager / org
|
|
1587
1582
|
* owner-admin). Populated on single-task GET; undefined elsewhere. Read this to
|
|
1588
1583
|
* gate subscriber-management UI — do not re-derive the rule client-side.
|
|
1589
1584
|
*/
|
|
@@ -1659,7 +1654,13 @@ export interface CreateTaskRequest {
|
|
|
1659
1654
|
priority?: TaskPriority;
|
|
1660
1655
|
assignee_id?: string;
|
|
1661
1656
|
parent_id?: string;
|
|
1662
|
-
|
|
1657
|
+
/**
|
|
1658
|
+
* Required: every Task is created inside a Project (missing → 400
|
|
1659
|
+
* MISSING_FIELDS with `error.details.available_projects`; archived project →
|
|
1660
|
+
* 400 PROJECT_ARCHIVED). A parent task's subtasks must use the parent's
|
|
1661
|
+
* project (400 INVALID_PARENT otherwise). Immutable after creation.
|
|
1662
|
+
*/
|
|
1663
|
+
project_id: string;
|
|
1663
1664
|
source_chat_id?: string;
|
|
1664
1665
|
sort_order?: number;
|
|
1665
1666
|
/** Planned start date, YYYY-MM-DD. Must be <= due_date when both are set. */
|
|
@@ -1676,7 +1677,9 @@ export interface UpdateTaskRequest {
|
|
|
1676
1677
|
priority?: TaskPriority;
|
|
1677
1678
|
assignee_id?: string | null;
|
|
1678
1679
|
parent_id?: string | null;
|
|
1679
|
-
project_id
|
|
1680
|
+
// project_id is deliberately absent: a Task's Project is immutable after
|
|
1681
|
+
// creation (server answers 400 PROJECT_IMMUTABLE; resubmitting the current
|
|
1682
|
+
// value is an idempotent no-op).
|
|
1680
1683
|
sort_order?: number;
|
|
1681
1684
|
/**
|
|
1682
1685
|
* Ordering intent resolved server-side in the update transaction:
|
|
@@ -1723,36 +1726,123 @@ export interface CreateTaskRelationRequest {
|
|
|
1723
1726
|
|
|
1724
1727
|
export type ProjectStatus = 'active' | 'paused' | 'completed' | 'archived';
|
|
1725
1728
|
|
|
1729
|
+
/** Visibility only decides how someone becomes a member (self-join /
|
|
1730
|
+
* request+approval / invite-only); membership rights are identical on every
|
|
1731
|
+
* tier, and reads are always roster-scoped. */
|
|
1732
|
+
export type ProjectVisibility = 'public' | 'restricted' | 'private';
|
|
1733
|
+
|
|
1734
|
+
/** A role held on a project roster. Managers administer the project; members
|
|
1735
|
+
* only reach it. Org owners and admins are implicit managers everywhere, which
|
|
1736
|
+
* is why a project can never become unmanageable. */
|
|
1737
|
+
export type ProjectRole = 'member' | 'manager';
|
|
1738
|
+
|
|
1726
1739
|
export interface Project {
|
|
1727
1740
|
id: string;
|
|
1728
1741
|
org_id: string;
|
|
1729
1742
|
name: string;
|
|
1730
1743
|
key: string;
|
|
1731
1744
|
description: string | null;
|
|
1732
|
-
lead_id: string | null;
|
|
1733
1745
|
status: ProjectStatus;
|
|
1746
|
+
visibility: ProjectVisibility;
|
|
1734
1747
|
color: string | null;
|
|
1735
1748
|
sort_order: number;
|
|
1736
1749
|
created_at: string;
|
|
1737
1750
|
updated_at: string;
|
|
1751
|
+
/** The requesting user's own role, computed per request rather than stored.
|
|
1752
|
+
* Absent means they hold no membership (direct or team-derived). */
|
|
1753
|
+
my_role?: ProjectRole;
|
|
1754
|
+
/** True when the requesting user holds their own roster row — the fact
|
|
1755
|
+
* Leave acts on, as opposed to team-derived or org-admin standing. */
|
|
1756
|
+
my_direct_member?: boolean;
|
|
1757
|
+
/**
|
|
1758
|
+
* @deprecated Project authority now comes from the project roster. Retained
|
|
1759
|
+
* only for source compatibility during the pre-GA migration window; current
|
|
1760
|
+
* API responses omit it.
|
|
1761
|
+
*/
|
|
1762
|
+
lead_id?: string | null;
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
/** One join-library row: the minimal metadata a non-member may see about a
|
|
1766
|
+
* discoverable project, plus the caller's own admission state. */
|
|
1767
|
+
export interface ProjectLibraryEntry {
|
|
1768
|
+
id: string;
|
|
1769
|
+
name: string;
|
|
1770
|
+
key: string;
|
|
1771
|
+
color?: string | null;
|
|
1772
|
+
visibility: ProjectVisibility;
|
|
1773
|
+
joined: boolean;
|
|
1774
|
+
requested: boolean;
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
/** One pending join request, as the Collaborators pending tab renders it. */
|
|
1778
|
+
export interface ProjectJoinRequest {
|
|
1779
|
+
id: string;
|
|
1780
|
+
requester_id: string;
|
|
1781
|
+
created_at: string;
|
|
1782
|
+
requester?: User;
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
/** One roster entry. `subject` is a bare user ID or a bare team ID; exactly one
|
|
1786
|
+
* of `user` / `team` is filled in for display, according to which kind it is. */
|
|
1787
|
+
export interface ProjectMember {
|
|
1788
|
+
project_id: string;
|
|
1789
|
+
subject: string;
|
|
1790
|
+
role: ProjectRole;
|
|
1791
|
+
added_by?: string;
|
|
1792
|
+
added_at: string;
|
|
1793
|
+
user?: User;
|
|
1794
|
+
team?: Team;
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
/**
|
|
1798
|
+
* Adds one subject to a project's roster. Create-only: an existing row answers
|
|
1799
|
+
* `409 MEMBER_EXISTS` rather than being mutated — role changes go through the
|
|
1800
|
+
* member role endpoint. A subject naming nobody reachable answers
|
|
1801
|
+
* `400 UNKNOWN_SUBJECT`. Member rows are storable on every tier.
|
|
1802
|
+
*/
|
|
1803
|
+
export interface AddProjectMemberRequest {
|
|
1804
|
+
/** A bare user ID, or a bare team ID (`team_...`) for a team. */
|
|
1805
|
+
subject: string;
|
|
1806
|
+
/** Defaults to `member` when omitted. */
|
|
1807
|
+
role?: ProjectRole;
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
/**
|
|
1811
|
+
* Changes one roster entry's role. Demoting the last manager answers
|
|
1812
|
+
* `400 LAST_MANAGER`; a concurrent roster change answers `409 CONFLICT`.
|
|
1813
|
+
*/
|
|
1814
|
+
export interface UpdateProjectMemberRequest {
|
|
1815
|
+
role: ProjectRole;
|
|
1738
1816
|
}
|
|
1739
1817
|
|
|
1740
1818
|
export interface CreateProjectRequest {
|
|
1741
1819
|
name: string;
|
|
1742
1820
|
key?: string;
|
|
1743
1821
|
description?: string;
|
|
1744
|
-
|
|
1822
|
+
/** Defaults to `public` when omitted. The creator is always written as the
|
|
1823
|
+
* first manager, which is what naming yourself lead used to mean. */
|
|
1824
|
+
visibility?: ProjectVisibility;
|
|
1745
1825
|
color?: string;
|
|
1826
|
+
/**
|
|
1827
|
+
* @deprecated Use the project roster after creation. Retained only for
|
|
1828
|
+
* source compatibility; the current API ignores this retired field.
|
|
1829
|
+
*/
|
|
1830
|
+
lead_id?: string;
|
|
1746
1831
|
}
|
|
1747
1832
|
|
|
1748
1833
|
export interface UpdateProjectRequest {
|
|
1749
1834
|
name?: string;
|
|
1750
1835
|
key?: string;
|
|
1751
1836
|
description?: string | null;
|
|
1752
|
-
lead_id?: string | null;
|
|
1753
1837
|
status?: ProjectStatus;
|
|
1838
|
+
visibility?: ProjectVisibility;
|
|
1754
1839
|
color?: string | null;
|
|
1755
1840
|
sort_order?: number;
|
|
1841
|
+
/**
|
|
1842
|
+
* @deprecated Use the project roster. Retained only for source
|
|
1843
|
+
* compatibility; the current API ignores this retired field.
|
|
1844
|
+
*/
|
|
1845
|
+
lead_id?: string | null;
|
|
1756
1846
|
}
|
|
1757
1847
|
|
|
1758
1848
|
export interface ProjectTaskStatusCounts {
|
|
@@ -2623,6 +2713,17 @@ export interface MessageNewData {
|
|
|
2623
2713
|
attachments?: Attachment[];
|
|
2624
2714
|
}
|
|
2625
2715
|
|
|
2716
|
+
/** @deprecated The `message.patch` event is retired — the server no longer
|
|
2717
|
+
* publishes it (content updates arrive as full-content `message.edit`). Kept
|
|
2718
|
+
* only so existing consumers keep compiling through the deprecation window;
|
|
2719
|
+
* a handler typed with this will never fire. */
|
|
2720
|
+
export interface JsonPatchOp {
|
|
2721
|
+
op: 'replace' | 'add';
|
|
2722
|
+
path: string;
|
|
2723
|
+
value: unknown;
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2726
|
+
/** @deprecated See {@link JsonPatchOp} — `message.patch` is never published. */
|
|
2626
2727
|
export interface MessagePatchData {
|
|
2627
2728
|
message_id: string;
|
|
2628
2729
|
chat_id: string;
|
|
@@ -2630,11 +2731,20 @@ export interface MessagePatchData {
|
|
|
2630
2731
|
ops: JsonPatchOp[];
|
|
2631
2732
|
}
|
|
2632
2733
|
|
|
2734
|
+
/**
|
|
2735
|
+
* Unified message-content-update event: every persisted content write (author
|
|
2736
|
+
* edit, server link-preview write-back) publishes it with the full content and
|
|
2737
|
+
* post-write version. Apply only when `version` is greater than the local one;
|
|
2738
|
+
* the "(edited)" marker keys off `edited_at` alone — a preview write-back
|
|
2739
|
+
* never creates or changes edited state (it carries the pre-existing value,
|
|
2740
|
+
* absent when the message was never author-edited).
|
|
2741
|
+
*/
|
|
2633
2742
|
export interface MessageEditData {
|
|
2634
2743
|
message_id: string;
|
|
2635
2744
|
chat_id: string;
|
|
2636
2745
|
content: MessageContent;
|
|
2637
|
-
|
|
2746
|
+
version: number;
|
|
2747
|
+
edited_at?: string;
|
|
2638
2748
|
}
|
|
2639
2749
|
|
|
2640
2750
|
export interface MessageDeleteData {
|
|
@@ -3700,6 +3810,7 @@ export interface NotificationAlertData {
|
|
|
3700
3810
|
export type WsEventMap = {
|
|
3701
3811
|
hello: HelloData;
|
|
3702
3812
|
'message.new': MessageNewData;
|
|
3813
|
+
/** @deprecated Never published anymore — kept so existing `ws.on('message.patch', …)` registrations keep compiling. */
|
|
3703
3814
|
'message.patch': MessagePatchData;
|
|
3704
3815
|
'message.edit': MessageEditData;
|
|
3705
3816
|
'message.delete': MessageDeleteData;
|
|
@@ -3898,6 +4009,14 @@ export interface ResolvedRef {
|
|
|
3898
4009
|
created_at?: string;
|
|
3899
4010
|
attachments?: Attachment[];
|
|
3900
4011
|
|
|
4012
|
+
// Partial-quote fields (msg_ refs with a ?v= + #t= anchor): the exact text
|
|
4013
|
+
// sliced from the body that was live at the anchor's content version.
|
|
4014
|
+
// quote_from_edited marks that the body was edited after the quote was
|
|
4015
|
+
// taken. Absent on bounds/validity failure — degrade to the whole-message
|
|
4016
|
+
// reference.
|
|
4017
|
+
quoted_text?: string;
|
|
4018
|
+
quote_from_edited?: boolean;
|
|
4019
|
+
|
|
3901
4020
|
// Range fields (cht_ + range anchor)
|
|
3902
4021
|
range_messages?: Array<{
|
|
3903
4022
|
id: string;
|
|
@@ -4894,6 +5013,54 @@ export interface SetEdgeProfileProxyRequest {
|
|
|
4894
5013
|
password?: string;
|
|
4895
5014
|
}
|
|
4896
5015
|
|
|
5016
|
+
/**
|
|
5017
|
+
* One normalized cookie in a hosted-profile cookie-seed import — the exact shape
|
|
5018
|
+
* the pod-side `session.cookies.set()` consumes (mirrors the desktop
|
|
5019
|
+
* cookie-import output). Web parses the manager's paste (a raw `Cookie` header +
|
|
5020
|
+
* target domain, or a Cookie-Editor JSON export) into an array of these before
|
|
5021
|
+
* the PUT. Values are write-only; the sanitized status never echoes them.
|
|
5022
|
+
*/
|
|
5023
|
+
export interface EdgeCookie {
|
|
5024
|
+
url: string;
|
|
5025
|
+
name: string;
|
|
5026
|
+
value: string;
|
|
5027
|
+
domain: string;
|
|
5028
|
+
path: string;
|
|
5029
|
+
secure: boolean;
|
|
5030
|
+
httpOnly: boolean;
|
|
5031
|
+
/** Unix epoch seconds; null for a session cookie (no persisted expiry). */
|
|
5032
|
+
expirationDate: number | null;
|
|
5033
|
+
sameSite: 'no_restriction' | 'lax' | 'strict' | null;
|
|
5034
|
+
}
|
|
5035
|
+
|
|
5036
|
+
/**
|
|
5037
|
+
* PUT body for a hosted profile's one-shot cookie seed: the full normalized
|
|
5038
|
+
* cookie array. Injected at the next cold start and consumed once. Clearing is
|
|
5039
|
+
* DELETE, never an empty PUT.
|
|
5040
|
+
*/
|
|
5041
|
+
export interface SetEdgeCookieSeedRequest {
|
|
5042
|
+
cookies: EdgeCookie[];
|
|
5043
|
+
}
|
|
5044
|
+
|
|
5045
|
+
/**
|
|
5046
|
+
* Sanitized cookie-seed status (hosted Cloud Profiles) — the GET response and
|
|
5047
|
+
* the PUT/DELETE result. NEVER carries cookie values: only the count and the
|
|
5048
|
+
* distinct target domains are exposed.
|
|
5049
|
+
*/
|
|
5050
|
+
export interface EdgeCookieSeedStatus {
|
|
5051
|
+
configured: boolean;
|
|
5052
|
+
cookie_count: number;
|
|
5053
|
+
domains: string[];
|
|
5054
|
+
/** Opaque compare-and-swap token for conditional PUT/DELETE (`cookieseed-<version>` ETag). */
|
|
5055
|
+
version: string;
|
|
5056
|
+
/** Authoritative mutation gate; false whenever a non-released lease exists. */
|
|
5057
|
+
can_mutate: boolean;
|
|
5058
|
+
/** Actual lease state blocking a mutation (never inferred from device status). */
|
|
5059
|
+
lease_status?: 'pending' | 'assigned' | 'active' | 'releasing' | 'repair';
|
|
5060
|
+
/** Suggested delay before re-reading authoritative state. */
|
|
5061
|
+
retry_after_seconds?: number | null;
|
|
5062
|
+
}
|
|
5063
|
+
|
|
4897
5064
|
export interface ClipConnection {
|
|
4898
5065
|
id: string;
|
|
4899
5066
|
clip_id: string;
|
|
@@ -4916,7 +5083,18 @@ export interface ClipConnection {
|
|
|
4916
5083
|
* would make `putClipMCPConfig({auth_type: 'oauth'})` type-legal while its
|
|
4917
5084
|
* declared return type is wrong. Reads use MCPConfigAuthType.
|
|
4918
5085
|
*/
|
|
4919
|
-
export type MCPAuthType = 'none' | 'bearer' | 'api_key';
|
|
5086
|
+
export type MCPAuthType = 'none' | 'bearer' | 'api_key' | 'basic';
|
|
5087
|
+
|
|
5088
|
+
/**
|
|
5089
|
+
* One declared credential input of an `api_key` clip (manifest
|
|
5090
|
+
* `mcp.auth_headers`): the header the value is delivered in and, for
|
|
5091
|
+
* `Authorization`, the `Bearer` scheme prefix. `bearer` remains the legacy
|
|
5092
|
+
* alias for the single `Authorization: Bearer` shape.
|
|
5093
|
+
*/
|
|
5094
|
+
export interface MCPAuthHeaderSlot {
|
|
5095
|
+
name: string;
|
|
5096
|
+
scheme?: 'Bearer';
|
|
5097
|
+
}
|
|
4920
5098
|
|
|
4921
5099
|
/**
|
|
4922
5100
|
* MCP clip auth modes a config can REPORT. A config authorized through the
|
|
@@ -5044,9 +5222,20 @@ export interface MCPConfigResponse {
|
|
|
5044
5222
|
* persists nothing.
|
|
5045
5223
|
*/
|
|
5046
5224
|
export interface MCPConfigPutRequest {
|
|
5225
|
+
/**
|
|
5226
|
+
* Required on the wire, but when the clip's manifest declares the server
|
|
5227
|
+
* an empty string means "use the declaration" — the server fills it in and
|
|
5228
|
+
* refuses a contradicting value. (The Console sends '' for declared clips.)
|
|
5229
|
+
*/
|
|
5047
5230
|
server_url: string;
|
|
5048
5231
|
auth_type: MCPAuthType;
|
|
5049
5232
|
credential?: string;
|
|
5233
|
+
/**
|
|
5234
|
+
* Slot-aligned multi-value form: one value per declared `auth_headers`
|
|
5235
|
+
* slot, or `[username, password]` for `basic`. Mutually exclusive with
|
|
5236
|
+
* `credential`.
|
|
5237
|
+
*/
|
|
5238
|
+
credentials?: string[];
|
|
5050
5239
|
}
|
|
5051
5240
|
|
|
5052
5241
|
/**
|
|
@@ -5065,6 +5254,8 @@ export interface MCPConfigCreateRequest {
|
|
|
5065
5254
|
server_url?: string;
|
|
5066
5255
|
auth_type: MCPAuthType | 'oauth';
|
|
5067
5256
|
credential?: string;
|
|
5257
|
+
/** See MCPConfigPutRequest.credentials. */
|
|
5258
|
+
credentials?: string[];
|
|
5068
5259
|
alias?: string;
|
|
5069
5260
|
oauth_client?: MCPOAuthClientParams;
|
|
5070
5261
|
}
|
|
@@ -5175,13 +5366,33 @@ export interface PublishRegistryClipRequest {
|
|
|
5175
5366
|
files: Record<string, string>;
|
|
5176
5367
|
}
|
|
5177
5368
|
|
|
5369
|
+
/**
|
|
5370
|
+
* One granted agent's entry under `selected_agents` (ADR-019).
|
|
5371
|
+
*
|
|
5372
|
+
* - `connection_scope: 'all'` — the grant covers every connection of the clip
|
|
5373
|
+
* (what a legacy `agent_ids` write means). `connection_ids` must be [].
|
|
5374
|
+
* - `connection_scope: 'selected'` — the grant admits only the connections in
|
|
5375
|
+
* `connection_ids` (non-empty on write; a grant can still READ back with []
|
|
5376
|
+
* when its granted connections were deleted, and then admits nothing).
|
|
5377
|
+
*/
|
|
5378
|
+
export interface ClipAgentExecGrant {
|
|
5379
|
+
agent_id: string;
|
|
5380
|
+
connection_scope: 'all' | 'selected';
|
|
5381
|
+
/** Granted connection ids (`ccn_…`) under `selected`, sorted; [] under `all`. */
|
|
5382
|
+
connection_ids: string[];
|
|
5383
|
+
}
|
|
5384
|
+
|
|
5178
5385
|
/**
|
|
5179
5386
|
* A clip's per-org agent exec access (`GET/PUT /orgs/{orgId}/clips/{clipId}/exec-access`).
|
|
5180
5387
|
*
|
|
5181
5388
|
* - `all_agents` (default): every org agent may exec the clip.
|
|
5182
|
-
* - `selected_agents`: only the agents in `
|
|
5183
|
-
*
|
|
5184
|
-
* `clips/installed
|
|
5389
|
+
* - `selected_agents`: only the agents in `grants` may exec, each through the
|
|
5390
|
+
* connections its `connection_scope` admits; an empty list blocks every
|
|
5391
|
+
* agent. Denied agents also stop seeing the clip in `clips/installed`; exec
|
|
5392
|
+
* answers `403 CLIP_AGENT_NOT_ALLOWED` (no grant at all) or
|
|
5393
|
+
* `403 CLIP_AGENT_CONNECTION_NOT_ALLOWED` (grant does not cover the named
|
|
5394
|
+
* connection). Agents must always exec through a connection — a
|
|
5395
|
+
* connectionless agent exec answers `400 AGENT_CONNECTION_REQUIRED`.
|
|
5185
5396
|
*
|
|
5186
5397
|
* Decided by the CALLING org (an installer restricts its own agents, never the
|
|
5187
5398
|
* publisher's). Humans are never restricted; the PUT is human-only (an agent
|
|
@@ -5189,8 +5400,24 @@ export interface PublishRegistryClipRequest {
|
|
|
5189
5400
|
*/
|
|
5190
5401
|
export interface ClipAgentExecAccess {
|
|
5191
5402
|
mode: 'all_agents' | 'selected_agents';
|
|
5192
|
-
/**
|
|
5403
|
+
/**
|
|
5404
|
+
* Granted agent user ids under `selected_agents` — the flat projection of
|
|
5405
|
+
* `grants`, kept for older readers; always [] under `all_agents`.
|
|
5406
|
+
*/
|
|
5193
5407
|
agent_ids: string[];
|
|
5408
|
+
/** Per-agent connection scope under `selected_agents`, sorted by agent id. */
|
|
5409
|
+
grants: ClipAgentExecGrant[];
|
|
5410
|
+
}
|
|
5411
|
+
|
|
5412
|
+
/**
|
|
5413
|
+
* The PUT body for a clip's agent exec access. Two shapes, one semantic
|
|
5414
|
+
* space — pass EITHER `agent_ids` (legacy flat form; every listed agent gets
|
|
5415
|
+
* `connection_scope: 'all'`) OR `grants` (connection-scoped form), never both.
|
|
5416
|
+
*/
|
|
5417
|
+
export interface ClipAgentExecAccessUpdate {
|
|
5418
|
+
mode: 'all_agents' | 'selected_agents';
|
|
5419
|
+
agent_ids?: string[];
|
|
5420
|
+
grants?: ClipAgentExecGrant[];
|
|
5194
5421
|
}
|
|
5195
5422
|
|
|
5196
5423
|
/**
|
|
@@ -5205,6 +5432,10 @@ export interface ClipAgentExecAccess {
|
|
|
5205
5432
|
* here is refused (`400 HOSTED_CONNECTION_REQUIRED`).
|
|
5206
5433
|
* - neither: legacy BYOC fallback — resolves only to the caller's OWN online
|
|
5207
5434
|
* desktop device, never to a hosted one.
|
|
5435
|
+
*
|
|
5436
|
+
* AGENT principals must always pass `connection` (ADR-019): the device paths
|
|
5437
|
+
* answer `400 AGENT_CONNECTION_REQUIRED`, and a connection outside the agent's
|
|
5438
|
+
* granted scope answers `403 CLIP_AGENT_CONNECTION_NOT_ALLOWED`.
|
|
5208
5439
|
*/
|
|
5209
5440
|
export interface ExecEdgeClipRequest {
|
|
5210
5441
|
/**
|