@company-semantics/contracts 23.0.0 → 25.0.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/package.json +1 -1
- package/src/api/generated-spec-hash.ts +2 -2
- package/src/api/generated.ts +88 -13
- package/src/email/registry.ts +18 -0
- package/src/email/types.ts +35 -1
- package/src/identity/README.md +2 -0
- package/src/identity/index.ts +2 -0
- package/src/identity/org-chart-actor.ts +24 -0
- package/src/identity/people-org-chart.ts +21 -5
- package/src/index.ts +4 -0
- package/src/org/README.md +4 -1
- package/src/org/company-md.ts +52 -0
- package/src/org/index.ts +2 -0
- package/src/org/schemas.ts +6 -3
- package/src/permissions/access-request.ts +67 -0
- package/src/permissions/index.ts +1 -0
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 = 'ca30049e5670' as const;
|
|
3
|
+
export const SPEC_HASH_FULL = 'ca30049e56707141ae807a8c218d97947e9aeade592540d5e2609eb985f43480' as const;
|
package/src/api/generated.ts
CHANGED
|
@@ -3697,25 +3697,62 @@ export interface components {
|
|
|
3697
3697
|
SetMemberManagerResponse: {
|
|
3698
3698
|
success: boolean;
|
|
3699
3699
|
memberId: string;
|
|
3700
|
-
|
|
3700
|
+
manager: ({
|
|
3701
|
+
/** @constant */
|
|
3702
|
+
kind: "member";
|
|
3703
|
+
/** Format: uuid */
|
|
3704
|
+
userId: string;
|
|
3705
|
+
} | {
|
|
3706
|
+
/** @constant */
|
|
3707
|
+
kind: "open-role";
|
|
3708
|
+
/** Format: uuid */
|
|
3709
|
+
openRoleId: string;
|
|
3710
|
+
}) | null;
|
|
3701
3711
|
relationshipType: string;
|
|
3702
3712
|
message: string;
|
|
3703
3713
|
};
|
|
3704
3714
|
SetMemberManagerRequest: {
|
|
3705
|
-
|
|
3706
|
-
|
|
3715
|
+
manager: {
|
|
3716
|
+
/** @constant */
|
|
3717
|
+
kind: "member";
|
|
3718
|
+
/** Format: uuid */
|
|
3719
|
+
userId: string;
|
|
3720
|
+
} | {
|
|
3721
|
+
/** @constant */
|
|
3722
|
+
kind: "open-role";
|
|
3723
|
+
/** Format: uuid */
|
|
3724
|
+
openRoleId: string;
|
|
3725
|
+
};
|
|
3707
3726
|
};
|
|
3708
3727
|
BulkReparentReportingResponse: {
|
|
3709
3728
|
/** @constant */
|
|
3710
3729
|
success: true;
|
|
3711
3730
|
movedCount: number;
|
|
3712
|
-
|
|
3713
|
-
|
|
3731
|
+
toManager: {
|
|
3732
|
+
/** @constant */
|
|
3733
|
+
kind: "member";
|
|
3734
|
+
/** Format: uuid */
|
|
3735
|
+
userId: string;
|
|
3736
|
+
} | {
|
|
3737
|
+
/** @constant */
|
|
3738
|
+
kind: "open-role";
|
|
3739
|
+
/** Format: uuid */
|
|
3740
|
+
openRoleId: string;
|
|
3741
|
+
};
|
|
3714
3742
|
};
|
|
3715
3743
|
BulkReparentReportingRequest: {
|
|
3716
3744
|
memberIds: string[];
|
|
3717
|
-
|
|
3718
|
-
|
|
3745
|
+
toManager: {
|
|
3746
|
+
/** @constant */
|
|
3747
|
+
kind: "member";
|
|
3748
|
+
/** Format: uuid */
|
|
3749
|
+
userId: string;
|
|
3750
|
+
} | {
|
|
3751
|
+
/** @constant */
|
|
3752
|
+
kind: "open-role";
|
|
3753
|
+
/** Format: uuid */
|
|
3754
|
+
openRoleId: string;
|
|
3755
|
+
};
|
|
3719
3756
|
idempotencyKey: string;
|
|
3720
3757
|
};
|
|
3721
3758
|
SubmitInteractiveTaskResponse: {
|
|
@@ -4856,10 +4893,28 @@ export interface components {
|
|
|
4856
4893
|
}[];
|
|
4857
4894
|
}[];
|
|
4858
4895
|
edges: {
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4896
|
+
report: {
|
|
4897
|
+
/** @constant */
|
|
4898
|
+
kind: "member";
|
|
4899
|
+
/** Format: uuid */
|
|
4900
|
+
userId: string;
|
|
4901
|
+
} | {
|
|
4902
|
+
/** @constant */
|
|
4903
|
+
kind: "open-role";
|
|
4904
|
+
/** Format: uuid */
|
|
4905
|
+
openRoleId: string;
|
|
4906
|
+
};
|
|
4907
|
+
manager: {
|
|
4908
|
+
/** @constant */
|
|
4909
|
+
kind: "member";
|
|
4910
|
+
/** Format: uuid */
|
|
4911
|
+
userId: string;
|
|
4912
|
+
} | {
|
|
4913
|
+
/** @constant */
|
|
4914
|
+
kind: "open-role";
|
|
4915
|
+
/** Format: uuid */
|
|
4916
|
+
openRoleId: string;
|
|
4917
|
+
};
|
|
4863
4918
|
/** @enum {string} */
|
|
4864
4919
|
relationshipType: "solid" | "dotted";
|
|
4865
4920
|
}[];
|
|
@@ -4869,7 +4924,17 @@ export interface components {
|
|
|
4869
4924
|
/** Format: uuid */
|
|
4870
4925
|
unitId: string;
|
|
4871
4926
|
title: string | null;
|
|
4872
|
-
|
|
4927
|
+
reportsTo: ({
|
|
4928
|
+
/** @constant */
|
|
4929
|
+
kind: "member";
|
|
4930
|
+
/** Format: uuid */
|
|
4931
|
+
userId: string;
|
|
4932
|
+
} | {
|
|
4933
|
+
/** @constant */
|
|
4934
|
+
kind: "open-role";
|
|
4935
|
+
/** Format: uuid */
|
|
4936
|
+
openRoleId: string;
|
|
4937
|
+
}) | null;
|
|
4873
4938
|
}[];
|
|
4874
4939
|
};
|
|
4875
4940
|
/** @description Polling snapshot of a generic ingestion operation. */
|
|
@@ -9018,7 +9083,17 @@ export interface operations {
|
|
|
9018
9083
|
requestBody: {
|
|
9019
9084
|
content: {
|
|
9020
9085
|
"application/json": {
|
|
9021
|
-
|
|
9086
|
+
manager: ({
|
|
9087
|
+
/** @constant */
|
|
9088
|
+
kind: "member";
|
|
9089
|
+
/** Format: uuid */
|
|
9090
|
+
userId: string;
|
|
9091
|
+
} | {
|
|
9092
|
+
/** @constant */
|
|
9093
|
+
kind: "open-role";
|
|
9094
|
+
/** Format: uuid */
|
|
9095
|
+
openRoleId: string;
|
|
9096
|
+
}) | null;
|
|
9022
9097
|
};
|
|
9023
9098
|
};
|
|
9024
9099
|
};
|
package/src/email/registry.ts
CHANGED
|
@@ -112,6 +112,24 @@ export const EMAIL_KINDS = {
|
|
|
112
112
|
plainTextRequired: true,
|
|
113
113
|
htmlSupported: true,
|
|
114
114
|
},
|
|
115
|
+
"companyMd.access_requested": {
|
|
116
|
+
kind: "companyMd.access_requested",
|
|
117
|
+
subject: "Someone requested access to a document",
|
|
118
|
+
plainTextRequired: true,
|
|
119
|
+
htmlSupported: true,
|
|
120
|
+
},
|
|
121
|
+
"companyMd.access_request_approved": {
|
|
122
|
+
kind: "companyMd.access_request_approved",
|
|
123
|
+
subject: "Your access request was approved",
|
|
124
|
+
plainTextRequired: true,
|
|
125
|
+
htmlSupported: true,
|
|
126
|
+
},
|
|
127
|
+
"companyMd.access_request_denied": {
|
|
128
|
+
kind: "companyMd.access_request_denied",
|
|
129
|
+
subject: "Your access request was reviewed",
|
|
130
|
+
plainTextRequired: true,
|
|
131
|
+
htmlSupported: true,
|
|
132
|
+
},
|
|
115
133
|
} as const satisfies Record<EmailKind, EmailKindDefinition>;
|
|
116
134
|
|
|
117
135
|
// =============================================================================
|
package/src/email/types.ts
CHANGED
|
@@ -32,7 +32,10 @@ export type EmailKind =
|
|
|
32
32
|
| "org.ownership_transfer_completed"
|
|
33
33
|
| "security.alert" // future
|
|
34
34
|
| "chat.shared"
|
|
35
|
-
| "share.granted"
|
|
35
|
+
| "share.granted"
|
|
36
|
+
| "companyMd.access_requested"
|
|
37
|
+
| "companyMd.access_request_approved"
|
|
38
|
+
| "companyMd.access_request_denied";
|
|
36
39
|
|
|
37
40
|
// =============================================================================
|
|
38
41
|
// Email Payloads
|
|
@@ -128,6 +131,37 @@ export interface EmailPayloads {
|
|
|
128
131
|
/** Optional message from the granter, included in the email only (not persisted) */
|
|
129
132
|
message?: string;
|
|
130
133
|
};
|
|
134
|
+
/** Sent to the doc owner(s) when an actor requests access (ADR-BE-338). */
|
|
135
|
+
"companyMd.access_requested": {
|
|
136
|
+
/** Display name of the requester */
|
|
137
|
+
requesterName: string;
|
|
138
|
+
/** Title of the company.md node access is requested for */
|
|
139
|
+
docTitle: string;
|
|
140
|
+
/** Optional message from the requester (email only) */
|
|
141
|
+
message?: string;
|
|
142
|
+
/** Deep-link that opens the doc's ShareDialog scrolled to the pending request */
|
|
143
|
+
reviewUrl: string;
|
|
144
|
+
};
|
|
145
|
+
/** Sent to the requester when an owner approves (ADR-BE-338). */
|
|
146
|
+
"companyMd.access_request_approved": {
|
|
147
|
+
/** Display name of the owner who approved */
|
|
148
|
+
approverName: string;
|
|
149
|
+
/** Title of the company.md node */
|
|
150
|
+
docTitle: string;
|
|
151
|
+
/** Access level granted */
|
|
152
|
+
accessLevel: "editor" | "commenter" | "viewer";
|
|
153
|
+
/** Full URL to view the node */
|
|
154
|
+
docUrl: string;
|
|
155
|
+
};
|
|
156
|
+
/** Sent to the requester when an owner denies (ADR-BE-338). */
|
|
157
|
+
"companyMd.access_request_denied": {
|
|
158
|
+
/** Display name of the owner who denied */
|
|
159
|
+
approverName: string;
|
|
160
|
+
/** Title of the company.md node */
|
|
161
|
+
docTitle: string;
|
|
162
|
+
/** Optional reason from the owner (email only) */
|
|
163
|
+
reason?: string;
|
|
164
|
+
};
|
|
131
165
|
}
|
|
132
166
|
|
|
133
167
|
// =============================================================================
|
package/src/identity/README.md
CHANGED
|
@@ -49,6 +49,8 @@ TypeScript types and functions for user identity and display name resolution.
|
|
|
49
49
|
- `MeResponse` _(type)_
|
|
50
50
|
- `MeResponseSchema` — Full identity context returned by GET /api/me.
|
|
51
51
|
- `NameSource` _(type)_ — Source of the user's name data.
|
|
52
|
+
- `OrgChartActorRef` _(type)_
|
|
53
|
+
- `OrgChartActorRefSchema`
|
|
52
54
|
- `PeopleOrgChartEdge` _(type)_
|
|
53
55
|
- `PeopleOrgChartEdgeSchema`
|
|
54
56
|
- `PeopleOrgChartNode` _(type)_
|
package/src/identity/index.ts
CHANGED
|
@@ -64,6 +64,7 @@ export type {
|
|
|
64
64
|
// People Org Chart (GET /api/users/org-chart)
|
|
65
65
|
export {
|
|
66
66
|
ReportingRelationshipTypeSchema,
|
|
67
|
+
OrgChartActorRefSchema,
|
|
67
68
|
PeopleOrgChartNodeSchema,
|
|
68
69
|
PeopleOrgChartOwnedUnitSchema,
|
|
69
70
|
PeopleOrgChartEdgeSchema,
|
|
@@ -72,6 +73,7 @@ export {
|
|
|
72
73
|
} from "./people-org-chart";
|
|
73
74
|
export type {
|
|
74
75
|
ReportingRelationshipType,
|
|
76
|
+
OrgChartActorRef,
|
|
75
77
|
PeopleOrgChartNode,
|
|
76
78
|
PeopleOrgChartOwnedUnit,
|
|
77
79
|
PeopleOrgChartEdge,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Org-chart actor reference — either endpoint of a reporting edge.
|
|
3
|
+
*
|
|
4
|
+
* A node in the people chart that can sit on EITHER side of a reporting edge: a
|
|
5
|
+
* filled member (keyed by occupant `userId`) OR an unfilled open-role seat
|
|
6
|
+
* (keyed by its own `openRoleId`). A vacant seat is a first-class reporting
|
|
7
|
+
* actor — it can be a manager that real people report to (ADR-BE-312), not just
|
|
8
|
+
* a report. The discriminant lets an edge point at either kind without losing
|
|
9
|
+
* what the id means. Mirrors the app's `ActorIdentity` shape exactly so the app
|
|
10
|
+
* consumes this type directly (one common spine across wire + UI).
|
|
11
|
+
*
|
|
12
|
+
* Lives in its own zero-dependency module (zod only) so both `people-org-chart`
|
|
13
|
+
* (which already depends on `org/schemas` for AuthorityMutability) and
|
|
14
|
+
* `org/schemas` (which needs it for the set-manager request/response) can import
|
|
15
|
+
* it without forming a module-init cycle.
|
|
16
|
+
*/
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
|
|
19
|
+
export const OrgChartActorRefSchema = z.discriminatedUnion("kind", [
|
|
20
|
+
z.object({ kind: z.literal("member"), userId: z.string().uuid() }),
|
|
21
|
+
z.object({ kind: z.literal("open-role"), openRoleId: z.string().uuid() }),
|
|
22
|
+
]);
|
|
23
|
+
|
|
24
|
+
export type OrgChartActorRef = z.infer<typeof OrgChartActorRefSchema>;
|
|
@@ -23,6 +23,15 @@ export type ReportingRelationshipType = z.infer<
|
|
|
23
23
|
typeof ReportingRelationshipTypeSchema
|
|
24
24
|
>;
|
|
25
25
|
|
|
26
|
+
// Actor reference — either endpoint of a reporting edge (member | open-role).
|
|
27
|
+
// Defined in its own zero-dependency module to avoid a module-init cycle with
|
|
28
|
+
// `org/schemas` (which this file imports AuthorityMutabilitySchema from, and
|
|
29
|
+
// which needs the actor ref for the set-manager request/response). Re-exported
|
|
30
|
+
// here so the existing import site keeps working.
|
|
31
|
+
export { OrgChartActorRefSchema } from "./org-chart-actor";
|
|
32
|
+
export type { OrgChartActorRef } from "./org-chart-actor";
|
|
33
|
+
import { OrgChartActorRefSchema } from "./org-chart-actor";
|
|
34
|
+
|
|
26
35
|
// ---------------------------------------------------------------------------
|
|
27
36
|
// Node — a person in the chart
|
|
28
37
|
// ---------------------------------------------------------------------------
|
|
@@ -68,8 +77,12 @@ export type PeopleOrgChartNode = z.infer<typeof PeopleOrgChartNodeSchema>;
|
|
|
68
77
|
// ---------------------------------------------------------------------------
|
|
69
78
|
|
|
70
79
|
export const PeopleOrgChartEdgeSchema = z.object({
|
|
71
|
-
|
|
72
|
-
|
|
80
|
+
// Either endpoint may be a member or an open-role seat. An edge whose
|
|
81
|
+
// `manager` is an open-role seat is "a person reports to a vacant role"
|
|
82
|
+
// (ADR-BE-312); whose `report` is an open-role seat is "an open role reports
|
|
83
|
+
// to someone" (ADR-BE-291) — both are now expressible symmetrically.
|
|
84
|
+
report: OrgChartActorRefSchema,
|
|
85
|
+
manager: OrgChartActorRefSchema,
|
|
73
86
|
relationshipType: ReportingRelationshipTypeSchema,
|
|
74
87
|
});
|
|
75
88
|
|
|
@@ -79,7 +92,7 @@ export type PeopleOrgChartEdge = z.infer<typeof PeopleOrgChartEdgeSchema>;
|
|
|
79
92
|
// Open role — a persisted placeholder seat rendered as a dashed "Open role"
|
|
80
93
|
// card in its unit's sibling column. Only active roles (open + hiring) are
|
|
81
94
|
// included; filled/closed roles never appear here. `unitId` seats the card in
|
|
82
|
-
// the right column. `
|
|
95
|
+
// the right column. `reportsTo` is the open role's OWN reporting edge
|
|
83
96
|
// (ADR-BE-291): it defaults to the role's creator and is editable/clearable, so
|
|
84
97
|
// a person-less seat is placed by reporting like everyone else (the chart owns
|
|
85
98
|
// placement, ADR-CTRL-159). Null → the role hangs in its unit's projection-only
|
|
@@ -90,7 +103,10 @@ export const PeopleOrgChartOpenRoleSchema = z.object({
|
|
|
90
103
|
id: z.string().uuid(),
|
|
91
104
|
unitId: z.string().uuid(),
|
|
92
105
|
title: z.string().nullable(),
|
|
93
|
-
|
|
106
|
+
// The open role's OWN reporting edge (ADR-BE-291). An actor ref so an open
|
|
107
|
+
// role can report to a person OR to another open-role seat (ADR-BE-312). Null
|
|
108
|
+
// → the role hangs in its unit's projection-only Unassigned bucket.
|
|
109
|
+
reportsTo: OrgChartActorRefSchema.nullable(),
|
|
94
110
|
});
|
|
95
111
|
|
|
96
112
|
export type PeopleOrgChartOpenRole = z.infer<
|
|
@@ -103,7 +119,7 @@ export type PeopleOrgChartOpenRole = z.infer<
|
|
|
103
119
|
//
|
|
104
120
|
// Person-less cards (empty-unit placeholders, ghosts, open roles) no longer
|
|
105
121
|
// anchor under a stored unit-head "tether" (ADR-BE-284, retired by ADR-BE-292).
|
|
106
|
-
// Open roles carry their own `
|
|
122
|
+
// Open roles carry their own `reportsTo` edge; placeholders fall back to
|
|
107
123
|
// the render-time reporting heuristic.
|
|
108
124
|
|
|
109
125
|
export const PeopleOrgChartResponseSchema = z.object({
|
package/src/index.ts
CHANGED
|
@@ -175,6 +175,7 @@ export type {
|
|
|
175
175
|
// People Org Chart (GET /api/users/org-chart)
|
|
176
176
|
export {
|
|
177
177
|
ReportingRelationshipTypeSchema,
|
|
178
|
+
OrgChartActorRefSchema,
|
|
178
179
|
PeopleOrgChartNodeSchema,
|
|
179
180
|
PeopleOrgChartOwnedUnitSchema,
|
|
180
181
|
PeopleOrgChartEdgeSchema,
|
|
@@ -183,6 +184,7 @@ export {
|
|
|
183
184
|
} from "./identity/index";
|
|
184
185
|
export type {
|
|
185
186
|
ReportingRelationshipType,
|
|
187
|
+
OrgChartActorRef,
|
|
186
188
|
PeopleOrgChartNode,
|
|
187
189
|
PeopleOrgChartOwnedUnit,
|
|
188
190
|
PeopleOrgChartEdge,
|
|
@@ -338,6 +340,8 @@ export type {
|
|
|
338
340
|
TransferMemberEligibility,
|
|
339
341
|
// Company.md domain types (PRD-00173)
|
|
340
342
|
CompanyMdVisibility,
|
|
343
|
+
CompanyMdDiscoverabilityPolicy,
|
|
344
|
+
CompanyMdClassification,
|
|
341
345
|
CompanyMdDocLevel,
|
|
342
346
|
CompanyMdDocKind,
|
|
343
347
|
CompanyMdNodeType,
|
package/src/org/README.md
CHANGED
|
@@ -57,8 +57,10 @@ Shared type vocabulary for organization ownership, type classification, and tran
|
|
|
57
57
|
- `ChangeMemberRoleRequest` _(type)_ — Request payload for changing a member's role.
|
|
58
58
|
- `ChangeMemberRoleResponse` _(type)_
|
|
59
59
|
- `ChangeMemberRoleResponseSchema`
|
|
60
|
+
- `CompanyMdClassification` _(type)_ — Information classification for a Company.md node — what the document is, for governance, NOT permissions.
|
|
60
61
|
- `CompanyMdContextBankItem` _(type)_ — A context bank item — a company.md doc associated with one or more parent nodes.
|
|
61
62
|
- `CompanyMdDependency` _(type)_
|
|
63
|
+
- `CompanyMdDiscoverabilityPolicy` _(type)_ — Discoverability policy for a Company.md node — who knows it exists, orthogonal to who may read it (authority…
|
|
62
64
|
- `CompanyMdDoc` _(type)_
|
|
63
65
|
- `CompanyMdDocCollaborators` _(type)_
|
|
64
66
|
- `CompanyMdDocCore` _(type)_
|
|
@@ -247,7 +249,7 @@ Shared type vocabulary for organization ownership, type classification, and tran
|
|
|
247
249
|
- `SetActiveOrgResponse` _(type)_
|
|
248
250
|
- `SetActiveOrgResponseSchema`
|
|
249
251
|
- `SetMemberManagerResponse` _(type)_
|
|
250
|
-
- `SetMemberManagerResponseSchema` — Response for setting (PATCH) or clearing (DELETE) a member's solid-line manager — the
|
|
252
|
+
- `SetMemberManagerResponseSchema` — Response for setting (PATCH) or clearing (DELETE) a member's solid-line manager — the reporting edge that the…
|
|
251
253
|
- `SharePolicy` _(type)_ — Document sharing policy. - restricted: Only explicit ACL + owning unit + org admins - orgread: All org…
|
|
252
254
|
- `ShareState` _(type)_ — Complete sharing state for a document.
|
|
253
255
|
- `SourceAuthority` _(type)_
|
|
@@ -336,6 +338,7 @@ Shared type vocabulary for organization ownership, type classification, and tran
|
|
|
336
338
|
**Internal domains:**
|
|
337
339
|
|
|
338
340
|
- `api`
|
|
341
|
+
- `identity`
|
|
339
342
|
- `permissions`
|
|
340
343
|
|
|
341
344
|
**External packages:**
|
package/src/org/company-md.ts
CHANGED
|
@@ -23,6 +23,32 @@
|
|
|
23
23
|
*/
|
|
24
24
|
export type CompanyMdVisibility = "private" | "unit" | "org";
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Discoverability policy for a Company.md node — *who knows it exists*, orthogonal
|
|
28
|
+
* to who may read it (authority resolution). See ADR-CTRL-194 / ADR-BE-338.
|
|
29
|
+
*
|
|
30
|
+
* - `org`: every org member knows the node exists; a non-reader sees the locked
|
|
31
|
+
* meta-stub (title + owner byline) and may request access.
|
|
32
|
+
* - `owners`: only readers know it exists; a non-reader gets a no-leak 404.
|
|
33
|
+
*
|
|
34
|
+
* A *policy*, not a boolean — intentionally extensible (`unit | partners |
|
|
35
|
+
* customers`). It also governs retrieval (search, semantic search, suggested
|
|
36
|
+
* context, citation, agent browsing).
|
|
37
|
+
*/
|
|
38
|
+
export type CompanyMdDiscoverabilityPolicy = "org" | "owners";
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Information classification for a Company.md node — *what the document is*, for
|
|
42
|
+
* governance, NOT permissions (ADR-CTRL-194 / ADR-BE-338). Later drives export
|
|
43
|
+
* watermarking, share-approval gates, retrieval rules, and audit verbosity
|
|
44
|
+
* without changing who can read. Named now; enforcement behaviors deferred.
|
|
45
|
+
*/
|
|
46
|
+
export type CompanyMdClassification =
|
|
47
|
+
| "public"
|
|
48
|
+
| "internal"
|
|
49
|
+
| "confidential"
|
|
50
|
+
| "highly_confidential";
|
|
51
|
+
|
|
26
52
|
/**
|
|
27
53
|
* @deprecated Since 1.12.0. `CompanyMdDocLevel` is superseded by `CompanyMdDocKind` + `depth`.
|
|
28
54
|
*
|
|
@@ -107,6 +133,17 @@ export interface CompanyMdNodeIdentity {
|
|
|
107
133
|
readonly depth: 1 | 2 | 3 | 4 | 5 | null;
|
|
108
134
|
readonly parentId: string | null;
|
|
109
135
|
readonly visibility: CompanyMdVisibility;
|
|
136
|
+
/**
|
|
137
|
+
* Who knows this node exists (orthogonal to who may read it). Governs the
|
|
138
|
+
* non-reader branch: `org` → locked meta-stub + request-access; `owners` →
|
|
139
|
+
* no-leak 404. See ADR-CTRL-194 / ADR-BE-338.
|
|
140
|
+
*/
|
|
141
|
+
readonly discoverabilityPolicy: CompanyMdDiscoverabilityPolicy;
|
|
142
|
+
/**
|
|
143
|
+
* Governance classification of the node (not a permission). Drives future
|
|
144
|
+
* governance behaviors (watermarking, share-approval, retrieval, audit).
|
|
145
|
+
*/
|
|
146
|
+
readonly classification: CompanyMdClassification;
|
|
110
147
|
/** Owning org_unit. Null for root docs or when the owning unit has been archived. */
|
|
111
148
|
readonly owningUnitId: string | null;
|
|
112
149
|
}
|
|
@@ -132,6 +169,21 @@ export interface CompanyMdDocCore extends CompanyMdNodeIdentity {
|
|
|
132
169
|
* its body (ADR-BE-245). Omitted/`false` on the normal full-content path.
|
|
133
170
|
*/
|
|
134
171
|
readonly contentRedacted?: boolean;
|
|
172
|
+
/**
|
|
173
|
+
* Read-state of this node for the requesting actor (ADR-CTRL-194 / ADR-BE-338):
|
|
174
|
+
* - `full`: actor may read; `content` is the real body.
|
|
175
|
+
* - `redacted_admin`: meta-tier admin meta-view (ADR-BE-245).
|
|
176
|
+
* - `locked_requestable`: non-reader of an `org`-discoverable node — body is the
|
|
177
|
+
* redacted stub and the actor may request access.
|
|
178
|
+
* Omitted on legacy paths that only set `contentRedacted`.
|
|
179
|
+
*/
|
|
180
|
+
readonly accessState?: "full" | "redacted_admin" | "locked_requestable";
|
|
181
|
+
/**
|
|
182
|
+
* Whether the requesting actor may request access to this node. A *separate*
|
|
183
|
+
* resolver, intentionally NOT equal to `discoverabilityPolicy` (a direct-link
|
|
184
|
+
* recipient to an `owners` node may still be allowed to request).
|
|
185
|
+
*/
|
|
186
|
+
readonly canRequestAccess?: boolean;
|
|
135
187
|
}
|
|
136
188
|
|
|
137
189
|
export interface CompanyMdDocCollaborators {
|
package/src/org/index.ts
CHANGED
|
@@ -163,6 +163,8 @@ export { orderTreeNodes } from "./tree-ordering";
|
|
|
163
163
|
// Company.md domain types (PRD-00173)
|
|
164
164
|
export type {
|
|
165
165
|
CompanyMdVisibility,
|
|
166
|
+
CompanyMdDiscoverabilityPolicy,
|
|
167
|
+
CompanyMdClassification,
|
|
166
168
|
CompanyMdDocLevel,
|
|
167
169
|
CompanyMdDocKind,
|
|
168
170
|
CompanyMdNodeType,
|
package/src/org/schemas.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import { z } from "zod";
|
|
14
14
|
import { CursorPageSchema } from "../api/primitives";
|
|
15
15
|
import { OrgChartRoleSchema } from "../permissions/orgchart-roles";
|
|
16
|
+
import { OrgChartActorRefSchema } from "../identity/org-chart-actor";
|
|
16
17
|
|
|
17
18
|
// ---------------------------------------------------------------------------
|
|
18
19
|
// Sub-schemas
|
|
@@ -505,8 +506,10 @@ export type ChangeMemberRoleResponse = z.infer<
|
|
|
505
506
|
|
|
506
507
|
/**
|
|
507
508
|
* Response for setting (PATCH) or clearing (DELETE) a member's solid-line
|
|
508
|
-
* manager — the
|
|
509
|
-
*
|
|
509
|
+
* manager — the reporting edge that the org chart is built from. `manager` is
|
|
510
|
+
* the actor the member now reports to: a `member` (person→person) OR an
|
|
511
|
+
* `open-role` seat (person reports to a vacant role — ADR-BE-312); null after a
|
|
512
|
+
* clear.
|
|
510
513
|
*
|
|
511
514
|
* Distinct from team membership (RBAC scopes) and `primary_unit_id` (home
|
|
512
515
|
* unit): neither of those places a person in the reporting hierarchy.
|
|
@@ -515,7 +518,7 @@ export type ChangeMemberRoleResponse = z.infer<
|
|
|
515
518
|
export const SetMemberManagerResponseSchema = z.object({
|
|
516
519
|
success: z.boolean(),
|
|
517
520
|
memberId: z.string(),
|
|
518
|
-
|
|
521
|
+
manager: OrgChartActorRefSchema.nullable(),
|
|
519
522
|
relationshipType: z.string(),
|
|
520
523
|
message: z.string(),
|
|
521
524
|
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Company.md Access-Request DTOs (ADR-CONTRACTS-071 / ADR-BE-338)
|
|
3
|
+
*
|
|
4
|
+
* The request-access workflow: a non-reader of an `org`-discoverable node asks
|
|
5
|
+
* the owner(s) for access; the first owner to act resolves the request, minting a
|
|
6
|
+
* normal grant. These are the shared request/response shapes.
|
|
7
|
+
*
|
|
8
|
+
* Zod-canonical: schema is the source of truth, the type is inferred.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { GrantableAccessLevelSchema } from "./share-api";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Lifecycle status of an access request. A single pending request exists per
|
|
15
|
+
* (node, actor); the first owner to act transitions it terminally.
|
|
16
|
+
*/
|
|
17
|
+
export const ACCESS_REQUEST_STATUSES = [
|
|
18
|
+
"pending",
|
|
19
|
+
"approved",
|
|
20
|
+
"denied",
|
|
21
|
+
"withdrawn",
|
|
22
|
+
"expired",
|
|
23
|
+
] as const;
|
|
24
|
+
export const AccessRequestStatusSchema = z.enum(ACCESS_REQUEST_STATUSES);
|
|
25
|
+
export type AccessRequestStatus = z.infer<typeof AccessRequestStatusSchema>;
|
|
26
|
+
|
|
27
|
+
/** POST body to create an access request. */
|
|
28
|
+
export const AccessRequestCreateSchema = z.object({
|
|
29
|
+
/** Optional context the requester sends to the owner(s). */
|
|
30
|
+
message: z.string().max(2000).optional(),
|
|
31
|
+
});
|
|
32
|
+
export type AccessRequestCreate = z.infer<typeof AccessRequestCreateSchema>;
|
|
33
|
+
|
|
34
|
+
/** A single actor that requested access (actor-generic; today a user). */
|
|
35
|
+
export const AccessRequestActorSchema = z.object({
|
|
36
|
+
id: z.string(),
|
|
37
|
+
name: z.string(),
|
|
38
|
+
});
|
|
39
|
+
export type AccessRequestActor = z.infer<typeof AccessRequestActorSchema>;
|
|
40
|
+
|
|
41
|
+
/** Full access-request record returned to owners (and the requester). */
|
|
42
|
+
export const AccessRequestSchema = z.object({
|
|
43
|
+
id: z.string(),
|
|
44
|
+
requestor: AccessRequestActorSchema,
|
|
45
|
+
docId: z.string(),
|
|
46
|
+
status: AccessRequestStatusSchema,
|
|
47
|
+
message: z.string().nullable(),
|
|
48
|
+
createdAt: z.string(),
|
|
49
|
+
resolvedAt: z.string().nullable(),
|
|
50
|
+
});
|
|
51
|
+
export type AccessRequest = z.infer<typeof AccessRequestSchema>;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* POST body to approve a request. The owner chooses the granted level (default
|
|
55
|
+
* `viewer` is applied server-side if the field is omitted by older clients).
|
|
56
|
+
*/
|
|
57
|
+
export const ApproveAccessRequestSchema = z.object({
|
|
58
|
+
accessLevel: GrantableAccessLevelSchema,
|
|
59
|
+
});
|
|
60
|
+
export type ApproveAccessRequest = z.infer<typeof ApproveAccessRequestSchema>;
|
|
61
|
+
|
|
62
|
+
/** POST body to deny a request. */
|
|
63
|
+
export const DenyAccessRequestSchema = z.object({
|
|
64
|
+
/** Optional reason, surfaced to the requester (email only). */
|
|
65
|
+
reason: z.string().max(2000).optional(),
|
|
66
|
+
});
|
|
67
|
+
export type DenyAccessRequest = z.infer<typeof DenyAccessRequestSchema>;
|