@company-semantics/contracts 24.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@company-semantics/contracts",
3
- "version": "24.0.0",
3
+ "version": "25.0.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -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
  // =============================================================================
@@ -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/index.ts CHANGED
@@ -340,6 +340,8 @@ export type {
340
340
  TransferMemberEligibility,
341
341
  // Company.md domain types (PRD-00173)
342
342
  CompanyMdVisibility,
343
+ CompanyMdDiscoverabilityPolicy,
344
+ CompanyMdClassification,
343
345
  CompanyMdDocLevel,
344
346
  CompanyMdDocKind,
345
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)_
@@ -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,
@@ -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>;
@@ -8,4 +8,5 @@ export * from "./access-levels";
8
8
  export * from "./orgchart-roles";
9
9
  export * from "./access-source";
10
10
  export * from "./share-api";
11
+ export * from "./access-request";
11
12
  export * from "./permission-introspection";