@company-semantics/contracts 2.16.0 → 2.18.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,3 +1,3 @@
|
|
|
1
1
|
// AUTO-GENERATED — do not edit. Run pnpm generate:spec-hash to regenerate.
|
|
2
|
-
export const SPEC_HASH = '
|
|
3
|
-
export const SPEC_HASH_FULL = '
|
|
2
|
+
export const SPEC_HASH = '3d5da96bdeb1' as const;
|
|
3
|
+
export const SPEC_HASH_FULL = '3d5da96bdeb12a1223f19d67956bfa0a481abc37813c181c0897a10c7e8f9b80' as const;
|
package/src/api/generated.ts
CHANGED
|
@@ -1815,6 +1815,23 @@ export interface paths {
|
|
|
1815
1815
|
patch?: never;
|
|
1816
1816
|
trace?: never;
|
|
1817
1817
|
};
|
|
1818
|
+
"/api/org-units/{unitId}/my-authority": {
|
|
1819
|
+
parameters: {
|
|
1820
|
+
query?: never;
|
|
1821
|
+
header?: never;
|
|
1822
|
+
path?: never;
|
|
1823
|
+
cookie?: never;
|
|
1824
|
+
};
|
|
1825
|
+
/** Get the calling actor's OrgChart role + action booleans on a unit */
|
|
1826
|
+
get: operations["getMyOrgUnitAuthority"];
|
|
1827
|
+
put?: never;
|
|
1828
|
+
post?: never;
|
|
1829
|
+
delete?: never;
|
|
1830
|
+
options?: never;
|
|
1831
|
+
head?: never;
|
|
1832
|
+
patch?: never;
|
|
1833
|
+
trace?: never;
|
|
1834
|
+
};
|
|
1818
1835
|
"/api/org-units/{unitId}/memberships": {
|
|
1819
1836
|
parameters: {
|
|
1820
1837
|
query?: never;
|
|
@@ -2553,6 +2570,57 @@ export interface paths {
|
|
|
2553
2570
|
patch?: never;
|
|
2554
2571
|
trace?: never;
|
|
2555
2572
|
};
|
|
2573
|
+
"/api/{entityType}/{id}/who-can-access": {
|
|
2574
|
+
parameters: {
|
|
2575
|
+
query?: never;
|
|
2576
|
+
header?: never;
|
|
2577
|
+
path?: never;
|
|
2578
|
+
cookie?: never;
|
|
2579
|
+
};
|
|
2580
|
+
/** List every principal with effective access to an entity (grouped by source) */
|
|
2581
|
+
get: operations["getEntityWhoCanAccess"];
|
|
2582
|
+
put?: never;
|
|
2583
|
+
post?: never;
|
|
2584
|
+
delete?: never;
|
|
2585
|
+
options?: never;
|
|
2586
|
+
head?: never;
|
|
2587
|
+
patch?: never;
|
|
2588
|
+
trace?: never;
|
|
2589
|
+
};
|
|
2590
|
+
"/api/{entityType}/{id}/recent-decisions": {
|
|
2591
|
+
parameters: {
|
|
2592
|
+
query?: never;
|
|
2593
|
+
header?: never;
|
|
2594
|
+
path?: never;
|
|
2595
|
+
cookie?: never;
|
|
2596
|
+
};
|
|
2597
|
+
/** Newest-first permission_decisions rows for an entity (introspection timeline) */
|
|
2598
|
+
get: operations["getEntityRecentDecisions"];
|
|
2599
|
+
put?: never;
|
|
2600
|
+
post?: never;
|
|
2601
|
+
delete?: never;
|
|
2602
|
+
options?: never;
|
|
2603
|
+
head?: never;
|
|
2604
|
+
patch?: never;
|
|
2605
|
+
trace?: never;
|
|
2606
|
+
};
|
|
2607
|
+
"/api/me/access-list": {
|
|
2608
|
+
parameters: {
|
|
2609
|
+
query?: never;
|
|
2610
|
+
header?: never;
|
|
2611
|
+
path?: never;
|
|
2612
|
+
cookie?: never;
|
|
2613
|
+
};
|
|
2614
|
+
/** Every effective grant for the calling user — "what can I access?" */
|
|
2615
|
+
get: operations["getMyAccessList"];
|
|
2616
|
+
put?: never;
|
|
2617
|
+
post?: never;
|
|
2618
|
+
delete?: never;
|
|
2619
|
+
options?: never;
|
|
2620
|
+
head?: never;
|
|
2621
|
+
patch?: never;
|
|
2622
|
+
trace?: never;
|
|
2623
|
+
};
|
|
2556
2624
|
"/api/internal-admin/impersonate/start": {
|
|
2557
2625
|
parameters: {
|
|
2558
2626
|
query?: never;
|
|
@@ -4011,6 +4079,16 @@ export interface components {
|
|
|
4011
4079
|
revokedAt: string | null;
|
|
4012
4080
|
reason: string | null;
|
|
4013
4081
|
};
|
|
4082
|
+
OrgUnitMyAuthorityResponse: {
|
|
4083
|
+
/** Format: uuid */
|
|
4084
|
+
unitId: string;
|
|
4085
|
+
role: ("ceo" | "leader" | "delegate" | "admin") | null;
|
|
4086
|
+
canManageMembers: boolean;
|
|
4087
|
+
canAssignDelegate: boolean;
|
|
4088
|
+
canAssignAdmin: boolean;
|
|
4089
|
+
canCreateSubUnit: boolean;
|
|
4090
|
+
canArchiveSubUnit: boolean;
|
|
4091
|
+
};
|
|
4014
4092
|
OrgUnitMembershipListResponse: {
|
|
4015
4093
|
/** Format: uuid */
|
|
4016
4094
|
unitId: string;
|
|
@@ -4507,6 +4585,50 @@ export interface components {
|
|
|
4507
4585
|
id: string;
|
|
4508
4586
|
};
|
|
4509
4587
|
};
|
|
4588
|
+
WhoCanAccessResponse: {
|
|
4589
|
+
entity_type: string;
|
|
4590
|
+
/** Format: uuid */
|
|
4591
|
+
entity_id: string;
|
|
4592
|
+
principals: {
|
|
4593
|
+
principal: {
|
|
4594
|
+
/** @enum {string} */
|
|
4595
|
+
type: "user" | "unit" | "org";
|
|
4596
|
+
/** Format: uuid */
|
|
4597
|
+
id: string;
|
|
4598
|
+
};
|
|
4599
|
+
/** @enum {string} */
|
|
4600
|
+
access_level: "owner" | "editor" | "commenter" | "viewer";
|
|
4601
|
+
/** @enum {string} */
|
|
4602
|
+
source: "explicit" | "ownership" | "visibility" | "inheritance" | "migration";
|
|
4603
|
+
}[];
|
|
4604
|
+
};
|
|
4605
|
+
RecentDecisionsResponse: {
|
|
4606
|
+
entity_type: string;
|
|
4607
|
+
/** Format: uuid */
|
|
4608
|
+
entity_id: string;
|
|
4609
|
+
rows: {
|
|
4610
|
+
/** Format: uuid */
|
|
4611
|
+
id: string;
|
|
4612
|
+
policy_name: string;
|
|
4613
|
+
actor_user_id: string | null;
|
|
4614
|
+
allow: boolean;
|
|
4615
|
+
reason: string;
|
|
4616
|
+
source_chain: ("explicit" | "ownership" | "visibility" | "inheritance" | "migration")[];
|
|
4617
|
+
/** Format: date-time */
|
|
4618
|
+
decided_at: string;
|
|
4619
|
+
}[];
|
|
4620
|
+
};
|
|
4621
|
+
MyAccessListResponse: {
|
|
4622
|
+
entries: {
|
|
4623
|
+
entity_type: string;
|
|
4624
|
+
/** Format: uuid */
|
|
4625
|
+
entity_id: string;
|
|
4626
|
+
/** @enum {string} */
|
|
4627
|
+
access_level: "owner" | "editor" | "commenter" | "viewer";
|
|
4628
|
+
/** @enum {string} */
|
|
4629
|
+
source: "explicit" | "ownership" | "visibility" | "inheritance" | "migration";
|
|
4630
|
+
}[];
|
|
4631
|
+
};
|
|
4510
4632
|
ImpersonationSessionResponse: {
|
|
4511
4633
|
session: {
|
|
4512
4634
|
impersonationSessionId: string;
|
|
@@ -7448,6 +7570,28 @@ export interface operations {
|
|
|
7448
7570
|
};
|
|
7449
7571
|
};
|
|
7450
7572
|
};
|
|
7573
|
+
getMyOrgUnitAuthority: {
|
|
7574
|
+
parameters: {
|
|
7575
|
+
query?: never;
|
|
7576
|
+
header?: never;
|
|
7577
|
+
path: {
|
|
7578
|
+
unitId: string;
|
|
7579
|
+
};
|
|
7580
|
+
cookie?: never;
|
|
7581
|
+
};
|
|
7582
|
+
requestBody?: never;
|
|
7583
|
+
responses: {
|
|
7584
|
+
/** @description Resolved OrgChartRole + the five action booleans for the calling actor on the unit */
|
|
7585
|
+
200: {
|
|
7586
|
+
headers: {
|
|
7587
|
+
[name: string]: unknown;
|
|
7588
|
+
};
|
|
7589
|
+
content: {
|
|
7590
|
+
"application/json": components["schemas"]["OrgUnitMyAuthorityResponse"];
|
|
7591
|
+
};
|
|
7592
|
+
};
|
|
7593
|
+
};
|
|
7594
|
+
};
|
|
7451
7595
|
listOrgUnitMemberships: {
|
|
7452
7596
|
parameters: {
|
|
7453
7597
|
query?: never;
|
|
@@ -8752,6 +8896,88 @@ export interface operations {
|
|
|
8752
8896
|
};
|
|
8753
8897
|
};
|
|
8754
8898
|
};
|
|
8899
|
+
getEntityWhoCanAccess: {
|
|
8900
|
+
parameters: {
|
|
8901
|
+
query?: never;
|
|
8902
|
+
header?: never;
|
|
8903
|
+
path: {
|
|
8904
|
+
entityType: string;
|
|
8905
|
+
id: string;
|
|
8906
|
+
};
|
|
8907
|
+
cookie?: never;
|
|
8908
|
+
};
|
|
8909
|
+
requestBody?: never;
|
|
8910
|
+
responses: {
|
|
8911
|
+
/** @description Effective grants for the entity — one element per (principal, source) row in effective_acl_grants */
|
|
8912
|
+
200: {
|
|
8913
|
+
headers: {
|
|
8914
|
+
[name: string]: unknown;
|
|
8915
|
+
};
|
|
8916
|
+
content: {
|
|
8917
|
+
"application/json": components["schemas"]["WhoCanAccessResponse"];
|
|
8918
|
+
};
|
|
8919
|
+
};
|
|
8920
|
+
/** @description Entity not found or caller lacks View on the entity (no-leak — the deny path 404s like the missing-entity path) */
|
|
8921
|
+
404: {
|
|
8922
|
+
headers: {
|
|
8923
|
+
[name: string]: unknown;
|
|
8924
|
+
};
|
|
8925
|
+
content?: never;
|
|
8926
|
+
};
|
|
8927
|
+
};
|
|
8928
|
+
};
|
|
8929
|
+
getEntityRecentDecisions: {
|
|
8930
|
+
parameters: {
|
|
8931
|
+
query?: {
|
|
8932
|
+
limit?: number;
|
|
8933
|
+
};
|
|
8934
|
+
header?: never;
|
|
8935
|
+
path: {
|
|
8936
|
+
entityType: string;
|
|
8937
|
+
id: string;
|
|
8938
|
+
};
|
|
8939
|
+
cookie?: never;
|
|
8940
|
+
};
|
|
8941
|
+
requestBody?: never;
|
|
8942
|
+
responses: {
|
|
8943
|
+
/** @description Newest-first permission_decisions rows for the entity (reason verbatim) */
|
|
8944
|
+
200: {
|
|
8945
|
+
headers: {
|
|
8946
|
+
[name: string]: unknown;
|
|
8947
|
+
};
|
|
8948
|
+
content: {
|
|
8949
|
+
"application/json": components["schemas"]["RecentDecisionsResponse"];
|
|
8950
|
+
};
|
|
8951
|
+
};
|
|
8952
|
+
/** @description Entity not found or caller lacks View on the entity (no-leak — the deny path 404s like the missing-entity path) */
|
|
8953
|
+
404: {
|
|
8954
|
+
headers: {
|
|
8955
|
+
[name: string]: unknown;
|
|
8956
|
+
};
|
|
8957
|
+
content?: never;
|
|
8958
|
+
};
|
|
8959
|
+
};
|
|
8960
|
+
};
|
|
8961
|
+
getMyAccessList: {
|
|
8962
|
+
parameters: {
|
|
8963
|
+
query?: never;
|
|
8964
|
+
header?: never;
|
|
8965
|
+
path?: never;
|
|
8966
|
+
cookie?: never;
|
|
8967
|
+
};
|
|
8968
|
+
requestBody?: never;
|
|
8969
|
+
responses: {
|
|
8970
|
+
/** @description Effective grants for the calling user across all sources */
|
|
8971
|
+
200: {
|
|
8972
|
+
headers: {
|
|
8973
|
+
[name: string]: unknown;
|
|
8974
|
+
};
|
|
8975
|
+
content: {
|
|
8976
|
+
"application/json": components["schemas"]["MyAccessListResponse"];
|
|
8977
|
+
};
|
|
8978
|
+
};
|
|
8979
|
+
};
|
|
8980
|
+
};
|
|
8755
8981
|
startImpersonation: {
|
|
8756
8982
|
parameters: {
|
|
8757
8983
|
query?: never;
|
package/src/permissions/index.ts
CHANGED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permission Introspection API Vocabulary
|
|
3
|
+
*
|
|
4
|
+
* Zod schemas for the AUTH-010 introspection surfaces (PRD-00678): three
|
|
5
|
+
* read-only GET routes over the AUTH-002 effective_acl_grants projection and
|
|
6
|
+
* the AUTH-006 permission_decisions audit sink.
|
|
7
|
+
*
|
|
8
|
+
* Backend routes:
|
|
9
|
+
* - GET /api/{entityType}/{id}/who-can-access
|
|
10
|
+
* - GET /api/{entityType}/{id}/recent-decisions
|
|
11
|
+
* - GET /api/me/access-list
|
|
12
|
+
*
|
|
13
|
+
* No new tables or policies — every read goes through existing infrastructure
|
|
14
|
+
* + the AUTH-006 evaluate() + assertAllowed() gate (entity-scoped routes).
|
|
15
|
+
*
|
|
16
|
+
* Per `feedback-decision-logic-must-be-visible`: reason strings + source chains
|
|
17
|
+
* flow verbatim to the UI. The schema mirrors what the evaluator records into
|
|
18
|
+
* permission_decisions; the UI never re-derives.
|
|
19
|
+
*/
|
|
20
|
+
import { z } from 'zod';
|
|
21
|
+
import { AccessLevelSchema } from './access-levels';
|
|
22
|
+
import { AccessSourceSchema } from './access-source';
|
|
23
|
+
import { PrincipalSchema } from './share-api';
|
|
24
|
+
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// WhoCanAccess — every principal with effective access to an entity.
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
export const WhoCanAccessPrincipalSchema = z.object({
|
|
30
|
+
principal: PrincipalSchema,
|
|
31
|
+
access_level: AccessLevelSchema,
|
|
32
|
+
source: AccessSourceSchema,
|
|
33
|
+
});
|
|
34
|
+
export type WhoCanAccessPrincipal = z.infer<typeof WhoCanAccessPrincipalSchema>;
|
|
35
|
+
|
|
36
|
+
export const WhoCanAccessResponseSchema = z.object({
|
|
37
|
+
entity_type: z.string(),
|
|
38
|
+
entity_id: z.string().uuid(),
|
|
39
|
+
principals: z.array(WhoCanAccessPrincipalSchema),
|
|
40
|
+
});
|
|
41
|
+
export type WhoCanAccessResponse = z.infer<typeof WhoCanAccessResponseSchema>;
|
|
42
|
+
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
// RecentDecisions — newest-first permission_decisions rows for an entity.
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
|
|
47
|
+
export const RecentDecisionSchema = z.object({
|
|
48
|
+
id: z.string().uuid(),
|
|
49
|
+
policy_name: z.string(),
|
|
50
|
+
actor_user_id: z.string().uuid().nullable(),
|
|
51
|
+
allow: z.boolean(),
|
|
52
|
+
reason: z.string(),
|
|
53
|
+
source_chain: z.array(AccessSourceSchema),
|
|
54
|
+
decided_at: z.string().datetime(),
|
|
55
|
+
});
|
|
56
|
+
export type RecentDecision = z.infer<typeof RecentDecisionSchema>;
|
|
57
|
+
|
|
58
|
+
export const RecentDecisionsResponseSchema = z.object({
|
|
59
|
+
entity_type: z.string(),
|
|
60
|
+
entity_id: z.string().uuid(),
|
|
61
|
+
rows: z.array(RecentDecisionSchema),
|
|
62
|
+
});
|
|
63
|
+
export type RecentDecisionsResponse = z.infer<typeof RecentDecisionsResponseSchema>;
|
|
64
|
+
|
|
65
|
+
export const RecentDecisionsQuerySchema = z.object({
|
|
66
|
+
limit: z.coerce.number().int().min(1).max(200).default(50),
|
|
67
|
+
});
|
|
68
|
+
export type RecentDecisionsQuery = z.infer<typeof RecentDecisionsQuerySchema>;
|
|
69
|
+
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// MyAccessList — every effective row for the calling user's principal.
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
export const MyAccessEntrySchema = z.object({
|
|
75
|
+
entity_type: z.string(),
|
|
76
|
+
entity_id: z.string().uuid(),
|
|
77
|
+
access_level: AccessLevelSchema,
|
|
78
|
+
source: AccessSourceSchema,
|
|
79
|
+
});
|
|
80
|
+
export type MyAccessEntry = z.infer<typeof MyAccessEntrySchema>;
|
|
81
|
+
|
|
82
|
+
export const MyAccessListResponseSchema = z.object({
|
|
83
|
+
entries: z.array(MyAccessEntrySchema),
|
|
84
|
+
});
|
|
85
|
+
export type MyAccessListResponse = z.infer<typeof MyAccessListResponseSchema>;
|