@company-semantics/contracts 45.1.0 → 45.3.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.
Files changed (32) hide show
  1. package/package.json +10 -3
  2. package/src/__tests__/resource-keys.test.ts +59 -0
  3. package/src/api/generated-spec-hash.ts +2 -2
  4. package/src/api/generated.ts +540 -1
  5. package/src/comments/README.md +115 -0
  6. package/src/comments/__tests__/README.md +49 -0
  7. package/src/comments/__tests__/anchor-corpus.test.ts +202 -0
  8. package/src/comments/__tests__/fixtures/README.md +58 -0
  9. package/src/comments/__tests__/fixtures/comment-anchors.json +94 -0
  10. package/src/comments/__tests__/fixtures/comment-anchors.provenance.json +9 -0
  11. package/src/comments/__tests__/schemas.test.ts +274 -0
  12. package/src/comments/anchor.ts +120 -0
  13. package/src/comments/index.ts +43 -0
  14. package/src/comments/schemas.ts +227 -0
  15. package/src/generated/openapi-routes.ts +7 -0
  16. package/src/index.ts +42 -0
  17. package/src/notifications/__tests__/__snapshots__/registry.test.ts.snap +4 -0
  18. package/src/notifications/__tests__/__snapshots__/render-snapshot.test.ts.snap +741 -0
  19. package/src/notifications/__tests__/definition.test.ts +4 -3
  20. package/src/notifications/__tests__/fixtures.ts +34 -0
  21. package/src/notifications/__tests__/kinds.test.ts +11 -4
  22. package/src/notifications/__tests__/registry.test.ts +7 -5
  23. package/src/notifications/__tests__/render-snapshot.test.ts +36 -0
  24. package/src/notifications/kinds/comment-mention.ts +82 -0
  25. package/src/notifications/kinds/comment-reply.ts +79 -0
  26. package/src/notifications/kinds/index.ts +2 -0
  27. package/src/notifications/kinds.ts +12 -3
  28. package/src/notifications/payloads.ts +49 -0
  29. package/src/notifications/registry.ts +6 -2
  30. package/src/org/schemas.ts +23 -0
  31. package/src/resource-keys.ts +68 -0
  32. package/src/user-notifications/kinds.ts +13 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@company-semantics/contracts",
3
- "version": "45.1.0",
3
+ "version": "45.3.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -48,6 +48,10 @@
48
48
  "types": "./src/chat/index.ts",
49
49
  "default": "./src/chat/index.ts"
50
50
  },
51
+ "./comments": {
52
+ "types": "./src/comments/index.ts",
53
+ "default": "./src/comments/index.ts"
54
+ },
51
55
  "./api": {
52
56
  "types": "./src/api/index.ts",
53
57
  "default": "./src/api/index.ts"
@@ -105,6 +109,8 @@
105
109
  "test": "NODE_OPTIONS='--max-old-space-size=4096' bash scripts/vitest-run.sh run",
106
110
  "test:run": "NODE_OPTIONS='--max-old-space-size=4096' bash scripts/vitest-run.sh run",
107
111
  "color": "tsx scripts/color.ts",
112
+ "anchor-corpus:check": "tsx scripts/anchor-corpus.ts",
113
+ "anchor-corpus:sync": "tsx scripts/anchor-corpus.ts --sync",
108
114
  "generate:spec-hash": "tsx scripts/generate-spec-hash.ts",
109
115
  "generate:spec-hash:check": "tsx scripts/generate-spec-hash.ts --check",
110
116
  "generate:api": "pnpm generate:api-types && pnpm generate:spec-hash && pnpm generate:openapi-routes",
@@ -149,7 +155,8 @@
149
155
  "overrides": {
150
156
  "brace-expansion@<5.0.9": ">=5.0.9",
151
157
  "minimatch@<10.2.3": ">=10.2.3",
152
- "js-yaml@>=4.0.0 <4.3.0": ">=4.3.0 <5.0.0",
158
+ "nanoid@<3.3.17": ">=3.3.17",
159
+ "js-yaml@>=4.0.0 <4.3.1": ">=4.3.1 <5.0.0",
153
160
  "js-yaml@>=5.0.0 <5.2.2": ">=5.2.2 <6.0.0",
154
161
  "picomatch@<4.0.4": ">=4.0.4",
155
162
  "esbuild@<0.28.1": ">=0.28.1",
@@ -163,5 +170,5 @@
163
170
  "*.md": "markdownlint-cli2",
164
171
  "package.json": "node -e \"JSON.parse(require('fs').readFileSync('package.json'))\""
165
172
  },
166
- "securityRequirementsVersion": "5227de9b2a68460019c85186c0318d77915e02df1eb8aa8d1516b001e84bc524"
173
+ "securityRequirementsVersion": "dfe68368cb5b7fdc67290fba5cd5a920c9a2ca9c20a9e297232a467b2022e5b5"
167
174
  }
@@ -2,6 +2,7 @@ import { describe, it, expect } from "vitest";
2
2
  import {
3
3
  toQueryKey,
4
4
  fromQueryKey,
5
+ isResourceKeyShape,
5
6
  matchesResourceKey,
6
7
  type ResourceKey,
7
8
  } from "../resource-keys.js";
@@ -172,3 +173,61 @@ describe("resource-keys: companyMdAccessRequests (per-doc identity)", () => {
172
173
  expect(matchesResourceKey(toQueryKey(key), docKey)).toBe(false);
173
174
  });
174
175
  });
176
+
177
+ describe("resource-keys: commentThreads (composite subject identity)", () => {
178
+ // The FIRST member of the union whose identity needs two segments. Every
179
+ // other key is [type, scope] or [type, scope, oneId], and `fromQueryKey`'s
180
+ // single-field path hard-asserts exactly two trailing segments — so this key
181
+ // exercises machinery nothing else does. See ADR-CONTRACTS-116.
182
+ const SUBJECT_ID = "77777777-7777-4777-8777-777777777777";
183
+ const key: ResourceKey = {
184
+ type: "commentThreads",
185
+ orgId: ORG_ID,
186
+ subjectType: "company_md",
187
+ subjectId: SUBJECT_ID,
188
+ };
189
+
190
+ it("serialises to [type, orgId, subjectType, subjectId]", () => {
191
+ const qk = toQueryKey(key);
192
+ expect(qk).toEqual(["commentThreads", ORG_ID, "company_md", SUBJECT_ID]);
193
+ expect(qk).toHaveLength(4);
194
+ });
195
+
196
+ it("round-trips through fromQueryKey", () => {
197
+ expect(fromQueryKey(toQueryKey(key))).toEqual(key);
198
+ });
199
+
200
+ it("is recognised by isResourceKeyShape", () => {
201
+ // The wire-boundary predicate the user-event schema gates
202
+ // `resource.invalidated` payloads on. It counts scope discriminators, and a
203
+ // key with two identity segments must still present exactly ONE scope —
204
+ // otherwise the coalescer drops every comment invalidation frame.
205
+ expect(isResourceKeyShape(key)).toBe(true);
206
+ });
207
+
208
+ it("discriminates two subjects of the same CLASS", () => {
209
+ const other: ResourceKey = {
210
+ ...key,
211
+ subjectId: "88888888-8888-4888-8888-888888888888",
212
+ };
213
+ expect(matchesResourceKey(toQueryKey(key), key)).toBe(true);
214
+ expect(matchesResourceKey(toQueryKey(other), key)).toBe(false);
215
+ });
216
+
217
+ it("discriminates two subjects that share an ID across CLASSES", () => {
218
+ // The reason subjectType is in the key at all. Subject ids are per-class
219
+ // uuids; without the class segment, invalidating one class's thread list
220
+ // would flush another's for a colliding id.
221
+ const other: ResourceKey = { ...key, subjectType: "work_item" };
222
+ expect(matchesResourceKey(toQueryKey(other), key)).toBe(false);
223
+ expect(matchesResourceKey(toQueryKey(key), other)).toBe(false);
224
+ });
225
+
226
+ it("refuses a query key that is missing a segment", () => {
227
+ // A three-segment key would otherwise parse as some OTHER shape and hand
228
+ // the caller a ResourceKey with an undefined subjectId.
229
+ expect(() =>
230
+ fromQueryKey(["commentThreads", ORG_ID, "company_md"]),
231
+ ).toThrow(/commentThreads/);
232
+ });
233
+ });
@@ -1,3 +1,3 @@
1
1
  // AUTO-GENERATED — do not edit. Run pnpm generate:spec-hash to regenerate.
2
- export const SPEC_HASH = 'b10dd357bc4f' as const;
3
- export const SPEC_HASH_FULL = 'b10dd357bc4fd990f9d6646954b3b1aa38f9dce4dd64ecfe8f5f83eb8f51a568' as const;
2
+ export const SPEC_HASH = '6859374aa9bc' as const;
3
+ export const SPEC_HASH_FULL = '6859374aa9bcdd861ecd151d6500ccc3a611774ffbce7830fcacbfd873393f95' as const;