@forgebase/database 0.0.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/LICENSE +21 -0
- package/README.md +470 -0
- package/dist/cjs/adapters/base.d.ts +20 -0
- package/dist/cjs/adapters/base.d.ts.map +1 -0
- package/dist/cjs/adapters/base.js +13 -0
- package/dist/cjs/adapters/base.js.map +1 -0
- package/dist/cjs/adapters/index.d.ts +6 -0
- package/dist/cjs/adapters/index.d.ts.map +1 -0
- package/dist/cjs/adapters/index.js +24 -0
- package/dist/cjs/adapters/index.js.map +1 -0
- package/dist/cjs/adapters/postgres.d.ts +13 -0
- package/dist/cjs/adapters/postgres.d.ts.map +1 -0
- package/dist/cjs/adapters/postgres.js +51 -0
- package/dist/cjs/adapters/postgres.js.map +1 -0
- package/dist/cjs/adapters/sqlite.d.ts +13 -0
- package/dist/cjs/adapters/sqlite.d.ts.map +1 -0
- package/dist/cjs/adapters/sqlite.js +47 -0
- package/dist/cjs/adapters/sqlite.js.map +1 -0
- package/dist/cjs/adapters/types.d.ts +8 -0
- package/dist/cjs/adapters/types.d.ts.map +1 -0
- package/dist/cjs/adapters/types.js +3 -0
- package/dist/cjs/adapters/types.js.map +1 -0
- package/dist/cjs/database.d.ts +73 -0
- package/dist/cjs/database.d.ts.map +1 -0
- package/dist/cjs/database.js +673 -0
- package/dist/cjs/database.js.map +1 -0
- package/dist/cjs/errors.d.ts +37 -0
- package/dist/cjs/errors.d.ts.map +1 -0
- package/dist/cjs/errors.js +64 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/index.d.ts +16 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +31 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/kysely-hooks.d.ts +45 -0
- package/dist/cjs/kysely-hooks.d.ts.map +1 -0
- package/dist/cjs/kysely-hooks.js +93 -0
- package/dist/cjs/kysely-hooks.js.map +1 -0
- package/dist/cjs/libsql/example.d.ts +2 -0
- package/dist/cjs/libsql/example.d.ts.map +1 -0
- package/dist/cjs/libsql/example.js +44 -0
- package/dist/cjs/libsql/example.js.map +1 -0
- package/dist/cjs/libsql/index.d.ts +36 -0
- package/dist/cjs/libsql/index.d.ts.map +1 -0
- package/dist/cjs/libsql/index.js +155 -0
- package/dist/cjs/libsql/index.js.map +1 -0
- package/dist/cjs/permissionService.d.ts +20 -0
- package/dist/cjs/permissionService.d.ts.map +1 -0
- package/dist/cjs/permissionService.js +107 -0
- package/dist/cjs/permissionService.js.map +1 -0
- package/dist/cjs/rlsFunctionRegistry.d.ts +43 -0
- package/dist/cjs/rlsFunctionRegistry.d.ts.map +1 -0
- package/dist/cjs/rlsFunctionRegistry.js +63 -0
- package/dist/cjs/rlsFunctionRegistry.js.map +1 -0
- package/dist/cjs/rlsManager.d.ts +23 -0
- package/dist/cjs/rlsManager.d.ts.map +1 -0
- package/dist/cjs/rlsManager.js +371 -0
- package/dist/cjs/rlsManager.js.map +1 -0
- package/dist/cjs/schema.d.ts +15 -0
- package/dist/cjs/schema.d.ts.map +1 -0
- package/dist/cjs/schema.js +119 -0
- package/dist/cjs/schema.js.map +1 -0
- package/dist/cjs/sdk/client.d.ts +324 -0
- package/dist/cjs/sdk/client.d.ts.map +1 -0
- package/dist/cjs/sdk/client.js +554 -0
- package/dist/cjs/sdk/client.js.map +1 -0
- package/dist/cjs/sdk/examples.d.ts +68 -0
- package/dist/cjs/sdk/examples.d.ts.map +1 -0
- package/dist/cjs/sdk/examples.js +232 -0
- package/dist/cjs/sdk/examples.js.map +1 -0
- package/dist/cjs/sdk/server.d.ts +115 -0
- package/dist/cjs/sdk/server.d.ts.map +1 -0
- package/dist/cjs/sdk/server.js +140 -0
- package/dist/cjs/sdk/server.js.map +1 -0
- package/dist/cjs/types.d.ts +217 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +5 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cjs/utils/column-utils.d.ts +8 -0
- package/dist/cjs/utils/column-utils.d.ts.map +1 -0
- package/dist/cjs/utils/column-utils.js +131 -0
- package/dist/cjs/utils/column-utils.js.map +1 -0
- package/dist/cjs/utils/db.d.ts +2 -0
- package/dist/cjs/utils/db.d.ts.map +1 -0
- package/dist/cjs/utils/db.js +6 -0
- package/dist/cjs/utils/db.js.map +1 -0
- package/dist/cjs/utils/inspector.d.ts +39 -0
- package/dist/cjs/utils/inspector.d.ts.map +1 -0
- package/dist/cjs/utils/inspector.js +164 -0
- package/dist/cjs/utils/inspector.js.map +1 -0
- package/dist/cjs/utils/permission-initializer.d.ts +15 -0
- package/dist/cjs/utils/permission-initializer.d.ts.map +1 -0
- package/dist/cjs/utils/permission-initializer.js +173 -0
- package/dist/cjs/utils/permission-initializer.js.map +1 -0
- package/dist/cjs/websocket/RealtimeAdapter.d.ts +22 -0
- package/dist/cjs/websocket/RealtimeAdapter.d.ts.map +1 -0
- package/dist/cjs/websocket/RealtimeAdapter.js +3 -0
- package/dist/cjs/websocket/RealtimeAdapter.js.map +1 -0
- package/dist/cjs/websocket/SSEManager.d.ts +40 -0
- package/dist/cjs/websocket/SSEManager.d.ts.map +1 -0
- package/dist/cjs/websocket/SSEManager.js +268 -0
- package/dist/cjs/websocket/SSEManager.js.map +1 -0
- package/dist/cjs/websocket/WebSocketManager.d.ts +28 -0
- package/dist/cjs/websocket/WebSocketManager.d.ts.map +1 -0
- package/dist/cjs/websocket/WebSocketManager.js +156 -0
- package/dist/cjs/websocket/WebSocketManager.js.map +1 -0
- package/dist/cjs/websocket/index.d.ts +4 -0
- package/dist/cjs/websocket/index.d.ts.map +1 -0
- package/dist/cjs/websocket/index.js +20 -0
- package/dist/cjs/websocket/index.js.map +1 -0
- package/dist/esm/adapters/base.d.ts +20 -0
- package/dist/esm/adapters/base.d.ts.map +1 -0
- package/dist/esm/adapters/base.js +10 -0
- package/dist/esm/adapters/base.js.map +1 -0
- package/dist/esm/adapters/index.d.ts +6 -0
- package/dist/esm/adapters/index.d.ts.map +1 -0
- package/dist/esm/adapters/index.js +19 -0
- package/dist/esm/adapters/index.js.map +1 -0
- package/dist/esm/adapters/postgres.d.ts +13 -0
- package/dist/esm/adapters/postgres.d.ts.map +1 -0
- package/dist/esm/adapters/postgres.js +47 -0
- package/dist/esm/adapters/postgres.js.map +1 -0
- package/dist/esm/adapters/sqlite.d.ts +13 -0
- package/dist/esm/adapters/sqlite.d.ts.map +1 -0
- package/dist/esm/adapters/sqlite.js +43 -0
- package/dist/esm/adapters/sqlite.js.map +1 -0
- package/dist/esm/adapters/types.d.ts +8 -0
- package/dist/esm/adapters/types.d.ts.map +1 -0
- package/dist/esm/adapters/types.js +2 -0
- package/dist/esm/adapters/types.js.map +1 -0
- package/dist/esm/database.d.ts +73 -0
- package/dist/esm/database.d.ts.map +1 -0
- package/dist/esm/database.js +668 -0
- package/dist/esm/database.js.map +1 -0
- package/dist/esm/errors.d.ts +37 -0
- package/dist/esm/errors.d.ts.map +1 -0
- package/dist/esm/errors.js +55 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/index.d.ts +16 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +15 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/kysely-hooks.d.ts +45 -0
- package/dist/esm/kysely-hooks.d.ts.map +1 -0
- package/dist/esm/kysely-hooks.js +86 -0
- package/dist/esm/kysely-hooks.js.map +1 -0
- package/dist/esm/libsql/example.d.ts +2 -0
- package/dist/esm/libsql/example.d.ts.map +1 -0
- package/dist/esm/libsql/example.js +42 -0
- package/dist/esm/libsql/example.js.map +1 -0
- package/dist/esm/libsql/index.d.ts +36 -0
- package/dist/esm/libsql/index.d.ts.map +1 -0
- package/dist/esm/libsql/index.js +116 -0
- package/dist/esm/libsql/index.js.map +1 -0
- package/dist/esm/permissionService.d.ts +20 -0
- package/dist/esm/permissionService.d.ts.map +1 -0
- package/dist/esm/permissionService.js +103 -0
- package/dist/esm/permissionService.js.map +1 -0
- package/dist/esm/rlsFunctionRegistry.d.ts +43 -0
- package/dist/esm/rlsFunctionRegistry.d.ts.map +1 -0
- package/dist/esm/rlsFunctionRegistry.js +60 -0
- package/dist/esm/rlsFunctionRegistry.js.map +1 -0
- package/dist/esm/rlsManager.d.ts +23 -0
- package/dist/esm/rlsManager.d.ts.map +1 -0
- package/dist/esm/rlsManager.js +366 -0
- package/dist/esm/rlsManager.js.map +1 -0
- package/dist/esm/schema.d.ts +15 -0
- package/dist/esm/schema.d.ts.map +1 -0
- package/dist/esm/schema.js +113 -0
- package/dist/esm/schema.js.map +1 -0
- package/dist/esm/sdk/client.d.ts +324 -0
- package/dist/esm/sdk/client.d.ts.map +1 -0
- package/dist/esm/sdk/client.js +550 -0
- package/dist/esm/sdk/client.js.map +1 -0
- package/dist/esm/sdk/examples.d.ts +68 -0
- package/dist/esm/sdk/examples.d.ts.map +1 -0
- package/dist/esm/sdk/examples.js +229 -0
- package/dist/esm/sdk/examples.js.map +1 -0
- package/dist/esm/sdk/server.d.ts +115 -0
- package/dist/esm/sdk/server.d.ts.map +1 -0
- package/dist/esm/sdk/server.js +136 -0
- package/dist/esm/sdk/server.js.map +1 -0
- package/dist/esm/types.d.ts +217 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/utils/column-utils.d.ts +8 -0
- package/dist/esm/utils/column-utils.d.ts.map +1 -0
- package/dist/esm/utils/column-utils.js +127 -0
- package/dist/esm/utils/column-utils.js.map +1 -0
- package/dist/esm/utils/db.d.ts +2 -0
- package/dist/esm/utils/db.d.ts.map +1 -0
- package/dist/esm/utils/db.js +3 -0
- package/dist/esm/utils/db.js.map +1 -0
- package/dist/esm/utils/inspector.d.ts +39 -0
- package/dist/esm/utils/inspector.d.ts.map +1 -0
- package/dist/esm/utils/inspector.js +160 -0
- package/dist/esm/utils/inspector.js.map +1 -0
- package/dist/esm/utils/permission-initializer.d.ts +15 -0
- package/dist/esm/utils/permission-initializer.d.ts.map +1 -0
- package/dist/esm/utils/permission-initializer.js +137 -0
- package/dist/esm/utils/permission-initializer.js.map +1 -0
- package/dist/esm/websocket/RealtimeAdapter.d.ts +22 -0
- package/dist/esm/websocket/RealtimeAdapter.d.ts.map +1 -0
- package/dist/esm/websocket/RealtimeAdapter.js +2 -0
- package/dist/esm/websocket/RealtimeAdapter.js.map +1 -0
- package/dist/esm/websocket/SSEManager.d.ts +40 -0
- package/dist/esm/websocket/SSEManager.d.ts.map +1 -0
- package/dist/esm/websocket/SSEManager.js +231 -0
- package/dist/esm/websocket/SSEManager.js.map +1 -0
- package/dist/esm/websocket/WebSocketManager.d.ts +28 -0
- package/dist/esm/websocket/WebSocketManager.d.ts.map +1 -0
- package/dist/esm/websocket/WebSocketManager.js +152 -0
- package/dist/esm/websocket/WebSocketManager.js.map +1 -0
- package/dist/esm/websocket/index.d.ts +4 -0
- package/dist/esm/websocket/index.d.ts.map +1 -0
- package/dist/esm/websocket/index.js +4 -0
- package/dist/esm/websocket/index.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
import { Kysely } from 'kysely';
|
|
2
|
+
import { PermissionService } from './permissionService';
|
|
3
|
+
import { enforcePermissions, evaluateFieldCheckForRow } from './rlsManager';
|
|
4
|
+
import { DBInspector } from './utils/inspector';
|
|
5
|
+
import { KyselyHooks } from './kysely-hooks';
|
|
6
|
+
import { AuthenticationRequiredError, ExcludedTableError, PermissionDeniedError, } from './errors';
|
|
7
|
+
import { FG_PERMISSION_TABLE, } from './types';
|
|
8
|
+
import { createColumn } from './utils/column-utils';
|
|
9
|
+
import { addForeignKey, dropForeignKey, modifySchema, truncateTable, } from './schema';
|
|
10
|
+
import { KyselyQueryHandler } from './sdk/server';
|
|
11
|
+
import { WebSocketManager } from './websocket/WebSocketManager';
|
|
12
|
+
import { SSEManager } from './websocket/SSEManager';
|
|
13
|
+
import { initializePermissions } from './utils/permission-initializer';
|
|
14
|
+
import { LibsqlDialect } from './libsql';
|
|
15
|
+
export class ForgeDatabase {
|
|
16
|
+
constructor(config = {}) {
|
|
17
|
+
this.config = config;
|
|
18
|
+
this.defaultPermissions = {
|
|
19
|
+
operations: {
|
|
20
|
+
SELECT: [
|
|
21
|
+
{
|
|
22
|
+
allow: 'private',
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
INSERT: [
|
|
26
|
+
{
|
|
27
|
+
allow: 'private',
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
UPDATE: [
|
|
31
|
+
{
|
|
32
|
+
allow: 'private',
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
DELETE: [
|
|
36
|
+
{
|
|
37
|
+
allow: 'private',
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
this.excludedTables = [FG_PERMISSION_TABLE];
|
|
43
|
+
/**
|
|
44
|
+
* Get the endpoints for the database
|
|
45
|
+
* @returns Endpoints for the database
|
|
46
|
+
*/
|
|
47
|
+
this.endpoints = {
|
|
48
|
+
/**
|
|
49
|
+
* Work with the database schema
|
|
50
|
+
* @returns Schema endpoints
|
|
51
|
+
*/
|
|
52
|
+
schema: {
|
|
53
|
+
get: async (trx) => {
|
|
54
|
+
return await this.dbInspector.getDatabaseSchema(this.excludedTables);
|
|
55
|
+
},
|
|
56
|
+
create: async (payload, trx) => {
|
|
57
|
+
const { tableName, columns } = payload;
|
|
58
|
+
if (!tableName) {
|
|
59
|
+
throw new Error('Invalid request body');
|
|
60
|
+
}
|
|
61
|
+
// Efficiently check if table exists
|
|
62
|
+
const hasTable = await this.dbInspector.hasTable(tableName);
|
|
63
|
+
if (hasTable) {
|
|
64
|
+
console.log('Table already exists');
|
|
65
|
+
throw new Error('Table already exists');
|
|
66
|
+
}
|
|
67
|
+
// Use transaction if provided, otherwise use the db instance
|
|
68
|
+
const builder = trx || this.hooks.getDbInstance();
|
|
69
|
+
// Start creating the table
|
|
70
|
+
// Start creating the table
|
|
71
|
+
let tableBuilder = builder.schema.createTable(tableName);
|
|
72
|
+
// Add columns using strict createColumn util
|
|
73
|
+
columns.forEach((col) => {
|
|
74
|
+
tableBuilder = createColumn(tableBuilder, col, this.hooks.getDbInstance());
|
|
75
|
+
});
|
|
76
|
+
await tableBuilder.execute();
|
|
77
|
+
await this.permissionService.setPermissionsForTable(tableName, this.defaultPermissions, builder);
|
|
78
|
+
return {
|
|
79
|
+
message: 'Table created successfully',
|
|
80
|
+
tablename: tableName,
|
|
81
|
+
action: 'create',
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
delete: async (tableName, trx) => {
|
|
85
|
+
if (this.excludedTables.includes(tableName)) {
|
|
86
|
+
throw new ExcludedTableError(tableName);
|
|
87
|
+
}
|
|
88
|
+
// Use transaction if provided, otherwise use the db instance
|
|
89
|
+
const builder = trx || this.hooks.getDbInstance();
|
|
90
|
+
await builder.schema.dropTable(tableName).ifExists().execute();
|
|
91
|
+
await this.permissionService.deletePermissionsForTable(tableName, builder);
|
|
92
|
+
return {
|
|
93
|
+
message: 'Table deleted successfully',
|
|
94
|
+
tablename: tableName,
|
|
95
|
+
action: 'delete',
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
modify: async (payload, trx) => {
|
|
99
|
+
if (this.excludedTables.includes(payload.tableName)) {
|
|
100
|
+
throw new ExcludedTableError(payload.tableName);
|
|
101
|
+
}
|
|
102
|
+
const builder = this.hooks.getDbInstance();
|
|
103
|
+
return await modifySchema(builder, payload, trx);
|
|
104
|
+
},
|
|
105
|
+
addForeingKey: async (payload, trx) => {
|
|
106
|
+
if (this.excludedTables.includes(payload.tableName)) {
|
|
107
|
+
throw new ExcludedTableError(payload.tableName);
|
|
108
|
+
}
|
|
109
|
+
if (this.excludedTables.includes(payload.foreignTableName)) {
|
|
110
|
+
throw new ExcludedTableError(payload.foreignTableName);
|
|
111
|
+
}
|
|
112
|
+
return await addForeignKey(payload, this.hooks.getDbInstance(), trx);
|
|
113
|
+
},
|
|
114
|
+
dropForeignKey: async (payload, trx) => {
|
|
115
|
+
if (this.excludedTables.includes(payload.tableName)) {
|
|
116
|
+
throw new ExcludedTableError(payload.tableName);
|
|
117
|
+
}
|
|
118
|
+
return await dropForeignKey(payload, this.hooks.getDbInstance(), trx);
|
|
119
|
+
},
|
|
120
|
+
truncateTable: async (tableName, trx) => {
|
|
121
|
+
if (this.excludedTables.includes(tableName)) {
|
|
122
|
+
throw new ExcludedTableError(tableName);
|
|
123
|
+
}
|
|
124
|
+
return await truncateTable(tableName, this.hooks.getDbInstance(), trx);
|
|
125
|
+
},
|
|
126
|
+
getTableSchema: async (tableName, trx) => {
|
|
127
|
+
if (this.excludedTables.includes(tableName)) {
|
|
128
|
+
throw new ExcludedTableError(tableName);
|
|
129
|
+
}
|
|
130
|
+
const tableInfo = await this.dbInspector.getTableInfo(tableName);
|
|
131
|
+
return {
|
|
132
|
+
name: tableName,
|
|
133
|
+
info: tableInfo,
|
|
134
|
+
};
|
|
135
|
+
},
|
|
136
|
+
getTables: async (trx) => {
|
|
137
|
+
let tables = await this.dbInspector.getTables();
|
|
138
|
+
tables = tables.filter((t) => !this.excludedTables.includes(t));
|
|
139
|
+
return tables;
|
|
140
|
+
},
|
|
141
|
+
getTablePermissions: async (tableName, trx) => {
|
|
142
|
+
if (this.excludedTables.includes(tableName)) {
|
|
143
|
+
throw new ExcludedTableError(tableName);
|
|
144
|
+
}
|
|
145
|
+
return await this.permissionService.getPermissionsForTable(tableName, trx);
|
|
146
|
+
},
|
|
147
|
+
getTableSchemaWithPermissions: async (tableName, trx) => {
|
|
148
|
+
if (this.excludedTables.includes(tableName)) {
|
|
149
|
+
throw new ExcludedTableError(tableName);
|
|
150
|
+
}
|
|
151
|
+
const tableInfo = await this.dbInspector.getTableInfo(tableName);
|
|
152
|
+
const permissions = await this.permissionService.getPermissionsForTable(tableName, trx);
|
|
153
|
+
return {
|
|
154
|
+
name: tableName,
|
|
155
|
+
info: tableInfo,
|
|
156
|
+
permissions,
|
|
157
|
+
};
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
/**
|
|
161
|
+
* Work with the database data
|
|
162
|
+
* @returns Data endpoints
|
|
163
|
+
*/
|
|
164
|
+
data: {
|
|
165
|
+
query: async (tableName, params, user, isSystem = false, trx) => {
|
|
166
|
+
if (this.excludedTables.includes(tableName)) {
|
|
167
|
+
throw new ExcludedTableError(tableName);
|
|
168
|
+
}
|
|
169
|
+
// const queryParams = this.parseQueryParams(params);
|
|
170
|
+
const queryParams = params; // KyselyQueryHandler handles params object directly
|
|
171
|
+
if (!this.config.enforceRls || isSystem) {
|
|
172
|
+
return this.hooks.query(tableName, (db) => this.queryHandler
|
|
173
|
+
.buildQuery(queryParams, db.selectFrom(tableName))
|
|
174
|
+
.execute(), queryParams, trx);
|
|
175
|
+
}
|
|
176
|
+
if (!user && !isSystem && this.config.enforceRls) {
|
|
177
|
+
throw new AuthenticationRequiredError('Authentication required to query records');
|
|
178
|
+
}
|
|
179
|
+
const { status: initialStatus, hasFieldCheck: initialHasFieldCheck, hasCustomFunction: initialHasCustomFunction, fieldCheckRules: extractedFieldCheckRules, } = await enforcePermissions(tableName, 'SELECT', user, this.permissionService, undefined, this.hooks.getDbInstance());
|
|
180
|
+
if (!initialStatus &&
|
|
181
|
+
!initialHasFieldCheck &&
|
|
182
|
+
!initialHasCustomFunction) {
|
|
183
|
+
throw new PermissionDeniedError(`User does not have permission to query table "${tableName}"`);
|
|
184
|
+
}
|
|
185
|
+
const records = (await this.hooks.query(tableName, (db) => this.queryHandler
|
|
186
|
+
.buildQuery(queryParams, db.selectFrom(tableName))
|
|
187
|
+
.execute(), queryParams, trx));
|
|
188
|
+
if (initialStatus) {
|
|
189
|
+
// Simple rule matched — return all records
|
|
190
|
+
return records;
|
|
191
|
+
}
|
|
192
|
+
// Fast path: filter rows using pre-extracted fieldCheck rules
|
|
193
|
+
if (extractedFieldCheckRules?.length) {
|
|
194
|
+
const filtered = [];
|
|
195
|
+
for (const record of records) {
|
|
196
|
+
const allowed = await evaluateFieldCheckForRow(extractedFieldCheckRules, user, record, this.hooks.getDbInstance());
|
|
197
|
+
if (allowed) {
|
|
198
|
+
filtered.push(record);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (filtered.length === 0) {
|
|
202
|
+
throw new PermissionDeniedError(`User does not have permission to query table "${tableName}"`);
|
|
203
|
+
}
|
|
204
|
+
return filtered;
|
|
205
|
+
}
|
|
206
|
+
// Fallback for customFunction rules
|
|
207
|
+
const { status, row } = await enforcePermissions(tableName, 'SELECT', user, this.permissionService, records, this.hooks.getDbInstance());
|
|
208
|
+
if (!status) {
|
|
209
|
+
throw new PermissionDeniedError(`User does not have permission to query table "${tableName}"`);
|
|
210
|
+
}
|
|
211
|
+
return row;
|
|
212
|
+
},
|
|
213
|
+
create: async (params, user, isSystem = false, trx) => {
|
|
214
|
+
if (this.excludedTables.includes(params.tableName)) {
|
|
215
|
+
throw new ExcludedTableError(params.tableName);
|
|
216
|
+
}
|
|
217
|
+
const { data, tableName } = params;
|
|
218
|
+
// console.log('data-db', data, tableName);
|
|
219
|
+
// Handle both single record and array of records
|
|
220
|
+
const isArray = Array.isArray(data);
|
|
221
|
+
const records = isArray ? data : [data];
|
|
222
|
+
// Validate records
|
|
223
|
+
if (!records.length ||
|
|
224
|
+
!records.every((record) => typeof record === 'object' && Object.keys(record).length > 0)) {
|
|
225
|
+
console.log('Invalid request body', records);
|
|
226
|
+
throw new Error('Invalid request body');
|
|
227
|
+
}
|
|
228
|
+
if (!this.config.enforceRls || isSystem) {
|
|
229
|
+
return this.hooks.mutate(tableName, 'create', async (db) => db.insertInto(tableName).values(records).returningAll().execute(), records, undefined, trx);
|
|
230
|
+
}
|
|
231
|
+
if (!user && !isSystem && this.config.enforceRls) {
|
|
232
|
+
throw new AuthenticationRequiredError('Authentication required to create records');
|
|
233
|
+
}
|
|
234
|
+
const { status: initialStatus, hasFieldCheck: initialHasFieldCheck, hasCustomFunction: initialHasCustomFunction, } = await enforcePermissions(tableName, 'INSERT', user, this.permissionService, undefined, this.hooks.getDbInstance());
|
|
235
|
+
if (!initialStatus &&
|
|
236
|
+
!initialHasFieldCheck &&
|
|
237
|
+
!initialHasCustomFunction) {
|
|
238
|
+
throw new PermissionDeniedError(`User does not have permission to create record in table "${tableName}"`);
|
|
239
|
+
}
|
|
240
|
+
if (initialStatus) {
|
|
241
|
+
// If the user has permission to create, proceed with the creation
|
|
242
|
+
return this.hooks.mutate(tableName, 'create', async (db) => db.insertInto(tableName).values(records).returningAll().execute(), records, undefined, trx);
|
|
243
|
+
}
|
|
244
|
+
const { status, row } = await enforcePermissions(tableName, 'INSERT', user, this.permissionService, records, this.hooks.getDbInstance());
|
|
245
|
+
if (!status) {
|
|
246
|
+
throw new Error(`User does not have permission to create record in table "${tableName}"`);
|
|
247
|
+
}
|
|
248
|
+
if (!row || (Array.isArray(row) && row.length === 0)) {
|
|
249
|
+
throw new PermissionDeniedError(`User does not have permission to create this record in table "${tableName}"`);
|
|
250
|
+
}
|
|
251
|
+
const result = this.hooks.mutate(tableName, 'create', async (db) => db.insertInto(tableName).values(row).returningAll().execute(), row, undefined, trx);
|
|
252
|
+
return result;
|
|
253
|
+
},
|
|
254
|
+
update: async (params, user, isSystem = false, trx) => {
|
|
255
|
+
if (this.excludedTables.includes(params.tableName)) {
|
|
256
|
+
throw new ExcludedTableError(params.tableName);
|
|
257
|
+
}
|
|
258
|
+
const { id, tableName, data } = params;
|
|
259
|
+
if (!this.config.enforceRls || isSystem) {
|
|
260
|
+
const result = this.hooks.mutate(tableName, 'update', async (db) => db
|
|
261
|
+
.updateTable(tableName)
|
|
262
|
+
.set(data)
|
|
263
|
+
.where('id', '=', id)
|
|
264
|
+
.returningAll()
|
|
265
|
+
.execute(), { id, ...data }, undefined, trx);
|
|
266
|
+
return result;
|
|
267
|
+
}
|
|
268
|
+
if (!user && !isSystem && this.config.enforceRls) {
|
|
269
|
+
throw new AuthenticationRequiredError('Authentication required to update records');
|
|
270
|
+
}
|
|
271
|
+
const { status: initialStatus, hasFieldCheck: initialHasFieldCheck, hasCustomFunction: initialHasCustomFunction, fieldCheckRules: extractedFieldCheckRules, } = await enforcePermissions(tableName, 'UPDATE', user, this.permissionService, undefined, this.hooks.getDbInstance());
|
|
272
|
+
if (!initialStatus &&
|
|
273
|
+
!initialHasFieldCheck &&
|
|
274
|
+
!initialHasCustomFunction) {
|
|
275
|
+
throw new Error(`User does not have permission to update record with id ${id}`);
|
|
276
|
+
}
|
|
277
|
+
if (initialStatus) {
|
|
278
|
+
// Simple rule matched — proceed directly
|
|
279
|
+
const result = this.hooks.mutate(tableName, 'update', async (db) => db
|
|
280
|
+
.updateTable(tableName)
|
|
281
|
+
.set(data)
|
|
282
|
+
.where('id', '=', id)
|
|
283
|
+
.returningAll()
|
|
284
|
+
.execute(), { id, ...data }, undefined, trx);
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
// fieldCheck/customFunction path — fetch the row then evaluate
|
|
288
|
+
const record = await this.hooks.query(tableName, (db) => {
|
|
289
|
+
return db
|
|
290
|
+
.selectFrom(tableName)
|
|
291
|
+
.where('id', '=', id)
|
|
292
|
+
.selectAll()
|
|
293
|
+
.execute();
|
|
294
|
+
}, { id }, trx);
|
|
295
|
+
// Fast path: use pre-extracted rules instead of full enforcePermissions
|
|
296
|
+
if (extractedFieldCheckRules?.length) {
|
|
297
|
+
const allowed = await evaluateFieldCheckForRow(extractedFieldCheckRules, user, record[0], this.hooks.getDbInstance());
|
|
298
|
+
if (!allowed) {
|
|
299
|
+
throw new PermissionDeniedError(`User does not have permission to update record with id ${id}`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
// Fallback for customFunction rules
|
|
304
|
+
const { status } = await enforcePermissions(tableName, 'UPDATE', user, this.permissionService, record[0], this.hooks.getDbInstance());
|
|
305
|
+
if (!status) {
|
|
306
|
+
throw new PermissionDeniedError(`User does not have permission to update record with id ${id}`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const result = this.hooks.mutate(tableName, 'update', async (db) => db
|
|
310
|
+
.updateTable(tableName)
|
|
311
|
+
.set(data)
|
|
312
|
+
.where('id', '=', id)
|
|
313
|
+
.returningAll()
|
|
314
|
+
.execute(), { id, ...data }, undefined, trx);
|
|
315
|
+
return result;
|
|
316
|
+
},
|
|
317
|
+
advanceUpdate: async (params, user, isSystem = false, trx) => {
|
|
318
|
+
if (this.excludedTables.includes(params.tableName)) {
|
|
319
|
+
throw new ExcludedTableError(params.tableName);
|
|
320
|
+
}
|
|
321
|
+
const { query, tableName, data } = params;
|
|
322
|
+
// const queryParams = this.parseQueryParams(query);
|
|
323
|
+
const queryParams = query;
|
|
324
|
+
if (!this.config.enforceRls || isSystem) {
|
|
325
|
+
const result = this.hooks.mutate(tableName, 'update', async (db) => this.queryHandler
|
|
326
|
+
.buildQuery(queryParams, db.updateTable(tableName))
|
|
327
|
+
.set(data)
|
|
328
|
+
.returningAll()
|
|
329
|
+
.execute(), { ...data }, undefined, trx);
|
|
330
|
+
return result;
|
|
331
|
+
}
|
|
332
|
+
if (!user && !isSystem && this.config.enforceRls) {
|
|
333
|
+
throw new AuthenticationRequiredError('Authentication required to update records');
|
|
334
|
+
}
|
|
335
|
+
const { status: initialStatus, hasFieldCheck: initialHasFieldCheck, hasCustomFunction: initialHasCustomFunction, fieldCheckRules: extractedFieldCheckRules, } = await enforcePermissions(tableName, 'UPDATE', user, this.permissionService, undefined, this.hooks.getDbInstance());
|
|
336
|
+
if (!initialStatus &&
|
|
337
|
+
!initialHasFieldCheck &&
|
|
338
|
+
!initialHasCustomFunction) {
|
|
339
|
+
throw new Error(`User does not have permission to update this records`);
|
|
340
|
+
}
|
|
341
|
+
if (initialStatus) {
|
|
342
|
+
// Simple rule matched — proceed directly
|
|
343
|
+
const result = this.hooks.mutate(tableName, 'update', async (db) => this.queryHandler
|
|
344
|
+
.buildQuery(queryParams, db.updateTable(tableName))
|
|
345
|
+
.set(data)
|
|
346
|
+
.returningAll()
|
|
347
|
+
.execute(), { ...data }, queryParams, trx);
|
|
348
|
+
return result;
|
|
349
|
+
}
|
|
350
|
+
// fieldCheck/customFunction path — fetch matching rows then evaluate
|
|
351
|
+
const records = (await this.hooks.query(tableName, (db) => this.queryHandler
|
|
352
|
+
.buildQuery(queryParams, db.selectFrom(tableName))
|
|
353
|
+
.selectAll()
|
|
354
|
+
.execute(), queryParams, trx));
|
|
355
|
+
// Fast path: use pre-extracted rules instead of full enforcePermissions
|
|
356
|
+
if (extractedFieldCheckRules?.length) {
|
|
357
|
+
for (const record of records) {
|
|
358
|
+
const allowed = await evaluateFieldCheckForRow(extractedFieldCheckRules, user, record, this.hooks.getDbInstance());
|
|
359
|
+
if (!allowed) {
|
|
360
|
+
throw new PermissionDeniedError(`User does not have permission to update this records`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
// Fallback for customFunction rules
|
|
366
|
+
const { status } = await enforcePermissions(tableName, 'UPDATE', user, this.permissionService, records, this.hooks.getDbInstance());
|
|
367
|
+
if (!status) {
|
|
368
|
+
throw new PermissionDeniedError(`User does not have permission to update this records`);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
const result = this.hooks.mutate(tableName, 'update', async (db) => this.queryHandler
|
|
372
|
+
.buildQuery(queryParams, db.updateTable(tableName))
|
|
373
|
+
.set(data)
|
|
374
|
+
.returningAll()
|
|
375
|
+
.execute(), { ...data }, queryParams, trx);
|
|
376
|
+
return result;
|
|
377
|
+
},
|
|
378
|
+
delete: async (params, user, isSystem = false, trx) => {
|
|
379
|
+
if (this.excludedTables.includes(params.tableName)) {
|
|
380
|
+
throw new ExcludedTableError(params.tableName);
|
|
381
|
+
}
|
|
382
|
+
const { id, tableName } = params;
|
|
383
|
+
if (!this.config.enforceRls || isSystem) {
|
|
384
|
+
return this.hooks.mutate(tableName, 'delete', async (db) => db
|
|
385
|
+
.deleteFrom(tableName)
|
|
386
|
+
.where('id', '=', id)
|
|
387
|
+
.returning('id')
|
|
388
|
+
.execute(), { id }, undefined, trx);
|
|
389
|
+
}
|
|
390
|
+
if (!user && !isSystem && this.config.enforceRls) {
|
|
391
|
+
throw new AuthenticationRequiredError('Authentication required to delete records');
|
|
392
|
+
}
|
|
393
|
+
const { status: initialStatus, hasFieldCheck: initialHasFieldCheck, hasCustomFunction: initialHasCustomFunction, fieldCheckRules: extractedFieldCheckRules, } = await enforcePermissions(tableName, 'DELETE', user, this.permissionService, undefined, this.hooks.getDbInstance());
|
|
394
|
+
if (!initialStatus &&
|
|
395
|
+
!initialHasFieldCheck &&
|
|
396
|
+
!initialHasCustomFunction) {
|
|
397
|
+
throw new PermissionDeniedError(`User does not have permission to delete record with id ${id}`);
|
|
398
|
+
}
|
|
399
|
+
if (initialStatus) {
|
|
400
|
+
// If the user has permission to delete, proceed with the deletion
|
|
401
|
+
return this.hooks.mutate(tableName, 'delete', async (db) => db.deleteFrom(tableName).where('id', '=', id).execute(), { id }, undefined, trx);
|
|
402
|
+
}
|
|
403
|
+
// fieldCheck/customFunction path — fetch the record then evaluate
|
|
404
|
+
const record = (await this.hooks.query(tableName, (db) => {
|
|
405
|
+
return db
|
|
406
|
+
.selectFrom(tableName)
|
|
407
|
+
.where('id', '=', id)
|
|
408
|
+
.selectAll()
|
|
409
|
+
.execute();
|
|
410
|
+
}, { id }, trx));
|
|
411
|
+
// Fast path: use pre-extracted rules instead of full enforcePermissions
|
|
412
|
+
if (extractedFieldCheckRules?.length) {
|
|
413
|
+
const allowed = await evaluateFieldCheckForRow(extractedFieldCheckRules, user, record[0], this.hooks.getDbInstance());
|
|
414
|
+
if (!allowed) {
|
|
415
|
+
throw new PermissionDeniedError(`User does not have permission to delete record with id ${id}`);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
// Fallback for customFunction rules
|
|
420
|
+
const { status } = await enforcePermissions(tableName, 'DELETE', user, this.permissionService, record, this.hooks.getDbInstance());
|
|
421
|
+
if (!status) {
|
|
422
|
+
throw new PermissionDeniedError(`User does not have permission to delete record with id ${id}`);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return this.hooks.mutate(tableName, 'delete', async (db) => db.deleteFrom(tableName).where('id', '=', id).execute(), { id }, undefined, trx);
|
|
426
|
+
},
|
|
427
|
+
advanceDelete: async (params, user, isSystem = false, trx) => {
|
|
428
|
+
if (this.excludedTables.includes(params.tableName)) {
|
|
429
|
+
throw new ExcludedTableError(params.tableName);
|
|
430
|
+
}
|
|
431
|
+
const { query, tableName } = params;
|
|
432
|
+
// const queryParams = this.parseQueryParams(query);
|
|
433
|
+
const queryParams = query;
|
|
434
|
+
if (!this.config.enforceRls || isSystem) {
|
|
435
|
+
return this.hooks.mutate(tableName, 'delete', async (db) => this.queryHandler
|
|
436
|
+
.buildQuery(queryParams, db.deleteFrom(tableName))
|
|
437
|
+
.returningAll()
|
|
438
|
+
.execute(), undefined, queryParams, trx);
|
|
439
|
+
}
|
|
440
|
+
if (!user && !isSystem && this.config.enforceRls) {
|
|
441
|
+
throw new AuthenticationRequiredError('Authentication required to delete records');
|
|
442
|
+
}
|
|
443
|
+
const { status: initialStatus, hasFieldCheck: initialHasFieldCheck, hasCustomFunction: initialHasCustomFunction, fieldCheckRules: extractedFieldCheckRules, } = await enforcePermissions(tableName, 'DELETE', user, this.permissionService, undefined, this.hooks.getDbInstance());
|
|
444
|
+
if (!initialStatus &&
|
|
445
|
+
!initialHasFieldCheck &&
|
|
446
|
+
!initialHasCustomFunction) {
|
|
447
|
+
throw new PermissionDeniedError(`User does not have permission to delete this records`);
|
|
448
|
+
}
|
|
449
|
+
if (initialStatus) {
|
|
450
|
+
// Simple rule matched — proceed directly
|
|
451
|
+
return this.hooks.mutate(tableName, 'delete', async (db) => this.queryHandler
|
|
452
|
+
.buildQuery(queryParams, db.deleteFrom(tableName))
|
|
453
|
+
.returningAll()
|
|
454
|
+
.execute(), undefined, queryParams, trx);
|
|
455
|
+
}
|
|
456
|
+
// fieldCheck/customFunction path — fetch matching rows then evaluate
|
|
457
|
+
const records = (await this.hooks.query(tableName, async (db) => this.queryHandler
|
|
458
|
+
.buildQuery(queryParams, db.selectFrom(tableName))
|
|
459
|
+
.execute(), queryParams, trx));
|
|
460
|
+
// Fast path: use pre-extracted rules instead of full enforcePermissions
|
|
461
|
+
if (extractedFieldCheckRules?.length) {
|
|
462
|
+
for (const record of records) {
|
|
463
|
+
const allowed = await evaluateFieldCheckForRow(extractedFieldCheckRules, user, record, this.hooks.getDbInstance());
|
|
464
|
+
if (!allowed) {
|
|
465
|
+
throw new PermissionDeniedError(`User does not have permission to delete this records`);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
// Fallback for customFunction rules
|
|
471
|
+
const { status } = await enforcePermissions(tableName, 'DELETE', user, this.permissionService, records, this.hooks.getDbInstance());
|
|
472
|
+
if (!status) {
|
|
473
|
+
throw new PermissionDeniedError(`User does not have permission to delete this records`);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return this.hooks.mutate(tableName, 'delete', async (db) => this.queryHandler
|
|
477
|
+
.buildQuery(queryParams, db.deleteFrom(tableName))
|
|
478
|
+
.returningAll()
|
|
479
|
+
.execute(), undefined, queryParams, trx);
|
|
480
|
+
},
|
|
481
|
+
},
|
|
482
|
+
/**
|
|
483
|
+
* Work with the database permissions
|
|
484
|
+
* @returns Permissions endpoints
|
|
485
|
+
*/
|
|
486
|
+
permissions: {
|
|
487
|
+
get: async (params, trx) => {
|
|
488
|
+
if (this.excludedTables.includes(params.tableName)) {
|
|
489
|
+
throw new ExcludedTableError(params.tableName);
|
|
490
|
+
}
|
|
491
|
+
// If no transaction is provided, create one internally
|
|
492
|
+
if (!trx) {
|
|
493
|
+
return this.transaction(async (newTrx) => {
|
|
494
|
+
return await this.endpoints.permissions.get(params, newTrx);
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
const { tableName } = params;
|
|
498
|
+
return this.permissionService.getPermissionsForTable(tableName, trx);
|
|
499
|
+
},
|
|
500
|
+
set: async (params, trx) => {
|
|
501
|
+
if (this.excludedTables.includes(params.tableName)) {
|
|
502
|
+
throw new ExcludedTableError(params.tableName);
|
|
503
|
+
}
|
|
504
|
+
// If no transaction is provided, create one internally and manage it
|
|
505
|
+
if (!trx) {
|
|
506
|
+
return this.transaction(async (newTrx) => {
|
|
507
|
+
return await this.endpoints.permissions.set(params, newTrx);
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
const { tableName, permissions } = params;
|
|
511
|
+
if (!permissions) {
|
|
512
|
+
throw new Error('Permissions object is required');
|
|
513
|
+
}
|
|
514
|
+
return this.permissionService.setPermissionsForTable(tableName, permissions, trx);
|
|
515
|
+
},
|
|
516
|
+
},
|
|
517
|
+
};
|
|
518
|
+
if (!config.db && !config.libsql) {
|
|
519
|
+
throw new Error('Either database instance (db) or libsql config is required');
|
|
520
|
+
}
|
|
521
|
+
if (!config.db && config.libsql) {
|
|
522
|
+
this.config.db = new Kysely({
|
|
523
|
+
dialect: new LibsqlDialect(config.libsql),
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
if (config.excludedTables) {
|
|
527
|
+
this.excludedTables = [...this.excludedTables, ...config.excludedTables];
|
|
528
|
+
}
|
|
529
|
+
this.permissionService =
|
|
530
|
+
config.permissionsService || new PermissionService(config.db);
|
|
531
|
+
this.dbInspector = new DBInspector(config.db);
|
|
532
|
+
// Initialize realtime adapter if realtime is enabled
|
|
533
|
+
if (config.realtime) {
|
|
534
|
+
const adapterType = config.realtimeAdapter || 'sse';
|
|
535
|
+
const port = config.websocketPort || 9001;
|
|
536
|
+
if (adapterType === 'websocket') {
|
|
537
|
+
this.realtimeAdapter = new WebSocketManager(port, this.permissionService);
|
|
538
|
+
}
|
|
539
|
+
else if (adapterType === 'sse') {
|
|
540
|
+
this.realtimeAdapter = new SSEManager(port, this.permissionService);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
this.hooks =
|
|
544
|
+
config.hooks || new KyselyHooks(config.db, this.realtimeAdapter);
|
|
545
|
+
this.queryHandler = new KyselyQueryHandler(this.hooks.getDbInstance());
|
|
546
|
+
// Set default permissions for all tables
|
|
547
|
+
if (config.defaultPermissions) {
|
|
548
|
+
this.defaultPermissions = config.defaultPermissions;
|
|
549
|
+
}
|
|
550
|
+
// Initialize permissions for all tables if enabled
|
|
551
|
+
if (config.initializePermissions) {
|
|
552
|
+
this.initializeTablePermissions();
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
getDbInspector() {
|
|
556
|
+
return this.dbInspector;
|
|
557
|
+
}
|
|
558
|
+
async ready() {
|
|
559
|
+
await this.permissionService.ready();
|
|
560
|
+
}
|
|
561
|
+
getExcludedTables() {
|
|
562
|
+
return this.excludedTables;
|
|
563
|
+
}
|
|
564
|
+
getDefaultPermissions() {
|
|
565
|
+
return this.defaultPermissions;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Initialize permissions for all tables in the database
|
|
569
|
+
* This is a non-blocking operation that runs in the background
|
|
570
|
+
*/
|
|
571
|
+
initializeTablePermissions() {
|
|
572
|
+
const { permissionReportPath, onPermissionInitComplete } = this.config;
|
|
573
|
+
// Use the public method to avoid code duplication
|
|
574
|
+
this.initializePermissions(permissionReportPath, onPermissionInitComplete);
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Add a table to the excluded tables list
|
|
578
|
+
* @param tables List of tables to exclude
|
|
579
|
+
*/
|
|
580
|
+
addExcludedTables(tables) {
|
|
581
|
+
this.excludedTables = [...this.excludedTables, ...tables];
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Remove a table from the excluded tables list
|
|
585
|
+
* @param tables List of tables to include
|
|
586
|
+
*/
|
|
587
|
+
removeExcludedTables(tables) {
|
|
588
|
+
this.excludedTables = this.excludedTables.filter((table) => !tables.includes(table));
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Manually trigger permission initialization for all tables
|
|
592
|
+
* @param reportPath Optional path to save the report file
|
|
593
|
+
* @param onComplete Optional callback function to call when initialization is complete
|
|
594
|
+
*/
|
|
595
|
+
initializePermissions(reportPath, onComplete) {
|
|
596
|
+
// Use provided parameters or fall back to config values
|
|
597
|
+
const finalReportPath = reportPath || this.config.permissionReportPath;
|
|
598
|
+
const finalCallback = onComplete || this.config.onPermissionInitComplete;
|
|
599
|
+
// Start the initialization process
|
|
600
|
+
initializePermissions(this.hooks.getDbInstance(), this.permissionService, this.dbInspector, this.excludedTables, this.defaultPermissions, finalReportPath, finalCallback);
|
|
601
|
+
console.log('Permission initialization started in the background');
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Get the database schema
|
|
605
|
+
* @returns Database schema
|
|
606
|
+
*/
|
|
607
|
+
getEndpoints() {
|
|
608
|
+
return this.endpoints;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Get the knex instance
|
|
612
|
+
* @returns Knex instance
|
|
613
|
+
*/
|
|
614
|
+
getDbInstance() {
|
|
615
|
+
return this.hooks.getDbInstance();
|
|
616
|
+
}
|
|
617
|
+
getHooksDb() {
|
|
618
|
+
return this.hooks;
|
|
619
|
+
}
|
|
620
|
+
getPermissionService() {
|
|
621
|
+
return this.permissionService;
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Execute a function within a transaction
|
|
625
|
+
* @param callback Function to execute within the transaction
|
|
626
|
+
* @returns Result of the callback function
|
|
627
|
+
*/
|
|
628
|
+
async transaction(callback) {
|
|
629
|
+
try {
|
|
630
|
+
return await this.hooks.getDbInstance().transaction().execute(callback);
|
|
631
|
+
}
|
|
632
|
+
catch (error) {
|
|
633
|
+
console.error('Transaction error:', error);
|
|
634
|
+
throw error;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
parseQueryParams(params) {
|
|
638
|
+
const queryParams = {};
|
|
639
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
640
|
+
if (typeof value === 'string') {
|
|
641
|
+
try {
|
|
642
|
+
queryParams[key] = JSON.parse(value);
|
|
643
|
+
}
|
|
644
|
+
catch {
|
|
645
|
+
if (key === 'limit' || key === 'offset') {
|
|
646
|
+
queryParams[key] = parseInt(value, 10) || 10;
|
|
647
|
+
}
|
|
648
|
+
else {
|
|
649
|
+
queryParams[key] = value;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
queryParams[key] = value;
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
return queryParams;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Create a new instance of the ForgeDatabase class
|
|
662
|
+
* @param config Configuration object for the ForgeDatabase instance
|
|
663
|
+
* @returns A new instance of the ForgeDatabase class
|
|
664
|
+
*/
|
|
665
|
+
export const createForgeDatabase = (config) => {
|
|
666
|
+
return new ForgeDatabase(config);
|
|
667
|
+
};
|
|
668
|
+
//# sourceMappingURL=database.js.map
|