@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.
Files changed (219) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +470 -0
  3. package/dist/cjs/adapters/base.d.ts +20 -0
  4. package/dist/cjs/adapters/base.d.ts.map +1 -0
  5. package/dist/cjs/adapters/base.js +13 -0
  6. package/dist/cjs/adapters/base.js.map +1 -0
  7. package/dist/cjs/adapters/index.d.ts +6 -0
  8. package/dist/cjs/adapters/index.d.ts.map +1 -0
  9. package/dist/cjs/adapters/index.js +24 -0
  10. package/dist/cjs/adapters/index.js.map +1 -0
  11. package/dist/cjs/adapters/postgres.d.ts +13 -0
  12. package/dist/cjs/adapters/postgres.d.ts.map +1 -0
  13. package/dist/cjs/adapters/postgres.js +51 -0
  14. package/dist/cjs/adapters/postgres.js.map +1 -0
  15. package/dist/cjs/adapters/sqlite.d.ts +13 -0
  16. package/dist/cjs/adapters/sqlite.d.ts.map +1 -0
  17. package/dist/cjs/adapters/sqlite.js +47 -0
  18. package/dist/cjs/adapters/sqlite.js.map +1 -0
  19. package/dist/cjs/adapters/types.d.ts +8 -0
  20. package/dist/cjs/adapters/types.d.ts.map +1 -0
  21. package/dist/cjs/adapters/types.js +3 -0
  22. package/dist/cjs/adapters/types.js.map +1 -0
  23. package/dist/cjs/database.d.ts +73 -0
  24. package/dist/cjs/database.d.ts.map +1 -0
  25. package/dist/cjs/database.js +673 -0
  26. package/dist/cjs/database.js.map +1 -0
  27. package/dist/cjs/errors.d.ts +37 -0
  28. package/dist/cjs/errors.d.ts.map +1 -0
  29. package/dist/cjs/errors.js +64 -0
  30. package/dist/cjs/errors.js.map +1 -0
  31. package/dist/cjs/index.d.ts +16 -0
  32. package/dist/cjs/index.d.ts.map +1 -0
  33. package/dist/cjs/index.js +31 -0
  34. package/dist/cjs/index.js.map +1 -0
  35. package/dist/cjs/kysely-hooks.d.ts +45 -0
  36. package/dist/cjs/kysely-hooks.d.ts.map +1 -0
  37. package/dist/cjs/kysely-hooks.js +93 -0
  38. package/dist/cjs/kysely-hooks.js.map +1 -0
  39. package/dist/cjs/libsql/example.d.ts +2 -0
  40. package/dist/cjs/libsql/example.d.ts.map +1 -0
  41. package/dist/cjs/libsql/example.js +44 -0
  42. package/dist/cjs/libsql/example.js.map +1 -0
  43. package/dist/cjs/libsql/index.d.ts +36 -0
  44. package/dist/cjs/libsql/index.d.ts.map +1 -0
  45. package/dist/cjs/libsql/index.js +155 -0
  46. package/dist/cjs/libsql/index.js.map +1 -0
  47. package/dist/cjs/permissionService.d.ts +20 -0
  48. package/dist/cjs/permissionService.d.ts.map +1 -0
  49. package/dist/cjs/permissionService.js +107 -0
  50. package/dist/cjs/permissionService.js.map +1 -0
  51. package/dist/cjs/rlsFunctionRegistry.d.ts +43 -0
  52. package/dist/cjs/rlsFunctionRegistry.d.ts.map +1 -0
  53. package/dist/cjs/rlsFunctionRegistry.js +63 -0
  54. package/dist/cjs/rlsFunctionRegistry.js.map +1 -0
  55. package/dist/cjs/rlsManager.d.ts +23 -0
  56. package/dist/cjs/rlsManager.d.ts.map +1 -0
  57. package/dist/cjs/rlsManager.js +371 -0
  58. package/dist/cjs/rlsManager.js.map +1 -0
  59. package/dist/cjs/schema.d.ts +15 -0
  60. package/dist/cjs/schema.d.ts.map +1 -0
  61. package/dist/cjs/schema.js +119 -0
  62. package/dist/cjs/schema.js.map +1 -0
  63. package/dist/cjs/sdk/client.d.ts +324 -0
  64. package/dist/cjs/sdk/client.d.ts.map +1 -0
  65. package/dist/cjs/sdk/client.js +554 -0
  66. package/dist/cjs/sdk/client.js.map +1 -0
  67. package/dist/cjs/sdk/examples.d.ts +68 -0
  68. package/dist/cjs/sdk/examples.d.ts.map +1 -0
  69. package/dist/cjs/sdk/examples.js +232 -0
  70. package/dist/cjs/sdk/examples.js.map +1 -0
  71. package/dist/cjs/sdk/server.d.ts +115 -0
  72. package/dist/cjs/sdk/server.d.ts.map +1 -0
  73. package/dist/cjs/sdk/server.js +140 -0
  74. package/dist/cjs/sdk/server.js.map +1 -0
  75. package/dist/cjs/types.d.ts +217 -0
  76. package/dist/cjs/types.d.ts.map +1 -0
  77. package/dist/cjs/types.js +5 -0
  78. package/dist/cjs/types.js.map +1 -0
  79. package/dist/cjs/utils/column-utils.d.ts +8 -0
  80. package/dist/cjs/utils/column-utils.d.ts.map +1 -0
  81. package/dist/cjs/utils/column-utils.js +131 -0
  82. package/dist/cjs/utils/column-utils.js.map +1 -0
  83. package/dist/cjs/utils/db.d.ts +2 -0
  84. package/dist/cjs/utils/db.d.ts.map +1 -0
  85. package/dist/cjs/utils/db.js +6 -0
  86. package/dist/cjs/utils/db.js.map +1 -0
  87. package/dist/cjs/utils/inspector.d.ts +39 -0
  88. package/dist/cjs/utils/inspector.d.ts.map +1 -0
  89. package/dist/cjs/utils/inspector.js +164 -0
  90. package/dist/cjs/utils/inspector.js.map +1 -0
  91. package/dist/cjs/utils/permission-initializer.d.ts +15 -0
  92. package/dist/cjs/utils/permission-initializer.d.ts.map +1 -0
  93. package/dist/cjs/utils/permission-initializer.js +173 -0
  94. package/dist/cjs/utils/permission-initializer.js.map +1 -0
  95. package/dist/cjs/websocket/RealtimeAdapter.d.ts +22 -0
  96. package/dist/cjs/websocket/RealtimeAdapter.d.ts.map +1 -0
  97. package/dist/cjs/websocket/RealtimeAdapter.js +3 -0
  98. package/dist/cjs/websocket/RealtimeAdapter.js.map +1 -0
  99. package/dist/cjs/websocket/SSEManager.d.ts +40 -0
  100. package/dist/cjs/websocket/SSEManager.d.ts.map +1 -0
  101. package/dist/cjs/websocket/SSEManager.js +268 -0
  102. package/dist/cjs/websocket/SSEManager.js.map +1 -0
  103. package/dist/cjs/websocket/WebSocketManager.d.ts +28 -0
  104. package/dist/cjs/websocket/WebSocketManager.d.ts.map +1 -0
  105. package/dist/cjs/websocket/WebSocketManager.js +156 -0
  106. package/dist/cjs/websocket/WebSocketManager.js.map +1 -0
  107. package/dist/cjs/websocket/index.d.ts +4 -0
  108. package/dist/cjs/websocket/index.d.ts.map +1 -0
  109. package/dist/cjs/websocket/index.js +20 -0
  110. package/dist/cjs/websocket/index.js.map +1 -0
  111. package/dist/esm/adapters/base.d.ts +20 -0
  112. package/dist/esm/adapters/base.d.ts.map +1 -0
  113. package/dist/esm/adapters/base.js +10 -0
  114. package/dist/esm/adapters/base.js.map +1 -0
  115. package/dist/esm/adapters/index.d.ts +6 -0
  116. package/dist/esm/adapters/index.d.ts.map +1 -0
  117. package/dist/esm/adapters/index.js +19 -0
  118. package/dist/esm/adapters/index.js.map +1 -0
  119. package/dist/esm/adapters/postgres.d.ts +13 -0
  120. package/dist/esm/adapters/postgres.d.ts.map +1 -0
  121. package/dist/esm/adapters/postgres.js +47 -0
  122. package/dist/esm/adapters/postgres.js.map +1 -0
  123. package/dist/esm/adapters/sqlite.d.ts +13 -0
  124. package/dist/esm/adapters/sqlite.d.ts.map +1 -0
  125. package/dist/esm/adapters/sqlite.js +43 -0
  126. package/dist/esm/adapters/sqlite.js.map +1 -0
  127. package/dist/esm/adapters/types.d.ts +8 -0
  128. package/dist/esm/adapters/types.d.ts.map +1 -0
  129. package/dist/esm/adapters/types.js +2 -0
  130. package/dist/esm/adapters/types.js.map +1 -0
  131. package/dist/esm/database.d.ts +73 -0
  132. package/dist/esm/database.d.ts.map +1 -0
  133. package/dist/esm/database.js +668 -0
  134. package/dist/esm/database.js.map +1 -0
  135. package/dist/esm/errors.d.ts +37 -0
  136. package/dist/esm/errors.d.ts.map +1 -0
  137. package/dist/esm/errors.js +55 -0
  138. package/dist/esm/errors.js.map +1 -0
  139. package/dist/esm/index.d.ts +16 -0
  140. package/dist/esm/index.d.ts.map +1 -0
  141. package/dist/esm/index.js +15 -0
  142. package/dist/esm/index.js.map +1 -0
  143. package/dist/esm/kysely-hooks.d.ts +45 -0
  144. package/dist/esm/kysely-hooks.d.ts.map +1 -0
  145. package/dist/esm/kysely-hooks.js +86 -0
  146. package/dist/esm/kysely-hooks.js.map +1 -0
  147. package/dist/esm/libsql/example.d.ts +2 -0
  148. package/dist/esm/libsql/example.d.ts.map +1 -0
  149. package/dist/esm/libsql/example.js +42 -0
  150. package/dist/esm/libsql/example.js.map +1 -0
  151. package/dist/esm/libsql/index.d.ts +36 -0
  152. package/dist/esm/libsql/index.d.ts.map +1 -0
  153. package/dist/esm/libsql/index.js +116 -0
  154. package/dist/esm/libsql/index.js.map +1 -0
  155. package/dist/esm/permissionService.d.ts +20 -0
  156. package/dist/esm/permissionService.d.ts.map +1 -0
  157. package/dist/esm/permissionService.js +103 -0
  158. package/dist/esm/permissionService.js.map +1 -0
  159. package/dist/esm/rlsFunctionRegistry.d.ts +43 -0
  160. package/dist/esm/rlsFunctionRegistry.d.ts.map +1 -0
  161. package/dist/esm/rlsFunctionRegistry.js +60 -0
  162. package/dist/esm/rlsFunctionRegistry.js.map +1 -0
  163. package/dist/esm/rlsManager.d.ts +23 -0
  164. package/dist/esm/rlsManager.d.ts.map +1 -0
  165. package/dist/esm/rlsManager.js +366 -0
  166. package/dist/esm/rlsManager.js.map +1 -0
  167. package/dist/esm/schema.d.ts +15 -0
  168. package/dist/esm/schema.d.ts.map +1 -0
  169. package/dist/esm/schema.js +113 -0
  170. package/dist/esm/schema.js.map +1 -0
  171. package/dist/esm/sdk/client.d.ts +324 -0
  172. package/dist/esm/sdk/client.d.ts.map +1 -0
  173. package/dist/esm/sdk/client.js +550 -0
  174. package/dist/esm/sdk/client.js.map +1 -0
  175. package/dist/esm/sdk/examples.d.ts +68 -0
  176. package/dist/esm/sdk/examples.d.ts.map +1 -0
  177. package/dist/esm/sdk/examples.js +229 -0
  178. package/dist/esm/sdk/examples.js.map +1 -0
  179. package/dist/esm/sdk/server.d.ts +115 -0
  180. package/dist/esm/sdk/server.d.ts.map +1 -0
  181. package/dist/esm/sdk/server.js +136 -0
  182. package/dist/esm/sdk/server.js.map +1 -0
  183. package/dist/esm/types.d.ts +217 -0
  184. package/dist/esm/types.d.ts.map +1 -0
  185. package/dist/esm/types.js +2 -0
  186. package/dist/esm/types.js.map +1 -0
  187. package/dist/esm/utils/column-utils.d.ts +8 -0
  188. package/dist/esm/utils/column-utils.d.ts.map +1 -0
  189. package/dist/esm/utils/column-utils.js +127 -0
  190. package/dist/esm/utils/column-utils.js.map +1 -0
  191. package/dist/esm/utils/db.d.ts +2 -0
  192. package/dist/esm/utils/db.d.ts.map +1 -0
  193. package/dist/esm/utils/db.js +3 -0
  194. package/dist/esm/utils/db.js.map +1 -0
  195. package/dist/esm/utils/inspector.d.ts +39 -0
  196. package/dist/esm/utils/inspector.d.ts.map +1 -0
  197. package/dist/esm/utils/inspector.js +160 -0
  198. package/dist/esm/utils/inspector.js.map +1 -0
  199. package/dist/esm/utils/permission-initializer.d.ts +15 -0
  200. package/dist/esm/utils/permission-initializer.d.ts.map +1 -0
  201. package/dist/esm/utils/permission-initializer.js +137 -0
  202. package/dist/esm/utils/permission-initializer.js.map +1 -0
  203. package/dist/esm/websocket/RealtimeAdapter.d.ts +22 -0
  204. package/dist/esm/websocket/RealtimeAdapter.d.ts.map +1 -0
  205. package/dist/esm/websocket/RealtimeAdapter.js +2 -0
  206. package/dist/esm/websocket/RealtimeAdapter.js.map +1 -0
  207. package/dist/esm/websocket/SSEManager.d.ts +40 -0
  208. package/dist/esm/websocket/SSEManager.d.ts.map +1 -0
  209. package/dist/esm/websocket/SSEManager.js +231 -0
  210. package/dist/esm/websocket/SSEManager.js.map +1 -0
  211. package/dist/esm/websocket/WebSocketManager.d.ts +28 -0
  212. package/dist/esm/websocket/WebSocketManager.d.ts.map +1 -0
  213. package/dist/esm/websocket/WebSocketManager.js +152 -0
  214. package/dist/esm/websocket/WebSocketManager.js.map +1 -0
  215. package/dist/esm/websocket/index.d.ts +4 -0
  216. package/dist/esm/websocket/index.d.ts.map +1 -0
  217. package/dist/esm/websocket/index.js +4 -0
  218. package/dist/esm/websocket/index.js.map +1 -0
  219. package/package.json +67 -0
@@ -0,0 +1,20 @@
1
+ import { Kysely, Transaction } from 'kysely';
2
+ import { type TablePermissions } from './types';
3
+ export declare class PermissionService {
4
+ private cache;
5
+ private db;
6
+ private initPromise;
7
+ constructor(db: Kysely<any>);
8
+ ready(): Promise<void>;
9
+ private initializeDatabase;
10
+ /**
11
+ * Sync-only lookup: returns cached permissions or undefined if not cached.
12
+ * Avoids async overhead when the permission is already in the LRU cache.
13
+ */
14
+ getPermissionsForTableSync(tableName: string): TablePermissions | undefined;
15
+ getPermissionsForTable(tableName: string, trx?: Transaction<any> | Kysely<any>): Promise<TablePermissions | any>;
16
+ setPermissionsForTable(tableName: string, permissions: TablePermissions, trx?: Transaction<any> | Kysely<any>): Promise<TablePermissions>;
17
+ deletePermissionsForTable(tableName: string, trx?: Transaction<any> | Kysely<any>): Promise<void>;
18
+ clearCache(): void;
19
+ }
20
+ //# sourceMappingURL=permissionService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissionService.d.ts","sourceRoot":"","sources":["../../src/permissionService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAO,WAAW,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAuB,KAAK,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGrE,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,KAAK,CAAqC;IAElD,OAAO,CAAC,EAAE,CAAc;IACxB,OAAO,CAAC,WAAW,CAAgB;gBAEvB,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC;IAWrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAId,kBAAkB;IAsBhC;;;OAGG;IACH,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAIrE,sBAAsB,CAC1B,SAAS,EAAE,MAAM,EACjB,GAAG,CAAC,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,GACnC,OAAO,CAAC,gBAAgB,GAAG,GAAG,CAAC;IA6B5B,sBAAsB,CAC1B,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,gBAAgB,EAC7B,GAAG,CAAC,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,GACnC,OAAO,CAAC,gBAAgB,CAAC;IA4BtB,yBAAyB,CAC7B,SAAS,EAAE,MAAM,EACjB,GAAG,CAAC,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,GACnC,OAAO,CAAC,IAAI,CAAC;IAYhB,UAAU,IAAI,IAAI;CAGnB"}
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PermissionService = void 0;
4
+ const kysely_1 = require("kysely");
5
+ const types_1 = require("./types");
6
+ const lru_cache_1 = require("lru-cache");
7
+ class PermissionService {
8
+ constructor(db) {
9
+ this.db = db;
10
+ this.cache = new lru_cache_1.LRUCache({
11
+ max: 500,
12
+ ttl: 5 * 60 * 1000, // 5 minutes TTL
13
+ allowStale: false,
14
+ updateAgeOnGet: true,
15
+ });
16
+ this.initPromise = this.initializeDatabase();
17
+ }
18
+ async ready() {
19
+ return this.initPromise;
20
+ }
21
+ async initializeDatabase() {
22
+ try {
23
+ const adapterName = this.db.getExecutor().adapter.constructor.name;
24
+ const isSqlite = adapterName.includes('Sqlite') || adapterName.includes('Libsql');
25
+ const now = isSqlite ? (0, kysely_1.sql) `CURRENT_TIMESTAMP` : (0, kysely_1.sql) `now()`;
26
+ await this.db.schema
27
+ .createTable(types_1.FG_PERMISSION_TABLE)
28
+ .ifNotExists()
29
+ .addColumn('table_name', 'varchar(255)', (col) => col.primaryKey().notNull())
30
+ .addColumn('permissions', 'json', (col) => col.notNull())
31
+ .addColumn('created_at', 'timestamp', (col) => col.defaultTo(now))
32
+ .addColumn('updated_at', 'timestamp', (col) => col.defaultTo(now))
33
+ .execute();
34
+ }
35
+ catch (e) {
36
+ console.warn('Permission table initialization warning:', e);
37
+ }
38
+ }
39
+ /**
40
+ * Sync-only lookup: returns cached permissions or undefined if not cached.
41
+ * Avoids async overhead when the permission is already in the LRU cache.
42
+ */
43
+ getPermissionsForTableSync(tableName) {
44
+ return this.cache.get(tableName);
45
+ }
46
+ async getPermissionsForTable(tableName, trx) {
47
+ const cachedPermissions = this.cache.get(tableName);
48
+ if (cachedPermissions) {
49
+ return cachedPermissions;
50
+ }
51
+ const executor = trx || this.db;
52
+ const result = await executor
53
+ .selectFrom(types_1.FG_PERMISSION_TABLE)
54
+ .where('table_name', '=', tableName)
55
+ .selectAll()
56
+ .executeTakeFirst();
57
+ if (!result)
58
+ return {};
59
+ let permissions = result.permissions;
60
+ if (typeof permissions === 'string') {
61
+ try {
62
+ permissions = JSON.parse(permissions);
63
+ }
64
+ catch (e) {
65
+ // ignore
66
+ }
67
+ }
68
+ this.cache.set(tableName, permissions);
69
+ return permissions;
70
+ }
71
+ async setPermissionsForTable(tableName, permissions, trx) {
72
+ const executor = trx || this.db;
73
+ const permissionsJson = JSON.stringify(permissions);
74
+ const adapterName = this.db.getExecutor().adapter.constructor.name;
75
+ const isSqlite = adapterName.includes('Sqlite') || adapterName.includes('Libsql');
76
+ const now = isSqlite ? (0, kysely_1.sql) `CURRENT_TIMESTAMP` : (0, kysely_1.sql) `now()`;
77
+ await executor
78
+ .insertInto(types_1.FG_PERMISSION_TABLE)
79
+ .values({
80
+ table_name: tableName,
81
+ permissions: permissionsJson,
82
+ updated_at: now,
83
+ })
84
+ .onConflict((oc) => oc.column('table_name').doUpdateSet({
85
+ permissions: permissionsJson,
86
+ updated_at: now,
87
+ }))
88
+ .execute();
89
+ this.cache.set(tableName, permissions);
90
+ return permissions;
91
+ }
92
+ async deletePermissionsForTable(tableName, trx) {
93
+ const executor = trx || this.db;
94
+ await executor
95
+ .deleteFrom(types_1.FG_PERMISSION_TABLE)
96
+ .where('table_name', '=', tableName)
97
+ .execute();
98
+ // Remove from cache
99
+ this.cache.delete(tableName);
100
+ }
101
+ // Method to clear the entire cache
102
+ clearCache() {
103
+ this.cache.clear();
104
+ }
105
+ }
106
+ exports.PermissionService = PermissionService;
107
+ //# sourceMappingURL=permissionService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissionService.js","sourceRoot":"","sources":["../../src/permissionService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type { CustomRlsFunction } from './types';
2
+ /**
3
+ * Registry for custom RLS functions that can be used in permission rules
4
+ */
5
+ declare class RlsFunctionRegistry {
6
+ private functions;
7
+ /**
8
+ * Register a custom RLS function
9
+ * @param name Unique name for the function
10
+ * @param fn The function implementation
11
+ */
12
+ register(name: string, fn: CustomRlsFunction): void;
13
+ /**
14
+ * Get a registered RLS function by name
15
+ * @param name Name of the function to retrieve
16
+ * @returns The function or undefined if not found
17
+ */
18
+ get(name: string): CustomRlsFunction | undefined;
19
+ /**
20
+ * Check if a function with the given name exists
21
+ * @param name Name to check
22
+ * @returns True if the function exists
23
+ */
24
+ has(name: string): boolean;
25
+ /**
26
+ * Remove a function from the registry
27
+ * @param name Name of the function to remove
28
+ * @returns True if the function was removed
29
+ */
30
+ unregister(name: string): boolean;
31
+ /**
32
+ * Clear all registered functions
33
+ */
34
+ clear(): void;
35
+ /**
36
+ * Get all registered function names
37
+ * @returns Array of function names
38
+ */
39
+ getRegisteredFunctionNames(): string[];
40
+ }
41
+ declare const rlsFunctionRegistry: RlsFunctionRegistry;
42
+ export { rlsFunctionRegistry };
43
+ //# sourceMappingURL=rlsFunctionRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rlsFunctionRegistry.d.ts","sourceRoot":"","sources":["../../src/rlsFunctionRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD;;GAEG;AACH,cAAM,mBAAmB;IACvB,OAAO,CAAC,SAAS,CAA6C;IAE9D;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,iBAAiB,GAAG,IAAI;IAOnD;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAIhD;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIjC;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;;OAGG;IACH,0BAA0B,IAAI,MAAM,EAAE;CAGvC;AAGD,QAAA,MAAM,mBAAmB,qBAA4B,CAAC;AAEtD,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rlsFunctionRegistry = void 0;
4
+ /**
5
+ * Registry for custom RLS functions that can be used in permission rules
6
+ */
7
+ class RlsFunctionRegistry {
8
+ constructor() {
9
+ this.functions = new Map();
10
+ }
11
+ /**
12
+ * Register a custom RLS function
13
+ * @param name Unique name for the function
14
+ * @param fn The function implementation
15
+ */
16
+ register(name, fn) {
17
+ if (this.functions.has(name)) {
18
+ console.warn(`RLS function "${name}" is being overwritten`);
19
+ }
20
+ this.functions.set(name, fn);
21
+ }
22
+ /**
23
+ * Get a registered RLS function by name
24
+ * @param name Name of the function to retrieve
25
+ * @returns The function or undefined if not found
26
+ */
27
+ get(name) {
28
+ return this.functions.get(name);
29
+ }
30
+ /**
31
+ * Check if a function with the given name exists
32
+ * @param name Name to check
33
+ * @returns True if the function exists
34
+ */
35
+ has(name) {
36
+ return this.functions.has(name);
37
+ }
38
+ /**
39
+ * Remove a function from the registry
40
+ * @param name Name of the function to remove
41
+ * @returns True if the function was removed
42
+ */
43
+ unregister(name) {
44
+ return this.functions.delete(name);
45
+ }
46
+ /**
47
+ * Clear all registered functions
48
+ */
49
+ clear() {
50
+ this.functions.clear();
51
+ }
52
+ /**
53
+ * Get all registered function names
54
+ * @returns Array of function names
55
+ */
56
+ getRegisteredFunctionNames() {
57
+ return Array.from(this.functions.keys());
58
+ }
59
+ }
60
+ // Create a singleton instance
61
+ const rlsFunctionRegistry = new RlsFunctionRegistry();
62
+ exports.rlsFunctionRegistry = rlsFunctionRegistry;
63
+ //# sourceMappingURL=rlsFunctionRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rlsFunctionRegistry.js","sourceRoot":"","sources":["../../src/rlsFunctionRegistry.ts"],"names":[],"mappings":";;;AAEA;;GAEG;AACH,MAAM,mBAAmB;IAAzB;QACU,cAAS,GAAmC,IAAI,GAAG,EAAE,CAAC;IAuDhE,CAAC;IArDC;;;;OAIG;IACH,QAAQ,CAAC,IAAY,EAAE,EAAqB;QAC1C,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,IAAI,CAAC,iBAAiB,IAAI,wBAAwB,CAAC,CAAC;QAC9D,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAED;;;;OAIG;IACH,UAAU,CAAC,IAAY;QACrB,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;IAED;;;OAGG;IACH,0BAA0B;QACxB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3C,CAAC;CACF;AAED,8BAA8B;AAC9B,MAAM,mBAAmB,GAAG,IAAI,mBAAmB,EAAE,CAAC;AAE7C,kDAAmB"}
@@ -0,0 +1,23 @@
1
+ import type { PermissionRule, UserContext } from './types';
2
+ import { PermissionService } from './permissionService';
3
+ import type { Kysely } from 'kysely';
4
+ export declare function evaluatePermission(rules: PermissionRule[], userContext: UserContext, row?: Record<string, unknown>, db?: Kysely<any>): Promise<boolean>;
5
+ /**
6
+ * Fast path: evaluate pre-extracted fieldCheck rules against a single row.
7
+ * Avoids the full enforcePermissions overhead (permission lookup, rule
8
+ * classification, array handling) when we already know we need a fieldCheck
9
+ * evaluation for one specific record.
10
+ */
11
+ export declare function evaluateFieldCheckForRow(fieldCheckRules: PermissionRule[], userContext: UserContext, row: Record<string, unknown>, db?: Kysely<any>): Promise<boolean>;
12
+ type Row = Record<string, unknown>;
13
+ export declare function enforcePermissions(tableName: string, operation: 'SELECT' | 'INSERT' | 'UPDATE' | 'DELETE', userContext: UserContext, permissionService: PermissionService, rows?: Row | Row[], db?: Kysely<any>): Promise<{
14
+ row?: Row | Row[];
15
+ status: boolean;
16
+ message?: string;
17
+ hasFieldCheck: boolean;
18
+ hasCustomFunction: boolean;
19
+ fieldCheckRules?: PermissionRule[];
20
+ customFunctionRules?: PermissionRule[];
21
+ }>;
22
+ export {};
23
+ //# sourceMappingURL=rlsManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rlsManager.d.ts","sourceRoot":"","sources":["../../src/rlsManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EAEd,WAAW,EAEZ,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIrC,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,cAAc,EAAE,EACvB,WAAW,EAAE,WAAW,EACxB,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACjC,EAAE,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,GACf,OAAO,CAAC,OAAO,CAAC,CAiMlB;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,eAAe,EAAE,cAAc,EAAE,EACjC,WAAW,EAAE,WAAW,EACxB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,EAAE,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,GACf,OAAO,CAAC,OAAO,CAAC,CAOlB;AAID,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEnC,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,EACpD,WAAW,EAAE,WAAW,EACxB,iBAAiB,EAAE,iBAAiB,EACpC,IAAI,CAAC,EAAE,GAAG,GAAG,GAAG,EAAE,EAClB,EAAE,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,GACf,OAAO,CAAC;IACT,GAAG,CAAC,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;IACnC,mBAAmB,CAAC,EAAE,cAAc,EAAE,CAAC;CACxC,CAAC,CAwND"}
@@ -0,0 +1,371 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.evaluatePermission = evaluatePermission;
4
+ exports.evaluateFieldCheckForRow = evaluateFieldCheckForRow;
5
+ exports.enforcePermissions = enforcePermissions;
6
+ const kysely_1 = require("kysely");
7
+ const rlsFunctionRegistry_1 = require("./rlsFunctionRegistry");
8
+ async function evaluatePermission(rules, userContext, row = {}, db) {
9
+ for (const rule of rules) {
10
+ switch (rule.allow) {
11
+ case 'public':
12
+ return true;
13
+ case 'private':
14
+ return false;
15
+ case 'role':
16
+ if (!rule.roles || rule.roles.length === 0) {
17
+ // If no roles specified, continue to next rule
18
+ continue;
19
+ }
20
+ if (rule.roles &&
21
+ userContext.role &&
22
+ rule.roles?.includes(userContext.role)) {
23
+ return true;
24
+ }
25
+ // If we reach here, the role rule didn't match
26
+ // Continue to the next rule instead of returning false
27
+ continue;
28
+ case 'auth':
29
+ if (userContext.userId) {
30
+ return true;
31
+ }
32
+ // If we reach here, the auth rule didn't match
33
+ // Continue to the next rule instead of breaking
34
+ continue;
35
+ case 'guest':
36
+ if (!userContext.userId)
37
+ return true;
38
+ // If we reach here, the guest rule didn't match
39
+ // Continue to the next rule instead of breaking
40
+ continue;
41
+ case 'labels':
42
+ if (rule.labels !== undefined &&
43
+ userContext.labels.some((label) => rule.labels && rule.labels.includes(label))) {
44
+ return true;
45
+ }
46
+ // If we reach here, the labels rule didn't match
47
+ // Continue to the next rule instead of breaking
48
+ continue;
49
+ case 'teams':
50
+ if (rule.teams !== undefined &&
51
+ userContext.teams.some((team) => rule.teams && rule.teams.includes(team))) {
52
+ return true;
53
+ }
54
+ // If we reach here, the teams rule didn't match
55
+ // Continue to the next rule instead of breaking
56
+ continue;
57
+ case 'static':
58
+ if (typeof rule.static === 'boolean') {
59
+ return rule.static;
60
+ }
61
+ // If we reach here, the static rule didn't match
62
+ // Continue to the next rule instead of breaking
63
+ continue;
64
+ case 'fieldCheck':
65
+ if (rule.fieldCheck) {
66
+ const { field, operator, valueType, value } = rule.fieldCheck;
67
+ const dataValue = row[field];
68
+ // console.log('Data value:', dataValue);
69
+ const comparisonValue = valueType === 'userContext'
70
+ ? userContext[value]
71
+ : value;
72
+ switch (operator) {
73
+ case '===':
74
+ if (dataValue === comparisonValue)
75
+ return true;
76
+ break;
77
+ case '!==':
78
+ if (dataValue !== comparisonValue)
79
+ return true;
80
+ break;
81
+ case 'in':
82
+ if (Array.isArray(comparisonValue) &&
83
+ comparisonValue.includes(dataValue)) {
84
+ return true;
85
+ }
86
+ break;
87
+ case 'notIn':
88
+ if (Array.isArray(comparisonValue) &&
89
+ !comparisonValue.includes(dataValue)) {
90
+ return true;
91
+ }
92
+ break;
93
+ }
94
+ }
95
+ // If we reach here, the fieldCheck rule didn't match
96
+ // Continue to the next rule instead of breaking
97
+ continue;
98
+ case 'customSql':
99
+ if (rule.customSql && db) {
100
+ try {
101
+ // Replace placeholders with userContext values
102
+ const parsedSql = rule.customSql.replace(/:([a-zA-Z_]+)/g, (_match, key) => {
103
+ if (userContext[key] === undefined) {
104
+ throw new Error(`Missing context value for key: ${key}`);
105
+ }
106
+ // For SQL parameters, we need to handle different types appropriately
107
+ const value = userContext[key];
108
+ if (typeof value === 'string') {
109
+ return `'${value.replace(/'/g, "''")}'`; // Escape single quotes for SQL
110
+ }
111
+ else if (value === null) {
112
+ return 'NULL';
113
+ }
114
+ else if (Array.isArray(value)) {
115
+ // Convert array to SQL array format
116
+ return `(${value
117
+ .map((item) => {
118
+ if (typeof item === 'string')
119
+ return `'${item.replace(/'/g, "''")}'`;
120
+ return item;
121
+ })
122
+ .join(', ')})`;
123
+ }
124
+ return String(value);
125
+ });
126
+ // console.log(`Executing custom SQL: ${parsedSql}`);
127
+ // Execute the SQL query
128
+ // Kysely sql.raw returns a builder, we need to execute it.
129
+ const result = await kysely_1.sql.raw(parsedSql).execute(db);
130
+ const rows = result.rows;
131
+ // Check if the query returned any rows or a truthy value
132
+ // Kysely result.rows is array of rows
133
+ return rows.length > 0;
134
+ }
135
+ catch (error) {
136
+ console.error(`Error executing custom SQL:`, error);
137
+ return false;
138
+ }
139
+ }
140
+ // If we reach here, the customSql rule didn't match
141
+ // Continue to the next rule instead of breaking
142
+ continue;
143
+ case 'customFunction':
144
+ if (rule.customFunction) {
145
+ try {
146
+ // Get the function from the registry
147
+ const customFn = rlsFunctionRegistry_1.rlsFunctionRegistry.get(rule.customFunction);
148
+ if (!customFn) {
149
+ console.error(`Custom RLS function "${rule.customFunction}" not found in registry`);
150
+ return false;
151
+ }
152
+ // Execute the custom function with userContext and row data
153
+ const result = await Promise.resolve(customFn(userContext, row, db));
154
+ return !!result;
155
+ }
156
+ catch (error) {
157
+ console.error(`Error executing custom RLS function "${rule.customFunction}":`, error);
158
+ return false;
159
+ }
160
+ }
161
+ // If we reach here, the customFunction rule didn't match
162
+ // Continue to the next rule instead of breaking
163
+ continue;
164
+ }
165
+ }
166
+ return false;
167
+ }
168
+ /**
169
+ * Fast path: evaluate pre-extracted fieldCheck rules against a single row.
170
+ * Avoids the full enforcePermissions overhead (permission lookup, rule
171
+ * classification, array handling) when we already know we need a fieldCheck
172
+ * evaluation for one specific record.
173
+ */
174
+ async function evaluateFieldCheckForRow(fieldCheckRules, userContext, row, db) {
175
+ for (const rule of fieldCheckRules) {
176
+ if (await evaluatePermission([rule], userContext, row, db)) {
177
+ return true;
178
+ }
179
+ }
180
+ return false;
181
+ }
182
+ const CHUNK_SIZE = 1000;
183
+ async function enforcePermissions(tableName, operation, userContext, permissionService, rows, db) {
184
+ // Try sync cache lookup first to avoid async overhead on cache hits
185
+ const tablePermissions = (permissionService.getPermissionsForTableSync(tableName) ??
186
+ (await permissionService.getPermissionsForTable(tableName)));
187
+ if (!tablePermissions) {
188
+ return {
189
+ row: rows,
190
+ status: false,
191
+ message: `No permissions defined for table "${tableName}"`,
192
+ hasFieldCheck: false,
193
+ hasCustomFunction: false,
194
+ };
195
+ }
196
+ if (!tablePermissions?.operations?.[operation]) {
197
+ return {
198
+ row: rows,
199
+ status: false,
200
+ message: `No permissions defined for operation "${operation}" on table "${tableName}"`,
201
+ hasFieldCheck: false,
202
+ hasCustomFunction: false,
203
+ };
204
+ }
205
+ const rules = tablePermissions.operations[operation];
206
+ // Early return if no rules
207
+ if (!rules || rules.length === 0) {
208
+ return {
209
+ row: rows,
210
+ status: true,
211
+ hasFieldCheck: false,
212
+ hasCustomFunction: false,
213
+ };
214
+ }
215
+ // Single-pass rule classification (avoids 3× Array.filter)
216
+ const fieldCheckRules = [];
217
+ const customFunctionRules = [];
218
+ const simpleRules = [];
219
+ for (const rule of rules) {
220
+ if (rule.allow === 'fieldCheck')
221
+ fieldCheckRules.push(rule);
222
+ else if (rule.allow === 'customFunction')
223
+ customFunctionRules.push(rule);
224
+ else
225
+ simpleRules.push(rule);
226
+ }
227
+ // First check simple rules that don't need row data
228
+ if (simpleRules.length > 0) {
229
+ // Check each rule and find the first one that grants access
230
+ for (const rule of simpleRules) {
231
+ const hasAccess = await evaluatePermission([rule], userContext, {}, db);
232
+ if (hasAccess) {
233
+ return {
234
+ row: rows,
235
+ status: true,
236
+ hasFieldCheck: false,
237
+ hasCustomFunction: false,
238
+ };
239
+ }
240
+ }
241
+ }
242
+ // Check customFunction rules if no simple rules matched
243
+ // These need row data like fieldCheck rules
244
+ if (customFunctionRules.length > 0) {
245
+ // If no rows provided but we need to check with custom functions, return early
246
+ if (!rows) {
247
+ return {
248
+ row: undefined,
249
+ status: false,
250
+ hasFieldCheck: false,
251
+ hasCustomFunction: true,
252
+ fieldCheckRules,
253
+ customFunctionRules,
254
+ message: 'Custom function check required, please provide row data',
255
+ };
256
+ }
257
+ // Handle array of rows
258
+ if (Array.isArray(rows)) {
259
+ const result = [];
260
+ for (let i = 0; i < rows.length; i += CHUNK_SIZE) {
261
+ const chunk = rows.slice(i, i + CHUNK_SIZE);
262
+ // Filter rows based on custom function rules
263
+ const filteredChunk = [];
264
+ for (const row of chunk) {
265
+ // Check each row against all custom function rules
266
+ for (const rule of customFunctionRules) {
267
+ const hasAccess = await evaluatePermission([rule], userContext, row, db);
268
+ if (hasAccess) {
269
+ filteredChunk.push(row);
270
+ break; // Move to the next row once we find a rule that grants access
271
+ }
272
+ }
273
+ }
274
+ result.push(...filteredChunk);
275
+ }
276
+ // If any rows passed the custom function checks, return success
277
+ if (result.length > 0) {
278
+ return {
279
+ row: result,
280
+ status: true,
281
+ hasFieldCheck: false,
282
+ hasCustomFunction: false,
283
+ };
284
+ }
285
+ }
286
+ else {
287
+ // Handle single row
288
+ for (const rule of customFunctionRules) {
289
+ const hasAccess = await evaluatePermission([rule], userContext, rows, db);
290
+ if (hasAccess) {
291
+ return {
292
+ row: rows,
293
+ status: true,
294
+ hasFieldCheck: false,
295
+ hasCustomFunction: false,
296
+ };
297
+ }
298
+ }
299
+ }
300
+ }
301
+ // If we reach here, no non-fieldCheck rules passed
302
+ // Check if we have fieldCheck rules
303
+ if (fieldCheckRules.length > 0) {
304
+ // If no rows provided but we need to check fields, return early
305
+ if (!rows) {
306
+ return {
307
+ row: undefined,
308
+ status: false,
309
+ hasFieldCheck: true,
310
+ hasCustomFunction: false,
311
+ fieldCheckRules,
312
+ customFunctionRules,
313
+ message: 'Field-level check required, please provide row data',
314
+ };
315
+ }
316
+ // Handle array of rows
317
+ if (Array.isArray(rows)) {
318
+ const result = [];
319
+ for (let i = 0; i < rows.length; i += CHUNK_SIZE) {
320
+ const chunk = rows.slice(i, i + CHUNK_SIZE);
321
+ // Filter rows based on field check rules
322
+ const filteredChunk = [];
323
+ for (const row of chunk) {
324
+ // Check each row against all field check rules
325
+ for (const rule of fieldCheckRules) {
326
+ const hasAccess = await evaluatePermission([rule], userContext, row, db);
327
+ if (hasAccess) {
328
+ filteredChunk.push(row);
329
+ break; // Move to the next row once we find a rule that grants access
330
+ }
331
+ }
332
+ }
333
+ result.push(...filteredChunk);
334
+ }
335
+ return {
336
+ row: result,
337
+ status: result.length > 0,
338
+ hasFieldCheck: false,
339
+ hasCustomFunction: false,
340
+ message: result.length === 0
341
+ ? 'No rows matched the field-level permission rules'
342
+ : undefined,
343
+ };
344
+ }
345
+ // Handle single row
346
+ let hasFieldAccess = false;
347
+ for (const rule of fieldCheckRules) {
348
+ hasFieldAccess = await evaluatePermission([rule], userContext, rows, db);
349
+ if (hasFieldAccess)
350
+ break;
351
+ }
352
+ return {
353
+ row: rows,
354
+ status: hasFieldAccess,
355
+ hasFieldCheck: false,
356
+ hasCustomFunction: false,
357
+ message: !hasFieldAccess
358
+ ? `User does not have field-level permission to perform operation "${operation}" on table "${tableName}"`
359
+ : undefined,
360
+ };
361
+ }
362
+ // If we reach here, no rules passed
363
+ return {
364
+ row: rows,
365
+ status: false,
366
+ hasFieldCheck: false,
367
+ hasCustomFunction: false,
368
+ message: `User does not have permission to perform operation "${operation}" on table "${tableName}"`,
369
+ };
370
+ }
371
+ //# sourceMappingURL=rlsManager.js.map