@company-semantics/contracts 7.0.0 → 7.1.1
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/package.json +1 -1
- package/src/api/generated-spec-hash.ts +2 -2
- package/src/api/generated.ts +135 -4
- package/src/generated/openapi-routes.ts +1 -0
- package/src/org/index.ts +4 -0
- package/src/org/schemas.ts +69 -0
- package/src/org/types.ts +6 -51
package/package.json
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// AUTO-GENERATED — do not edit. Run pnpm generate:spec-hash to regenerate.
|
|
2
|
-
export const SPEC_HASH = '
|
|
3
|
-
export const SPEC_HASH_FULL = '
|
|
2
|
+
export const SPEC_HASH = '937aecbfe6e6' as const;
|
|
3
|
+
export const SPEC_HASH_FULL = '937aecbfe6e6533edabb1b83d66be83f63100e519ecf9e4531af3e8a627e122a' as const;
|
package/src/api/generated.ts
CHANGED
|
@@ -1972,6 +1972,30 @@ export interface paths {
|
|
|
1972
1972
|
patch?: never;
|
|
1973
1973
|
trace?: never;
|
|
1974
1974
|
};
|
|
1975
|
+
"/api/users/{userId}/avatar": {
|
|
1976
|
+
parameters: {
|
|
1977
|
+
query?: never;
|
|
1978
|
+
header?: never;
|
|
1979
|
+
path?: never;
|
|
1980
|
+
cookie?: never;
|
|
1981
|
+
};
|
|
1982
|
+
get?: never;
|
|
1983
|
+
/**
|
|
1984
|
+
* Upload (replace) a user's avatar photo from an image file
|
|
1985
|
+
* @description Accepts a multipart image upload (PNG/JPEG/WebP/HEIC) up to 5 MB. The caller must be the target user or hold org.manage_users. HEIC/HEIF is converted to JPEG and the bytes are re-hosted via the blob store. Returns the resolved avatar.
|
|
1986
|
+
*/
|
|
1987
|
+
put: operations["uploadUserAvatar"];
|
|
1988
|
+
post?: never;
|
|
1989
|
+
/**
|
|
1990
|
+
* Clear a user's uploaded avatar (reverts to Slack photo or initials)
|
|
1991
|
+
* @description Clears an in-app uploaded avatar only (source=upload); Slack-sourced avatars are left intact. The caller must be the target user or hold org.manage_users. Returns the resolved avatar after reverting.
|
|
1992
|
+
*/
|
|
1993
|
+
delete: operations["deleteUserAvatar"];
|
|
1994
|
+
options?: never;
|
|
1995
|
+
head?: never;
|
|
1996
|
+
patch?: never;
|
|
1997
|
+
trace?: never;
|
|
1998
|
+
};
|
|
1975
1999
|
"/api/drive/files": {
|
|
1976
2000
|
parameters: {
|
|
1977
2001
|
query?: never;
|
|
@@ -2782,7 +2806,7 @@ export interface components {
|
|
|
2782
2806
|
slackUserId: string | null;
|
|
2783
2807
|
avatar: {
|
|
2784
2808
|
/** @enum {string} */
|
|
2785
|
-
source: "
|
|
2809
|
+
source: "photo" | "initials";
|
|
2786
2810
|
url?: string;
|
|
2787
2811
|
initials: string;
|
|
2788
2812
|
};
|
|
@@ -3108,6 +3132,12 @@ export interface components {
|
|
|
3108
3132
|
/** @enum {string} */
|
|
3109
3133
|
role: "owner" | "manager" | "member";
|
|
3110
3134
|
}[];
|
|
3135
|
+
manages: {
|
|
3136
|
+
unitId: string;
|
|
3137
|
+
unitName: string;
|
|
3138
|
+
/** @enum {string} */
|
|
3139
|
+
designation: "whole_org" | "admin" | "leader" | "delegate" | "member";
|
|
3140
|
+
}[];
|
|
3111
3141
|
unitMembershipsTruncated: boolean;
|
|
3112
3142
|
inviteStatus: ("active" | "pending" | "expired") | null;
|
|
3113
3143
|
}[];
|
|
@@ -3296,6 +3326,12 @@ export interface components {
|
|
|
3296
3326
|
/** @enum {string} */
|
|
3297
3327
|
role: "owner" | "manager" | "member";
|
|
3298
3328
|
}[];
|
|
3329
|
+
manages: {
|
|
3330
|
+
unitId: string;
|
|
3331
|
+
unitName: string;
|
|
3332
|
+
/** @enum {string} */
|
|
3333
|
+
designation: "whole_org" | "admin" | "leader" | "delegate" | "member";
|
|
3334
|
+
}[];
|
|
3299
3335
|
unitMembershipsTruncated: boolean;
|
|
3300
3336
|
inviteStatus: ("active" | "pending" | "expired") | null;
|
|
3301
3337
|
effectiveScopes: string[];
|
|
@@ -4067,7 +4103,7 @@ export interface components {
|
|
|
4067
4103
|
userId: string;
|
|
4068
4104
|
fullName: string;
|
|
4069
4105
|
jobTitle: string | null;
|
|
4070
|
-
|
|
4106
|
+
avatarUrl: string | null;
|
|
4071
4107
|
authorities: {
|
|
4072
4108
|
/** @enum {string} */
|
|
4073
4109
|
mechanism: "structural" | "delegated" | "rbac";
|
|
@@ -4094,7 +4130,7 @@ export interface components {
|
|
|
4094
4130
|
userId: string;
|
|
4095
4131
|
fullName: string;
|
|
4096
4132
|
jobTitle: string | null;
|
|
4097
|
-
|
|
4133
|
+
avatarUrl: string | null;
|
|
4098
4134
|
authorities: {
|
|
4099
4135
|
/** @enum {string} */
|
|
4100
4136
|
mechanism: "structural" | "delegated" | "rbac";
|
|
@@ -4228,7 +4264,7 @@ export interface components {
|
|
|
4228
4264
|
id: string;
|
|
4229
4265
|
fullName: string;
|
|
4230
4266
|
jobTitle: string | null;
|
|
4231
|
-
|
|
4267
|
+
avatarUrl: string | null;
|
|
4232
4268
|
primaryUnitId: string | null;
|
|
4233
4269
|
}[];
|
|
4234
4270
|
edges: {
|
|
@@ -7923,6 +7959,101 @@ export interface operations {
|
|
|
7923
7959
|
};
|
|
7924
7960
|
};
|
|
7925
7961
|
};
|
|
7962
|
+
uploadUserAvatar: {
|
|
7963
|
+
parameters: {
|
|
7964
|
+
query?: never;
|
|
7965
|
+
header?: never;
|
|
7966
|
+
path: {
|
|
7967
|
+
userId: string;
|
|
7968
|
+
};
|
|
7969
|
+
cookie?: never;
|
|
7970
|
+
};
|
|
7971
|
+
requestBody: {
|
|
7972
|
+
content: {
|
|
7973
|
+
"multipart/form-data": {
|
|
7974
|
+
[key: string]: unknown;
|
|
7975
|
+
};
|
|
7976
|
+
};
|
|
7977
|
+
};
|
|
7978
|
+
responses: {
|
|
7979
|
+
/** @description Avatar uploaded; resolved avatar returned */
|
|
7980
|
+
200: {
|
|
7981
|
+
headers: {
|
|
7982
|
+
[name: string]: unknown;
|
|
7983
|
+
};
|
|
7984
|
+
content?: never;
|
|
7985
|
+
};
|
|
7986
|
+
/** @description Missing or malformed multipart upload */
|
|
7987
|
+
400: {
|
|
7988
|
+
headers: {
|
|
7989
|
+
[name: string]: unknown;
|
|
7990
|
+
};
|
|
7991
|
+
content?: never;
|
|
7992
|
+
};
|
|
7993
|
+
/** @description Caller may not change this avatar */
|
|
7994
|
+
403: {
|
|
7995
|
+
headers: {
|
|
7996
|
+
[name: string]: unknown;
|
|
7997
|
+
};
|
|
7998
|
+
content?: never;
|
|
7999
|
+
};
|
|
8000
|
+
/** @description Target user is not a member of the caller org */
|
|
8001
|
+
404: {
|
|
8002
|
+
headers: {
|
|
8003
|
+
[name: string]: unknown;
|
|
8004
|
+
};
|
|
8005
|
+
content?: never;
|
|
8006
|
+
};
|
|
8007
|
+
/** @description Upload exceeds the 5 MB size limit */
|
|
8008
|
+
413: {
|
|
8009
|
+
headers: {
|
|
8010
|
+
[name: string]: unknown;
|
|
8011
|
+
};
|
|
8012
|
+
content?: never;
|
|
8013
|
+
};
|
|
8014
|
+
/** @description Unsupported image type or bytes are not a valid image */
|
|
8015
|
+
415: {
|
|
8016
|
+
headers: {
|
|
8017
|
+
[name: string]: unknown;
|
|
8018
|
+
};
|
|
8019
|
+
content?: never;
|
|
8020
|
+
};
|
|
8021
|
+
};
|
|
8022
|
+
};
|
|
8023
|
+
deleteUserAvatar: {
|
|
8024
|
+
parameters: {
|
|
8025
|
+
query?: never;
|
|
8026
|
+
header?: never;
|
|
8027
|
+
path: {
|
|
8028
|
+
userId: string;
|
|
8029
|
+
};
|
|
8030
|
+
cookie?: never;
|
|
8031
|
+
};
|
|
8032
|
+
requestBody?: never;
|
|
8033
|
+
responses: {
|
|
8034
|
+
/** @description Uploaded avatar cleared; resolved avatar returned */
|
|
8035
|
+
200: {
|
|
8036
|
+
headers: {
|
|
8037
|
+
[name: string]: unknown;
|
|
8038
|
+
};
|
|
8039
|
+
content?: never;
|
|
8040
|
+
};
|
|
8041
|
+
/** @description Caller may not change this avatar */
|
|
8042
|
+
403: {
|
|
8043
|
+
headers: {
|
|
8044
|
+
[name: string]: unknown;
|
|
8045
|
+
};
|
|
8046
|
+
content?: never;
|
|
8047
|
+
};
|
|
8048
|
+
/** @description Target user is not a member of the caller org */
|
|
8049
|
+
404: {
|
|
8050
|
+
headers: {
|
|
8051
|
+
[name: string]: unknown;
|
|
8052
|
+
};
|
|
8053
|
+
content?: never;
|
|
8054
|
+
};
|
|
8055
|
+
};
|
|
8056
|
+
};
|
|
7926
8057
|
listDriveFiles: {
|
|
7927
8058
|
parameters: {
|
|
7928
8059
|
query?: never;
|
|
@@ -117,6 +117,7 @@ export const openApiRoutes = {
|
|
|
117
117
|
'/api/users/org-chart': ['GET'],
|
|
118
118
|
'/api/users/org-chart/import': ['POST'],
|
|
119
119
|
'/api/users/org-chart/import/{operationId}/retry': ['POST'],
|
|
120
|
+
'/api/users/{userId}/avatar': ['DELETE', 'PUT'],
|
|
120
121
|
'/api/work-items/{id}': ['GET'],
|
|
121
122
|
'/api/work-items/{id}/content': ['PUT'],
|
|
122
123
|
'/api/work-items/{id}/title': ['PUT'],
|
package/src/org/index.ts
CHANGED
|
@@ -125,6 +125,8 @@ export {
|
|
|
125
125
|
WorkspaceOverviewSchema,
|
|
126
126
|
WorkspaceMembersResponseSchema,
|
|
127
127
|
WorkspaceMemberDetailSchema,
|
|
128
|
+
WorkspaceMemberManagesEntrySchema,
|
|
129
|
+
OrgUnitDesignationSchema,
|
|
128
130
|
RoleCatalogEntrySchema,
|
|
129
131
|
RoleCatalogResponseSchema,
|
|
130
132
|
WorkspaceAuthConfigSchema,
|
|
@@ -148,6 +150,8 @@ export type {
|
|
|
148
150
|
WorkspaceAccessResponse,
|
|
149
151
|
WorkspaceOverview as WorkspaceOverviewDto,
|
|
150
152
|
WorkspaceMembersResponse,
|
|
153
|
+
WorkspaceMemberManagesEntry,
|
|
154
|
+
OrgUnitDesignation,
|
|
151
155
|
WorkspaceAuthConfig as WorkspaceAuthConfigDto,
|
|
152
156
|
WorkspaceAuditEvent as WorkspaceAuditEventDto,
|
|
153
157
|
WorkspaceResolvePathResponse,
|
package/src/org/schemas.ts
CHANGED
|
@@ -25,18 +25,74 @@ const WorkspaceMemberUnitSummarySchema = z.object({
|
|
|
25
25
|
role: z.enum(['owner', 'manager', 'member']),
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Designation a member holds over a unit they manage (ADR-CTRL-112).
|
|
30
|
+
*
|
|
31
|
+
* Precedence, highest-first: whole_org > admin > leader > delegate > member.
|
|
32
|
+
* The org-wide designations (`whole_org`, `admin`) anchor to the org root
|
|
33
|
+
* unit. This vocabulary is DISPLAY-ONLY — it summarizes management reach for
|
|
34
|
+
* UI surfaces and is NEVER an authorization input (authority resolution uses
|
|
35
|
+
* the orthogonal membership/delegation axes, not this enum).
|
|
36
|
+
*/
|
|
37
|
+
export const OrgUnitDesignationSchema = z.enum([
|
|
38
|
+
'whole_org',
|
|
39
|
+
'admin',
|
|
40
|
+
'leader',
|
|
41
|
+
'delegate',
|
|
42
|
+
'member',
|
|
43
|
+
]);
|
|
44
|
+
export type OrgUnitDesignation = z.infer<typeof OrgUnitDesignationSchema>;
|
|
45
|
+
|
|
46
|
+
export const WorkspaceMemberManagesEntrySchema = z.object({
|
|
47
|
+
unitId: z.string(),
|
|
48
|
+
unitName: z.string(),
|
|
49
|
+
designation: OrgUnitDesignationSchema,
|
|
50
|
+
});
|
|
51
|
+
export type WorkspaceMemberManagesEntry = z.infer<typeof WorkspaceMemberManagesEntrySchema>;
|
|
52
|
+
|
|
28
53
|
const WorkspaceMemberSchema = z.object({
|
|
29
54
|
id: z.string(),
|
|
30
55
|
name: z.string(),
|
|
31
56
|
email: z.string(),
|
|
57
|
+
/**
|
|
58
|
+
* Resolved avatar photo URL for the member, or `null`/absent when none is
|
|
59
|
+
* stored. SOURCE-AGNOSTIC: today the backend resolves this from the Slack
|
|
60
|
+
* profile photo cached on the user record, but the field name deliberately
|
|
61
|
+
* does not encode the origin so future sources (in-app upload, etc.) slot in
|
|
62
|
+
* behind the backend avatar resolver without a contract change. UI MUST fall
|
|
63
|
+
* back to initials when this is absent. Optional because it is an additive
|
|
64
|
+
* display-only enrichment (see ADR-CONTRACTS-055).
|
|
65
|
+
*/
|
|
66
|
+
avatarUrl: z.string().nullable().optional(),
|
|
67
|
+
/** Free-text job title (`users.job_title`). Null when unset. */
|
|
32
68
|
jobTitle: z.string().nullable(),
|
|
69
|
+
/**
|
|
70
|
+
* Display role — the member's highest org-chart standing, or `null` for a
|
|
71
|
+
* plain member with no org-chart authority. Render via `orgChartRoleLabel`.
|
|
72
|
+
*/
|
|
33
73
|
role: OrgChartRoleSchema.nullable(),
|
|
74
|
+
/** Raw RBAC role names (e.g. 'ceo', 'admin', 'delegate'). Superset of `role`. */
|
|
34
75
|
roleNames: z.array(z.string()),
|
|
35
76
|
joinedAt: z.string(),
|
|
77
|
+
/** ISO timestamp of last activity; null if never recorded. */
|
|
36
78
|
lastActiveAt: z.string().nullable(),
|
|
79
|
+
/**
|
|
80
|
+
* Home org-unit (`users.primary_unit_id`). Null for org-scoped users
|
|
81
|
+
* (no level-2 home assignment). Used by the unit-detail Members table to
|
|
82
|
+
* roll up "people in this org-unit" across the subtree.
|
|
83
|
+
*/
|
|
37
84
|
primaryUnitId: z.string().uuid().nullable(),
|
|
85
|
+
/** OrgUnit memberships for this member, capped at a small number server-side. */
|
|
38
86
|
unitMemberships: z.array(WorkspaceMemberUnitSummarySchema),
|
|
87
|
+
/**
|
|
88
|
+
* Per-unit org-chart designations the member holds where they manage
|
|
89
|
+
* (ADR-CTRL-112). Display-only summary of management reach; never an
|
|
90
|
+
* authorization input. Empty array when the member manages nothing.
|
|
91
|
+
*/
|
|
92
|
+
manages: z.array(WorkspaceMemberManagesEntrySchema),
|
|
93
|
+
/** True when server truncated `unitMemberships`; detail endpoint returns the full list. */
|
|
39
94
|
unitMembershipsTruncated: z.boolean(),
|
|
95
|
+
/** Invite lifecycle status. `null` for members without an invite record. */
|
|
40
96
|
inviteStatus: z.enum(['active', 'pending', 'expired']).nullable(),
|
|
41
97
|
});
|
|
42
98
|
|
|
@@ -52,6 +108,19 @@ export const WorkspaceMemberDetailSchema = WorkspaceMemberSchema.extend({
|
|
|
52
108
|
recentActions: z.array(MemberRecentActionSchema),
|
|
53
109
|
});
|
|
54
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Workspace member for the members list. Human users only (no agent actors).
|
|
113
|
+
* Canonical type — inferred from {@link WorkspaceMemberSchema} so the runtime
|
|
114
|
+
* schema is the single source of truth (no parallel hand-written interface).
|
|
115
|
+
*/
|
|
116
|
+
export type WorkspaceMember = z.infer<typeof WorkspaceMemberSchema>;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Full member detail (GET /api/workspace/members/:userId and /api/me self-view).
|
|
120
|
+
* Inferred from {@link WorkspaceMemberDetailSchema}.
|
|
121
|
+
*/
|
|
122
|
+
export type WorkspaceMemberDetail = z.infer<typeof WorkspaceMemberDetailSchema>;
|
|
123
|
+
|
|
55
124
|
export const RoleCatalogEntrySchema = z.object({
|
|
56
125
|
name: z.string(),
|
|
57
126
|
type: z.enum(['system', 'custom']),
|
package/src/org/types.ts
CHANGED
|
@@ -97,48 +97,13 @@ export interface WorkspaceMemberUnitSummary {
|
|
|
97
97
|
export type WorkspaceMemberInviteStatus = 'active' | 'pending' | 'expired';
|
|
98
98
|
|
|
99
99
|
/**
|
|
100
|
-
* Workspace member
|
|
101
|
-
*
|
|
100
|
+
* Workspace member types. Inferred from their Zod schemas in `./schemas`
|
|
101
|
+
* (the single source of truth) and re-exported here so existing import paths
|
|
102
|
+
* (`from '@company-semantics/contracts/org'`) stay stable. The schema carries
|
|
103
|
+
* the field-level documentation; do not reintroduce a parallel interface (it
|
|
104
|
+
* was the cause of the `manages`/`avatarUrl` drift — see ADR-CTRL-112).
|
|
102
105
|
*/
|
|
103
|
-
export
|
|
104
|
-
id: string;
|
|
105
|
-
name: string;
|
|
106
|
-
email: string;
|
|
107
|
-
/**
|
|
108
|
-
* Resolved avatar photo URL for the member, or `null`/absent when none is
|
|
109
|
-
* stored. SOURCE-AGNOSTIC: today the backend resolves this from the Slack
|
|
110
|
-
* profile photo cached on the user record, but the field name deliberately
|
|
111
|
-
* does not encode the origin so future sources (in-app upload, etc.) slot in
|
|
112
|
-
* behind the backend avatar resolver without a contract change. UI MUST fall
|
|
113
|
-
* back to initials when this is absent. Optional because it is an additive
|
|
114
|
-
* display-only enrichment (see ADR-CONTRACTS-055).
|
|
115
|
-
*/
|
|
116
|
-
avatarUrl?: string | null;
|
|
117
|
-
/** Free-text job title (`users.job_title`). Null when unset. */
|
|
118
|
-
jobTitle: string | null;
|
|
119
|
-
/**
|
|
120
|
-
* Display role — the member's highest org-chart standing, or `null` for a
|
|
121
|
-
* plain member with no org-chart authority. Render via `orgChartRoleLabel`.
|
|
122
|
-
*/
|
|
123
|
-
role: OrgChartRole | null;
|
|
124
|
-
/** Raw RBAC role names (e.g. 'ceo', 'admin', 'delegate'). Superset of `role`. */
|
|
125
|
-
roleNames: string[];
|
|
126
|
-
joinedAt: string;
|
|
127
|
-
/** ISO timestamp of last activity; null if never recorded. */
|
|
128
|
-
lastActiveAt: string | null;
|
|
129
|
-
/**
|
|
130
|
-
* Home org-unit (`users.primary_unit_id`). Null for org-scoped users
|
|
131
|
-
* (no level-2 home assignment). Used by the unit-detail Members table to
|
|
132
|
-
* roll up "people in this org-unit" across the subtree.
|
|
133
|
-
*/
|
|
134
|
-
primaryUnitId: string | null;
|
|
135
|
-
/** OrgUnit memberships for this member, capped at a small number server-side. */
|
|
136
|
-
unitMemberships: WorkspaceMemberUnitSummary[];
|
|
137
|
-
/** True when server truncated `unitMemberships`; detail endpoint returns the full list. */
|
|
138
|
-
unitMembershipsTruncated: boolean;
|
|
139
|
-
/** Invite lifecycle status. `null` for members without an invite record. */
|
|
140
|
-
inviteStatus: WorkspaceMemberInviteStatus | null;
|
|
141
|
-
}
|
|
106
|
+
export type { WorkspaceMember, WorkspaceMemberDetail } from './schemas';
|
|
142
107
|
|
|
143
108
|
/**
|
|
144
109
|
* Recent audit action attached to a member-detail response.
|
|
@@ -151,16 +116,6 @@ export interface MemberRecentAction {
|
|
|
151
116
|
summary: string;
|
|
152
117
|
}
|
|
153
118
|
|
|
154
|
-
/**
|
|
155
|
-
* Full member detail, returned by GET /api/workspace/members/:userId and also
|
|
156
|
-
* the shape projected from /api/me for self-view.
|
|
157
|
-
*/
|
|
158
|
-
export interface WorkspaceMemberDetail extends WorkspaceMember {
|
|
159
|
-
/** Full resolved scope patterns — union of grants from all assigned roles. */
|
|
160
|
-
effectiveScopes: string[];
|
|
161
|
-
/** Up to N most recent audit actions attributed to this member. */
|
|
162
|
-
recentActions: MemberRecentAction[];
|
|
163
|
-
}
|
|
164
119
|
|
|
165
120
|
/**
|
|
166
121
|
* Entry in the RBAC roles catalog (GET /api/rbac/roles).
|