@inkeep/agents-core 0.0.0-dev-20260118170655 → 0.0.0-dev-20260119170007
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/dist/auth/auth-schema.d.ts +82 -82
- package/dist/auth/auth-validation-schemas.d.ts +146 -146
- package/dist/auth/auth.d.ts +78 -18
- package/dist/auth/auth.js +46 -0
- package/dist/auth/authz/client.d.ts +81 -0
- package/dist/auth/authz/client.js +189 -0
- package/dist/auth/authz/config.d.ts +76 -0
- package/dist/auth/authz/config.js +76 -0
- package/dist/auth/authz/index.d.ts +5 -0
- package/dist/auth/authz/index.js +6 -0
- package/dist/auth/authz/permissions.d.ts +57 -0
- package/dist/auth/authz/permissions.js +83 -0
- package/dist/auth/authz/sync.d.ts +85 -0
- package/dist/auth/authz/sync.js +237 -0
- package/dist/auth/permissions.d.ts +13 -13
- package/dist/auth/permissions.js +2 -181
- package/dist/client-exports.d.ts +1 -0
- package/dist/data-access/manage/agentFull.js +51 -2
- package/dist/data-access/manage/projectLifecycle.d.ts +1 -0
- package/dist/data-access/manage/projectLifecycle.js +3 -2
- package/dist/data-access/manage/projects.d.ts +4 -0
- package/dist/data-access/manage/projects.js +11 -4
- package/dist/data-access/runtime/conversations.d.ts +7 -7
- package/dist/data-access/runtime/messages.d.ts +9 -9
- package/dist/data-access/runtime/projects.d.ts +2 -0
- package/dist/data-access/runtime/projects.js +16 -2
- package/dist/data-access/runtime/tasks.d.ts +4 -4
- package/dist/db/manage/manage-schema.d.ts +360 -360
- package/dist/db/runtime/runtime-schema.d.ts +169 -169
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/dist/validation/dolt-schemas.d.ts +1 -1
- package/dist/validation/drizzle-schema-helpers.d.ts +3 -3
- package/dist/validation/schemas.d.ts +1180 -1180
- package/package.json +6 -1
package/dist/auth/auth.d.ts
CHANGED
|
@@ -846,25 +846,25 @@ declare function createAuth(config: BetterAuthConfig): better_auth0.Auth<{
|
|
|
846
846
|
ac: better_auth_plugins0.AccessControl;
|
|
847
847
|
roles: {
|
|
848
848
|
member: {
|
|
849
|
-
authorize<K_1 extends "
|
|
850
|
-
actions: better_auth_plugins0.Subset<"
|
|
849
|
+
authorize<K_1 extends "organization" | "ac" | "member" | "project" | "team" | "invitation">(request: K_1 extends infer T extends K ? { [key in T]?: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>[key] | {
|
|
850
|
+
actions: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>[key];
|
|
851
851
|
connector: "OR" | "AND";
|
|
852
852
|
} | undefined } : never, connector?: "OR" | "AND"): better_auth_plugins0.AuthorizeResponse;
|
|
853
|
-
statements: better_auth_plugins0.Subset<"
|
|
853
|
+
statements: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>;
|
|
854
854
|
};
|
|
855
855
|
admin: {
|
|
856
|
-
authorize<K_1 extends "
|
|
857
|
-
actions: better_auth_plugins0.Subset<"
|
|
856
|
+
authorize<K_1 extends "organization" | "ac" | "member" | "project" | "team" | "invitation">(request: K_1 extends infer T extends K ? { [key in T]?: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>[key] | {
|
|
857
|
+
actions: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>[key];
|
|
858
858
|
connector: "OR" | "AND";
|
|
859
859
|
} | undefined } : never, connector?: "OR" | "AND"): better_auth_plugins0.AuthorizeResponse;
|
|
860
|
-
statements: better_auth_plugins0.Subset<"
|
|
860
|
+
statements: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>;
|
|
861
861
|
};
|
|
862
862
|
owner: {
|
|
863
|
-
authorize<K_1 extends "
|
|
864
|
-
actions: better_auth_plugins0.Subset<"
|
|
863
|
+
authorize<K_1 extends "organization" | "ac" | "member" | "project" | "team" | "invitation">(request: K_1 extends infer T extends K ? { [key in T]?: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>[key] | {
|
|
864
|
+
actions: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>[key];
|
|
865
865
|
connector: "OR" | "AND";
|
|
866
866
|
} | undefined } : never, connector?: "OR" | "AND"): better_auth_plugins0.AuthorizeResponse;
|
|
867
|
-
statements: better_auth_plugins0.Subset<"
|
|
867
|
+
statements: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>;
|
|
868
868
|
};
|
|
869
869
|
};
|
|
870
870
|
membershipLimit: number;
|
|
@@ -880,6 +880,36 @@ declare function createAuth(config: BetterAuthConfig): better_auth0.Auth<{
|
|
|
880
880
|
user: better_auth0.User;
|
|
881
881
|
};
|
|
882
882
|
}): Promise<void>;
|
|
883
|
+
organizationHooks: {
|
|
884
|
+
afterAcceptInvitation: ({
|
|
885
|
+
member,
|
|
886
|
+
user,
|
|
887
|
+
organization: org
|
|
888
|
+
}: {
|
|
889
|
+
invitation: better_auth_plugins0.Invitation & Record<string, any>;
|
|
890
|
+
member: better_auth_plugins0.Member & Record<string, any>;
|
|
891
|
+
user: better_auth0.User & Record<string, any>;
|
|
892
|
+
organization: better_auth_plugins0.Organization & Record<string, any>;
|
|
893
|
+
}) => Promise<void>;
|
|
894
|
+
afterUpdateMemberRole: ({
|
|
895
|
+
member,
|
|
896
|
+
organization: org,
|
|
897
|
+
previousRole
|
|
898
|
+
}: {
|
|
899
|
+
member: better_auth_plugins0.Member & Record<string, any>;
|
|
900
|
+
previousRole: string;
|
|
901
|
+
user: better_auth0.User & Record<string, any>;
|
|
902
|
+
organization: better_auth_plugins0.Organization & Record<string, any>;
|
|
903
|
+
}) => Promise<void>;
|
|
904
|
+
afterRemoveMember: ({
|
|
905
|
+
member,
|
|
906
|
+
organization: org
|
|
907
|
+
}: {
|
|
908
|
+
member: better_auth_plugins0.Member & Record<string, any>;
|
|
909
|
+
user: better_auth0.User & Record<string, any>;
|
|
910
|
+
organization: better_auth_plugins0.Organization & Record<string, any>;
|
|
911
|
+
}) => Promise<void>;
|
|
912
|
+
};
|
|
883
913
|
}>;
|
|
884
914
|
schema: {
|
|
885
915
|
organization: {
|
|
@@ -1125,25 +1155,25 @@ declare function createAuth(config: BetterAuthConfig): better_auth0.Auth<{
|
|
|
1125
1155
|
ac: better_auth_plugins0.AccessControl;
|
|
1126
1156
|
roles: {
|
|
1127
1157
|
member: {
|
|
1128
|
-
authorize<K_1 extends "
|
|
1129
|
-
actions: better_auth_plugins0.Subset<"
|
|
1158
|
+
authorize<K_1 extends "organization" | "ac" | "member" | "project" | "team" | "invitation">(request: K_1 extends infer T extends K ? { [key in T]?: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>[key] | {
|
|
1159
|
+
actions: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>[key];
|
|
1130
1160
|
connector: "OR" | "AND";
|
|
1131
1161
|
} | undefined } : never, connector?: "OR" | "AND"): better_auth_plugins0.AuthorizeResponse;
|
|
1132
|
-
statements: better_auth_plugins0.Subset<"
|
|
1162
|
+
statements: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>;
|
|
1133
1163
|
};
|
|
1134
1164
|
admin: {
|
|
1135
|
-
authorize<K_1 extends "
|
|
1136
|
-
actions: better_auth_plugins0.Subset<"
|
|
1165
|
+
authorize<K_1 extends "organization" | "ac" | "member" | "project" | "team" | "invitation">(request: K_1 extends infer T extends K ? { [key in T]?: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>[key] | {
|
|
1166
|
+
actions: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>[key];
|
|
1137
1167
|
connector: "OR" | "AND";
|
|
1138
1168
|
} | undefined } : never, connector?: "OR" | "AND"): better_auth_plugins0.AuthorizeResponse;
|
|
1139
|
-
statements: better_auth_plugins0.Subset<"
|
|
1169
|
+
statements: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>;
|
|
1140
1170
|
};
|
|
1141
1171
|
owner: {
|
|
1142
|
-
authorize<K_1 extends "
|
|
1143
|
-
actions: better_auth_plugins0.Subset<"
|
|
1172
|
+
authorize<K_1 extends "organization" | "ac" | "member" | "project" | "team" | "invitation">(request: K_1 extends infer T extends K ? { [key in T]?: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>[key] | {
|
|
1173
|
+
actions: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>[key];
|
|
1144
1174
|
connector: "OR" | "AND";
|
|
1145
1175
|
} | undefined } : never, connector?: "OR" | "AND"): better_auth_plugins0.AuthorizeResponse;
|
|
1146
|
-
statements: better_auth_plugins0.Subset<"
|
|
1176
|
+
statements: better_auth_plugins0.Subset<"organization" | "ac" | "member" | "project" | "team" | "invitation", better_auth_plugins0.Statements>;
|
|
1147
1177
|
};
|
|
1148
1178
|
};
|
|
1149
1179
|
membershipLimit: number;
|
|
@@ -1159,6 +1189,36 @@ declare function createAuth(config: BetterAuthConfig): better_auth0.Auth<{
|
|
|
1159
1189
|
user: better_auth0.User;
|
|
1160
1190
|
};
|
|
1161
1191
|
}): Promise<void>;
|
|
1192
|
+
organizationHooks: {
|
|
1193
|
+
afterAcceptInvitation: ({
|
|
1194
|
+
member,
|
|
1195
|
+
user,
|
|
1196
|
+
organization: org
|
|
1197
|
+
}: {
|
|
1198
|
+
invitation: better_auth_plugins0.Invitation & Record<string, any>;
|
|
1199
|
+
member: better_auth_plugins0.Member & Record<string, any>;
|
|
1200
|
+
user: better_auth0.User & Record<string, any>;
|
|
1201
|
+
organization: better_auth_plugins0.Organization & Record<string, any>;
|
|
1202
|
+
}) => Promise<void>;
|
|
1203
|
+
afterUpdateMemberRole: ({
|
|
1204
|
+
member,
|
|
1205
|
+
organization: org,
|
|
1206
|
+
previousRole
|
|
1207
|
+
}: {
|
|
1208
|
+
member: better_auth_plugins0.Member & Record<string, any>;
|
|
1209
|
+
previousRole: string;
|
|
1210
|
+
user: better_auth0.User & Record<string, any>;
|
|
1211
|
+
organization: better_auth_plugins0.Organization & Record<string, any>;
|
|
1212
|
+
}) => Promise<void>;
|
|
1213
|
+
afterRemoveMember: ({
|
|
1214
|
+
member,
|
|
1215
|
+
organization: org
|
|
1216
|
+
}: {
|
|
1217
|
+
member: better_auth_plugins0.Member & Record<string, any>;
|
|
1218
|
+
user: better_auth0.User & Record<string, any>;
|
|
1219
|
+
organization: better_auth_plugins0.Organization & Record<string, any>;
|
|
1220
|
+
}) => Promise<void>;
|
|
1221
|
+
};
|
|
1162
1222
|
}>;
|
|
1163
1223
|
}, {
|
|
1164
1224
|
id: "device-authorization";
|
package/dist/auth/auth.js
CHANGED
|
@@ -139,6 +139,52 @@ function createAuth(config) {
|
|
|
139
139
|
organization: data.organization.name,
|
|
140
140
|
invitationId: data.id
|
|
141
141
|
});
|
|
142
|
+
},
|
|
143
|
+
organizationHooks: {
|
|
144
|
+
afterAcceptInvitation: async ({ member: member$1, user, organization: org }) => {
|
|
145
|
+
try {
|
|
146
|
+
const { syncOrgMemberToSpiceDb } = await import("./authz/sync.js");
|
|
147
|
+
await syncOrgMemberToSpiceDb({
|
|
148
|
+
tenantId: org.id,
|
|
149
|
+
userId: user.id,
|
|
150
|
+
role: member$1.role,
|
|
151
|
+
action: "add"
|
|
152
|
+
});
|
|
153
|
+
console.log(`🔐 SpiceDB: Synced member ${user.email} as ${member$1.role} to org ${org.name}`);
|
|
154
|
+
} catch (error) {
|
|
155
|
+
console.error("❌ SpiceDB sync failed for new member:", error);
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
afterUpdateMemberRole: async ({ member: member$1, organization: org, previousRole }) => {
|
|
159
|
+
try {
|
|
160
|
+
const { changeOrgRole } = await import("./authz/sync.js");
|
|
161
|
+
const oldRole = previousRole;
|
|
162
|
+
const newRole = member$1.role;
|
|
163
|
+
await changeOrgRole({
|
|
164
|
+
tenantId: org.id,
|
|
165
|
+
userId: member$1.userId,
|
|
166
|
+
oldRole,
|
|
167
|
+
newRole
|
|
168
|
+
});
|
|
169
|
+
console.log(`🔐 SpiceDB: Updated member ${member$1.userId} role from ${oldRole} to ${newRole} in org ${org.name}`);
|
|
170
|
+
} catch (error) {
|
|
171
|
+
console.error("❌ SpiceDB sync failed for role update:", error);
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
afterRemoveMember: async ({ member: member$1, organization: org }) => {
|
|
175
|
+
try {
|
|
176
|
+
const { syncOrgMemberToSpiceDb } = await import("./authz/sync.js");
|
|
177
|
+
await syncOrgMemberToSpiceDb({
|
|
178
|
+
tenantId: org.id,
|
|
179
|
+
userId: member$1.userId,
|
|
180
|
+
role: member$1.role,
|
|
181
|
+
action: "remove"
|
|
182
|
+
});
|
|
183
|
+
console.log(`🔐 SpiceDB: Removed member ${member$1.userId} from org ${org.name}`);
|
|
184
|
+
} catch (error) {
|
|
185
|
+
console.error("❌ SpiceDB sync failed for member removal:", error);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
142
188
|
}
|
|
143
189
|
}),
|
|
144
190
|
deviceAuthorization({
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { v1 } from "@authzed/authzed-node";
|
|
2
|
+
|
|
3
|
+
//#region src/auth/authz/client.d.ts
|
|
4
|
+
|
|
5
|
+
type ZedClientInterface = ReturnType<typeof v1.NewClient>;
|
|
6
|
+
/**
|
|
7
|
+
* Get the SpiceDB client singleton.
|
|
8
|
+
* Creates a new client on first call.
|
|
9
|
+
*/
|
|
10
|
+
declare function getSpiceClient(): ZedClientInterface;
|
|
11
|
+
/**
|
|
12
|
+
* Reset the client (useful for testing)
|
|
13
|
+
*/
|
|
14
|
+
declare function resetSpiceClient(): void;
|
|
15
|
+
/**
|
|
16
|
+
* Check if a subject has a permission on a resource.
|
|
17
|
+
* Note: Caller must verify isAuthzEnabled(tenantId) before calling.
|
|
18
|
+
*/
|
|
19
|
+
declare function checkPermission(params: {
|
|
20
|
+
resourceType: string;
|
|
21
|
+
resourceId: string;
|
|
22
|
+
permission: string;
|
|
23
|
+
subjectType: string;
|
|
24
|
+
subjectId: string;
|
|
25
|
+
}): Promise<boolean>;
|
|
26
|
+
/**
|
|
27
|
+
* Check multiple permissions on a resource in a single request.
|
|
28
|
+
* More efficient than multiple checkPermission calls.
|
|
29
|
+
*
|
|
30
|
+
* @returns Record mapping permission names to boolean results
|
|
31
|
+
*/
|
|
32
|
+
declare function checkBulkPermissions(params: {
|
|
33
|
+
resourceType: string;
|
|
34
|
+
resourceId: string;
|
|
35
|
+
permissions: string[];
|
|
36
|
+
subjectType: string;
|
|
37
|
+
subjectId: string;
|
|
38
|
+
}): Promise<Record<string, boolean>>;
|
|
39
|
+
/**
|
|
40
|
+
* Find all resources of a type that a subject has a permission on.
|
|
41
|
+
*/
|
|
42
|
+
declare function lookupResources(params: {
|
|
43
|
+
resourceType: string;
|
|
44
|
+
permission: string;
|
|
45
|
+
subjectType: string;
|
|
46
|
+
subjectId: string;
|
|
47
|
+
}): Promise<string[]>;
|
|
48
|
+
/**
|
|
49
|
+
* Write a relationship to SpiceDB.
|
|
50
|
+
*/
|
|
51
|
+
declare function writeRelationship(params: {
|
|
52
|
+
resourceType: string;
|
|
53
|
+
resourceId: string;
|
|
54
|
+
relation: string;
|
|
55
|
+
subjectType: string;
|
|
56
|
+
subjectId: string;
|
|
57
|
+
}): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Delete a relationship from SpiceDB.
|
|
60
|
+
*/
|
|
61
|
+
declare function deleteRelationship(params: {
|
|
62
|
+
resourceType: string;
|
|
63
|
+
resourceId: string;
|
|
64
|
+
relation: string;
|
|
65
|
+
subjectType: string;
|
|
66
|
+
subjectId: string;
|
|
67
|
+
}): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Read relationships for a resource to list subjects with access.
|
|
70
|
+
*/
|
|
71
|
+
declare function readRelationships(params: {
|
|
72
|
+
resourceType: string;
|
|
73
|
+
resourceId: string;
|
|
74
|
+
relation?: string;
|
|
75
|
+
}): Promise<Array<{
|
|
76
|
+
subjectType: string;
|
|
77
|
+
subjectId: string;
|
|
78
|
+
relation: string;
|
|
79
|
+
}>>;
|
|
80
|
+
//#endregion
|
|
81
|
+
export { checkBulkPermissions, checkPermission, deleteRelationship, getSpiceClient, lookupResources, readRelationships, resetSpiceClient, v1, writeRelationship };
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { getSpiceDbConfig } from "./config.js";
|
|
2
|
+
import { v1 } from "@authzed/authzed-node";
|
|
3
|
+
|
|
4
|
+
//#region src/auth/authz/client.ts
|
|
5
|
+
/**
|
|
6
|
+
* SpiceDB Client Wrapper
|
|
7
|
+
*
|
|
8
|
+
* Provides a singleton SpiceDB client and helper functions for common operations.
|
|
9
|
+
*/
|
|
10
|
+
let client = null;
|
|
11
|
+
/**
|
|
12
|
+
* Get the SpiceDB client singleton.
|
|
13
|
+
* Creates a new client on first call.
|
|
14
|
+
*/
|
|
15
|
+
function getSpiceClient() {
|
|
16
|
+
if (!client) {
|
|
17
|
+
const config = getSpiceDbConfig();
|
|
18
|
+
client = v1.NewClient(config.token, config.endpoint, config.tlsEnabled ? v1.ClientSecurity.SECURE : v1.ClientSecurity.INSECURE_LOCALHOST_ALLOWED);
|
|
19
|
+
}
|
|
20
|
+
return client;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Reset the client (useful for testing)
|
|
24
|
+
*/
|
|
25
|
+
function resetSpiceClient() {
|
|
26
|
+
client = null;
|
|
27
|
+
}
|
|
28
|
+
const PERMISSIONSHIP_HAS_PERMISSION = 2;
|
|
29
|
+
const RELATIONSHIP_OPERATION_CREATE = 1;
|
|
30
|
+
/**
|
|
31
|
+
* Check if a subject has a permission on a resource.
|
|
32
|
+
* Note: Caller must verify isAuthzEnabled(tenantId) before calling.
|
|
33
|
+
*/
|
|
34
|
+
async function checkPermission(params) {
|
|
35
|
+
return (await getSpiceClient().promises.checkPermission({
|
|
36
|
+
resource: {
|
|
37
|
+
objectType: params.resourceType,
|
|
38
|
+
objectId: params.resourceId
|
|
39
|
+
},
|
|
40
|
+
permission: params.permission,
|
|
41
|
+
subject: {
|
|
42
|
+
object: {
|
|
43
|
+
objectType: params.subjectType,
|
|
44
|
+
objectId: params.subjectId
|
|
45
|
+
},
|
|
46
|
+
optionalRelation: ""
|
|
47
|
+
},
|
|
48
|
+
consistency: { requirement: {
|
|
49
|
+
oneofKind: "minimizeLatency",
|
|
50
|
+
minimizeLatency: true
|
|
51
|
+
} },
|
|
52
|
+
context: void 0,
|
|
53
|
+
withTracing: false
|
|
54
|
+
})).permissionship === PERMISSIONSHIP_HAS_PERMISSION;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Check multiple permissions on a resource in a single request.
|
|
58
|
+
* More efficient than multiple checkPermission calls.
|
|
59
|
+
*
|
|
60
|
+
* @returns Record mapping permission names to boolean results
|
|
61
|
+
*/
|
|
62
|
+
async function checkBulkPermissions(params) {
|
|
63
|
+
const spice = getSpiceClient();
|
|
64
|
+
const items = params.permissions.map((permission) => v1.CheckBulkPermissionsRequestItem.create({
|
|
65
|
+
resource: v1.ObjectReference.create({
|
|
66
|
+
objectType: params.resourceType,
|
|
67
|
+
objectId: params.resourceId
|
|
68
|
+
}),
|
|
69
|
+
permission,
|
|
70
|
+
subject: v1.SubjectReference.create({ object: v1.ObjectReference.create({
|
|
71
|
+
objectType: params.subjectType,
|
|
72
|
+
objectId: params.subjectId
|
|
73
|
+
}) })
|
|
74
|
+
}));
|
|
75
|
+
const response = await spice.promises.checkBulkPermissions(v1.CheckBulkPermissionsRequest.create({
|
|
76
|
+
items,
|
|
77
|
+
consistency: { requirement: {
|
|
78
|
+
oneofKind: "minimizeLatency",
|
|
79
|
+
minimizeLatency: true
|
|
80
|
+
} }
|
|
81
|
+
}));
|
|
82
|
+
const result = {};
|
|
83
|
+
for (let i = 0; i < params.permissions.length; i++) {
|
|
84
|
+
const permission = params.permissions[i];
|
|
85
|
+
const pair = response.pairs[i];
|
|
86
|
+
if (pair.response.oneofKind === "item") result[permission] = pair.response.item.permissionship === PERMISSIONSHIP_HAS_PERMISSION;
|
|
87
|
+
else result[permission] = false;
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Find all resources of a type that a subject has a permission on.
|
|
93
|
+
*/
|
|
94
|
+
async function lookupResources(params) {
|
|
95
|
+
return (await getSpiceClient().promises.lookupResources({
|
|
96
|
+
resourceObjectType: params.resourceType,
|
|
97
|
+
permission: params.permission,
|
|
98
|
+
subject: {
|
|
99
|
+
object: {
|
|
100
|
+
objectType: params.subjectType,
|
|
101
|
+
objectId: params.subjectId
|
|
102
|
+
},
|
|
103
|
+
optionalRelation: ""
|
|
104
|
+
},
|
|
105
|
+
consistency: { requirement: {
|
|
106
|
+
oneofKind: "minimizeLatency",
|
|
107
|
+
minimizeLatency: true
|
|
108
|
+
} },
|
|
109
|
+
context: void 0,
|
|
110
|
+
optionalLimit: 0,
|
|
111
|
+
optionalCursor: void 0
|
|
112
|
+
})).map((item) => item.resourceObjectId);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Write a relationship to SpiceDB.
|
|
116
|
+
*/
|
|
117
|
+
async function writeRelationship(params) {
|
|
118
|
+
await getSpiceClient().promises.writeRelationships({
|
|
119
|
+
updates: [{
|
|
120
|
+
operation: RELATIONSHIP_OPERATION_CREATE,
|
|
121
|
+
relationship: {
|
|
122
|
+
resource: {
|
|
123
|
+
objectType: params.resourceType,
|
|
124
|
+
objectId: params.resourceId
|
|
125
|
+
},
|
|
126
|
+
relation: params.relation,
|
|
127
|
+
subject: {
|
|
128
|
+
object: {
|
|
129
|
+
objectType: params.subjectType,
|
|
130
|
+
objectId: params.subjectId
|
|
131
|
+
},
|
|
132
|
+
optionalRelation: ""
|
|
133
|
+
},
|
|
134
|
+
optionalCaveat: void 0
|
|
135
|
+
}
|
|
136
|
+
}],
|
|
137
|
+
optionalPreconditions: [],
|
|
138
|
+
optionalTransactionMetadata: void 0
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Delete a relationship from SpiceDB.
|
|
143
|
+
*/
|
|
144
|
+
async function deleteRelationship(params) {
|
|
145
|
+
await getSpiceClient().promises.deleteRelationships({
|
|
146
|
+
relationshipFilter: {
|
|
147
|
+
resourceType: params.resourceType,
|
|
148
|
+
optionalResourceId: params.resourceId,
|
|
149
|
+
optionalResourceIdPrefix: "",
|
|
150
|
+
optionalRelation: params.relation,
|
|
151
|
+
optionalSubjectFilter: {
|
|
152
|
+
subjectType: params.subjectType,
|
|
153
|
+
optionalSubjectId: params.subjectId,
|
|
154
|
+
optionalRelation: void 0
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
optionalPreconditions: [],
|
|
158
|
+
optionalLimit: 0,
|
|
159
|
+
optionalAllowPartialDeletions: false,
|
|
160
|
+
optionalTransactionMetadata: void 0
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Read relationships for a resource to list subjects with access.
|
|
165
|
+
*/
|
|
166
|
+
async function readRelationships(params) {
|
|
167
|
+
return (await getSpiceClient().promises.readRelationships({
|
|
168
|
+
relationshipFilter: {
|
|
169
|
+
resourceType: params.resourceType,
|
|
170
|
+
optionalResourceId: params.resourceId,
|
|
171
|
+
optionalResourceIdPrefix: "",
|
|
172
|
+
optionalRelation: params.relation || "",
|
|
173
|
+
optionalSubjectFilter: void 0
|
|
174
|
+
},
|
|
175
|
+
consistency: { requirement: {
|
|
176
|
+
oneofKind: "minimizeLatency",
|
|
177
|
+
minimizeLatency: true
|
|
178
|
+
} },
|
|
179
|
+
optionalLimit: 0,
|
|
180
|
+
optionalCursor: void 0
|
|
181
|
+
})).map((item) => ({
|
|
182
|
+
subjectType: item.relationship?.subject?.object?.objectType || "",
|
|
183
|
+
subjectId: item.relationship?.subject?.object?.objectId || "",
|
|
184
|
+
relation: item.relationship?.relation || ""
|
|
185
|
+
}));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
//#endregion
|
|
189
|
+
export { checkBulkPermissions, checkPermission, deleteRelationship, getSpiceClient, lookupResources, readRelationships, resetSpiceClient, v1, writeRelationship };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
//#region src/auth/authz/config.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* SpiceDB Authorization Configuration
|
|
4
|
+
*
|
|
5
|
+
* Feature flag and configuration for the SpiceDB authorization system.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Check if authorization is enabled.
|
|
9
|
+
*
|
|
10
|
+
* When called without tenantId:
|
|
11
|
+
* - Returns true if ENABLE_AUTHZ=true
|
|
12
|
+
*
|
|
13
|
+
* When called with tenantId:
|
|
14
|
+
* - If ENABLE_AUTHZ=false → returns false
|
|
15
|
+
* - If ENABLE_AUTHZ=true and TENANT_ID is not set → returns true (all tenants)
|
|
16
|
+
* - If ENABLE_AUTHZ=true and TENANT_ID is set → returns true only if tenantId matches
|
|
17
|
+
*/
|
|
18
|
+
declare function isAuthzEnabled(tenantId: string): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Get SpiceDB connection configuration from environment variables.
|
|
21
|
+
*/
|
|
22
|
+
declare function getSpiceDbConfig(): {
|
|
23
|
+
endpoint: string;
|
|
24
|
+
token: string;
|
|
25
|
+
tlsEnabled: boolean;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* SpiceDB resource types used in the schema
|
|
29
|
+
*/
|
|
30
|
+
declare const SpiceDbResourceTypes: {
|
|
31
|
+
readonly USER: "user";
|
|
32
|
+
readonly ORGANIZATION: "organization";
|
|
33
|
+
readonly PROJECT: "project";
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* SpiceDB relations used in the schema
|
|
37
|
+
*
|
|
38
|
+
* Relations are named as nouns (roles) per SpiceDB best practices.
|
|
39
|
+
* Project roles are prefixed for clarity when debugging/grepping.
|
|
40
|
+
*/
|
|
41
|
+
declare const SpiceDbRelations: {
|
|
42
|
+
readonly OWNER: "owner";
|
|
43
|
+
readonly ADMIN: "admin";
|
|
44
|
+
readonly MEMBER: "member";
|
|
45
|
+
readonly ORGANIZATION: "organization";
|
|
46
|
+
readonly PROJECT_ADMIN: "project_admin";
|
|
47
|
+
readonly PROJECT_MEMBER: "project_member";
|
|
48
|
+
readonly PROJECT_VIEWER: "project_viewer";
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* SpiceDB permissions used in the schema
|
|
52
|
+
*
|
|
53
|
+
* Permissions are named as verbs (actions) per SpiceDB best practices.
|
|
54
|
+
*/
|
|
55
|
+
/**
|
|
56
|
+
* SpiceDB permissions used in permission checks.
|
|
57
|
+
*
|
|
58
|
+
* Note: Organization-level permissions (manage) are handled via
|
|
59
|
+
* orgRole bypass in permission functions, not direct SpiceDB checks.
|
|
60
|
+
*/
|
|
61
|
+
declare const SpiceDbPermissions: {
|
|
62
|
+
readonly VIEW: "view";
|
|
63
|
+
readonly USE: "use";
|
|
64
|
+
readonly EDIT: "edit";
|
|
65
|
+
readonly DELETE: "delete";
|
|
66
|
+
};
|
|
67
|
+
type OrgRole = 'owner' | 'admin' | 'member';
|
|
68
|
+
/**
|
|
69
|
+
* Project roles hierarchy:
|
|
70
|
+
* - project_admin: Full access (view + use + edit + manage members + delete)
|
|
71
|
+
* - project_member: Operator access (view + use: invoke agents, create API keys)
|
|
72
|
+
* - project_viewer: Read-only access (view only)
|
|
73
|
+
*/
|
|
74
|
+
type ProjectRole = 'project_admin' | 'project_member' | 'project_viewer';
|
|
75
|
+
//#endregion
|
|
76
|
+
export { OrgRole, ProjectRole, SpiceDbPermissions, SpiceDbRelations, SpiceDbResourceTypes, getSpiceDbConfig, isAuthzEnabled };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
//#region src/auth/authz/config.ts
|
|
2
|
+
/**
|
|
3
|
+
* SpiceDB Authorization Configuration
|
|
4
|
+
*
|
|
5
|
+
* Feature flag and configuration for the SpiceDB authorization system.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Check if authorization is enabled.
|
|
9
|
+
*
|
|
10
|
+
* When called without tenantId:
|
|
11
|
+
* - Returns true if ENABLE_AUTHZ=true
|
|
12
|
+
*
|
|
13
|
+
* When called with tenantId:
|
|
14
|
+
* - If ENABLE_AUTHZ=false → returns false
|
|
15
|
+
* - If ENABLE_AUTHZ=true and TENANT_ID is not set → returns true (all tenants)
|
|
16
|
+
* - If ENABLE_AUTHZ=true and TENANT_ID is set → returns true only if tenantId matches
|
|
17
|
+
*/
|
|
18
|
+
function isAuthzEnabled(tenantId) {
|
|
19
|
+
if (process.env.ENABLE_AUTHZ !== "true") return false;
|
|
20
|
+
const configuredTenantId = process.env.TENANT_ID?.trim();
|
|
21
|
+
if (!configuredTenantId) return true;
|
|
22
|
+
return tenantId === configuredTenantId;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get SpiceDB connection configuration from environment variables.
|
|
26
|
+
*/
|
|
27
|
+
function getSpiceDbConfig() {
|
|
28
|
+
return {
|
|
29
|
+
endpoint: process.env.SPICEDB_ENDPOINT || "localhost:50051",
|
|
30
|
+
token: process.env.SPICEDB_PRESHARED_KEY || "",
|
|
31
|
+
tlsEnabled: process.env.SPICEDB_TLS_ENABLED === "true"
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* SpiceDB resource types used in the schema
|
|
36
|
+
*/
|
|
37
|
+
const SpiceDbResourceTypes = {
|
|
38
|
+
USER: "user",
|
|
39
|
+
ORGANIZATION: "organization",
|
|
40
|
+
PROJECT: "project"
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* SpiceDB relations used in the schema
|
|
44
|
+
*
|
|
45
|
+
* Relations are named as nouns (roles) per SpiceDB best practices.
|
|
46
|
+
* Project roles are prefixed for clarity when debugging/grepping.
|
|
47
|
+
*/
|
|
48
|
+
const SpiceDbRelations = {
|
|
49
|
+
OWNER: "owner",
|
|
50
|
+
ADMIN: "admin",
|
|
51
|
+
MEMBER: "member",
|
|
52
|
+
ORGANIZATION: "organization",
|
|
53
|
+
PROJECT_ADMIN: "project_admin",
|
|
54
|
+
PROJECT_MEMBER: "project_member",
|
|
55
|
+
PROJECT_VIEWER: "project_viewer"
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* SpiceDB permissions used in the schema
|
|
59
|
+
*
|
|
60
|
+
* Permissions are named as verbs (actions) per SpiceDB best practices.
|
|
61
|
+
*/
|
|
62
|
+
/**
|
|
63
|
+
* SpiceDB permissions used in permission checks.
|
|
64
|
+
*
|
|
65
|
+
* Note: Organization-level permissions (manage) are handled via
|
|
66
|
+
* orgRole bypass in permission functions, not direct SpiceDB checks.
|
|
67
|
+
*/
|
|
68
|
+
const SpiceDbPermissions = {
|
|
69
|
+
VIEW: "view",
|
|
70
|
+
USE: "use",
|
|
71
|
+
EDIT: "edit",
|
|
72
|
+
DELETE: "delete"
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
//#endregion
|
|
76
|
+
export { SpiceDbPermissions, SpiceDbRelations, SpiceDbResourceTypes, getSpiceDbConfig, isAuthzEnabled };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { checkBulkPermissions, checkPermission, deleteRelationship, getSpiceClient, lookupResources, readRelationships, resetSpiceClient, writeRelationship } from "./client.js";
|
|
2
|
+
import { OrgRole, ProjectRole, SpiceDbPermissions, SpiceDbRelations, SpiceDbResourceTypes, getSpiceDbConfig, isAuthzEnabled } from "./config.js";
|
|
3
|
+
import { canEditProject, canUseProject, canViewProject, listAccessibleProjectIds } from "./permissions.js";
|
|
4
|
+
import { changeProjectRole, grantProjectAccess, listProjectMembers, removeProjectFromSpiceDb, revokeProjectAccess, syncOrgMemberToSpiceDb, syncProjectToSpiceDb } from "./sync.js";
|
|
5
|
+
export { type OrgRole, type ProjectRole, SpiceDbPermissions, SpiceDbRelations, SpiceDbResourceTypes, canEditProject, canUseProject, canViewProject, changeProjectRole, checkBulkPermissions, checkPermission, deleteRelationship, getSpiceClient, getSpiceDbConfig, grantProjectAccess, isAuthzEnabled, listAccessibleProjectIds, listProjectMembers, lookupResources, readRelationships, removeProjectFromSpiceDb, resetSpiceClient, revokeProjectAccess, syncOrgMemberToSpiceDb, syncProjectToSpiceDb, writeRelationship };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { SpiceDbPermissions, SpiceDbRelations, SpiceDbResourceTypes, getSpiceDbConfig, isAuthzEnabled } from "./config.js";
|
|
2
|
+
import { checkBulkPermissions, checkPermission, deleteRelationship, getSpiceClient, lookupResources, readRelationships, resetSpiceClient, writeRelationship } from "./client.js";
|
|
3
|
+
import { canEditProject, canUseProject, canViewProject, listAccessibleProjectIds } from "./permissions.js";
|
|
4
|
+
import { changeProjectRole, grantProjectAccess, listProjectMembers, removeProjectFromSpiceDb, revokeProjectAccess, syncOrgMemberToSpiceDb, syncProjectToSpiceDb } from "./sync.js";
|
|
5
|
+
|
|
6
|
+
export { SpiceDbPermissions, SpiceDbRelations, SpiceDbResourceTypes, canEditProject, canUseProject, canViewProject, changeProjectRole, checkBulkPermissions, checkPermission, deleteRelationship, getSpiceClient, getSpiceDbConfig, grantProjectAccess, isAuthzEnabled, listAccessibleProjectIds, listProjectMembers, lookupResources, readRelationships, removeProjectFromSpiceDb, resetSpiceClient, revokeProjectAccess, syncOrgMemberToSpiceDb, syncProjectToSpiceDb, writeRelationship };
|