@inkeep/agents-core 0.68.4 → 0.70.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/dist/auth/auth-schema.d.ts +163 -163
- package/dist/auth/auth-validation-schemas.d.ts +154 -154
- package/dist/auth/auth.d.ts +9 -9
- package/dist/auth/authz/config.d.ts +33 -7
- package/dist/auth/authz/config.js +18 -8
- package/dist/auth/authz/credential-gateway.d.ts +57 -0
- package/dist/auth/authz/credential-gateway.js +118 -0
- package/dist/auth/authz/index.d.ts +4 -3
- package/dist/auth/authz/index.js +4 -3
- package/dist/auth/authz/types.d.ts +8 -1
- package/dist/auth/authz/types.js +7 -3
- package/dist/auth/entitlement-lock.js +2 -4
- package/dist/auth/entitlements.js +1 -1
- package/dist/auth/permissions.d.ts +13 -13
- package/dist/auth/support-copilot-platforms.d.ts +147 -0
- package/dist/auth/support-copilot-platforms.js +120 -0
- package/dist/client-exports.d.ts +3 -2
- package/dist/client-exports.js +3 -2
- package/dist/constants/allowed-file-formats.d.ts +6 -1
- package/dist/constants/allowed-file-formats.js +256 -24
- package/dist/constants/index.d.ts +2 -2
- package/dist/constants/index.js +2 -2
- package/dist/constants/signoz-queries.d.ts +1 -0
- package/dist/constants/signoz-queries.js +2 -1
- package/dist/context/TemplateEngine.d.ts +17 -1
- package/dist/context/TemplateEngine.js +37 -3
- package/dist/data-access/index.d.ts +2 -2
- package/dist/data-access/index.js +2 -2
- package/dist/data-access/manage/agents.d.ts +21 -21
- package/dist/data-access/manage/artifactComponents.d.ts +8 -8
- package/dist/data-access/manage/contextConfigs.d.ts +8 -8
- package/dist/data-access/manage/dataComponents.d.ts +2 -2
- package/dist/data-access/manage/functionTools.d.ts +10 -10
- package/dist/data-access/manage/skills.d.ts +10 -10
- package/dist/data-access/manage/subAgentExternalAgentRelations.d.ts +12 -12
- package/dist/data-access/manage/subAgentRelations.d.ts +16 -16
- package/dist/data-access/manage/subAgentTeamAgentRelations.d.ts +12 -12
- package/dist/data-access/manage/subAgents.d.ts +15 -15
- package/dist/data-access/manage/tools.d.ts +15 -15
- package/dist/data-access/manage/triggers.d.ts +1 -1
- package/dist/data-access/runtime/apiKeys.d.ts +12 -12
- package/dist/data-access/runtime/apps.d.ts +35 -11
- package/dist/data-access/runtime/conversations.d.ts +12 -12
- package/dist/data-access/runtime/entitlements.d.ts +2 -1
- package/dist/data-access/runtime/entitlements.js +5 -1
- package/dist/data-access/runtime/feedback.d.ts +6 -6
- package/dist/data-access/runtime/messages.d.ts +6 -6
- package/dist/data-access/runtime/scheduledTriggerUsers.d.ts +1 -1
- package/dist/data-access/runtime/tasks.d.ts +3 -3
- package/dist/db/runtime/runtime-schema.d.ts +395 -379
- package/dist/index.d.ts +7 -5
- package/dist/index.js +7 -5
- package/dist/middleware/no-auth.d.ts +2 -2
- package/dist/node_modules/.pnpm/{vitest@3.2.4_@edge-runtime_vm@3.2.0_@types_debug@4.1.12_@types_node@20.19.27_jiti@2.6.1_93023d256ff9ed909ae8f0d436c922a0 → vitest@3.2.4_@edge-runtime_vm@3.2.0_@types_debug@4.1.12_@types_node@20.19.27_jiti@2.6.1_e422349b438eb7189cab8b1648fc0621}/node_modules/vitest/dist/chunks/_commonjsHelpers.BFTU3MAI.js +1 -1
- package/dist/node_modules/.pnpm/{vitest@3.2.4_@edge-runtime_vm@3.2.0_@types_debug@4.1.12_@types_node@20.19.27_jiti@2.6.1_93023d256ff9ed909ae8f0d436c922a0 → vitest@3.2.4_@edge-runtime_vm@3.2.0_@types_debug@4.1.12_@types_node@20.19.27_jiti@2.6.1_e422349b438eb7189cab8b1648fc0621}/node_modules/vitest/dist/chunks/date.Bq6ZW5rf.js +1 -1
- package/dist/node_modules/.pnpm/{vitest@3.2.4_@edge-runtime_vm@3.2.0_@types_debug@4.1.12_@types_node@20.19.27_jiti@2.6.1_93023d256ff9ed909ae8f0d436c922a0 → vitest@3.2.4_@edge-runtime_vm@3.2.0_@types_debug@4.1.12_@types_node@20.19.27_jiti@2.6.1_e422349b438eb7189cab8b1648fc0621}/node_modules/vitest/dist/chunks/utils.XdZDrNZV.js +1 -1
- package/dist/node_modules/.pnpm/{vitest@3.2.4_@edge-runtime_vm@3.2.0_@types_debug@4.1.12_@types_node@20.19.27_jiti@2.6.1_93023d256ff9ed909ae8f0d436c922a0 → vitest@3.2.4_@edge-runtime_vm@3.2.0_@types_debug@4.1.12_@types_node@20.19.27_jiti@2.6.1_e422349b438eb7189cab8b1648fc0621}/node_modules/vitest/dist/chunks/vi.bdSIJ99Y.js +1 -1
- package/dist/test-utils/mocks/logger.js +1 -1
- package/dist/utils/apiKeys.js +1 -1
- package/dist/utils/error.d.ts +51 -51
- package/dist/validation/drizzle-schema-helpers.d.ts +3 -3
- package/dist/validation/index.d.ts +2 -2
- package/dist/validation/index.js +2 -2
- package/dist/validation/schemas/skills.d.ts +46 -46
- package/dist/validation/schemas.d.ts +2080 -1892
- package/dist/validation/schemas.js +16 -2
- package/package.json +1 -1
- package/spicedb/schema.zed +27 -0
package/dist/auth/auth.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import * as jose0 from "jose";
|
|
|
4
4
|
import * as zod0 from "zod";
|
|
5
5
|
import * as better_auth0 from "better-auth";
|
|
6
6
|
import * as _better_auth_oauth_provider0 from "@better-auth/oauth-provider";
|
|
7
|
-
import * as
|
|
7
|
+
import * as better_auth_plugins20 from "better-auth/plugins";
|
|
8
8
|
|
|
9
9
|
//#region src/auth/auth.d.ts
|
|
10
10
|
|
|
@@ -40,10 +40,10 @@ declare function _inferAuthType(): better_auth0.Auth<{
|
|
|
40
40
|
handler: (inputContext: better_auth0.MiddlewareInputContext<better_auth0.MiddlewareOptions>) => Promise<void>;
|
|
41
41
|
}[];
|
|
42
42
|
};
|
|
43
|
-
options:
|
|
43
|
+
options: better_auth_plugins20.BearerOptions | undefined;
|
|
44
44
|
}, {
|
|
45
45
|
id: "oauth-proxy";
|
|
46
|
-
options: NoInfer<
|
|
46
|
+
options: NoInfer<better_auth_plugins20.OAuthProxyOptions>;
|
|
47
47
|
endpoints: {
|
|
48
48
|
oAuthProxy: better_auth0.StrictEndpoint<"/oauth-proxy-callback", {
|
|
49
49
|
method: "GET";
|
|
@@ -97,7 +97,7 @@ declare function _inferAuthType(): better_auth0.Auth<{
|
|
|
97
97
|
};
|
|
98
98
|
}, {
|
|
99
99
|
id: "jwt";
|
|
100
|
-
options: NoInfer<
|
|
100
|
+
options: NoInfer<better_auth_plugins20.JwtOptions>;
|
|
101
101
|
endpoints: {
|
|
102
102
|
getJwks: better_auth0.StrictEndpoint<string, {
|
|
103
103
|
method: "GET";
|
|
@@ -234,7 +234,7 @@ declare function _inferAuthType(): better_auth0.Auth<{
|
|
|
234
234
|
$Infer: {
|
|
235
235
|
body: {
|
|
236
236
|
payload: jose0.JWTPayload;
|
|
237
|
-
overrideOptions?:
|
|
237
|
+
overrideOptions?: better_auth_plugins20.JwtOptions | undefined;
|
|
238
238
|
};
|
|
239
239
|
};
|
|
240
240
|
};
|
|
@@ -331,7 +331,7 @@ declare function _inferAuthType(): better_auth0.Auth<{
|
|
|
331
331
|
SERVER_ONLY: true;
|
|
332
332
|
};
|
|
333
333
|
}, Omit<_better_auth_oauth_provider0.OIDCMetadata, "id_token_signing_alg_values_supported"> & {
|
|
334
|
-
id_token_signing_alg_values_supported:
|
|
334
|
+
id_token_signing_alg_values_supported: better_auth_plugins20.JWSAlgorithms[] | ["HS256"];
|
|
335
335
|
}>;
|
|
336
336
|
oauth2Authorize: better_auth0.StrictEndpoint<"/oauth2/authorize", {
|
|
337
337
|
method: "GET";
|
|
@@ -2324,7 +2324,7 @@ declare function _inferAuthType(): better_auth0.Auth<{
|
|
|
2324
2324
|
window: number;
|
|
2325
2325
|
max: number;
|
|
2326
2326
|
})[];
|
|
2327
|
-
},
|
|
2327
|
+
}, better_auth_plugins20.DefaultOrganizationPlugin<{
|
|
2328
2328
|
schema: {
|
|
2329
2329
|
invitation: {
|
|
2330
2330
|
additionalFields: {
|
|
@@ -2687,8 +2687,8 @@ declare function _inferAuthType(): better_auth0.Auth<{
|
|
|
2687
2687
|
AUTHENTICATION_REQUIRED: better_auth0.RawError<"AUTHENTICATION_REQUIRED">;
|
|
2688
2688
|
};
|
|
2689
2689
|
options: Partial<{
|
|
2690
|
-
expiresIn:
|
|
2691
|
-
interval:
|
|
2690
|
+
expiresIn: better_auth_plugins20.TimeString;
|
|
2691
|
+
interval: better_auth_plugins20.TimeString;
|
|
2692
2692
|
deviceCodeLength: number;
|
|
2693
2693
|
userCodeLength: number;
|
|
2694
2694
|
schema: {
|
|
@@ -13,23 +13,49 @@ declare function getSpiceDbConfig(): {
|
|
|
13
13
|
tlsEnabled: boolean;
|
|
14
14
|
};
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
16
|
+
* Branded SpiceDB object ID types.
|
|
17
|
+
*
|
|
18
|
+
* SpiceDB object IDs are global — `credential_reference:cred_foo` refers to one
|
|
19
|
+
* object regardless of who wrote the tuple. To prevent cross-tenant collisions we
|
|
20
|
+
* namespace composite-PK resources under their scope (`{tenantId}/{projectId}/...`).
|
|
17
21
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
22
|
+
* The brand is enforcement, not decoration: downstream helpers accept only the
|
|
23
|
+
* branded type, so a raw DB ID can never be passed to a SpiceDB call without
|
|
24
|
+
* going through the appropriate `toSpiceDb*Id` constructor. This catches at
|
|
25
|
+
* compile time the "forgot to tenant-prefix" bug class.
|
|
26
|
+
*/
|
|
27
|
+
type SpiceDbProjectId = string & {
|
|
28
|
+
readonly __brand: 'SpiceDbProjectId';
|
|
29
|
+
};
|
|
30
|
+
type SpiceDbCredentialReferenceId = string & {
|
|
31
|
+
readonly __brand: 'SpiceDbCredentialReferenceId';
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Compose a tenant-scoped SpiceDB project object ID.
|
|
20
35
|
*
|
|
21
|
-
* Format: `{tenantId}/{projectId}`
|
|
36
|
+
* Format: `{tenantId}/{projectId}` — projects' backing-store PK is
|
|
37
|
+
* `(tenantId, projectId)`, so this mirrors that composite key verbatim.
|
|
22
38
|
*/
|
|
23
|
-
declare function toSpiceDbProjectId(tenantId: string, projectId: string):
|
|
39
|
+
declare function toSpiceDbProjectId(tenantId: string, projectId: string): SpiceDbProjectId;
|
|
24
40
|
/**
|
|
25
41
|
* Parse a tenant-scoped SpiceDB project object ID back into its parts.
|
|
26
42
|
*
|
|
27
43
|
* @returns `{ tenantId, projectId }` extracted from the composite ID.
|
|
28
44
|
* @throws if the ID does not contain the separator.
|
|
29
45
|
*/
|
|
30
|
-
declare function fromSpiceDbProjectId(spiceDbProjectId: string): {
|
|
46
|
+
declare function fromSpiceDbProjectId(spiceDbProjectId: SpiceDbProjectId | string): {
|
|
31
47
|
tenantId: string;
|
|
32
48
|
projectId: string;
|
|
33
49
|
};
|
|
50
|
+
/**
|
|
51
|
+
* Compose a tenant+project-scoped SpiceDB credential_reference object ID.
|
|
52
|
+
*
|
|
53
|
+
* Format: `{tenantId}/{projectId}/{credentialReferenceId}` — credentials' backing-store
|
|
54
|
+
* PK is `(tenantId, projectId, id)`, so this mirrors that composite key verbatim.
|
|
55
|
+
* Without this scoping, two tenants that each define a credential with the same
|
|
56
|
+
* slug (e.g. `cred_helpscout`) would share the same SpiceDB object and any grant
|
|
57
|
+
* on one would appear to grant the other.
|
|
58
|
+
*/
|
|
59
|
+
declare function toSpiceDbCredentialReferenceId(tenantId: string, projectId: string, credentialReferenceId: string): SpiceDbCredentialReferenceId;
|
|
34
60
|
//#endregion
|
|
35
|
-
export { fromSpiceDbProjectId, getSpiceDbConfig, isLocalhostEndpoint, toSpiceDbProjectId };
|
|
61
|
+
export { SpiceDbCredentialReferenceId, SpiceDbProjectId, fromSpiceDbProjectId, getSpiceDbConfig, isLocalhostEndpoint, toSpiceDbCredentialReferenceId, toSpiceDbProjectId };
|
|
@@ -19,17 +19,15 @@ function getSpiceDbConfig() {
|
|
|
19
19
|
tlsEnabled: env.SPICEDB_TLS_ENABLED ?? !isLocalhostEndpoint(endpoint)
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
|
-
const
|
|
22
|
+
const SPICEDB_ID_SEPARATOR = "/";
|
|
23
23
|
/**
|
|
24
24
|
* Compose a tenant-scoped SpiceDB project object ID.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* Format: `{tenantId}/{projectId}`
|
|
26
|
+
* Format: `{tenantId}/{projectId}` — projects' backing-store PK is
|
|
27
|
+
* `(tenantId, projectId)`, so this mirrors that composite key verbatim.
|
|
30
28
|
*/
|
|
31
29
|
function toSpiceDbProjectId(tenantId, projectId) {
|
|
32
|
-
return `${tenantId}${
|
|
30
|
+
return `${tenantId}${SPICEDB_ID_SEPARATOR}${projectId}`;
|
|
33
31
|
}
|
|
34
32
|
/**
|
|
35
33
|
* Parse a tenant-scoped SpiceDB project object ID back into its parts.
|
|
@@ -38,13 +36,25 @@ function toSpiceDbProjectId(tenantId, projectId) {
|
|
|
38
36
|
* @throws if the ID does not contain the separator.
|
|
39
37
|
*/
|
|
40
38
|
function fromSpiceDbProjectId(spiceDbProjectId) {
|
|
41
|
-
const separatorIndex = spiceDbProjectId.indexOf(
|
|
39
|
+
const separatorIndex = spiceDbProjectId.indexOf(SPICEDB_ID_SEPARATOR);
|
|
42
40
|
if (separatorIndex === -1) throw new Error(`Invalid SpiceDB project ID format: ${spiceDbProjectId}`);
|
|
43
41
|
return {
|
|
44
42
|
tenantId: spiceDbProjectId.substring(0, separatorIndex),
|
|
45
43
|
projectId: spiceDbProjectId.substring(separatorIndex + 1)
|
|
46
44
|
};
|
|
47
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Compose a tenant+project-scoped SpiceDB credential_reference object ID.
|
|
48
|
+
*
|
|
49
|
+
* Format: `{tenantId}/{projectId}/{credentialReferenceId}` — credentials' backing-store
|
|
50
|
+
* PK is `(tenantId, projectId, id)`, so this mirrors that composite key verbatim.
|
|
51
|
+
* Without this scoping, two tenants that each define a credential with the same
|
|
52
|
+
* slug (e.g. `cred_helpscout`) would share the same SpiceDB object and any grant
|
|
53
|
+
* on one would appear to grant the other.
|
|
54
|
+
*/
|
|
55
|
+
function toSpiceDbCredentialReferenceId(tenantId, projectId, credentialReferenceId) {
|
|
56
|
+
return `${tenantId}${SPICEDB_ID_SEPARATOR}${projectId}${SPICEDB_ID_SEPARATOR}${credentialReferenceId}`;
|
|
57
|
+
}
|
|
48
58
|
|
|
49
59
|
//#endregion
|
|
50
|
-
export { fromSpiceDbProjectId, getSpiceDbConfig, isLocalhostEndpoint, toSpiceDbProjectId };
|
|
60
|
+
export { fromSpiceDbProjectId, getSpiceDbConfig, isLocalhostEndpoint, toSpiceDbCredentialReferenceId, toSpiceDbProjectId };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
//#region src/auth/authz/credential-gateway.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Grant an app permission to read a credential.
|
|
4
|
+
*
|
|
5
|
+
* Requires the full credential scope (tenantId + projectId + credentialReferenceId)
|
|
6
|
+
* because credential_reference IDs are only unique within a project; the SpiceDB
|
|
7
|
+
* object ID is constructed via {@link toSpiceDbCredentialReferenceId}.
|
|
8
|
+
*/
|
|
9
|
+
declare function grantAppCredentialAccess(params: {
|
|
10
|
+
tenantId: string;
|
|
11
|
+
projectId: string;
|
|
12
|
+
credentialReferenceId: string;
|
|
13
|
+
appId: string;
|
|
14
|
+
}): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Revoke an app's permission to read a credential.
|
|
17
|
+
*/
|
|
18
|
+
declare function revokeAppCredentialAccess(params: {
|
|
19
|
+
tenantId: string;
|
|
20
|
+
projectId: string;
|
|
21
|
+
credentialReferenceId: string;
|
|
22
|
+
appId: string;
|
|
23
|
+
}): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Check whether an app has permission to read a credential.
|
|
26
|
+
*/
|
|
27
|
+
declare function canAppReadCredential(params: {
|
|
28
|
+
tenantId: string;
|
|
29
|
+
projectId: string;
|
|
30
|
+
credentialReferenceId: string;
|
|
31
|
+
appId: string;
|
|
32
|
+
}): Promise<boolean>;
|
|
33
|
+
/**
|
|
34
|
+
* Atomically reconcile the credential an app is granted read access to.
|
|
35
|
+
*
|
|
36
|
+
* One call covers all transitions:
|
|
37
|
+
* - prior=∅, next=∅ → no-op
|
|
38
|
+
* - prior=∅, next=Y → TOUCH new
|
|
39
|
+
* - prior=X, next=∅ → DELETE old (fixes the "user cleared the credential" case)
|
|
40
|
+
* - prior=X, next=X → idempotent TOUCH (collapsed, safe no-op in practice)
|
|
41
|
+
* - prior=X, next=Y (X≠Y) → DELETE old + TOUCH new in a single writeRelationships batch
|
|
42
|
+
*
|
|
43
|
+
* All mutations are issued via `WriteRelationships.updates[]`, so any transition
|
|
44
|
+
* involving both a delete and a write is observed atomically by readers (one
|
|
45
|
+
* zedtoken, no window where neither the old nor the new tuple is valid).
|
|
46
|
+
*
|
|
47
|
+
* Mirrors the pattern used by `changeOrgRole` / `changeProjectRole` in sync.ts.
|
|
48
|
+
*/
|
|
49
|
+
declare function rewriteAppCredentialAccess(params: {
|
|
50
|
+
tenantId: string;
|
|
51
|
+
projectId: string;
|
|
52
|
+
priorCredentialReferenceId?: string;
|
|
53
|
+
nextCredentialReferenceId?: string;
|
|
54
|
+
appId: string;
|
|
55
|
+
}): Promise<void>;
|
|
56
|
+
//#endregion
|
|
57
|
+
export { canAppReadCredential, grantAppCredentialAccess, revokeAppCredentialAccess, rewriteAppCredentialAccess };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { SpiceDbRelations, SpiceDbResourceTypes } from "./types.js";
|
|
2
|
+
import { toSpiceDbCredentialReferenceId } from "./config.js";
|
|
3
|
+
import { RelationshipOperation, checkPermission, deleteRelationship, getSpiceClient, writeRelationship } from "./client.js";
|
|
4
|
+
|
|
5
|
+
//#region src/auth/authz/credential-gateway.ts
|
|
6
|
+
/**
|
|
7
|
+
* Grant an app permission to read a credential.
|
|
8
|
+
*
|
|
9
|
+
* Requires the full credential scope (tenantId + projectId + credentialReferenceId)
|
|
10
|
+
* because credential_reference IDs are only unique within a project; the SpiceDB
|
|
11
|
+
* object ID is constructed via {@link toSpiceDbCredentialReferenceId}.
|
|
12
|
+
*/
|
|
13
|
+
async function grantAppCredentialAccess(params) {
|
|
14
|
+
await writeRelationship({
|
|
15
|
+
resourceType: SpiceDbResourceTypes.CREDENTIAL_REFERENCE,
|
|
16
|
+
resourceId: toSpiceDbCredentialReferenceId(params.tenantId, params.projectId, params.credentialReferenceId),
|
|
17
|
+
relation: SpiceDbRelations.APP_READER,
|
|
18
|
+
subjectType: SpiceDbResourceTypes.APP,
|
|
19
|
+
subjectId: params.appId
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Revoke an app's permission to read a credential.
|
|
24
|
+
*/
|
|
25
|
+
async function revokeAppCredentialAccess(params) {
|
|
26
|
+
await deleteRelationship({
|
|
27
|
+
resourceType: SpiceDbResourceTypes.CREDENTIAL_REFERENCE,
|
|
28
|
+
resourceId: toSpiceDbCredentialReferenceId(params.tenantId, params.projectId, params.credentialReferenceId),
|
|
29
|
+
relation: SpiceDbRelations.APP_READER,
|
|
30
|
+
subjectType: SpiceDbResourceTypes.APP,
|
|
31
|
+
subjectId: params.appId
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Check whether an app has permission to read a credential.
|
|
36
|
+
*/
|
|
37
|
+
async function canAppReadCredential(params) {
|
|
38
|
+
return checkPermission({
|
|
39
|
+
resourceType: SpiceDbResourceTypes.CREDENTIAL_REFERENCE,
|
|
40
|
+
resourceId: toSpiceDbCredentialReferenceId(params.tenantId, params.projectId, params.credentialReferenceId),
|
|
41
|
+
permission: "read",
|
|
42
|
+
subjectType: SpiceDbResourceTypes.APP,
|
|
43
|
+
subjectId: params.appId
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Atomically reconcile the credential an app is granted read access to.
|
|
48
|
+
*
|
|
49
|
+
* One call covers all transitions:
|
|
50
|
+
* - prior=∅, next=∅ → no-op
|
|
51
|
+
* - prior=∅, next=Y → TOUCH new
|
|
52
|
+
* - prior=X, next=∅ → DELETE old (fixes the "user cleared the credential" case)
|
|
53
|
+
* - prior=X, next=X → idempotent TOUCH (collapsed, safe no-op in practice)
|
|
54
|
+
* - prior=X, next=Y (X≠Y) → DELETE old + TOUCH new in a single writeRelationships batch
|
|
55
|
+
*
|
|
56
|
+
* All mutations are issued via `WriteRelationships.updates[]`, so any transition
|
|
57
|
+
* involving both a delete and a write is observed atomically by readers (one
|
|
58
|
+
* zedtoken, no window where neither the old nor the new tuple is valid).
|
|
59
|
+
*
|
|
60
|
+
* Mirrors the pattern used by `changeOrgRole` / `changeProjectRole` in sync.ts.
|
|
61
|
+
*/
|
|
62
|
+
async function rewriteAppCredentialAccess(params) {
|
|
63
|
+
const { priorCredentialReferenceId, nextCredentialReferenceId, tenantId, projectId, appId } = params;
|
|
64
|
+
if (!priorCredentialReferenceId && !nextCredentialReferenceId) return;
|
|
65
|
+
const spice = getSpiceClient();
|
|
66
|
+
const updates = [];
|
|
67
|
+
if (priorCredentialReferenceId && priorCredentialReferenceId !== nextCredentialReferenceId) {
|
|
68
|
+
const priorId = toSpiceDbCredentialReferenceId(tenantId, projectId, priorCredentialReferenceId);
|
|
69
|
+
updates.push({
|
|
70
|
+
operation: RelationshipOperation.DELETE,
|
|
71
|
+
relationship: {
|
|
72
|
+
resource: {
|
|
73
|
+
objectType: SpiceDbResourceTypes.CREDENTIAL_REFERENCE,
|
|
74
|
+
objectId: priorId
|
|
75
|
+
},
|
|
76
|
+
relation: SpiceDbRelations.APP_READER,
|
|
77
|
+
subject: {
|
|
78
|
+
object: {
|
|
79
|
+
objectType: SpiceDbResourceTypes.APP,
|
|
80
|
+
objectId: appId
|
|
81
|
+
},
|
|
82
|
+
optionalRelation: ""
|
|
83
|
+
},
|
|
84
|
+
optionalCaveat: void 0
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
if (nextCredentialReferenceId) {
|
|
89
|
+
const nextId = toSpiceDbCredentialReferenceId(tenantId, projectId, nextCredentialReferenceId);
|
|
90
|
+
updates.push({
|
|
91
|
+
operation: RelationshipOperation.TOUCH,
|
|
92
|
+
relationship: {
|
|
93
|
+
resource: {
|
|
94
|
+
objectType: SpiceDbResourceTypes.CREDENTIAL_REFERENCE,
|
|
95
|
+
objectId: nextId
|
|
96
|
+
},
|
|
97
|
+
relation: SpiceDbRelations.APP_READER,
|
|
98
|
+
subject: {
|
|
99
|
+
object: {
|
|
100
|
+
objectType: SpiceDbResourceTypes.APP,
|
|
101
|
+
objectId: appId
|
|
102
|
+
},
|
|
103
|
+
optionalRelation: ""
|
|
104
|
+
},
|
|
105
|
+
optionalCaveat: void 0
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
if (updates.length === 0) return;
|
|
110
|
+
await spice.promises.writeRelationships({
|
|
111
|
+
updates,
|
|
112
|
+
optionalPreconditions: [],
|
|
113
|
+
optionalTransactionMetadata: void 0
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
//#endregion
|
|
118
|
+
export { canAppReadCredential, grantAppCredentialAccess, revokeAppCredentialAccess, rewriteAppCredentialAccess };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { checkBulkPermissions, checkPermission, deleteRelationship, getSpiceClient, lookupResources, readRelationships, resetSpiceClient, writeRelationship } from "./client.js";
|
|
2
|
-
import { fromSpiceDbProjectId, getSpiceDbConfig, toSpiceDbProjectId } from "./config.js";
|
|
3
|
-
import {
|
|
2
|
+
import { SpiceDbCredentialReferenceId, SpiceDbProjectId, fromSpiceDbProjectId, getSpiceDbConfig, toSpiceDbCredentialReferenceId, toSpiceDbProjectId } from "./config.js";
|
|
3
|
+
import { canAppReadCredential, grantAppCredentialAccess, revokeAppCredentialAccess, rewriteAppCredentialAccess } from "./credential-gateway.js";
|
|
4
|
+
import { OrgRole, OrgRoles, ProjectPermissionLevel, ProjectPermissions, ProjectRole, ProjectRoles, SpiceDbCredentialReferencePermission, SpiceDbCredentialReferencePermissions, SpiceDbOrgPermission, SpiceDbOrgPermissions, SpiceDbProjectPermission, SpiceDbProjectPermissions, SpiceDbRelations, SpiceDbResourceTypes } from "./types.js";
|
|
4
5
|
import { canEditProject, canUseProject, canUseProjectStrict, canViewProject, listAccessibleProjectIds, listUsableProjectIds } from "./permissions.js";
|
|
5
6
|
import { changeOrgRole, changeProjectRole, grantProjectAccess, listProjectMembers, listUserProjectMembershipsInSpiceDb, removeProjectFromSpiceDb, revokeAllProjectMemberships, revokeProjectAccess, syncOrgMemberToSpiceDb, syncProjectToSpiceDb } from "./sync.js";
|
|
6
|
-
export { type OrgRole, OrgRoles, type ProjectPermissionLevel, type ProjectPermissions, type ProjectRole, ProjectRoles, type SpiceDbOrgPermission, SpiceDbOrgPermissions, type SpiceDbProjectPermission, SpiceDbProjectPermissions, SpiceDbRelations, SpiceDbResourceTypes, canEditProject, canUseProject, canUseProjectStrict, canViewProject, changeOrgRole, changeProjectRole, checkBulkPermissions, checkPermission, deleteRelationship, fromSpiceDbProjectId, getSpiceClient, getSpiceDbConfig, grantProjectAccess, listAccessibleProjectIds, listProjectMembers, listUsableProjectIds, listUserProjectMembershipsInSpiceDb, lookupResources, readRelationships, removeProjectFromSpiceDb, resetSpiceClient, revokeAllProjectMemberships, revokeProjectAccess, syncOrgMemberToSpiceDb, syncProjectToSpiceDb, toSpiceDbProjectId, writeRelationship };
|
|
7
|
+
export { type OrgRole, OrgRoles, type ProjectPermissionLevel, type ProjectPermissions, type ProjectRole, ProjectRoles, type SpiceDbCredentialReferenceId, type SpiceDbCredentialReferencePermission, SpiceDbCredentialReferencePermissions, type SpiceDbOrgPermission, SpiceDbOrgPermissions, type SpiceDbProjectId, type SpiceDbProjectPermission, SpiceDbProjectPermissions, SpiceDbRelations, SpiceDbResourceTypes, canAppReadCredential, canEditProject, canUseProject, canUseProjectStrict, canViewProject, changeOrgRole, changeProjectRole, checkBulkPermissions, checkPermission, deleteRelationship, fromSpiceDbProjectId, getSpiceClient, getSpiceDbConfig, grantAppCredentialAccess, grantProjectAccess, listAccessibleProjectIds, listProjectMembers, listUsableProjectIds, listUserProjectMembershipsInSpiceDb, lookupResources, readRelationships, removeProjectFromSpiceDb, resetSpiceClient, revokeAllProjectMemberships, revokeAppCredentialAccess, revokeProjectAccess, rewriteAppCredentialAccess, syncOrgMemberToSpiceDb, syncProjectToSpiceDb, toSpiceDbCredentialReferenceId, toSpiceDbProjectId, writeRelationship };
|
package/dist/auth/authz/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { OrgRoles, ProjectRoles, SpiceDbOrgPermissions, SpiceDbProjectPermissions, SpiceDbRelations, SpiceDbResourceTypes } from "./types.js";
|
|
2
|
-
import { fromSpiceDbProjectId, getSpiceDbConfig, toSpiceDbProjectId } from "./config.js";
|
|
1
|
+
import { OrgRoles, ProjectRoles, SpiceDbCredentialReferencePermissions, SpiceDbOrgPermissions, SpiceDbProjectPermissions, SpiceDbRelations, SpiceDbResourceTypes } from "./types.js";
|
|
2
|
+
import { fromSpiceDbProjectId, getSpiceDbConfig, toSpiceDbCredentialReferenceId, toSpiceDbProjectId } from "./config.js";
|
|
3
3
|
import { checkBulkPermissions, checkPermission, deleteRelationship, getSpiceClient, lookupResources, readRelationships, resetSpiceClient, writeRelationship } from "./client.js";
|
|
4
|
+
import { canAppReadCredential, grantAppCredentialAccess, revokeAppCredentialAccess, rewriteAppCredentialAccess } from "./credential-gateway.js";
|
|
4
5
|
import { canEditProject, canUseProject, canUseProjectStrict, canViewProject, listAccessibleProjectIds, listUsableProjectIds } from "./permissions.js";
|
|
5
6
|
import { changeOrgRole, changeProjectRole, grantProjectAccess, listProjectMembers, listUserProjectMembershipsInSpiceDb, removeProjectFromSpiceDb, revokeAllProjectMemberships, revokeProjectAccess, syncOrgMemberToSpiceDb, syncProjectToSpiceDb } from "./sync.js";
|
|
6
7
|
|
|
7
|
-
export { OrgRoles, ProjectRoles, SpiceDbOrgPermissions, SpiceDbProjectPermissions, SpiceDbRelations, SpiceDbResourceTypes, canEditProject, canUseProject, canUseProjectStrict, canViewProject, changeOrgRole, changeProjectRole, checkBulkPermissions, checkPermission, deleteRelationship, fromSpiceDbProjectId, getSpiceClient, getSpiceDbConfig, grantProjectAccess, listAccessibleProjectIds, listProjectMembers, listUsableProjectIds, listUserProjectMembershipsInSpiceDb, lookupResources, readRelationships, removeProjectFromSpiceDb, resetSpiceClient, revokeAllProjectMemberships, revokeProjectAccess, syncOrgMemberToSpiceDb, syncProjectToSpiceDb, toSpiceDbProjectId, writeRelationship };
|
|
8
|
+
export { OrgRoles, ProjectRoles, SpiceDbCredentialReferencePermissions, SpiceDbOrgPermissions, SpiceDbProjectPermissions, SpiceDbRelations, SpiceDbResourceTypes, canAppReadCredential, canEditProject, canUseProject, canUseProjectStrict, canViewProject, changeOrgRole, changeProjectRole, checkBulkPermissions, checkPermission, deleteRelationship, fromSpiceDbProjectId, getSpiceClient, getSpiceDbConfig, grantAppCredentialAccess, grantProjectAccess, listAccessibleProjectIds, listProjectMembers, listUsableProjectIds, listUserProjectMembershipsInSpiceDb, lookupResources, readRelationships, removeProjectFromSpiceDb, resetSpiceClient, revokeAllProjectMemberships, revokeAppCredentialAccess, revokeProjectAccess, rewriteAppCredentialAccess, syncOrgMemberToSpiceDb, syncProjectToSpiceDb, toSpiceDbCredentialReferenceId, toSpiceDbProjectId, writeRelationship };
|
|
@@ -10,6 +10,8 @@ declare const SpiceDbResourceTypes: {
|
|
|
10
10
|
readonly USER: "user";
|
|
11
11
|
readonly ORGANIZATION: "organization";
|
|
12
12
|
readonly PROJECT: "project";
|
|
13
|
+
readonly APP: "app";
|
|
14
|
+
readonly CREDENTIAL_REFERENCE: "credential_reference";
|
|
13
15
|
};
|
|
14
16
|
/**
|
|
15
17
|
* SpiceDB relations used in the schema
|
|
@@ -25,6 +27,7 @@ declare const SpiceDbRelations: {
|
|
|
25
27
|
readonly PROJECT_ADMIN: "project_admin";
|
|
26
28
|
readonly PROJECT_MEMBER: "project_member";
|
|
27
29
|
readonly PROJECT_VIEWER: "project_viewer";
|
|
30
|
+
readonly APP_READER: "app_reader";
|
|
28
31
|
};
|
|
29
32
|
/**
|
|
30
33
|
* SpiceDB permissions for organization resources.
|
|
@@ -52,6 +55,10 @@ declare const SpiceDbProjectPermissions: {
|
|
|
52
55
|
readonly EDIT: "edit";
|
|
53
56
|
};
|
|
54
57
|
type SpiceDbProjectPermission = (typeof SpiceDbProjectPermissions)[keyof typeof SpiceDbProjectPermissions];
|
|
58
|
+
declare const SpiceDbCredentialReferencePermissions: {
|
|
59
|
+
readonly READ: "read";
|
|
60
|
+
};
|
|
61
|
+
type SpiceDbCredentialReferencePermission = (typeof SpiceDbCredentialReferencePermissions)[keyof typeof SpiceDbCredentialReferencePermissions];
|
|
55
62
|
/**
|
|
56
63
|
* Permission levels for project access checks.
|
|
57
64
|
*/
|
|
@@ -89,4 +96,4 @@ interface ProjectPermissions {
|
|
|
89
96
|
canEdit: boolean;
|
|
90
97
|
}
|
|
91
98
|
//#endregion
|
|
92
|
-
export { OrgRole, OrgRoles, ProjectPermissionLevel, ProjectPermissions, ProjectRole, ProjectRoles, SpiceDbOrgPermission, SpiceDbOrgPermissions, SpiceDbProjectPermission, SpiceDbProjectPermissions, SpiceDbRelations, SpiceDbResourceTypes };
|
|
99
|
+
export { OrgRole, OrgRoles, ProjectPermissionLevel, ProjectPermissions, ProjectRole, ProjectRoles, SpiceDbCredentialReferencePermission, SpiceDbCredentialReferencePermissions, SpiceDbOrgPermission, SpiceDbOrgPermissions, SpiceDbProjectPermission, SpiceDbProjectPermissions, SpiceDbRelations, SpiceDbResourceTypes };
|
package/dist/auth/authz/types.js
CHANGED
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
const SpiceDbResourceTypes = {
|
|
10
10
|
USER: "user",
|
|
11
11
|
ORGANIZATION: "organization",
|
|
12
|
-
PROJECT: "project"
|
|
12
|
+
PROJECT: "project",
|
|
13
|
+
APP: "app",
|
|
14
|
+
CREDENTIAL_REFERENCE: "credential_reference"
|
|
13
15
|
};
|
|
14
16
|
/**
|
|
15
17
|
* SpiceDB relations used in the schema
|
|
@@ -24,7 +26,8 @@ const SpiceDbRelations = {
|
|
|
24
26
|
ORGANIZATION: "organization",
|
|
25
27
|
PROJECT_ADMIN: "project_admin",
|
|
26
28
|
PROJECT_MEMBER: "project_member",
|
|
27
|
-
PROJECT_VIEWER: "project_viewer"
|
|
29
|
+
PROJECT_VIEWER: "project_viewer",
|
|
30
|
+
APP_READER: "app_reader"
|
|
28
31
|
};
|
|
29
32
|
/**
|
|
30
33
|
* SpiceDB permissions for organization resources.
|
|
@@ -50,6 +53,7 @@ const SpiceDbProjectPermissions = {
|
|
|
50
53
|
USE: "use",
|
|
51
54
|
EDIT: "edit"
|
|
52
55
|
};
|
|
56
|
+
const SpiceDbCredentialReferencePermissions = { READ: "read" };
|
|
53
57
|
/**
|
|
54
58
|
* Organization roles from SpiceDB schema.
|
|
55
59
|
*/
|
|
@@ -73,4 +77,4 @@ const ProjectRoles = {
|
|
|
73
77
|
};
|
|
74
78
|
|
|
75
79
|
//#endregion
|
|
76
|
-
export { OrgRoles, ProjectRoles, SpiceDbOrgPermissions, SpiceDbProjectPermissions, SpiceDbRelations, SpiceDbResourceTypes };
|
|
80
|
+
export { OrgRoles, ProjectRoles, SpiceDbCredentialReferencePermissions, SpiceDbOrgPermissions, SpiceDbProjectPermissions, SpiceDbRelations, SpiceDbResourceTypes };
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { and, eq } from "drizzle-orm";
|
|
1
|
+
import { dalSelectEntitlementForUpdate } from "../data-access/runtime/entitlements.js";
|
|
3
2
|
|
|
4
3
|
//#region src/auth/entitlement-lock.ts
|
|
5
4
|
async function withEntitlementLock(db, orgId, resourceType, fn) {
|
|
6
5
|
return db.transaction(async (tx) => {
|
|
7
|
-
|
|
8
|
-
return fn(rows.length === 0 ? null : rows[0].maxValue, tx);
|
|
6
|
+
return fn(await dalSelectEntitlementForUpdate(tx, orgId, resourceType), tx);
|
|
9
7
|
});
|
|
10
8
|
}
|
|
11
9
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_MEMBERSHIP_LIMIT, SEAT_RESOURCE_TYPES } from "./entitlement-constants.js";
|
|
2
2
|
import { getLogger } from "../utils/logger.js";
|
|
3
|
-
import { withEntitlementLock } from "./entitlement-lock.js";
|
|
4
3
|
import { dalCountMembersByRoleBucket, dalGetServiceAccountUserId, dalResolveEntitlement, dalSumSeatEntitlements } from "../data-access/runtime/entitlements.js";
|
|
4
|
+
import { withEntitlementLock } from "./entitlement-lock.js";
|
|
5
5
|
import { APIError } from "better-auth/api";
|
|
6
6
|
|
|
7
7
|
//#region src/auth/entitlements.ts
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as better_auth_plugins0 from "better-auth/plugins";
|
|
2
2
|
import { AccessControl } from "better-auth/plugins/access";
|
|
3
3
|
import { organizationClient } from "better-auth/client/plugins";
|
|
4
4
|
|
|
5
5
|
//#region src/auth/permissions.d.ts
|
|
6
6
|
declare const ac: AccessControl;
|
|
7
7
|
declare const memberRole: {
|
|
8
|
-
authorize<K_1 extends "
|
|
9
|
-
actions:
|
|
8
|
+
authorize<K_1 extends "organization" | "project" | "invitation" | "member" | "team" | "ac">(request: K_1 extends infer T extends K ? { [key in T]?: better_auth_plugins0.Subset<"organization" | "project" | "invitation" | "member" | "team" | "ac", better_auth_plugins0.Statements>[key] | {
|
|
9
|
+
actions: better_auth_plugins0.Subset<"organization" | "project" | "invitation" | "member" | "team" | "ac", better_auth_plugins0.Statements>[key];
|
|
10
10
|
connector: "OR" | "AND";
|
|
11
|
-
} | undefined } : never, connector?: "OR" | "AND"):
|
|
12
|
-
statements:
|
|
11
|
+
} | undefined } : never, connector?: "OR" | "AND"): better_auth_plugins0.AuthorizeResponse;
|
|
12
|
+
statements: better_auth_plugins0.Subset<"organization" | "project" | "invitation" | "member" | "team" | "ac", better_auth_plugins0.Statements>;
|
|
13
13
|
};
|
|
14
14
|
declare const adminRole: {
|
|
15
|
-
authorize<K_1 extends "
|
|
16
|
-
actions:
|
|
15
|
+
authorize<K_1 extends "organization" | "project" | "invitation" | "member" | "team" | "ac">(request: K_1 extends infer T extends K ? { [key in T]?: better_auth_plugins0.Subset<"organization" | "project" | "invitation" | "member" | "team" | "ac", better_auth_plugins0.Statements>[key] | {
|
|
16
|
+
actions: better_auth_plugins0.Subset<"organization" | "project" | "invitation" | "member" | "team" | "ac", better_auth_plugins0.Statements>[key];
|
|
17
17
|
connector: "OR" | "AND";
|
|
18
|
-
} | undefined } : never, connector?: "OR" | "AND"):
|
|
19
|
-
statements:
|
|
18
|
+
} | undefined } : never, connector?: "OR" | "AND"): better_auth_plugins0.AuthorizeResponse;
|
|
19
|
+
statements: better_auth_plugins0.Subset<"organization" | "project" | "invitation" | "member" | "team" | "ac", better_auth_plugins0.Statements>;
|
|
20
20
|
};
|
|
21
21
|
declare const ownerRole: {
|
|
22
|
-
authorize<K_1 extends "
|
|
23
|
-
actions:
|
|
22
|
+
authorize<K_1 extends "organization" | "project" | "invitation" | "member" | "team" | "ac">(request: K_1 extends infer T extends K ? { [key in T]?: better_auth_plugins0.Subset<"organization" | "project" | "invitation" | "member" | "team" | "ac", better_auth_plugins0.Statements>[key] | {
|
|
23
|
+
actions: better_auth_plugins0.Subset<"organization" | "project" | "invitation" | "member" | "team" | "ac", better_auth_plugins0.Statements>[key];
|
|
24
24
|
connector: "OR" | "AND";
|
|
25
|
-
} | undefined } : never, connector?: "OR" | "AND"):
|
|
26
|
-
statements:
|
|
25
|
+
} | undefined } : never, connector?: "OR" | "AND"): better_auth_plugins0.AuthorizeResponse;
|
|
26
|
+
statements: better_auth_plugins0.Subset<"organization" | "project" | "invitation" | "member" | "team" | "ac", better_auth_plugins0.Statements>;
|
|
27
27
|
};
|
|
28
28
|
//#endregion
|
|
29
29
|
export { ac, adminRole, memberRole, organizationClient, ownerRole };
|