@kysera/rls 0.7.3 → 0.7.4

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/src/errors.ts CHANGED
@@ -2,13 +2,14 @@
2
2
  * RLS Error Classes
3
3
  *
4
4
  * This module provides specialized error classes for Row-Level Security operations.
5
- * All errors extend the base RLSError class and use unified error codes from @kysera/core
6
- * for consistency across the Kysera ecosystem.
5
+ * All errors extend base error classes from @kysera/core for consistency across
6
+ * the Kysera ecosystem.
7
7
  *
8
8
  * @module @kysera/rls/errors
9
9
  */
10
10
 
11
- import type { ErrorCode } from '@kysera/core';
11
+ import { DatabaseError } from '@kysera/core'
12
+ import type { ErrorCode } from '@kysera/core'
12
13
 
13
14
  // ============================================================================
14
15
  // RLS Error Codes
@@ -32,13 +33,13 @@ export const RLSErrorCodes = {
32
33
  /** RLS context validation failed */
33
34
  RLS_CONTEXT_INVALID: 'RLS_CONTEXT_INVALID' as ErrorCode,
34
35
  /** RLS policy evaluation threw an error */
35
- RLS_POLICY_EVALUATION_ERROR: 'RLS_POLICY_EVALUATION_ERROR' as ErrorCode,
36
- } as const;
36
+ RLS_POLICY_EVALUATION_ERROR: 'RLS_POLICY_EVALUATION_ERROR' as ErrorCode
37
+ } as const
37
38
 
38
39
  /**
39
40
  * Type for RLS error codes
40
41
  */
41
- export type RLSErrorCode = typeof RLSErrorCodes[keyof typeof RLSErrorCodes];
42
+ export type RLSErrorCode = (typeof RLSErrorCodes)[keyof typeof RLSErrorCodes]
42
43
 
43
44
  // ============================================================================
44
45
  // Base RLS Error
@@ -47,6 +48,7 @@ export type RLSErrorCode = typeof RLSErrorCodes[keyof typeof RLSErrorCodes];
47
48
  /**
48
49
  * Base class for all RLS-related errors
49
50
  *
51
+ * Extends DatabaseError from @kysera/core for consistency with other Kysera packages.
50
52
  * Provides common error functionality including error codes and JSON serialization.
51
53
  *
52
54
  * @example
@@ -54,9 +56,7 @@ export type RLSErrorCode = typeof RLSErrorCodes[keyof typeof RLSErrorCodes];
54
56
  * throw new RLSError('Something went wrong', RLSErrorCodes.RLS_POLICY_INVALID);
55
57
  * ```
56
58
  */
57
- export class RLSError extends Error {
58
- public readonly code: RLSErrorCode;
59
-
59
+ export class RLSError extends DatabaseError {
60
60
  /**
61
61
  * Creates a new RLS error
62
62
  *
@@ -64,22 +64,8 @@ export class RLSError extends Error {
64
64
  * @param code - RLS error code
65
65
  */
66
66
  constructor(message: string, code: RLSErrorCode) {
67
- super(message);
68
- this.name = 'RLSError';
69
- this.code = code;
70
- }
71
-
72
- /**
73
- * Serializes the error to JSON
74
- *
75
- * @returns JSON representation of the error
76
- */
77
- toJSON(): Record<string, unknown> {
78
- return {
79
- name: this.name,
80
- message: this.message,
81
- code: this.code,
82
- };
67
+ super(message, code)
68
+ this.name = 'RLSError'
83
69
  }
84
70
  }
85
71
 
@@ -110,15 +96,17 @@ export class RLSContextError extends RLSError {
110
96
  *
111
97
  * @param message - Error message (defaults to standard message)
112
98
  */
113
- constructor(message: string = 'No RLS context found. Ensure code runs within withRLSContext()') {
114
- super(message, RLSErrorCodes.RLS_CONTEXT_MISSING);
115
- this.name = 'RLSContextError';
99
+ constructor(message = 'No RLS context found. Ensure code runs within withRLSContext()') {
100
+ super(message, RLSErrorCodes.RLS_CONTEXT_MISSING)
101
+ this.name = 'RLSContextError'
116
102
  }
117
103
  }
118
104
 
119
105
  /**
120
106
  * Error thrown when RLS context validation fails
121
107
  *
108
+ * Extends RLSError as context validation failures are RLS-specific errors.
109
+ *
122
110
  * This error occurs when the provided RLS context is invalid or missing
123
111
  * required fields.
124
112
  *
@@ -138,7 +126,7 @@ export class RLSContextError extends RLSError {
138
126
  * ```
139
127
  */
140
128
  export class RLSContextValidationError extends RLSError {
141
- public readonly field: string;
129
+ public readonly field: string
142
130
 
143
131
  /**
144
132
  * Creates a new context validation error
@@ -147,16 +135,16 @@ export class RLSContextValidationError extends RLSError {
147
135
  * @param field - Field that failed validation
148
136
  */
149
137
  constructor(message: string, field: string) {
150
- super(message, RLSErrorCodes.RLS_CONTEXT_INVALID);
151
- this.name = 'RLSContextValidationError';
152
- this.field = field;
138
+ super(message, RLSErrorCodes.RLS_CONTEXT_INVALID)
139
+ this.name = 'RLSContextValidationError'
140
+ this.field = field
153
141
  }
154
142
 
155
143
  override toJSON(): Record<string, unknown> {
156
144
  return {
157
145
  ...super.toJSON(),
158
- field: this.field,
159
- };
146
+ field: this.field
147
+ }
160
148
  }
161
149
  }
162
150
 
@@ -183,10 +171,10 @@ export class RLSContextValidationError extends RLSError {
183
171
  * ```
184
172
  */
185
173
  export class RLSPolicyViolation extends RLSError {
186
- public readonly operation: string;
187
- public readonly table: string;
188
- public readonly reason: string;
189
- public readonly policyName?: string;
174
+ public readonly operation: string
175
+ public readonly table: string
176
+ public readonly reason: string
177
+ public readonly policyName?: string
190
178
 
191
179
  /**
192
180
  * Creates a new policy violation error
@@ -196,22 +184,17 @@ export class RLSPolicyViolation extends RLSError {
196
184
  * @param reason - Reason for the policy violation
197
185
  * @param policyName - Name of the policy that denied access (optional)
198
186
  */
199
- constructor(
200
- operation: string,
201
- table: string,
202
- reason: string,
203
- policyName?: string
204
- ) {
187
+ constructor(operation: string, table: string, reason: string, policyName?: string) {
205
188
  super(
206
189
  `RLS policy violation: ${operation} on ${table} - ${reason}`,
207
190
  RLSErrorCodes.RLS_POLICY_VIOLATION
208
- );
209
- this.name = 'RLSPolicyViolation';
210
- this.operation = operation;
211
- this.table = table;
212
- this.reason = reason;
191
+ )
192
+ this.name = 'RLSPolicyViolation'
193
+ this.operation = operation
194
+ this.table = table
195
+ this.reason = reason
213
196
  if (policyName !== undefined) {
214
- this.policyName = policyName;
197
+ this.policyName = policyName
215
198
  }
216
199
  }
217
200
 
@@ -220,12 +203,12 @@ export class RLSPolicyViolation extends RLSError {
220
203
  ...super.toJSON(),
221
204
  operation: this.operation,
222
205
  table: this.table,
223
- reason: this.reason,
224
- };
206
+ reason: this.reason
207
+ }
225
208
  if (this.policyName !== undefined) {
226
- json['policyName'] = this.policyName;
209
+ json['policyName'] = this.policyName
227
210
  }
228
- return json;
211
+ return json
229
212
  }
230
213
  }
231
214
 
@@ -250,10 +233,10 @@ export class RLSPolicyViolation extends RLSError {
250
233
  * ```
251
234
  */
252
235
  export class RLSPolicyEvaluationError extends RLSError {
253
- public readonly operation: string;
254
- public readonly table: string;
255
- public readonly policyName?: string;
256
- public readonly originalError?: Error;
236
+ public readonly operation: string
237
+ public readonly table: string
238
+ public readonly policyName?: string
239
+ public readonly originalError?: Error
257
240
 
258
241
  /**
259
242
  * Creates a new policy evaluation error
@@ -274,18 +257,18 @@ export class RLSPolicyEvaluationError extends RLSError {
274
257
  super(
275
258
  `RLS policy evaluation error during ${operation} on ${table}: ${message}`,
276
259
  RLSErrorCodes.RLS_POLICY_EVALUATION_ERROR
277
- );
278
- this.name = 'RLSPolicyEvaluationError';
279
- this.operation = operation;
280
- this.table = table;
260
+ )
261
+ this.name = 'RLSPolicyEvaluationError'
262
+ this.operation = operation
263
+ this.table = table
281
264
  if (policyName !== undefined) {
282
- this.policyName = policyName;
265
+ this.policyName = policyName
283
266
  }
284
267
  if (originalError !== undefined) {
285
- this.originalError = originalError;
268
+ this.originalError = originalError
286
269
  // Preserve the original stack trace for debugging
287
270
  if (originalError.stack) {
288
- this.stack = `${this.stack}\n\nCaused by:\n${originalError.stack}`;
271
+ this.stack = `${this.stack}\n\nCaused by:\n${originalError.stack}`
289
272
  }
290
273
  }
291
274
  }
@@ -294,18 +277,18 @@ export class RLSPolicyEvaluationError extends RLSError {
294
277
  const json: Record<string, unknown> = {
295
278
  ...super.toJSON(),
296
279
  operation: this.operation,
297
- table: this.table,
298
- };
280
+ table: this.table
281
+ }
299
282
  if (this.policyName !== undefined) {
300
- json['policyName'] = this.policyName;
283
+ json['policyName'] = this.policyName
301
284
  }
302
285
  if (this.originalError !== undefined) {
303
286
  json['originalError'] = {
304
287
  name: this.originalError.name,
305
- message: this.originalError.message,
306
- };
288
+ message: this.originalError.message
289
+ }
307
290
  }
308
- return json;
291
+ return json
309
292
  }
310
293
  }
311
294
 
@@ -316,6 +299,8 @@ export class RLSPolicyEvaluationError extends RLSError {
316
299
  /**
317
300
  * Error thrown when RLS schema validation fails
318
301
  *
302
+ * Extends RLSError as schema validation failures are RLS-specific errors.
303
+ *
319
304
  * This error occurs when the RLS schema definition is invalid or contains
320
305
  * configuration errors.
321
306
  *
@@ -339,7 +324,7 @@ export class RLSPolicyEvaluationError extends RLSError {
339
324
  * ```
340
325
  */
341
326
  export class RLSSchemaError extends RLSError {
342
- public readonly details: Record<string, unknown>;
327
+ public readonly details: Record<string, unknown>
343
328
 
344
329
  /**
345
330
  * Creates a new schema validation error
@@ -348,15 +333,15 @@ export class RLSSchemaError extends RLSError {
348
333
  * @param details - Additional details about the validation failure
349
334
  */
350
335
  constructor(message: string, details: Record<string, unknown> = {}) {
351
- super(message, RLSErrorCodes.RLS_SCHEMA_INVALID);
352
- this.name = 'RLSSchemaError';
353
- this.details = details;
336
+ super(message, RLSErrorCodes.RLS_SCHEMA_INVALID)
337
+ this.name = 'RLSSchemaError'
338
+ this.details = details
354
339
  }
355
340
 
356
341
  override toJSON(): Record<string, unknown> {
357
342
  return {
358
343
  ...super.toJSON(),
359
- details: this.details,
360
- };
344
+ details: this.details
345
+ }
361
346
  }
362
347
  }
package/src/index.ts CHANGED
@@ -12,20 +12,20 @@
12
12
  // ============================================================================
13
13
 
14
14
  // Schema definition
15
- export { defineRLSSchema, mergeRLSSchemas } from './policy/schema.js';
15
+ export { defineRLSSchema, mergeRLSSchemas } from './policy/schema.js'
16
16
 
17
17
  // Policy builders
18
- export { allow, deny, filter, validate, type PolicyOptions } from './policy/builder.js';
18
+ export { allow, deny, filter, validate, type PolicyOptions } from './policy/builder.js'
19
19
 
20
20
  // Policy registry (for advanced use cases)
21
- export { PolicyRegistry } from './policy/registry.js';
21
+ export { PolicyRegistry } from './policy/registry.js'
22
22
 
23
23
  // ============================================================================
24
24
  // Plugin
25
25
  // ============================================================================
26
26
 
27
- export { rlsPlugin } from './plugin.js';
28
- export type { RLSPluginOptions } from './plugin.js';
27
+ export { rlsPlugin, RLSPluginOptionsSchema } from './plugin.js'
28
+ export type { RLSPluginOptions } from './plugin.js'
29
29
 
30
30
  // ============================================================================
31
31
  // Context Management
@@ -36,8 +36,8 @@ export {
36
36
  createRLSContext,
37
37
  withRLSContext,
38
38
  withRLSContextAsync,
39
- type CreateRLSContextOptions,
40
- } from './context/index.js';
39
+ type CreateRLSContextOptions
40
+ } from './context/index.js'
41
41
 
42
42
  // ============================================================================
43
43
  // Types
@@ -64,8 +64,8 @@ export type {
64
64
  // Evaluation types
65
65
  PolicyEvaluationContext,
66
66
  CompiledPolicy,
67
- CompiledFilterPolicy,
68
- } from './policy/types.js';
67
+ CompiledFilterPolicy
68
+ } from './policy/types.js'
69
69
 
70
70
  // ============================================================================
71
71
  // Errors
@@ -79,8 +79,8 @@ export {
79
79
  RLSSchemaError,
80
80
  RLSContextValidationError,
81
81
  RLSErrorCodes,
82
- type RLSErrorCode,
83
- } from './errors.js';
82
+ type RLSErrorCode
83
+ } from './errors.js'
84
84
 
85
85
  // ============================================================================
86
86
  // Utilities
@@ -92,5 +92,5 @@ export {
92
92
  isAsyncFunction,
93
93
  safeEvaluate,
94
94
  deepMerge,
95
- hashString,
96
- } from './utils/index.js';
95
+ hashString
96
+ } from './utils/index.js'
@@ -14,14 +14,14 @@ This module provides native PostgreSQL Row-Level Security (RLS) policy generatio
14
14
  ### 1. Define RLS Schema with Native PostgreSQL Support
15
15
 
16
16
  ```typescript
17
- import type { RLSSchema } from '@kysera/rls';
17
+ import type { RLSSchema } from '@kysera/rls'
18
18
 
19
19
  interface Database {
20
20
  users: {
21
- id: number;
22
- email: string;
23
- tenant_id: string;
24
- };
21
+ id: number
22
+ email: string
23
+ tenant_id: string
24
+ }
25
25
  }
26
26
 
27
27
  const rlsSchema: RLSSchema<Database> = {
@@ -33,59 +33,59 @@ const rlsSchema: RLSSchema<Database> = {
33
33
  name: 'users_read_own',
34
34
  condition: () => true, // ORM-side condition
35
35
  using: 'id = rls_current_user_id()::integer', // Native PostgreSQL
36
- role: 'authenticated',
37
- },
38
- ],
39
- },
40
- };
36
+ role: 'authenticated'
37
+ }
38
+ ]
39
+ }
40
+ }
41
41
  ```
42
42
 
43
43
  ### 2. Generate PostgreSQL Statements
44
44
 
45
45
  ```typescript
46
- import { PostgresRLSGenerator } from '@kysera/rls/native';
46
+ import { PostgresRLSGenerator } from '@kysera/rls/native'
47
47
 
48
- const generator = new PostgresRLSGenerator();
48
+ const generator = new PostgresRLSGenerator()
49
49
 
50
50
  // Generate RLS policies
51
51
  const statements = generator.generateStatements(rlsSchema, {
52
52
  schemaName: 'public',
53
53
  policyPrefix: 'app_rls',
54
- force: true, // Force RLS on table owners
55
- });
54
+ force: true // Force RLS on table owners
55
+ })
56
56
 
57
57
  // Generate context functions
58
- const contextFunctions = generator.generateContextFunctions();
58
+ const contextFunctions = generator.generateContextFunctions()
59
59
 
60
60
  // Generate cleanup statements
61
61
  const dropStatements = generator.generateDropStatements(rlsSchema, {
62
62
  schemaName: 'public',
63
- policyPrefix: 'app_rls',
64
- });
63
+ policyPrefix: 'app_rls'
64
+ })
65
65
  ```
66
66
 
67
67
  ### 3. Generate Kysely Migration
68
68
 
69
69
  ```typescript
70
- import { RLSMigrationGenerator } from '@kysera/rls/native';
70
+ import { RLSMigrationGenerator } from '@kysera/rls/native'
71
71
 
72
- const migrationGenerator = new RLSMigrationGenerator();
72
+ const migrationGenerator = new RLSMigrationGenerator()
73
73
 
74
74
  const migrationContent = migrationGenerator.generateMigration(rlsSchema, {
75
75
  name: 'setup_rls',
76
76
  schemaName: 'public',
77
77
  policyPrefix: 'app_rls',
78
78
  includeContextFunctions: true,
79
- force: true,
80
- });
79
+ force: true
80
+ })
81
81
 
82
82
  // Get suggested filename with timestamp
83
- const filename = migrationGenerator.generateFilename('setup_rls');
83
+ const filename = migrationGenerator.generateFilename('setup_rls')
84
84
  // Example: 20231208_123456_setup_rls.ts
85
85
 
86
86
  // Write to migrations directory
87
- import fs from 'fs';
88
- fs.writeFileSync(`migrations/${filename}`, migrationContent);
87
+ import fs from 'fs'
88
+ fs.writeFileSync(`migrations/${filename}`, migrationContent)
89
89
  ```
90
90
 
91
91
  ### 4. Sync Context to PostgreSQL Session
@@ -141,13 +141,13 @@ Extend your Kysera policy definitions with native PostgreSQL support:
141
141
 
142
142
  ### Operations
143
143
 
144
- | Kysera | PostgreSQL |
145
- |--------|------------|
146
- | `read` | `SELECT` |
147
- | `create` | `INSERT` |
148
- | `update` | `UPDATE` |
149
- | `delete` | `DELETE` |
150
- | `all` | `ALL` |
144
+ | Kysera | PostgreSQL |
145
+ | -------- | ---------- |
146
+ | `read` | `SELECT` |
147
+ | `create` | `INSERT` |
148
+ | `update` | `UPDATE` |
149
+ | `delete` | `DELETE` |
150
+ | `all` | `ALL` |
151
151
 
152
152
  ## Context Functions
153
153
 
@@ -192,20 +192,21 @@ const rlsSchema: RLSSchema<Database> = {
192
192
  name: 'posts_read_tenant',
193
193
  condition: () => true,
194
194
  using: 'tenant_id = rls_current_tenant_id()',
195
- role: 'authenticated',
195
+ role: 'authenticated'
196
196
  },
197
197
  {
198
198
  type: 'allow',
199
199
  operation: 'create',
200
200
  name: 'posts_create_own',
201
201
  condition: () => true,
202
- withCheck: 'user_id = rls_current_user_id()::integer AND tenant_id = rls_current_tenant_id()',
203
- role: 'authenticated',
204
- },
202
+ withCheck:
203
+ 'user_id = rls_current_user_id()::integer AND tenant_id = rls_current_tenant_id()',
204
+ role: 'authenticated'
205
+ }
205
206
  ],
206
- defaultDeny: true,
207
- },
208
- };
207
+ defaultDeny: true
208
+ }
209
+ }
209
210
  ```
210
211
 
211
212
  ### Role-Based Access Control
@@ -219,21 +220,21 @@ const rlsSchema: RLSSchema<Database> = {
219
220
  operation: 'all',
220
221
  name: 'admin_full_access',
221
222
  condition: () => true,
222
- using: 'rls_has_role(\'admin\')',
223
- role: 'authenticated',
223
+ using: "rls_has_role('admin')",
224
+ role: 'authenticated'
224
225
  },
225
226
  {
226
227
  type: 'deny',
227
228
  operation: 'all',
228
229
  name: 'deny_non_admin',
229
230
  condition: () => true,
230
- using: 'NOT rls_has_role(\'admin\')',
231
- role: 'authenticated',
232
- },
231
+ using: "NOT rls_has_role('admin')",
232
+ role: 'authenticated'
233
+ }
233
234
  ],
234
- defaultDeny: true,
235
- },
236
- };
235
+ defaultDeny: true
236
+ }
237
+ }
237
238
  ```
238
239
 
239
240
  ### System Bypass
@@ -267,6 +268,7 @@ CREATE INDEX idx_posts_user ON posts(user_id);
267
268
  ## Migration Workflow
268
269
 
269
270
  1. **Generate Migration**:
271
+
270
272
  ```bash
271
273
  npx tsx -e "import { RLSMigrationGenerator } from './src/native'; ..."
272
274
  ```
@@ -274,6 +276,7 @@ CREATE INDEX idx_posts_user ON posts(user_id);
274
276
  2. **Review Generated SQL**: Check migration file before applying
275
277
 
276
278
  3. **Run Migration**:
279
+
277
280
  ```bash
278
281
  npx kysely migrate:latest
279
282
  ```
@@ -2,10 +2,7 @@ export {
2
2
  PostgresRLSGenerator,
3
3
  syncContextToPostgres,
4
4
  clearPostgresContext,
5
- type PostgresRLSOptions,
6
- } from './postgres.js';
5
+ type PostgresRLSOptions
6
+ } from './postgres.js'
7
7
 
8
- export {
9
- RLSMigrationGenerator,
10
- type MigrationOptions,
11
- } from './migration.js';
8
+ export { RLSMigrationGenerator, type MigrationOptions } from './migration.js'
@@ -1,14 +1,14 @@
1
- import type { RLSSchema } from '../policy/types.js';
2
- import { PostgresRLSGenerator, type PostgresRLSOptions } from './postgres.js';
1
+ import type { RLSSchema } from '../policy/types.js'
2
+ import { PostgresRLSGenerator, type PostgresRLSOptions } from './postgres.js'
3
3
 
4
4
  /**
5
5
  * Options for migration generation
6
6
  */
7
7
  export interface MigrationOptions extends PostgresRLSOptions {
8
8
  /** Migration name */
9
- name?: string;
9
+ name?: string
10
10
  /** Include context functions in migration */
11
- includeContextFunctions?: boolean;
11
+ includeContextFunctions?: boolean
12
12
  }
13
13
 
14
14
  /**
@@ -16,27 +16,20 @@ export interface MigrationOptions extends PostgresRLSOptions {
16
16
  * Generates Kysely migration files for RLS policies
17
17
  */
18
18
  export class RLSMigrationGenerator {
19
- private generator = new PostgresRLSGenerator();
19
+ private generator = new PostgresRLSGenerator()
20
20
 
21
21
  /**
22
22
  * Generate migration file content
23
23
  */
24
- generateMigration<DB>(
25
- schema: RLSSchema<DB>,
26
- options: MigrationOptions = {}
27
- ): string {
28
- const {
29
- name = 'rls_policies',
30
- includeContextFunctions = true,
31
- ...generatorOptions
32
- } = options;
24
+ generateMigration<DB>(schema: RLSSchema<DB>, options: MigrationOptions = {}): string {
25
+ const { name = 'rls_policies', includeContextFunctions = true, ...generatorOptions } = options
33
26
 
34
- const upStatements = this.generator.generateStatements(schema, generatorOptions);
35
- const downStatements = this.generator.generateDropStatements(schema, generatorOptions);
27
+ const upStatements = this.generator.generateStatements(schema, generatorOptions)
28
+ const downStatements = this.generator.generateDropStatements(schema, generatorOptions)
36
29
 
37
30
  const contextFunctions = includeContextFunctions
38
31
  ? this.generator.generateContextFunctions()
39
- : '';
32
+ : ''
40
33
 
41
34
  return `import { Kysely, sql } from 'kysely';
42
35
 
@@ -48,16 +41,22 @@ export class RLSMigrationGenerator {
48
41
  */
49
42
 
50
43
  export async function up(db: Kysely<any>): Promise<void> {
51
- ${includeContextFunctions ? ` // Create RLS context functions
44
+ ${
45
+ includeContextFunctions
46
+ ? ` // Create RLS context functions
52
47
  await sql.raw(\`${this.escapeTemplate(contextFunctions)}\`).execute(db);
53
48
 
54
- ` : ''} // Enable RLS and create policies
49
+ `
50
+ : ''
51
+ } // Enable RLS and create policies
55
52
  ${upStatements.map(s => ` await sql.raw(\`${this.escapeTemplate(s)}\`).execute(db);`).join('\n')}
56
53
  }
57
54
 
58
55
  export async function down(db: Kysely<any>): Promise<void> {
59
56
  ${downStatements.map(s => ` await sql.raw(\`${this.escapeTemplate(s)}\`).execute(db);`).join('\n')}
60
- ${includeContextFunctions ? `
57
+ ${
58
+ includeContextFunctions
59
+ ? `
61
60
  // Drop RLS context functions
62
61
  await sql.raw(\`
63
62
  DROP FUNCTION IF EXISTS rls_current_user_id();
@@ -67,26 +66,29 @@ ${includeContextFunctions ? `
67
66
  DROP FUNCTION IF EXISTS rls_current_permissions();
68
67
  DROP FUNCTION IF EXISTS rls_has_permission(text);
69
68
  DROP FUNCTION IF EXISTS rls_is_system();
70
- \`).execute(db);` : ''}
69
+ \`).execute(db);`
70
+ : ''
71
71
  }
72
- `;
72
+ }
73
+ `
73
74
  }
74
75
 
75
76
  /**
76
77
  * Escape template literal for embedding in string
77
78
  */
78
79
  private escapeTemplate(str: string): string {
79
- return str.replace(/`/g, '\\`').replace(/\$/g, '\\$');
80
+ return str.replace(/`/g, '\\`').replace(/\$/g, '\\$')
80
81
  }
81
82
 
82
83
  /**
83
84
  * Generate migration filename with timestamp
84
85
  */
85
- generateFilename(name: string = 'rls_policies'): string {
86
- const timestamp = new Date().toISOString()
86
+ generateFilename(name = 'rls_policies'): string {
87
+ const timestamp = new Date()
88
+ .toISOString()
87
89
  .replace(/[-:]/g, '')
88
90
  .replace('T', '_')
89
- .replace(/\..+/, '');
90
- return `${timestamp}_${name}.ts`;
91
+ .replace(/\..+/, '')
92
+ return `${timestamp}_${name}.ts`
91
93
  }
92
94
  }