@company-semantics/contracts 1.3.0 → 1.4.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.3.0",
3
+ "version": "1.4.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -12,6 +12,8 @@ import {
12
12
  OrgUnitClassificationSchema,
13
13
  OrgUnitRelationshipTypeSchema,
14
14
  OrgUnitMembershipSourceSchema,
15
+ OrgUnitPermissionsEntrySchema,
16
+ ListOrgUnitPermissionsResponseSchema,
15
17
  } from '../schemas.js';
16
18
 
17
19
  const UUID_A = '11111111-1111-4111-8111-111111111111';
@@ -200,3 +202,49 @@ describe('Enum exhaustiveness', () => {
200
202
  }
201
203
  });
202
204
  });
205
+
206
+ describe('OrgUnitPermissionsEntrySchema', () => {
207
+ const entry = {
208
+ userId: UUID_A,
209
+ membershipRole: 'manager' as const,
210
+ inheritedFromUnitId: UUID_C,
211
+ inheritedFromUnitName: 'Engineering',
212
+ };
213
+
214
+ it('accepts a well-formed entry', () => {
215
+ expect(() => OrgUnitPermissionsEntrySchema.parse(entry)).not.toThrow();
216
+ });
217
+
218
+ it('rejects invalid membershipRole', () => {
219
+ expect(() =>
220
+ OrgUnitPermissionsEntrySchema.parse({ ...entry, membershipRole: 'member' })
221
+ ).not.toThrow();
222
+ expect(() =>
223
+ OrgUnitPermissionsEntrySchema.parse({ ...entry, membershipRole: 'bogus' })
224
+ ).toThrow();
225
+ });
226
+
227
+ it('requires UUIDs for user and inherited unit', () => {
228
+ expect(() =>
229
+ OrgUnitPermissionsEntrySchema.parse({ ...entry, userId: 'nope' })
230
+ ).toThrow();
231
+ expect(() =>
232
+ OrgUnitPermissionsEntrySchema.parse({ ...entry, inheritedFromUnitId: 'nope' })
233
+ ).toThrow();
234
+ });
235
+
236
+ it('rejects empty inheritedFromUnitName', () => {
237
+ expect(() =>
238
+ OrgUnitPermissionsEntrySchema.parse({ ...entry, inheritedFromUnitName: '' })
239
+ ).toThrow();
240
+ });
241
+
242
+ it('list response wraps entries with unitId', () => {
243
+ const parsed = ListOrgUnitPermissionsResponseSchema.parse({
244
+ unitId: UUID_B,
245
+ entries: [entry],
246
+ });
247
+ expect(parsed.entries).toHaveLength(1);
248
+ expect(parsed.unitId).toBe(UUID_B);
249
+ });
250
+ });
package/src/org/index.ts CHANGED
@@ -225,6 +225,8 @@ export {
225
225
  OrgLevelConfigResponseSchema,
226
226
  OrgUnitMembershipResponseSchema,
227
227
  OrgUnitMembershipListResponseSchema,
228
+ OrgUnitPermissionsEntrySchema,
229
+ ListOrgUnitPermissionsResponseSchema,
228
230
  } from './schemas';
229
231
  export type {
230
232
  OrgUnit,
@@ -241,4 +243,6 @@ export type {
241
243
  OrgLevelConfigResponse,
242
244
  OrgUnitMembershipResponse,
243
245
  OrgUnitMembershipListResponse,
246
+ OrgUnitPermissionsEntry,
247
+ ListOrgUnitPermissionsResponse,
244
248
  } from './schemas';
@@ -756,6 +756,26 @@ export const OrgUnitMembershipListResponseSchema = z.object({
756
756
  memberships: z.array(OrgUnitMembershipSchema),
757
757
  });
758
758
 
759
+ /**
760
+ * Effective manager of an org unit — a user whose membership (direct or
761
+ * inherited from an ancestor) grants the `orgUnit.{id}.manage` capability.
762
+ *
763
+ * Direct grants have `inheritedFromUnitId === unitId`. For inherited grants,
764
+ * `inheritedFromUnitId` identifies the ancestor whose membership propagates
765
+ * authority down the subtree (ltree `path @>` containment).
766
+ */
767
+ export const OrgUnitPermissionsEntrySchema = z.object({
768
+ userId: z.string().uuid(),
769
+ membershipRole: OrgUnitMembershipRoleSchema,
770
+ inheritedFromUnitId: z.string().uuid(),
771
+ inheritedFromUnitName: z.string().min(1),
772
+ });
773
+
774
+ export const ListOrgUnitPermissionsResponseSchema = z.object({
775
+ unitId: z.string().uuid(),
776
+ entries: z.array(OrgUnitPermissionsEntrySchema),
777
+ });
778
+
759
779
  // --- Inferred types ---
760
780
 
761
781
  export type OrgUnit = z.infer<typeof OrgUnitSchema>;
@@ -772,3 +792,5 @@ export type OrgUnitRelationshipsResponse = z.infer<typeof OrgUnitRelationshipsRe
772
792
  export type OrgLevelConfigResponse = z.infer<typeof OrgLevelConfigResponseSchema>;
773
793
  export type OrgUnitMembershipResponse = z.infer<typeof OrgUnitMembershipResponseSchema>;
774
794
  export type OrgUnitMembershipListResponse = z.infer<typeof OrgUnitMembershipListResponseSchema>;
795
+ export type OrgUnitPermissionsEntry = z.infer<typeof OrgUnitPermissionsEntrySchema>;
796
+ export type ListOrgUnitPermissionsResponse = z.infer<typeof ListOrgUnitPermissionsResponseSchema>;