@kysera/rls 0.5.1

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.
@@ -0,0 +1,705 @@
1
+ import { R as RLSSchema, O as Operation, P as PolicyCondition, a as PolicyHints, b as PolicyDefinition, F as FilterCondition, T as TableRLSConfig, C as CompiledPolicy, c as CompiledFilterPolicy, d as RLSContext, e as RLSAuthContext, f as RLSRequestContext, g as PolicyEvaluationContext } from './types-Dtg6Lt1k.js';
2
+ export { h as PolicyType } from './types-Dtg6Lt1k.js';
3
+ import { KyseraLogger, ErrorCode } from '@kysera/core';
4
+ import { Plugin } from '@kysera/repository';
5
+ import 'kysely';
6
+
7
+ /**
8
+ * RLS schema definition and validation
9
+ *
10
+ * Provides functions to define, validate, and merge RLS schemas.
11
+ */
12
+
13
+ /**
14
+ * Define RLS schema with full type safety
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * interface Database {
19
+ * users: { id: number; email: string; tenant_id: number };
20
+ * posts: { id: number; user_id: number; tenant_id: number };
21
+ * }
22
+ *
23
+ * const schema = defineRLSSchema<Database>({
24
+ * users: {
25
+ * policies: [
26
+ * // Users can read their own records
27
+ * allow('read', ctx => ctx.auth.userId === ctx.row.id),
28
+ * // Filter by tenant
29
+ * filter('read', ctx => ({ tenant_id: ctx.auth.tenantId })),
30
+ * // Admins bypass all checks
31
+ * allow('all', ctx => ctx.auth.roles.includes('admin')),
32
+ * ],
33
+ * },
34
+ * posts: {
35
+ * policies: [
36
+ * // Filter posts by tenant
37
+ * filter('read', ctx => ({ tenant_id: ctx.auth.tenantId })),
38
+ * // Users can only edit their own posts
39
+ * allow(['update', 'delete'], ctx => ctx.auth.userId === ctx.row.user_id),
40
+ * // Validate new posts belong to user's tenant
41
+ * validate('create', ctx => ctx.data.tenant_id === ctx.auth.tenantId),
42
+ * ],
43
+ * defaultDeny: true, // Require explicit allow
44
+ * },
45
+ * });
46
+ * ```
47
+ */
48
+ declare function defineRLSSchema<DB>(schema: RLSSchema<DB>): RLSSchema<DB>;
49
+ /**
50
+ * Merge multiple RLS schemas
51
+ * Later schemas override earlier ones for the same table
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * const baseSchema = defineRLSSchema<Database>({
56
+ * users: {
57
+ * policies: [
58
+ * filter('read', ctx => ({ tenant_id: ctx.auth.tenantId })),
59
+ * ],
60
+ * },
61
+ * });
62
+ *
63
+ * const adminSchema = defineRLSSchema<Database>({
64
+ * users: {
65
+ * policies: [
66
+ * allow('all', ctx => ctx.auth.roles.includes('admin')),
67
+ * ],
68
+ * },
69
+ * });
70
+ *
71
+ * // Merged schema will have both filters and admin allow
72
+ * const merged = mergeRLSSchemas(baseSchema, adminSchema);
73
+ * ```
74
+ */
75
+ declare function mergeRLSSchemas<DB>(...schemas: RLSSchema<DB>[]): RLSSchema<DB>;
76
+
77
+ /**
78
+ * Fluent policy builders for Row-Level Security
79
+ *
80
+ * Provides intuitive builder functions for creating RLS policies:
81
+ * - allow: Grants access when condition is true
82
+ * - deny: Blocks access when condition is true (overrides allow)
83
+ * - filter: Adds WHERE conditions to SELECT queries
84
+ * - validate: Validates mutation data before execution
85
+ */
86
+
87
+ /**
88
+ * Options for policy definitions
89
+ */
90
+ interface PolicyOptions {
91
+ /** Policy name for debugging and identification */
92
+ name?: string;
93
+ /** Priority (higher runs first, deny policies default to 100) */
94
+ priority?: number;
95
+ /** Performance optimization hints */
96
+ hints?: PolicyHints;
97
+ }
98
+ /**
99
+ * Create an allow policy
100
+ * Grants access when condition evaluates to true
101
+ *
102
+ * @example
103
+ * ```typescript
104
+ * // Allow users to read their own records
105
+ * allow('read', ctx => ctx.auth.userId === ctx.row.userId)
106
+ *
107
+ * // Allow admins to do everything
108
+ * allow('all', ctx => ctx.auth.roles.includes('admin'))
109
+ *
110
+ * // Allow with multiple operations
111
+ * allow(['read', 'update'], ctx => ctx.auth.userId === ctx.row.userId)
112
+ *
113
+ * // Named policy with priority
114
+ * allow('read', ctx => ctx.auth.roles.includes('verified'), {
115
+ * name: 'verified-users-only',
116
+ * priority: 10
117
+ * })
118
+ * ```
119
+ */
120
+ declare function allow(operation: Operation | Operation[], condition: PolicyCondition, options?: PolicyOptions): PolicyDefinition;
121
+ /**
122
+ * Create a deny policy
123
+ * Blocks access when condition evaluates to true (overrides allow)
124
+ * If no condition is provided, always denies
125
+ *
126
+ * @example
127
+ * ```typescript
128
+ * // Deny access to banned users
129
+ * deny('all', ctx => ctx.auth.attributes?.banned === true)
130
+ *
131
+ * // Deny deletions on archived records
132
+ * deny('delete', ctx => ctx.row.archived === true)
133
+ *
134
+ * // Deny all access to sensitive table
135
+ * deny('all')
136
+ *
137
+ * // Named deny with high priority
138
+ * deny('all', ctx => ctx.auth.attributes?.suspended === true, {
139
+ * name: 'block-suspended-users',
140
+ * priority: 200
141
+ * })
142
+ * ```
143
+ */
144
+ declare function deny(operation: Operation | Operation[], condition?: PolicyCondition, options?: PolicyOptions): PolicyDefinition;
145
+ /**
146
+ * Create a filter policy
147
+ * Adds WHERE conditions to SELECT queries
148
+ *
149
+ * @example
150
+ * ```typescript
151
+ * // Filter by tenant
152
+ * filter('read', ctx => ({ tenant_id: ctx.auth.tenantId }))
153
+ *
154
+ * // Filter by organization with soft delete
155
+ * filter('read', ctx => ({
156
+ * organization_id: ctx.auth.organizationIds?.[0],
157
+ * deleted_at: null
158
+ * }))
159
+ *
160
+ * // Named filter
161
+ * filter('read', ctx => ({ tenant_id: ctx.auth.tenantId }), {
162
+ * name: 'tenant-filter'
163
+ * })
164
+ * ```
165
+ */
166
+ declare function filter(operation: 'read' | 'all', condition: FilterCondition, options?: PolicyOptions): PolicyDefinition;
167
+ /**
168
+ * Create a validate policy
169
+ * Validates mutation data before execution
170
+ *
171
+ * @example
172
+ * ```typescript
173
+ * // Validate user can only set their own user_id
174
+ * validate('create', ctx => ctx.data.userId === ctx.auth.userId)
175
+ *
176
+ * // Validate status transitions
177
+ * validate('update', ctx => {
178
+ * const { status } = ctx.data;
179
+ * return !status || ['draft', 'published'].includes(status);
180
+ * })
181
+ *
182
+ * // Apply to both create and update
183
+ * validate('all', ctx => ctx.data.price >= 0)
184
+ *
185
+ * // Named validation
186
+ * validate('create', ctx => validateEmail(ctx.data.email), {
187
+ * name: 'validate-email'
188
+ * })
189
+ * ```
190
+ */
191
+ declare function validate(operation: 'create' | 'update' | 'all', condition: PolicyCondition, options?: PolicyOptions): PolicyDefinition;
192
+
193
+ /**
194
+ * Policy Registry
195
+ * Central registry for managing RLS policies across all tables
196
+ *
197
+ * The PolicyRegistry compiles and stores RLS policies for efficient runtime lookup.
198
+ * It categorizes policies by type (allow/deny/filter/validate) and operation,
199
+ * and provides methods to query policies for specific tables and operations.
200
+ */
201
+
202
+ /**
203
+ * Policy Registry
204
+ * Manages and provides access to RLS policies
205
+ */
206
+ declare class PolicyRegistry<DB = unknown> {
207
+ private tables;
208
+ private compiled;
209
+ private logger;
210
+ constructor(schema?: RLSSchema<DB>, options?: {
211
+ logger?: KyseraLogger;
212
+ });
213
+ /**
214
+ * Load and compile policies from schema
215
+ *
216
+ * @example
217
+ * ```typescript
218
+ * const registry = new PolicyRegistry<Database>();
219
+ * registry.loadSchema({
220
+ * users: {
221
+ * policies: [
222
+ * allow('read', ctx => ctx.auth.userId === ctx.row.id),
223
+ * filter('read', ctx => ({ tenant_id: ctx.auth.tenantId })),
224
+ * ],
225
+ * defaultDeny: true,
226
+ * },
227
+ * });
228
+ * ```
229
+ */
230
+ loadSchema(schema: RLSSchema<DB>): void;
231
+ /**
232
+ * Register policies for a single table
233
+ *
234
+ * @param table - Table name
235
+ * @param config - Table RLS configuration
236
+ */
237
+ registerTable(table: string, config: TableRLSConfig): void;
238
+ /**
239
+ * Register policies - supports both schema and table-based registration
240
+ *
241
+ * @overload Register a full schema
242
+ * @overload Register policies for a single table (deprecated)
243
+ */
244
+ register(schemaOrTable: RLSSchema<DB>): void;
245
+ register(schemaOrTable: keyof DB & string, policies: PolicyDefinition[], options?: {
246
+ skipFor?: string[];
247
+ defaultDeny?: boolean;
248
+ }): void;
249
+ /**
250
+ * Compile a policy definition into an internal compiled policy
251
+ *
252
+ * @param policy - Policy definition to compile
253
+ * @param name - Policy name for debugging
254
+ * @returns Compiled policy ready for evaluation
255
+ */
256
+ private compilePolicy;
257
+ /**
258
+ * Compile a filter policy
259
+ *
260
+ * @param policy - Filter policy definition
261
+ * @param name - Policy name for debugging
262
+ * @returns Compiled filter policy
263
+ */
264
+ private compileFilterPolicy;
265
+ /**
266
+ * Convert internal compiled policy to public CompiledPolicy
267
+ */
268
+ private toCompiledPolicy;
269
+ /**
270
+ * Get allow policies for a table and operation
271
+ */
272
+ getAllows(table: string, operation: Operation): CompiledPolicy[];
273
+ /**
274
+ * Get deny policies for a table and operation
275
+ */
276
+ getDenies(table: string, operation: Operation): CompiledPolicy[];
277
+ /**
278
+ * Get validate policies for a table and operation
279
+ */
280
+ getValidates(table: string, operation: Operation): CompiledPolicy[];
281
+ /**
282
+ * Get filter policies for a table
283
+ */
284
+ getFilters(table: string): CompiledFilterPolicy[];
285
+ /**
286
+ * Get roles that skip RLS for a table
287
+ */
288
+ getSkipFor(table: string): string[];
289
+ /**
290
+ * Check if table has default deny
291
+ */
292
+ hasDefaultDeny(table: string): boolean;
293
+ /**
294
+ * Check if a table is registered
295
+ */
296
+ hasTable(table: string): boolean;
297
+ /**
298
+ * Get all registered table names
299
+ */
300
+ getTables(): string[];
301
+ /**
302
+ * Check if registry is compiled
303
+ */
304
+ isCompiled(): boolean;
305
+ /**
306
+ * Validate that all policies are properly defined
307
+ *
308
+ * This method checks for common issues:
309
+ * - Tables with no policies and defaultDeny=false (warns)
310
+ * - Tables with skipFor operations but no corresponding policies
311
+ */
312
+ validate(): void;
313
+ /**
314
+ * Clear all policies
315
+ */
316
+ clear(): void;
317
+ /**
318
+ * Remove policies for a specific table
319
+ */
320
+ remove(table: string): void;
321
+ }
322
+
323
+ /**
324
+ * RLS Error Classes
325
+ *
326
+ * This module provides specialized error classes for Row-Level Security operations.
327
+ * All errors extend the base RLSError class and use unified error codes from @kysera/core
328
+ * for consistency across the Kysera ecosystem.
329
+ *
330
+ * @module @kysera/rls/errors
331
+ */
332
+
333
+ /**
334
+ * RLS-specific error codes
335
+ *
336
+ * These codes extend the unified error codes from @kysera/core with
337
+ * RLS-specific error conditions.
338
+ */
339
+ declare const RLSErrorCodes: {
340
+ /** RLS context is missing or not set */
341
+ readonly RLS_CONTEXT_MISSING: ErrorCode;
342
+ /** RLS policy violation occurred */
343
+ readonly RLS_POLICY_VIOLATION: ErrorCode;
344
+ /** RLS policy definition is invalid */
345
+ readonly RLS_POLICY_INVALID: ErrorCode;
346
+ /** RLS schema definition is invalid */
347
+ readonly RLS_SCHEMA_INVALID: ErrorCode;
348
+ /** RLS context validation failed */
349
+ readonly RLS_CONTEXT_INVALID: ErrorCode;
350
+ };
351
+ /**
352
+ * Type for RLS error codes
353
+ */
354
+ type RLSErrorCode = typeof RLSErrorCodes[keyof typeof RLSErrorCodes];
355
+ /**
356
+ * Base class for all RLS-related errors
357
+ *
358
+ * Provides common error functionality including error codes and JSON serialization.
359
+ *
360
+ * @example
361
+ * ```typescript
362
+ * throw new RLSError('Something went wrong', RLSErrorCodes.RLS_POLICY_INVALID);
363
+ * ```
364
+ */
365
+ declare class RLSError extends Error {
366
+ readonly code: RLSErrorCode;
367
+ /**
368
+ * Creates a new RLS error
369
+ *
370
+ * @param message - Error message
371
+ * @param code - RLS error code
372
+ */
373
+ constructor(message: string, code: RLSErrorCode);
374
+ /**
375
+ * Serializes the error to JSON
376
+ *
377
+ * @returns JSON representation of the error
378
+ */
379
+ toJSON(): Record<string, unknown>;
380
+ }
381
+ /**
382
+ * Error thrown when RLS context is missing
383
+ *
384
+ * This error occurs when an operation requiring RLS context is executed
385
+ * outside of a context scope (i.e., without calling withRLSContext()).
386
+ *
387
+ * @example
388
+ * ```typescript
389
+ * // This will throw RLSContextError
390
+ * const result = await db.selectFrom('posts').execute();
391
+ *
392
+ * // Correct usage with context
393
+ * await withRLSContext(rlsContext, async () => {
394
+ * const result = await db.selectFrom('posts').execute();
395
+ * });
396
+ * ```
397
+ */
398
+ declare class RLSContextError extends RLSError {
399
+ /**
400
+ * Creates a new RLS context error
401
+ *
402
+ * @param message - Error message (defaults to standard message)
403
+ */
404
+ constructor(message?: string);
405
+ }
406
+ /**
407
+ * Error thrown when RLS context validation fails
408
+ *
409
+ * This error occurs when the provided RLS context is invalid or missing
410
+ * required fields.
411
+ *
412
+ * @example
413
+ * ```typescript
414
+ * // Missing required userId field
415
+ * const invalidContext = {
416
+ * auth: {
417
+ * roles: ['user']
418
+ * // userId is missing!
419
+ * },
420
+ * timestamp: new Date()
421
+ * };
422
+ *
423
+ * // This will throw RLSContextValidationError
424
+ * validateRLSContext(invalidContext);
425
+ * ```
426
+ */
427
+ declare class RLSContextValidationError extends RLSError {
428
+ readonly field: string;
429
+ /**
430
+ * Creates a new context validation error
431
+ *
432
+ * @param message - Error message
433
+ * @param field - Field that failed validation
434
+ */
435
+ constructor(message: string, field: string);
436
+ toJSON(): Record<string, unknown>;
437
+ }
438
+ /**
439
+ * Error thrown when an RLS policy violation occurs
440
+ *
441
+ * This error is thrown when a database operation is denied by RLS policies.
442
+ * It provides detailed information about the violation including the operation,
443
+ * table, and reason for denial.
444
+ *
445
+ * @example
446
+ * ```typescript
447
+ * // User tries to update a post they don't own
448
+ * throw new RLSPolicyViolation(
449
+ * 'update',
450
+ * 'posts',
451
+ * 'User does not own this post',
452
+ * 'ownership_policy'
453
+ * );
454
+ * ```
455
+ */
456
+ declare class RLSPolicyViolation extends RLSError {
457
+ readonly operation: string;
458
+ readonly table: string;
459
+ readonly reason: string;
460
+ readonly policyName?: string;
461
+ /**
462
+ * Creates a new policy violation error
463
+ *
464
+ * @param operation - Database operation that was denied (read, create, update, delete)
465
+ * @param table - Table name where violation occurred
466
+ * @param reason - Reason for the policy violation
467
+ * @param policyName - Name of the policy that denied access (optional)
468
+ */
469
+ constructor(operation: string, table: string, reason: string, policyName?: string);
470
+ toJSON(): Record<string, unknown>;
471
+ }
472
+ /**
473
+ * Error thrown when RLS schema validation fails
474
+ *
475
+ * This error occurs when the RLS schema definition is invalid or contains
476
+ * configuration errors.
477
+ *
478
+ * @example
479
+ * ```typescript
480
+ * // Invalid policy definition
481
+ * const invalidSchema = {
482
+ * posts: {
483
+ * policies: [
484
+ * {
485
+ * type: 'invalid-type', // Invalid policy type!
486
+ * operation: 'read',
487
+ * condition: (ctx) => true
488
+ * }
489
+ * ]
490
+ * }
491
+ * };
492
+ *
493
+ * // This will throw RLSSchemaError
494
+ * validateRLSSchema(invalidSchema);
495
+ * ```
496
+ */
497
+ declare class RLSSchemaError extends RLSError {
498
+ readonly details: Record<string, unknown>;
499
+ /**
500
+ * Creates a new schema validation error
501
+ *
502
+ * @param message - Error message
503
+ * @param details - Additional details about the validation failure
504
+ */
505
+ constructor(message: string, details?: Record<string, unknown>);
506
+ toJSON(): Record<string, unknown>;
507
+ }
508
+
509
+ /**
510
+ * RLS Plugin for Kysera Repository
511
+ *
512
+ * Implements Row-Level Security as a Kysera plugin, providing:
513
+ * - Automatic query filtering for SELECT operations
514
+ * - Policy enforcement for CREATE, UPDATE, DELETE operations
515
+ * - Repository method extensions for RLS-aware operations
516
+ * - System context bypass for privileged operations
517
+ *
518
+ * @module @kysera/rls
519
+ */
520
+
521
+ /**
522
+ * RLS Plugin configuration options
523
+ */
524
+ interface RLSPluginOptions<DB = unknown> {
525
+ /** RLS policy schema */
526
+ schema: RLSSchema<DB>;
527
+ /** Tables to skip RLS for (always bypass policies) */
528
+ skipTables?: string[];
529
+ /** Roles that bypass RLS entirely (e.g., ['admin', 'superuser']) */
530
+ bypassRoles?: string[];
531
+ /** Logger instance for RLS operations */
532
+ logger?: KyseraLogger;
533
+ /** Require RLS context for all operations (throws if missing) */
534
+ requireContext?: boolean;
535
+ /** Enable audit logging of policy decisions */
536
+ auditDecisions?: boolean;
537
+ /** Custom error handler for policy violations */
538
+ onViolation?: (violation: RLSPolicyViolation) => void;
539
+ }
540
+ /**
541
+ * Create RLS plugin for Kysera
542
+ *
543
+ * The RLS plugin provides declarative row-level security for your database operations.
544
+ * It automatically filters SELECT queries and validates mutations (CREATE, UPDATE, DELETE)
545
+ * against your policy schema.
546
+ *
547
+ * @example
548
+ * ```typescript
549
+ * import { rlsPlugin, defineRLSSchema, allow, filter } from '@kysera/rls';
550
+ * import { createORM } from '@kysera/repository';
551
+ *
552
+ * // Define your RLS schema
553
+ * const schema = defineRLSSchema<Database>({
554
+ * resources: {
555
+ * policies: [
556
+ * // Filter reads by tenant
557
+ * filter('read', ctx => ({ tenant_id: ctx.auth.tenantId })),
558
+ * // Allow updates for resource owners
559
+ * allow('update', ctx => ctx.auth.userId === ctx.row.owner_id),
560
+ * // Validate creates belong to user's tenant
561
+ * validate('create', ctx => ctx.data.tenant_id === ctx.auth.tenantId),
562
+ * ],
563
+ * },
564
+ * });
565
+ *
566
+ * // Create ORM with RLS plugin
567
+ * const orm = await createORM(db, [
568
+ * rlsPlugin({ schema }),
569
+ * ]);
570
+ *
571
+ * // Use within RLS context
572
+ * await rlsContext.runAsync(
573
+ * {
574
+ * auth: { userId: 1, tenantId: 100, roles: ['user'], isSystem: false },
575
+ * timestamp: new Date(),
576
+ * },
577
+ * async () => {
578
+ * // All queries automatically filtered by tenant_id
579
+ * const resources = await orm.resources.findAll();
580
+ * }
581
+ * );
582
+ * ```
583
+ *
584
+ * @param options - Plugin configuration options
585
+ * @returns Kysera plugin instance
586
+ */
587
+ declare function rlsPlugin<DB>(options: RLSPluginOptions<DB>): Plugin;
588
+
589
+ /**
590
+ * Options for creating RLS context
591
+ */
592
+ interface CreateRLSContextOptions<TUser = unknown, TMeta = unknown> {
593
+ auth: RLSAuthContext<TUser>;
594
+ request?: Partial<RLSRequestContext>;
595
+ meta?: TMeta;
596
+ }
597
+ /**
598
+ * Create a new RLS context
599
+ */
600
+ declare function createRLSContext<TUser = unknown, TMeta = unknown>(options: CreateRLSContextOptions<TUser, TMeta>): RLSContext<TUser, TMeta>;
601
+ /**
602
+ * RLS Context Manager
603
+ * Manages RLS context using AsyncLocalStorage for automatic propagation
604
+ */
605
+ declare class RLSContextManager {
606
+ /**
607
+ * Run a synchronous function within an RLS context
608
+ */
609
+ run<T>(context: RLSContext, fn: () => T): T;
610
+ /**
611
+ * Run an async function within an RLS context
612
+ */
613
+ runAsync<T>(context: RLSContext, fn: () => Promise<T>): Promise<T>;
614
+ /**
615
+ * Get current RLS context
616
+ * @throws RLSContextError if no context is set
617
+ */
618
+ getContext(): RLSContext;
619
+ /**
620
+ * Get current RLS context or null if not set
621
+ */
622
+ getContextOrNull(): RLSContext | null;
623
+ /**
624
+ * Check if running within RLS context
625
+ */
626
+ hasContext(): boolean;
627
+ /**
628
+ * Get current auth context
629
+ * @throws RLSContextError if no context is set
630
+ */
631
+ getAuth(): RLSAuthContext;
632
+ /**
633
+ * Get current user ID
634
+ * @throws RLSContextError if no context is set
635
+ */
636
+ getUserId(): string | number;
637
+ /**
638
+ * Get current tenant ID
639
+ * @throws RLSContextError if no context is set
640
+ */
641
+ getTenantId(): string | number | undefined;
642
+ /**
643
+ * Check if current user has a specific role
644
+ */
645
+ hasRole(role: string): boolean;
646
+ /**
647
+ * Check if current user has a specific permission
648
+ */
649
+ hasPermission(permission: string): boolean;
650
+ /**
651
+ * Check if current context is a system context (bypasses RLS)
652
+ */
653
+ isSystem(): boolean;
654
+ /**
655
+ * Create a system context for operations that should bypass RLS
656
+ */
657
+ asSystem<T>(fn: () => T): T;
658
+ /**
659
+ * Create a system context for async operations
660
+ */
661
+ asSystemAsync<T>(fn: () => Promise<T>): Promise<T>;
662
+ }
663
+ declare const rlsContext: RLSContextManager;
664
+ /**
665
+ * Convenience function to run code within RLS context
666
+ */
667
+ declare function withRLSContext<T>(context: RLSContext, fn: () => T): T;
668
+ /**
669
+ * Convenience function to run async code within RLS context
670
+ */
671
+ declare function withRLSContextAsync<T>(context: RLSContext, fn: () => Promise<T>): Promise<T>;
672
+
673
+ /**
674
+ * Utility helper functions for RLS
675
+ */
676
+
677
+ /**
678
+ * Create a policy evaluation context from RLS context
679
+ */
680
+ declare function createEvaluationContext<TRow = unknown, TData = unknown>(rlsCtx: RLSContext, options?: {
681
+ row?: TRow;
682
+ data?: TData;
683
+ }): PolicyEvaluationContext<unknown, TRow, TData>;
684
+ /**
685
+ * Check if a condition function is async
686
+ */
687
+ declare function isAsyncFunction(fn: unknown): fn is (...args: unknown[]) => Promise<unknown>;
688
+ /**
689
+ * Safely evaluate a policy condition
690
+ */
691
+ declare function safeEvaluate<T>(fn: () => T | Promise<T>, defaultValue: T): Promise<T>;
692
+ /**
693
+ * Deep merge two objects
694
+ */
695
+ declare function deepMerge<T extends Record<string, unknown>>(target: T, source: Partial<T>): T;
696
+ /**
697
+ * Create a simple hash for cache keys
698
+ */
699
+ declare function hashString(str: string): string;
700
+ /**
701
+ * Normalize operations to array format
702
+ */
703
+ declare function normalizeOperations(operation: Operation | Operation[]): Operation[];
704
+
705
+ export { CompiledFilterPolicy, CompiledPolicy, type CreateRLSContextOptions, FilterCondition, Operation, PolicyCondition, PolicyDefinition, PolicyEvaluationContext, PolicyHints, type PolicyOptions, PolicyRegistry, RLSAuthContext, RLSContext, RLSContextError, RLSContextValidationError, RLSError, type RLSErrorCode, RLSErrorCodes, type RLSPluginOptions, RLSPolicyViolation, RLSRequestContext, RLSSchema, RLSSchemaError, TableRLSConfig, allow, createEvaluationContext, createRLSContext, deepMerge, defineRLSSchema, deny, filter, hashString, isAsyncFunction, mergeRLSSchemas, normalizeOperations, rlsContext, rlsPlugin, safeEvaluate, validate, withRLSContext, withRLSContextAsync };