@@ -164,14 +164,14 @@ export class ObjectStackRuntimeProtocol {
164164 // Query Methods
165165 async findData(objectName : string , query ? : any ): Promise <{ value: any []; count: number }> {
166166 if (! this .kernel .find ) {
167- throw new Error (' Kernel does not support find operation' );
167+ throw new Error (' The kernel does not support the find operation' );
168168 }
169169 return await this .kernel .find (objectName , query || {});
170170 }
171171
172172 async getData(objectName : string , id : string ): Promise <any > {
173173 if (! this .kernel .get ) {
174- throw new Error (' Kernel does not support get operation' );
174+ throw new Error (' The kernel does not support the get operation' );
175175 }
176176 return await this .kernel .get (objectName , id );
177177 }
@@ -184,21 +184,21 @@ export class ObjectStackRuntimeProtocol {
184184 // Mutation Methods
185185 async createData(objectName : string , data : any ): Promise <any > {
186186 if (! this .kernel .create ) {
187- throw new Error (' Kernel does not support create operation' );
187+ throw new Error (' The kernel does not support the create operation' );
188188 }
189189 return await this .kernel .create (objectName , data );
190190 }
191191
192192 async updateData(objectName : string , id : string , data : any ): Promise <any > {
193193 if (! this .kernel .update ) {
194- throw new Error (' Kernel does not support update operation' );
194+ throw new Error (' The kernel does not support the update operation' );
195195 }
196196 return await this .kernel .update (objectName , id , data );
197197 }
198198
199199 async deleteData(objectName : string , id : string ): Promise <boolean > {
200200 if (! this .kernel .delete ) {
201- throw new Error (' Kernel does not support delete operation' );
201+ throw new Error (' The kernel does not support the delete operation' );
202202 }
203203 return await this .kernel .delete (objectName , id );
204204 }
@@ -338,7 +338,7 @@ import type Redis from 'ioredis';
338338export interface RedisPermissionStorageConfig {
339339 redis: Redis ;
340340 keyPrefix? : string ;
341- ttl? : number ; // Time to live in seconds
341+ ttl? : number ; // Time to live in seconds (sliding expiration - refreshed on each access)
342342}
343343
344344export class RedisPermissionStorage {
@@ -369,20 +369,31 @@ export class RedisPermissionStorage {
369369 await this .redis .del (key );
370370 } else {
371371 // Delete all permissions for role
372+ // Using SCAN instead of KEYS for production safety (non-blocking)
372373 const pattern = ` ${this .keyPrefix }${role }:* ` ;
373- const keys = await this .redis .keys (pattern );
374- if (keys .length > 0 ) {
375- await this .redis .del (... keys );
376- }
374+ await this .scanAndDelete (pattern );
377375 }
378376 }
379377
380378 async clear(): Promise <void > {
379+ // Using SCAN instead of KEYS for production safety (non-blocking)
381380 const pattern = ` ${this .keyPrefix }* ` ;
382- const keys = await this .redis .keys (pattern );
383- if (keys .length > 0 ) {
384- await this .redis .del (... keys );
385- }
381+ await this .scanAndDelete (pattern );
382+ }
383+
384+ /**
385+ * Safely delete keys matching pattern using SCAN (non-blocking)
386+ * @private
387+ */
388+ private async scanAndDelete(pattern : string ): Promise <void > {
389+ let cursor = ' 0' ;
390+ do {
391+ const [newCursor, keys] = await this .redis .scan (cursor , ' MATCH' , pattern , ' COUNT' , 100 );
392+ cursor = newCursor ;
393+ if (keys .length > 0 ) {
394+ await this .redis .del (... keys );
395+ }
396+ } while (cursor !== ' 0' );
386397 }
387398}
388399```
0 commit comments