@company-semantics/contracts 1.8.0 → 1.10.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": "1.8.0",
3
+ "version": "1.10.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,3 +1,3 @@
1
1
  // AUTO-GENERATED — do not edit. Run pnpm generate:spec-hash to regenerate.
2
- export const SPEC_HASH = '6dcd4788f96e' as const;
3
- export const SPEC_HASH_FULL = '6dcd4788f96e0955ff7b5fcc0fa336cbaa88d3e8fced75e9f1cce650f8f8c0d7' as const;
2
+ export const SPEC_HASH = '6984169ab437' as const;
3
+ export const SPEC_HASH_FULL = '6984169ab4377753eff4a502240d80cc7504b083f7971a424943ae628dbb1fea' as const;
@@ -1553,6 +1553,23 @@ export interface paths {
1553
1553
  patch?: never;
1554
1554
  trace?: never;
1555
1555
  };
1556
+ "/api/org-units/tree": {
1557
+ parameters: {
1558
+ query?: never;
1559
+ header?: never;
1560
+ path?: never;
1561
+ cookie?: never;
1562
+ };
1563
+ /** Get the org tree (path-ordered snapshot) with level labels */
1564
+ get: operations["getOrgUnitsTree"];
1565
+ put?: never;
1566
+ post?: never;
1567
+ delete?: never;
1568
+ options?: never;
1569
+ head?: never;
1570
+ patch?: never;
1571
+ trace?: never;
1572
+ };
1556
1573
  "/api/orgs/{orgId}/tree": {
1557
1574
  parameters: {
1558
1575
  query?: never;
@@ -5728,6 +5745,26 @@ export interface operations {
5728
5745
  };
5729
5746
  };
5730
5747
  };
5748
+ getOrgUnitsTree: {
5749
+ parameters: {
5750
+ query?: never;
5751
+ header?: never;
5752
+ path?: never;
5753
+ cookie?: never;
5754
+ };
5755
+ requestBody?: never;
5756
+ responses: {
5757
+ /** @description Org tree snapshot */
5758
+ 200: {
5759
+ headers: {
5760
+ [name: string]: unknown;
5761
+ };
5762
+ content: {
5763
+ "application/json": components["schemas"]["OrgUnitTreeResponse"];
5764
+ };
5765
+ };
5766
+ };
5767
+ };
5731
5768
  getOrgTree: {
5732
5769
  parameters: {
5733
5770
  query?: never;
@@ -128,17 +128,24 @@ describe('OrgUnitRelationshipSchema', () => {
128
128
  });
129
129
 
130
130
  describe('OrgLevelConfigSchema', () => {
131
- it('enforces depth 1..5 and non-empty label', () => {
131
+ it('enforces depth 1..5, non-empty-when-present label, and icon enum', () => {
132
132
  const entry = {
133
133
  orgId: UUID_B,
134
134
  depth: 2,
135
135
  label: 'Department',
136
+ icon: 'users-four' as const,
136
137
  createdAt: '2026-04-17T00:00:00Z',
137
138
  updatedAt: '2026-04-17T00:00:00Z',
138
139
  };
139
140
  expect(() => OrgLevelConfigSchema.parse(entry)).not.toThrow();
141
+ expect(() =>
142
+ OrgLevelConfigSchema.parse({ ...entry, label: null, icon: null })
143
+ ).not.toThrow();
140
144
  expect(() => OrgLevelConfigSchema.parse({ ...entry, depth: 6 })).toThrow();
141
145
  expect(() => OrgLevelConfigSchema.parse({ ...entry, label: '' })).toThrow();
146
+ expect(() =>
147
+ OrgLevelConfigSchema.parse({ ...entry, icon: 'not-an-icon' })
148
+ ).toThrow();
142
149
  });
143
150
  });
144
151
 
package/src/org/index.ts CHANGED
@@ -204,7 +204,9 @@ export type {
204
204
  OrgUnitMembershipStatus,
205
205
  OrgUnitMembershipSource,
206
206
  OrgUnitErrorCode,
207
+ OrgTreeResponse,
207
208
  } from './org-units';
209
+ export { ORG_UNITS_ROUTES } from './org-units';
208
210
  export {
209
211
  OrgUnitClassificationSchema,
210
212
  OrgUnitSyncModeSchema,
@@ -220,6 +222,7 @@ export {
220
222
  OrgUnitMembershipSchema,
221
223
  OrgUnitRelationshipSchema,
222
224
  OrgLevelConfigSchema,
225
+ OrgLevelIconSchema,
223
226
  OrgUnitResponseSchema,
224
227
  OrgUnitTreeResponseSchema,
225
228
  OrgUnitChildrenResponseSchema,
@@ -238,6 +241,7 @@ export type {
238
241
  OrgUnitMembership,
239
242
  OrgUnitRelationship,
240
243
  OrgLevelConfig,
244
+ OrgLevelIcon,
241
245
  OrgUnitResponse,
242
246
  OrgUnitTreeResponse,
243
247
  OrgUnitChildrenResponse,
@@ -45,6 +45,48 @@ export type OrgUnitMembershipStatus = 'active' | 'pending' | 'removed';
45
45
  /** External directory origin of a membership row. */
46
46
  export type OrgUnitMembershipSource = 'manual' | 'google_groups' | 'scim' | 'hris';
47
47
 
48
+ /**
49
+ * Canonical route path constants for the `/api/org-units` surface.
50
+ *
51
+ * Consumers (backend route handlers, app hooks, typed clients) MUST import
52
+ * these rather than inlining path literals so a single rename stays
53
+ * consistent across the system. Parameterised paths are exposed as
54
+ * functions so callers cannot forget to interpolate the id.
55
+ *
56
+ * `tree` returns an `OrgTreeResponse` (alias for `OrgUnitTreeResponse`,
57
+ * shape `{ nodes, levelConfig }` — see `./schemas`).
58
+ *
59
+ * Used by PRD-00511 to consolidate the legacy `/api/org-tree` handler
60
+ * into `/api/org-units/tree` without changing the response shape.
61
+ */
62
+ export const ORG_UNITS_ROUTES = {
63
+ list: '/api/org-units',
64
+ tree: '/api/org-units/tree',
65
+ byId: (unitId: string) => `/api/org-units/${unitId}`,
66
+ children: (unitId: string) => `/api/org-units/${unitId}/children`,
67
+ ancestors: (unitId: string) => `/api/org-units/${unitId}/ancestors`,
68
+ descendants: (unitId: string) => `/api/org-units/${unitId}/descendants`,
69
+ archive: (unitId: string) => `/api/org-units/${unitId}/archive`,
70
+ reparent: (unitId: string) => `/api/org-units/${unitId}/reparent`,
71
+ reorder: (unitId: string) => `/api/org-units/${unitId}/reorder`,
72
+ relationships: (unitId: string) => `/api/org-units/${unitId}/relationships`,
73
+ memberships: (unitId: string) => `/api/org-units/${unitId}/memberships`,
74
+ membershipByUser: (unitId: string, userId: string) =>
75
+ `/api/org-units/${unitId}/memberships/${userId}`,
76
+ membershipRole: (unitId: string, userId: string) =>
77
+ `/api/org-units/${unitId}/memberships/${userId}/role`,
78
+ permissions: (unitId: string) => `/api/org-units/${unitId}/permissions`,
79
+ } as const;
80
+
81
+ /**
82
+ * Domain-level alias for the tree endpoint response type.
83
+ *
84
+ * The canonical schema lives in `./schemas` as `OrgUnitTreeResponseSchema`
85
+ * / `OrgUnitTreeResponse`. This alias gives consumers the shorter
86
+ * `OrgTreeResponse` name used by `GET /api/org-units/tree`.
87
+ */
88
+ export type { OrgUnitTreeResponse as OrgTreeResponse } from './schemas';
89
+
48
90
  /**
49
91
  * Error codes returned by `POST /api/org-units/:id/reparent` and related
50
92
  * mutation endpoints. Clients must handle these explicitly.
@@ -707,10 +707,19 @@ export const OrgUnitRelationshipSchema = z.object({
707
707
  createdAt: z.string(),
708
708
  });
709
709
 
710
+ export const OrgLevelIconSchema = z.enum([
711
+ 'city',
712
+ 'buildings',
713
+ 'users-four',
714
+ 'users-three',
715
+ 'users',
716
+ ]);
717
+
710
718
  export const OrgLevelConfigSchema = z.object({
711
719
  orgId: z.string().uuid(),
712
720
  depth: z.number().int().min(1).max(5),
713
- label: z.string().min(1),
721
+ label: z.string().min(1).nullable(),
722
+ icon: OrgLevelIconSchema.nullable(),
714
723
  createdAt: z.string(),
715
724
  updatedAt: z.string(),
716
725
  });
@@ -785,6 +794,7 @@ export type OrgUnitTreeNode = z.infer<typeof OrgUnitTreeNodeSchema>;
785
794
  export type OrgUnitMembership = z.infer<typeof OrgUnitMembershipSchema>;
786
795
  export type OrgUnitRelationship = z.infer<typeof OrgUnitRelationshipSchema>;
787
796
  export type OrgLevelConfig = z.infer<typeof OrgLevelConfigSchema>;
797
+ export type OrgLevelIcon = z.infer<typeof OrgLevelIconSchema>;
788
798
  export type OrgUnitResponse = z.infer<typeof OrgUnitResponseSchema>;
789
799
  export type OrgUnitTreeResponse = z.infer<typeof OrgUnitTreeResponseSchema>;
790
800
  export type OrgUnitChildrenResponse = z.infer<typeof OrgUnitChildrenResponseSchema>;