odgn-rights 0.2.0 → 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.
package/README.md CHANGED
@@ -98,6 +98,100 @@ rights.write('/posts/1', { userId: 'abc', ownerId: 'xyz' }); // false
98
98
  - `**` matches across segments (`/*/device/**`)
99
99
  - `?` matches a single character (no slash)
100
100
 
101
+ ## Rule Priority
102
+
103
+ By default, rules are matched by **specificity** — the most specific matching rule wins. However, you can override this with explicit **priority** values.
104
+
105
+ ### How Priority Works
106
+
107
+ 1. **Higher priority wins** regardless of specificity
108
+ 2. **Equal priorities** fall back to specificity comparison
109
+ 3. **Default priority is 0** when not specified
110
+ 4. **Negative priorities** can deprioritize rules below the default
111
+
112
+ ```ts
113
+ const rights = new Rights();
114
+
115
+ // Specific path, default priority (0)
116
+ rights.add(
117
+ new Right('/posts/123', {
118
+ allow: [Flags.READ],
119
+ deny: [Flags.WRITE]
120
+ })
121
+ );
122
+
123
+ // Wildcard path, but high priority (100) — this rule wins!
124
+ rights.add(
125
+ new Right('/posts/*', {
126
+ allow: [Flags.READ, Flags.WRITE],
127
+ priority: 100
128
+ })
129
+ );
130
+
131
+ rights.write('/posts/123'); // true — high-priority wildcard rule wins
132
+ ```
133
+
134
+ ### Priority in Serialization
135
+
136
+ Priority is included in both text and JSON serialization formats.
137
+
138
+ **Text format** uses `^` after the path:
139
+
140
+ ```ts
141
+ const right = new Right('/posts/*', {
142
+ allow: [Flags.WRITE],
143
+ priority: 100
144
+ });
145
+ right.toString(); // "+w:/posts/*^100"
146
+
147
+ // With tags and time ranges
148
+ // Format: [flags]:[path]^[priority]#[tags]@[validFrom]/[validUntil]
149
+ Right.parse('+rw:/admin/*^50#secure');
150
+ ```
151
+
152
+ **JSON format** includes an optional `priority` field:
153
+
154
+ ```json
155
+ [
156
+ { "path": "/posts/*", "allow": "rw", "priority": 100 },
157
+ { "path": "/posts/123", "allow": "r", "deny": "w" }
158
+ ]
159
+ ```
160
+
161
+ Priority is omitted from serialization when it equals 0 (the default).
162
+
163
+ ### Use Cases
164
+
165
+ - **Emergency overrides**: Grant temporary high-priority access that bypasses normal rules
166
+ - **Default deny rules**: Use negative priority for fallback deny rules
167
+ - **Policy layers**: Implement organizational policies at different priority levels
168
+
169
+ ```ts
170
+ // Low-priority default: deny all writes
171
+ rights.add(
172
+ new Right('/**', {
173
+ deny: [Flags.WRITE],
174
+ priority: -100
175
+ })
176
+ );
177
+
178
+ // Normal priority: department-level permissions
179
+ rights.add(
180
+ new Right('/dept/engineering/**', {
181
+ allow: [Flags.READ, Flags.WRITE]
182
+ })
183
+ );
184
+
185
+ // High priority: emergency maintenance access
186
+ rights.add(
187
+ new Right('/system/**', {
188
+ allow: [Flags.ALL],
189
+ priority: 1000,
190
+ tags: ['emergency']
191
+ })
192
+ );
193
+ ```
194
+
101
195
  ## JSON Round‑Trip
102
196
 
103
197
  ```ts
@@ -106,6 +200,74 @@ const json = rights.toJSON();
106
200
  const loaded = Rights.fromJSON(json);
107
201
  ```
108
202
 
203
+ ## Batch Permission Checks
204
+
205
+ Efficiently check multiple permissions at once with `checkMany()`.
206
+
207
+ ### Basic Usage
208
+
209
+ ```ts
210
+ const rights = new Rights();
211
+ rights.allow('/users/*', Flags.READ);
212
+ rights.allow('/posts/*', Flags.WRITE);
213
+ rights.deny('/admin', Flags.ALL);
214
+
215
+ const results = rights.checkMany([
216
+ { path: '/users/1', flags: Flags.READ },
217
+ { path: '/posts/1', flags: Flags.WRITE },
218
+ { path: '/admin', flags: Flags.ALL }
219
+ ]);
220
+ // Returns: [true, true, false]
221
+ ```
222
+
223
+ ### With Context
224
+
225
+ The same context is shared across all checks:
226
+
227
+ ```ts
228
+ rights.add(
229
+ new Right('/posts/*', {
230
+ allow: [Flags.WRITE],
231
+ condition: ctx => ctx.userId === ctx.ownerId
232
+ })
233
+ );
234
+
235
+ const results = rights.checkMany(
236
+ [
237
+ { path: '/posts/1', flags: Flags.WRITE },
238
+ { path: '/posts/2', flags: Flags.WRITE },
239
+ { path: '/posts/3', flags: Flags.WRITE }
240
+ ],
241
+ { userId: 'user1', ownerId: 'user1' }
242
+ );
243
+ // Returns: [true, true, true]
244
+ ```
245
+
246
+ ### With Subjects
247
+
248
+ Works with subjects that have multiple roles:
249
+
250
+ ```ts
251
+ const viewer = new Role('viewer', new Rights().allow('/docs', Flags.READ));
252
+ const writer = new Role('writer', new Rights().allow('/docs', Flags.WRITE));
253
+
254
+ const subject = new Subject().memberOf(viewer).memberOf(writer);
255
+
256
+ const results = subject.checkMany([
257
+ { path: '/docs', flags: Flags.READ },
258
+ { path: '/docs', flags: Flags.WRITE },
259
+ { path: '/docs', flags: Flags.DELETE }
260
+ ]);
261
+ // Returns: [true, true, false]
262
+ ```
263
+
264
+ ### Use Cases
265
+
266
+ - **Bulk authorization**: Check multiple resource permissions in a single call
267
+ - **Feature flags**: Enable/disable multiple features based on permissions
268
+ - **API responses**: Include permission information for multiple resources
269
+ - **UI rendering**: Determine visibility of multiple UI elements efficiently
270
+
109
271
  ## CLI Tool
110
272
 
111
273
  The CLI tool helps test and debug permission configurations from the command line.
@@ -226,3 +388,209 @@ The CLI supports two configuration formats:
226
388
  | ALL | \* | All permissions |
227
389
 
228
390
  Flags can be combined: `RW`, `READ,WRITE`, `RWCDX`
391
+
392
+ ## Database Adapters
393
+
394
+ Database adapters enable persistent storage of rights configurations in SQLite or PostgreSQL databases. This is useful for applications that need to load permissions from a database, share configurations across services, or audit permission changes.
395
+
396
+ ### Installation
397
+
398
+ The adapters use Bun's built-in database drivers (`bun:sqlite` and `bun` SQL), so no additional dependencies are required.
399
+
400
+ ```ts
401
+ import { PostgresAdapter, SQLiteAdapter } from 'odgn-rights/adapters';
402
+ ```
403
+
404
+ ### Table Prefix
405
+
406
+ All adapters support a configurable table prefix. The default prefix is `tbl_`.
407
+
408
+ ```ts
409
+ // Default prefix creates tables: tbl_rights, tbl_roles, etc.
410
+ const adapter = new SQLiteAdapter({ filename: './permissions.db' });
411
+
412
+ // Custom prefix creates tables: auth_rights, auth_roles, etc.
413
+ const adapter = new SQLiteAdapter({
414
+ filename: './permissions.db',
415
+ tablePrefix: 'auth_'
416
+ });
417
+
418
+ // No prefix creates tables: rights, roles, etc.
419
+ const adapter = new SQLiteAdapter({
420
+ filename: './permissions.db',
421
+ tablePrefix: ''
422
+ });
423
+ ```
424
+
425
+ ### SQLite Adapter
426
+
427
+ SQLite is ideal for single-process applications, embedded systems, or local development.
428
+
429
+ ```ts
430
+ import { Flags, Right, Rights } from 'odgn-rights';
431
+ import { SQLiteAdapter } from 'odgn-rights/adapters';
432
+
433
+ // Create adapter and connect
434
+ const adapter = new SQLiteAdapter({
435
+ filename: './permissions.db', // Use ':memory:' for in-memory
436
+ enableWAL: true // Enable WAL mode for better concurrency
437
+ });
438
+
439
+ await adapter.connect();
440
+ await adapter.migrate();
441
+
442
+ // Save rights
443
+ const rights = new Rights();
444
+ rights.allow('/users/*', Flags.READ);
445
+ rights.allow('/admin/**', Flags.ALL);
446
+ await adapter.saveRights(rights);
447
+
448
+ // Load rights
449
+ const loaded = await adapter.loadRights();
450
+ loaded.has('/users/123', Flags.READ); // true
451
+
452
+ // Save and load roles
453
+ const { Role, RoleRegistry } = await import('odgn-rights');
454
+ const registry = new RoleRegistry();
455
+ const admin = registry.define('admin');
456
+ admin.rights.allow('/**', Flags.ALL);
457
+ await registry.saveTo(adapter);
458
+
459
+ // Load registry from database
460
+ const loadedRegistry = await RoleRegistry.loadFrom(adapter);
461
+
462
+ await adapter.disconnect();
463
+ ```
464
+
465
+ ### PostgreSQL Adapter
466
+
467
+ PostgreSQL is ideal for multi-process applications, microservices, or when you need shared access to permissions.
468
+
469
+ ```ts
470
+ import { Flags, RoleRegistry, Subject } from 'odgn-rights';
471
+ import { PostgresAdapter } from 'odgn-rights/adapters';
472
+
473
+ const adapter = new PostgresAdapter({
474
+ url: 'postgres://user:pass@localhost:5432/mydb',
475
+ // Or use individual options:
476
+ // hostname: 'localhost',
477
+ // port: 5432,
478
+ // database: 'mydb',
479
+ // username: 'user',
480
+ // password: 'pass',
481
+ tablePrefix: 'perms_' // Optional custom prefix
482
+ });
483
+
484
+ await adapter.connect();
485
+ await adapter.migrate();
486
+
487
+ // Load registry and make changes
488
+ const registry = await adapter.loadRegistry();
489
+ const editor = registry.define('editor');
490
+ editor.rights.allow('/content/**', Flags.READ, Flags.WRITE);
491
+
492
+ // Save back
493
+ await adapter.saveRegistry(registry);
494
+
495
+ // Save subjects with roles
496
+ const user = new Subject();
497
+ user.memberOf(editor);
498
+ await adapter.saveSubject('user-123', user);
499
+
500
+ await adapter.disconnect();
501
+ ```
502
+
503
+ ### Factory Functions
504
+
505
+ Convenience functions for common patterns:
506
+
507
+ ```ts
508
+ import {
509
+ createPostgresRegistry,
510
+ createPostgresRights,
511
+ createSQLiteRegistry,
512
+ createSQLiteRights
513
+ } from 'odgn-rights/adapters';
514
+
515
+ // Create SQLite adapter with rights
516
+ const { adapter, rights } = await createSQLiteRights({
517
+ filename: './permissions.db'
518
+ });
519
+ rights.allow('/public/**', Flags.READ);
520
+ await adapter.saveRights(rights);
521
+ await adapter.disconnect();
522
+
523
+ // Create SQLite adapter with registry
524
+ const { adapter: regAdapter, registry } = await createSQLiteRegistry({
525
+ filename: ':memory:'
526
+ });
527
+ const viewer = registry.define('viewer');
528
+ viewer.rights.allow('/read/*', Flags.READ);
529
+ await registry.saveTo(regAdapter);
530
+ await regAdapter.disconnect();
531
+ ```
532
+
533
+ ### Transactions
534
+
535
+ Both adapters support transactions for atomic operations:
536
+
537
+ ```ts
538
+ await adapter.transaction(async () => {
539
+ await adapter.saveRight(new Right('/a', { allow: [Flags.READ] }));
540
+ await adapter.saveRight(new Right('/b', { allow: [Flags.WRITE] }));
541
+ // If an error is thrown, all changes are rolled back
542
+ });
543
+ ```
544
+
545
+ ### Adapter Interface
546
+
547
+ All adapters implement the `DatabaseAdapter` interface:
548
+
549
+ | Method | Description |
550
+ | ---------------------------------- | --------------------------------- |
551
+ | `connect()` | Connect to the database |
552
+ | `disconnect()` | Disconnect from the database |
553
+ | `migrate()` | Create or update schema |
554
+ | `saveRight(right)` | Save a single right |
555
+ | `saveRights(rights)` | Save multiple rights |
556
+ | `loadRight(id)` | Load a right by ID |
557
+ | `loadRights()` | Load all rights |
558
+ | `loadRightsByPath(pattern)` | Load rights matching a pattern |
559
+ | `deleteRight(id)` | Delete a right |
560
+ | `saveRole(role)` | Save a role with its rights |
561
+ | `loadRole(name)` | Load a role by name |
562
+ | `loadRoles()` | Load all roles |
563
+ | `deleteRole(name)` | Delete a role |
564
+ | `saveRegistry(registry)` | Save entire RoleRegistry |
565
+ | `loadRegistry()` | Load RoleRegistry with all roles |
566
+ | `saveSubject(identifier, subject)` | Save a subject |
567
+ | `loadSubject(identifier)` | Load a subject |
568
+ | `deleteSubject(identifier)` | Delete a subject |
569
+ | `clear()` | Clear all data (for testing) |
570
+ | `transaction(fn)` | Execute operations in transaction |
571
+
572
+ ### Database Schema
573
+
574
+ The adapters create the following tables (with the configured prefix):
575
+
576
+ | Table | Purpose |
577
+ | -------------------------- | ------------------------------------ |
578
+ | `{prefix}rights` | Individual rights with paths & flags |
579
+ | `{prefix}roles` | Role definitions |
580
+ | `{prefix}role_rights` | Role-to-rights mapping |
581
+ | `{prefix}role_inheritance` | Role inheritance relationships |
582
+ | `{prefix}subjects` | Subject records |
583
+ | `{prefix}subject_roles` | Subject-to-roles mapping |
584
+ | `{prefix}subject_rights` | Direct subject rights |
585
+
586
+ ### Persistence Metadata
587
+
588
+ Rights saved to the database receive a `dbId` property:
589
+
590
+ ```ts
591
+ const right = new Right('/test', { allow: [Flags.READ] });
592
+ console.log(right.dbId); // undefined
593
+
594
+ await adapter.saveRight(right);
595
+ console.log(right.dbId); // 1 (database ID)
596
+ ```
@@ -0,0 +1,83 @@
1
+ import { Flags } from '../constants';
2
+ import { Right } from '../right';
3
+ import { Rights } from '../rights';
4
+ import { Role } from '../role';
5
+ import { RoleRegistry } from '../role-registry';
6
+ import { Subject } from '../subject';
7
+ import type { BaseAdapterOptions, DatabaseAdapter, RightsRow, TableNames } from './types';
8
+ /**
9
+ * Abstract base class for database adapters.
10
+ * Provides common utility methods for serialization/deserialization
11
+ * and table name management.
12
+ */
13
+ export declare abstract class BaseAdapter implements DatabaseAdapter {
14
+ protected readonly tablePrefix: string;
15
+ protected readonly _tables: TableNames;
16
+ constructor(options?: BaseAdapterOptions);
17
+ /**
18
+ * Get the table names with the configured prefix
19
+ */
20
+ protected get tables(): TableNames;
21
+ /**
22
+ * Serialize tags array to JSON string
23
+ */
24
+ protected serializeTags: (tags: string[]) => string | null;
25
+ /**
26
+ * Deserialize JSON string to tags array
27
+ */
28
+ protected deserializeTags: (json: string | null) => string[];
29
+ /**
30
+ * Convert a Right instance to a database row (partial, without id and timestamps)
31
+ */
32
+ protected rightToRow: (right: Right) => Omit<RightsRow, "id" | "created_at" | "updated_at">;
33
+ /**
34
+ * Convert a database row to a Right instance
35
+ */
36
+ protected rowToRight: (row: RightsRow) => Right;
37
+ /**
38
+ * Convert a bitmask to an array of Flag values
39
+ */
40
+ protected maskToFlags: (mask: number) => Flags[];
41
+ /**
42
+ * Convert an array of Flag values to a bitmask
43
+ */
44
+ protected flagsToMask: (flags: Flags[]) => number;
45
+ /**
46
+ * Parse an ISO 8601 timestamp string to a Date, or undefined if null/invalid
47
+ */
48
+ protected parseTimestamp: (value: string | null) => Date | undefined;
49
+ abstract connect(): Promise<void>;
50
+ abstract disconnect(): Promise<void>;
51
+ abstract migrate(): Promise<void>;
52
+ abstract saveRight(right: Right): Promise<number>;
53
+ abstract saveRights(rights: Rights): Promise<number[]>;
54
+ abstract loadRight(id: number): Promise<Right | null>;
55
+ abstract loadRights(): Promise<Rights>;
56
+ abstract loadRightsByPath(pathPattern: string): Promise<Rights>;
57
+ abstract deleteRight(id: number): Promise<boolean>;
58
+ abstract saveRole(role: Role): Promise<number>;
59
+ abstract loadRole(name: string): Promise<Role | null>;
60
+ abstract loadRoles(): Promise<Role[]>;
61
+ abstract deleteRole(name: string): Promise<boolean>;
62
+ abstract saveRegistry(registry: RoleRegistry): Promise<void>;
63
+ abstract loadRegistry(): Promise<RoleRegistry>;
64
+ abstract saveSubject(identifier: string, subject: Subject): Promise<number>;
65
+ abstract loadSubject(identifier: string): Promise<Subject | null>;
66
+ abstract deleteSubject(identifier: string): Promise<boolean>;
67
+ /**
68
+ * Get all subject identifiers from the database.
69
+ * Used by findSubjectsWithAccess and can be overridden for optimization.
70
+ */
71
+ protected abstract getAllSubjectIdentifiers(): Promise<string[]>;
72
+ /**
73
+ * Find all subject identifiers that have access to a specific path with given flags.
74
+ * Default implementation uses getAllSubjectIdentifiers + loadSubject.
75
+ * Subclasses can override with optimized batch loading implementations.
76
+ * @param pathPattern The path pattern to check (supports wildcards)
77
+ * @param flags The flags to check for
78
+ * @returns Array of subject identifiers that have access
79
+ */
80
+ findSubjectsWithAccess(pathPattern: string, flags: Flags): Promise<string[]>;
81
+ abstract clear(): Promise<void>;
82
+ abstract transaction<T>(fn: (adapter: DatabaseAdapter) => Promise<T>): Promise<T>;
83
+ }
@@ -0,0 +1,144 @@
1
+ import { Flags, hasBit } from '../constants';
2
+ import { Right } from '../right';
3
+ import { Rights } from '../rights';
4
+ import { Role } from '../role';
5
+ import { RoleRegistry } from '../role-registry';
6
+ import { Subject } from '../subject';
7
+ import { DEFAULT_TABLE_PREFIX, createTableNames } from './schema';
8
+ /**
9
+ * Abstract base class for database adapters.
10
+ * Provides common utility methods for serialization/deserialization
11
+ * and table name management.
12
+ */
13
+ export class BaseAdapter {
14
+ constructor(options = {}) {
15
+ // ===========================================================================
16
+ // Serialization Utilities
17
+ // ===========================================================================
18
+ /**
19
+ * Serialize tags array to JSON string
20
+ */
21
+ this.serializeTags = (tags) => {
22
+ if (tags.length === 0) {
23
+ return null;
24
+ }
25
+ return JSON.stringify(tags.sort());
26
+ };
27
+ /**
28
+ * Deserialize JSON string to tags array
29
+ */
30
+ this.deserializeTags = (json) => {
31
+ if (!json) {
32
+ return [];
33
+ }
34
+ try {
35
+ return JSON.parse(json);
36
+ }
37
+ catch {
38
+ return [];
39
+ }
40
+ };
41
+ /**
42
+ * Convert a Right instance to a database row (partial, without id and timestamps)
43
+ */
44
+ this.rightToRow = (right) => ({
45
+ allow_mask: right.allowMaskValue,
46
+ deny_mask: right.denyMaskValue,
47
+ description: right.description ?? null,
48
+ path: right.path,
49
+ priority: right.priority,
50
+ tags: this.serializeTags(right.tags),
51
+ valid_from: right.validFrom?.toISOString() ?? null,
52
+ valid_until: right.validUntil?.toISOString() ?? null
53
+ });
54
+ /**
55
+ * Convert a database row to a Right instance
56
+ */
57
+ this.rowToRight = (row) => {
58
+ const init = {
59
+ allow: this.maskToFlags(row.allow_mask),
60
+ deny: this.maskToFlags(row.deny_mask),
61
+ description: row.description ?? undefined,
62
+ priority: row.priority,
63
+ tags: this.deserializeTags(row.tags),
64
+ validFrom: row.valid_from ? new Date(row.valid_from) : undefined,
65
+ validUntil: row.valid_until ? new Date(row.valid_until) : undefined
66
+ };
67
+ const right = new Right(row.path, init);
68
+ right._setDbId(row.id);
69
+ return right;
70
+ };
71
+ /**
72
+ * Convert a bitmask to an array of Flag values
73
+ */
74
+ this.maskToFlags = (mask) => {
75
+ const flags = [];
76
+ if (hasBit(mask, Flags.READ)) {
77
+ flags.push(Flags.READ);
78
+ }
79
+ if (hasBit(mask, Flags.WRITE)) {
80
+ flags.push(Flags.WRITE);
81
+ }
82
+ if (hasBit(mask, Flags.CREATE)) {
83
+ flags.push(Flags.CREATE);
84
+ }
85
+ if (hasBit(mask, Flags.DELETE)) {
86
+ flags.push(Flags.DELETE);
87
+ }
88
+ if (hasBit(mask, Flags.EXECUTE)) {
89
+ flags.push(Flags.EXECUTE);
90
+ }
91
+ return flags;
92
+ };
93
+ /**
94
+ * Convert an array of Flag values to a bitmask
95
+ */
96
+ this.flagsToMask = (flags) => {
97
+ let mask = 0;
98
+ for (const f of flags) {
99
+ mask |= f;
100
+ }
101
+ return mask;
102
+ };
103
+ /**
104
+ * Parse an ISO 8601 timestamp string to a Date, or undefined if null/invalid
105
+ */
106
+ this.parseTimestamp = (value) => {
107
+ if (!value) {
108
+ return undefined;
109
+ }
110
+ const d = new Date(value);
111
+ if (Number.isNaN(d.getTime())) {
112
+ return undefined;
113
+ }
114
+ return d;
115
+ };
116
+ this.tablePrefix = options.tablePrefix ?? DEFAULT_TABLE_PREFIX;
117
+ this._tables = createTableNames(this.tablePrefix);
118
+ }
119
+ /**
120
+ * Get the table names with the configured prefix
121
+ */
122
+ get tables() {
123
+ return this._tables;
124
+ }
125
+ /**
126
+ * Find all subject identifiers that have access to a specific path with given flags.
127
+ * Default implementation uses getAllSubjectIdentifiers + loadSubject.
128
+ * Subclasses can override with optimized batch loading implementations.
129
+ * @param pathPattern The path pattern to check (supports wildcards)
130
+ * @param flags The flags to check for
131
+ * @returns Array of subject identifiers that have access
132
+ */
133
+ async findSubjectsWithAccess(pathPattern, flags) {
134
+ const allIdentifiers = await this.getAllSubjectIdentifiers();
135
+ const matchingSubjects = [];
136
+ for (const identifier of allIdentifiers) {
137
+ const subject = await this.loadSubject(identifier);
138
+ if (subject?.has(pathPattern, flags)) {
139
+ matchingSubjects.push(identifier);
140
+ }
141
+ }
142
+ return matchingSubjects;
143
+ }
144
+ }
@@ -0,0 +1,31 @@
1
+ import { Rights, RoleRegistry } from '../index';
2
+ import { PostgresAdapter, type PostgresAdapterOptions } from './postgres-adapter';
3
+ import { RedisAdapter, type RedisAdapterOptions } from './redis-adapter';
4
+ import { SQLiteAdapter, type SQLiteAdapterOptions } from './sqlite-adapter';
5
+ export type CreateSQLiteRightsOptions = SQLiteAdapterOptions;
6
+ export type CreatePostgresRegistryOptions = PostgresAdapterOptions;
7
+ export declare const createSQLiteRights: (options?: CreateSQLiteRightsOptions) => Promise<{
8
+ adapter: SQLiteAdapter;
9
+ rights: Rights;
10
+ }>;
11
+ export declare const createPostgresRegistry: (options: CreatePostgresRegistryOptions) => Promise<{
12
+ adapter: PostgresAdapter;
13
+ registry: RoleRegistry;
14
+ }>;
15
+ export declare const createSQLiteRegistry: (options?: CreateSQLiteRightsOptions) => Promise<{
16
+ adapter: SQLiteAdapter;
17
+ registry: RoleRegistry;
18
+ }>;
19
+ export declare const createPostgresRights: (options: CreatePostgresRegistryOptions) => Promise<{
20
+ adapter: PostgresAdapter;
21
+ rights: Rights;
22
+ }>;
23
+ export type CreateRedisRightsOptions = RedisAdapterOptions;
24
+ export declare const createRedisRights: (options: CreateRedisRightsOptions) => Promise<{
25
+ adapter: RedisAdapter;
26
+ rights: Rights;
27
+ }>;
28
+ export declare const createRedisRegistry: (options: CreateRedisRightsOptions) => Promise<{
29
+ adapter: RedisAdapter;
30
+ registry: RoleRegistry;
31
+ }>;
@@ -0,0 +1,48 @@
1
+ import { Rights, RoleRegistry } from '../index';
2
+ import { PostgresAdapter } from './postgres-adapter';
3
+ import { RedisAdapter } from './redis-adapter';
4
+ import { SQLiteAdapter } from './sqlite-adapter';
5
+ export const createSQLiteRights = async (options = {}) => {
6
+ const adapter = new SQLiteAdapter(options);
7
+ await adapter.connect();
8
+ await adapter.migrate();
9
+ adapter.prepareStatementsAfterMigration();
10
+ const rights = await adapter.loadRights();
11
+ return { adapter, rights };
12
+ };
13
+ export const createPostgresRegistry = async (options) => {
14
+ const adapter = new PostgresAdapter(options);
15
+ await adapter.connect();
16
+ await adapter.migrate();
17
+ const registry = await adapter.loadRegistry();
18
+ return { adapter, registry };
19
+ };
20
+ export const createSQLiteRegistry = async (options = {}) => {
21
+ const adapter = new SQLiteAdapter(options);
22
+ await adapter.connect();
23
+ await adapter.migrate();
24
+ adapter.prepareStatementsAfterMigration();
25
+ const registry = await adapter.loadRegistry();
26
+ return { adapter, registry };
27
+ };
28
+ export const createPostgresRights = async (options) => {
29
+ const adapter = new PostgresAdapter(options);
30
+ await adapter.connect();
31
+ await adapter.migrate();
32
+ const rights = await adapter.loadRights();
33
+ return { adapter, rights };
34
+ };
35
+ export const createRedisRights = async (options) => {
36
+ const adapter = new RedisAdapter(options);
37
+ await adapter.connect();
38
+ await adapter.migrate();
39
+ const rights = await adapter.loadRights();
40
+ return { adapter, rights };
41
+ };
42
+ export const createRedisRegistry = async (options) => {
43
+ const adapter = new RedisAdapter(options);
44
+ await adapter.connect();
45
+ await adapter.migrate();
46
+ const registry = await adapter.loadRegistry();
47
+ return { adapter, registry };
48
+ };