From 4954ac1c769149813fa757a289148677c36c71e6 Mon Sep 17 00:00:00 2001 From: ShakedSol Date: Tue, 30 Dec 2025 16:18:02 +0200 Subject: [PATCH 1/5] feat(spicedb): release From ca1c761e35b69107b35ecd181e0f3a6de7eec185 Mon Sep 17 00:00:00 2001 From: ShakedSol Date: Wed, 31 Dec 2025 12:11:30 +0200 Subject: [PATCH 2/5] enhance(spicedb): integrate logging client into query methods for improved request tracking --- src/spicedb/spicedb-entitlements.client.ts | 13 ++++++++++++- .../entitlements-spicedb.query.ts | 18 +++++++++++++++++- .../spicedb-queries/features-spicedb.query.ts | 8 ++++++-- .../spicedb-queries/fga-spicedb.query.ts | 8 ++++++-- .../permission-spicedb.query.ts | 8 ++++++-- .../spicedb-queries/route-spicedb.query.ts | 8 ++++++-- .../spicedb-queries/spicedb-query.client.ts | 14 +++++++++----- 7 files changed, 62 insertions(+), 15 deletions(-) diff --git a/src/spicedb/spicedb-entitlements.client.ts b/src/spicedb/spicedb-entitlements.client.ts index 79dd373..e096001 100644 --- a/src/spicedb/spicedb-entitlements.client.ts +++ b/src/spicedb/spicedb-entitlements.client.ts @@ -38,7 +38,7 @@ export class SpiceDBEntitlementsClient { v1.ClientSecurity.INSECURE_PLAINTEXT_CREDENTIALS ).promises; - this.spiceDBQueryClient = new SpiceDBQueryClient(this.spiceClient); + this.spiceDBQueryClient = new SpiceDBQueryClient(this.spiceClient, this.loggingClient); } catch (initError) { void this.loggingClient.error({ action: 'SpiceDBClient:init:error', @@ -55,7 +55,18 @@ export class SpiceDBEntitlementsClient { requestContext: RequestContext ): Promise { try { + await this.loggingClient.logRequest( + { action: 'SpiceDB:isEntitledTo:request', subjectContext, requestContext }, + null + ); + const res = await this.spiceDBQueryClient.spiceDBQuery(subjectContext, requestContext); + + await this.loggingClient.logRequest( + { action: 'SpiceDB:isEntitledTo:response', subjectContext, requestContext }, + res + ); + if (res.result.monitoring || this.logResults) { await this.loggingClient.log(subjectContext, requestContext, res); } diff --git a/src/spicedb/spicedb-queries/entitlements-spicedb.query.ts b/src/spicedb/spicedb-queries/entitlements-spicedb.query.ts index 1810c0a..8de88ef 100644 --- a/src/spicedb/spicedb-queries/entitlements-spicedb.query.ts +++ b/src/spicedb/spicedb-queries/entitlements-spicedb.query.ts @@ -9,6 +9,7 @@ import { import { SpiceDBResponse } from '../../types/spicedb.dto'; import { SpiceDBEntities } from '../../types/spicedb-consts'; import { encodeObjectId } from './base64.utils'; +import { LoggingClient } from '../../logging'; export interface HashOptions { hashResourceId: boolean; @@ -16,7 +17,10 @@ export interface HashOptions { } export abstract class EntitlementsSpiceDBQuery { - protected constructor(protected readonly client: v1.ZedPromiseClientInterface) {} + protected constructor( + protected readonly client: v1.ZedPromiseClientInterface, + protected readonly loggingClient?: LoggingClient + ) {} abstract query( entitlementsQuery: EntitlementsDynamicQuery @@ -128,7 +132,19 @@ export abstract class EntitlementsSpiceDBQuery { const context = subjectContext; const caveatContext = this.createCaveatContext(context); const request = this.createBulkPermissionsRequest(objectType, objectId, context, caveatContext); + + await this.loggingClient?.logRequest( + { action: 'SpiceDB:checkBulkPermissions:request', objectType, objectId, subjectContext }, + { request: JSON.stringify(request, null, 2) } + ); + const res = await this.client.checkBulkPermissions(request); + + await this.loggingClient?.logRequest( + { action: 'SpiceDB:checkBulkPermissions:response', objectType, objectId }, + { response: JSON.stringify(res, null, 2) } + ); + const result = this.processCheckBulkPermissionsResponse(res); return { diff --git a/src/spicedb/spicedb-queries/features-spicedb.query.ts b/src/spicedb/spicedb-queries/features-spicedb.query.ts index eba4c42..fef3f7d 100644 --- a/src/spicedb/spicedb-queries/features-spicedb.query.ts +++ b/src/spicedb/spicedb-queries/features-spicedb.query.ts @@ -3,10 +3,14 @@ import { EntitlementsDynamicQuery, EntitlementsResult, RequestContextType, UserS import { SpiceDBResponse } from '../../types/spicedb.dto'; import { v1 } from '@authzed/authzed-node'; import { SpiceDBEntities } from '../../types/spicedb-consts'; +import { LoggingClient } from '../../logging'; export class FeaturesSpiceDBQuery extends EntitlementsSpiceDBQuery { - constructor(protected readonly client: v1.ZedPromiseClientInterface) { - super(client); + constructor( + protected readonly client: v1.ZedPromiseClientInterface, + loggingClient?: LoggingClient + ) { + super(client, loggingClient); } async query({ diff --git a/src/spicedb/spicedb-queries/fga-spicedb.query.ts b/src/spicedb/spicedb-queries/fga-spicedb.query.ts index f8f2b5b..474d3a7 100644 --- a/src/spicedb/spicedb-queries/fga-spicedb.query.ts +++ b/src/spicedb/spicedb-queries/fga-spicedb.query.ts @@ -3,10 +3,14 @@ import { EntitlementsDynamicQuery, EntitlementsResult, FGASubjectContext, Reques import { SpiceDBResponse } from '../../types/spicedb.dto'; import { v1 } from '@authzed/authzed-node'; import { encodeObjectId } from './base64.utils'; +import { LoggingClient } from '../../logging'; export class FgaSpiceDBQuery extends EntitlementsSpiceDBQuery { - constructor(protected readonly client: v1.ZedPromiseClientInterface) { - super(client); + constructor( + protected readonly client: v1.ZedPromiseClientInterface, + loggingClient?: LoggingClient + ) { + super(client, loggingClient); } async query({ diff --git a/src/spicedb/spicedb-queries/permission-spicedb.query.ts b/src/spicedb/spicedb-queries/permission-spicedb.query.ts index b872a46..17de43e 100644 --- a/src/spicedb/spicedb-queries/permission-spicedb.query.ts +++ b/src/spicedb/spicedb-queries/permission-spicedb.query.ts @@ -3,10 +3,14 @@ import { EntitlementsDynamicQuery, EntitlementsResult, RequestContextType, UserS import { SpiceDBResponse } from '../../types/spicedb.dto'; import { v1 } from '@authzed/authzed-node'; import { SpiceDBEntities } from '../../types/spicedb-consts'; +import { LoggingClient } from '../../logging'; export class PermissionSpiceDBQuery extends EntitlementsSpiceDBQuery { - constructor(protected readonly client: v1.ZedPromiseClientInterface) { - super(client); + constructor( + protected readonly client: v1.ZedPromiseClientInterface, + loggingClient?: LoggingClient + ) { + super(client, loggingClient); } public async query({ diff --git a/src/spicedb/spicedb-queries/route-spicedb.query.ts b/src/spicedb/spicedb-queries/route-spicedb.query.ts index 0a7fd6b..1f68bad 100644 --- a/src/spicedb/spicedb-queries/route-spicedb.query.ts +++ b/src/spicedb/spicedb-queries/route-spicedb.query.ts @@ -5,13 +5,17 @@ import { v1 } from '@authzed/authzed-node'; import { LRUCache } from 'lru-cache'; import { SpiceDBEntities } from '../../types/spicedb-consts'; import { encodeObjectId } from './base64.utils'; +import { LoggingClient } from '../../logging'; export class RouteSpiceDBQuery extends EntitlementsSpiceDBQuery { private readonly cache: LRUCache; private static readonly CACHE_TTL = 30 * 1000; - constructor(protected readonly client: v1.ZedPromiseClientInterface) { - super(client); + constructor( + protected readonly client: v1.ZedPromiseClientInterface, + loggingClient?: LoggingClient + ) { + super(client, loggingClient); this.cache = new LRUCache({ max: 100, ttl: RouteSpiceDBQuery.CACHE_TTL }); } diff --git a/src/spicedb/spicedb-queries/spicedb-query.client.ts b/src/spicedb/spicedb-queries/spicedb-query.client.ts index e74f7b9..81a6ead 100644 --- a/src/spicedb/spicedb-queries/spicedb-query.client.ts +++ b/src/spicedb/spicedb-queries/spicedb-query.client.ts @@ -6,16 +6,20 @@ import { FeaturesSpiceDBQuery } from './features-spicedb.query'; import { FgaSpiceDBQuery } from './fga-spicedb.query'; import { RouteSpiceDBQuery } from './route-spicedb.query'; import { v1 } from '@authzed/authzed-node'; +import { LoggingClient } from '../../logging'; export class SpiceDBQueryClient { private readonly strategy: Record; - constructor(private readonly client: v1.ZedPromiseClientInterface) { + constructor( + private readonly client: v1.ZedPromiseClientInterface, + loggingClient?: LoggingClient + ) { this.strategy = { - [RequestContextType.Permission]: new PermissionSpiceDBQuery(client), - [RequestContextType.Feature]: new FeaturesSpiceDBQuery(client), - [RequestContextType.Entity]: new FgaSpiceDBQuery(client), - [RequestContextType.Route]: new RouteSpiceDBQuery(client) + [RequestContextType.Permission]: new PermissionSpiceDBQuery(client, loggingClient), + [RequestContextType.Feature]: new FeaturesSpiceDBQuery(client, loggingClient), + [RequestContextType.Entity]: new FgaSpiceDBQuery(client, loggingClient), + [RequestContextType.Route]: new RouteSpiceDBQuery(client, loggingClient) }; } From b582c1454427865f6b87fb2132af7dc415edd01b Mon Sep 17 00:00:00 2001 From: ShakedSol Date: Wed, 31 Dec 2025 12:21:13 +0200 Subject: [PATCH 3/5] refactor(spicedb): optimize logging format in checkBulkPermissions method --- src/spicedb/spicedb-queries/entitlements-spicedb.query.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spicedb/spicedb-queries/entitlements-spicedb.query.ts b/src/spicedb/spicedb-queries/entitlements-spicedb.query.ts index 8de88ef..754da3f 100644 --- a/src/spicedb/spicedb-queries/entitlements-spicedb.query.ts +++ b/src/spicedb/spicedb-queries/entitlements-spicedb.query.ts @@ -135,14 +135,14 @@ export abstract class EntitlementsSpiceDBQuery { await this.loggingClient?.logRequest( { action: 'SpiceDB:checkBulkPermissions:request', objectType, objectId, subjectContext }, - { request: JSON.stringify(request, null, 2) } + { request } ); const res = await this.client.checkBulkPermissions(request); await this.loggingClient?.logRequest( { action: 'SpiceDB:checkBulkPermissions:response', objectType, objectId }, - { response: JSON.stringify(res, null, 2) } + { response: res } ); const result = this.processCheckBulkPermissionsResponse(res); From a70fc1136f51714b2ea71ac1d18c37641e9ff7af Mon Sep 17 00:00:00 2001 From: ShakedSol Date: Wed, 31 Dec 2025 12:23:39 +0200 Subject: [PATCH 4/5] refactor(spicedb): conditionally log requests and responses in isEntitledTo method --- src/spicedb/spicedb-entitlements.client.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/spicedb/spicedb-entitlements.client.ts b/src/spicedb/spicedb-entitlements.client.ts index e096001..04601f6 100644 --- a/src/spicedb/spicedb-entitlements.client.ts +++ b/src/spicedb/spicedb-entitlements.client.ts @@ -55,17 +55,21 @@ export class SpiceDBEntitlementsClient { requestContext: RequestContext ): Promise { try { - await this.loggingClient.logRequest( - { action: 'SpiceDB:isEntitledTo:request', subjectContext, requestContext }, - null - ); + if (this.logResults) { + await this.loggingClient.logRequest( + { action: 'SpiceDB:isEntitledTo:request', subjectContext, requestContext }, + null + ); + } const res = await this.spiceDBQueryClient.spiceDBQuery(subjectContext, requestContext); - await this.loggingClient.logRequest( - { action: 'SpiceDB:isEntitledTo:response', subjectContext, requestContext }, - res - ); + if (this.logResults) { + await this.loggingClient.logRequest( + { action: 'SpiceDB:isEntitledTo:response', subjectContext, requestContext }, + res + ); + } if (res.result.monitoring || this.logResults) { await this.loggingClient.log(subjectContext, requestContext, res); From 08601b634bdd4f9d4e8863717015aefae96b0ddb Mon Sep 17 00:00:00 2001 From: ShakedSol Date: Wed, 31 Dec 2025 12:32:15 +0200 Subject: [PATCH 5/5] refactor(spicedb): add logResults parameter to query classes for conditional logging --- src/spicedb/spicedb-entitlements.client.ts | 2 +- .../entitlements-spicedb.query.ts | 23 +++++++++++-------- .../spicedb-queries/features-spicedb.query.ts | 5 ++-- .../spicedb-queries/fga-spicedb.query.ts | 5 ++-- .../permission-spicedb.query.ts | 5 ++-- .../spicedb-queries/route-spicedb.query.ts | 5 ++-- .../spicedb-queries/spicedb-query.client.ts | 11 +++++---- 7 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/spicedb/spicedb-entitlements.client.ts b/src/spicedb/spicedb-entitlements.client.ts index 04601f6..d4aa093 100644 --- a/src/spicedb/spicedb-entitlements.client.ts +++ b/src/spicedb/spicedb-entitlements.client.ts @@ -38,7 +38,7 @@ export class SpiceDBEntitlementsClient { v1.ClientSecurity.INSECURE_PLAINTEXT_CREDENTIALS ).promises; - this.spiceDBQueryClient = new SpiceDBQueryClient(this.spiceClient, this.loggingClient); + this.spiceDBQueryClient = new SpiceDBQueryClient(this.spiceClient, this.loggingClient, this.logResults); } catch (initError) { void this.loggingClient.error({ action: 'SpiceDBClient:init:error', diff --git a/src/spicedb/spicedb-queries/entitlements-spicedb.query.ts b/src/spicedb/spicedb-queries/entitlements-spicedb.query.ts index 754da3f..ec01b2b 100644 --- a/src/spicedb/spicedb-queries/entitlements-spicedb.query.ts +++ b/src/spicedb/spicedb-queries/entitlements-spicedb.query.ts @@ -19,7 +19,8 @@ export interface HashOptions { export abstract class EntitlementsSpiceDBQuery { protected constructor( protected readonly client: v1.ZedPromiseClientInterface, - protected readonly loggingClient?: LoggingClient + protected readonly loggingClient?: LoggingClient, + protected readonly logResults: boolean = false ) {} abstract query( @@ -133,17 +134,21 @@ export abstract class EntitlementsSpiceDBQuery { const caveatContext = this.createCaveatContext(context); const request = this.createBulkPermissionsRequest(objectType, objectId, context, caveatContext); - await this.loggingClient?.logRequest( - { action: 'SpiceDB:checkBulkPermissions:request', objectType, objectId, subjectContext }, - { request } - ); + if (this.logResults) { + await this.loggingClient?.logRequest( + { action: 'SpiceDB:checkBulkPermissions:request', objectType, objectId, subjectContext }, + { request } + ); + } const res = await this.client.checkBulkPermissions(request); - await this.loggingClient?.logRequest( - { action: 'SpiceDB:checkBulkPermissions:response', objectType, objectId }, - { response: res } - ); + if (this.logResults) { + await this.loggingClient?.logRequest( + { action: 'SpiceDB:checkBulkPermissions:response', objectType, objectId }, + { response: res } + ); + } const result = this.processCheckBulkPermissionsResponse(res); diff --git a/src/spicedb/spicedb-queries/features-spicedb.query.ts b/src/spicedb/spicedb-queries/features-spicedb.query.ts index fef3f7d..689e542 100644 --- a/src/spicedb/spicedb-queries/features-spicedb.query.ts +++ b/src/spicedb/spicedb-queries/features-spicedb.query.ts @@ -8,9 +8,10 @@ import { LoggingClient } from '../../logging'; export class FeaturesSpiceDBQuery extends EntitlementsSpiceDBQuery { constructor( protected readonly client: v1.ZedPromiseClientInterface, - loggingClient?: LoggingClient + loggingClient?: LoggingClient, + logResults: boolean = false ) { - super(client, loggingClient); + super(client, loggingClient, logResults); } async query({ diff --git a/src/spicedb/spicedb-queries/fga-spicedb.query.ts b/src/spicedb/spicedb-queries/fga-spicedb.query.ts index 474d3a7..6d7a760 100644 --- a/src/spicedb/spicedb-queries/fga-spicedb.query.ts +++ b/src/spicedb/spicedb-queries/fga-spicedb.query.ts @@ -8,9 +8,10 @@ import { LoggingClient } from '../../logging'; export class FgaSpiceDBQuery extends EntitlementsSpiceDBQuery { constructor( protected readonly client: v1.ZedPromiseClientInterface, - loggingClient?: LoggingClient + loggingClient?: LoggingClient, + logResults: boolean = false ) { - super(client, loggingClient); + super(client, loggingClient, logResults); } async query({ diff --git a/src/spicedb/spicedb-queries/permission-spicedb.query.ts b/src/spicedb/spicedb-queries/permission-spicedb.query.ts index 17de43e..ba8ef34 100644 --- a/src/spicedb/spicedb-queries/permission-spicedb.query.ts +++ b/src/spicedb/spicedb-queries/permission-spicedb.query.ts @@ -8,9 +8,10 @@ import { LoggingClient } from '../../logging'; export class PermissionSpiceDBQuery extends EntitlementsSpiceDBQuery { constructor( protected readonly client: v1.ZedPromiseClientInterface, - loggingClient?: LoggingClient + loggingClient?: LoggingClient, + logResults: boolean = false ) { - super(client, loggingClient); + super(client, loggingClient, logResults); } public async query({ diff --git a/src/spicedb/spicedb-queries/route-spicedb.query.ts b/src/spicedb/spicedb-queries/route-spicedb.query.ts index 1f68bad..edfa74a 100644 --- a/src/spicedb/spicedb-queries/route-spicedb.query.ts +++ b/src/spicedb/spicedb-queries/route-spicedb.query.ts @@ -13,9 +13,10 @@ export class RouteSpiceDBQuery extends EntitlementsSpiceDBQuery { constructor( protected readonly client: v1.ZedPromiseClientInterface, - loggingClient?: LoggingClient + loggingClient?: LoggingClient, + logResults: boolean = false ) { - super(client, loggingClient); + super(client, loggingClient, logResults); this.cache = new LRUCache({ max: 100, ttl: RouteSpiceDBQuery.CACHE_TTL }); } diff --git a/src/spicedb/spicedb-queries/spicedb-query.client.ts b/src/spicedb/spicedb-queries/spicedb-query.client.ts index 81a6ead..40d9747 100644 --- a/src/spicedb/spicedb-queries/spicedb-query.client.ts +++ b/src/spicedb/spicedb-queries/spicedb-query.client.ts @@ -13,13 +13,14 @@ export class SpiceDBQueryClient { constructor( private readonly client: v1.ZedPromiseClientInterface, - loggingClient?: LoggingClient + loggingClient?: LoggingClient, + logResults: boolean = false ) { this.strategy = { - [RequestContextType.Permission]: new PermissionSpiceDBQuery(client, loggingClient), - [RequestContextType.Feature]: new FeaturesSpiceDBQuery(client, loggingClient), - [RequestContextType.Entity]: new FgaSpiceDBQuery(client, loggingClient), - [RequestContextType.Route]: new RouteSpiceDBQuery(client, loggingClient) + [RequestContextType.Permission]: new PermissionSpiceDBQuery(client, loggingClient, logResults), + [RequestContextType.Feature]: new FeaturesSpiceDBQuery(client, loggingClient, logResults), + [RequestContextType.Entity]: new FgaSpiceDBQuery(client, loggingClient, logResults), + [RequestContextType.Route]: new RouteSpiceDBQuery(client, loggingClient, logResults) }; }