@company-semantics/contracts 31.0.0 → 33.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": "31.0.0",
3
+ "version": "33.0.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -125,13 +125,13 @@
125
125
  "zod": "^4.4.3"
126
126
  },
127
127
  "devDependencies": {
128
- "@types/node": "^22.20.0",
128
+ "@types/node": "^22.20.1",
129
129
  "husky": "^9.1.7",
130
130
  "lint-staged": "^17.0.8",
131
131
  "markdownlint-cli2": "^0.23.0",
132
132
  "openapi-typescript": "^7.13.0",
133
- "prettier": "^3.9.4",
134
- "tsx": "^4.23.0",
133
+ "prettier": "^3.9.5",
134
+ "tsx": "^4.23.1",
135
135
  "typescript": "^5.8.3",
136
136
  "vitest": "^4.1.10",
137
137
  "yaml": "^2.9.0"
@@ -125,7 +125,24 @@ export const CompanyMdDocResponseSchema = z.object({
125
125
  ]),
126
126
  parentId: z.string().nullable(),
127
127
  owningUnitId: z.string().nullable(),
128
- owner: CompanyMdPersonSchema.nullable(),
128
+ /**
129
+ * The doc's EFFECTIVE owners (ADR-CONTRACTS-084), resolved by the same
130
+ * authority as the share dialog's `owner_user_ids`: a stored personal owner,
131
+ * else the owning unit's live authority holders, else the org account owner.
132
+ *
133
+ * A list, not a scalar — co-ownership is first-class (ADR-CTRL-161) and every
134
+ * entry is owner-equivalent (ADR-BE-189), so a surface naming one owner reads
135
+ * `owners[0]` and derives any co-owner count from `owners.length` (e.g. "Ada
136
+ * +2 are owners"). Ordered deterministically so the named owner is stable
137
+ * across reads. Empty only when the org has no account owner
138
+ * (runtime-impossible) — replaces the nullable `owner` scalar and the
139
+ * `ownerCount` shadow field.
140
+ */
141
+ owners: z
142
+ .array(CompanyMdPersonSchema)
143
+ .refine((a) => new Set(a.map((p) => p.id)).size === a.length, {
144
+ message: "duplicate id in owners",
145
+ }),
129
146
  canEdit: z.boolean(),
130
147
  /**
131
148
  * UI capability signal (ADR-BE-382): whether the requesting actor holds
@@ -10,7 +10,7 @@ describe("EMAIL_KINDS golden snapshot", () => {
10
10
  expect(EMAIL_KINDS).toStrictEqual({
11
11
  "auth.otp": {
12
12
  kind: "auth.otp",
13
- subject: "Your login code",
13
+ subject: "Your login code for Company Semantics",
14
14
  plainTextRequired: true,
15
15
  htmlSupported: false,
16
16
  },
@@ -22,13 +22,13 @@ describe("EMAIL_KINDS golden snapshot", () => {
22
22
  },
23
23
  "org.invite": {
24
24
  kind: "org.invite",
25
- subject: "You have been invited to join a workspace",
25
+ subject: "You've been invited to join {orgName} on Company Semantics",
26
26
  plainTextRequired: true,
27
27
  htmlSupported: true,
28
28
  },
29
29
  "org.unit_owner_granted": {
30
30
  kind: "org.unit_owner_granted",
31
- subject: "You've been added to a team",
31
+ subject: "You've been added as {roleWord} to {unitName} in {orgName}",
32
32
  plainTextRequired: true,
33
33
  htmlSupported: true,
34
34
  },
@@ -32,7 +32,9 @@ import type { EmailKind } from "./types";
32
32
  export interface EmailKindDefinition {
33
33
  /** The email kind this definition describes */
34
34
  kind: EmailKind;
35
- /** Email subject line (single source of truth) */
35
+ /** Email subject line (single source of truth). May contain `{field}`
36
+ * placeholders that `renderEmail` fills from the payload (e.g. `{orgName}`);
37
+ * an unmatched placeholder is left verbatim. */
36
38
  subject: string;
37
39
  /** Whether plain text body is required */
38
40
  plainTextRequired: boolean;
@@ -60,7 +62,7 @@ export interface EmailKindDefinition {
60
62
  export const EMAIL_KINDS = {
61
63
  "auth.otp": {
62
64
  kind: "auth.otp",
63
- subject: "Your login code",
65
+ subject: "Your login code for Company Semantics",
64
66
  plainTextRequired: true,
65
67
  htmlSupported: false,
66
68
  },
@@ -72,13 +74,13 @@ export const EMAIL_KINDS = {
72
74
  },
73
75
  "org.invite": {
74
76
  kind: "org.invite",
75
- subject: "You have been invited to join a workspace",
77
+ subject: "You've been invited to join {orgName} on Company Semantics",
76
78
  plainTextRequired: true,
77
79
  htmlSupported: true,
78
80
  },
79
81
  "org.unit_owner_granted": {
80
82
  kind: "org.unit_owner_granted",
81
- subject: "You've been added to a team",
83
+ subject: "You've been added as {roleWord} to {unitName} in {orgName}",
82
84
  plainTextRequired: true,
83
85
  htmlSupported: true,
84
86
  },