@holeauth/rbac-drizzle 0.0.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,275 @@
1
+ import * as drizzle_orm from 'drizzle-orm';
2
+ import * as drizzle_orm_mysql_core from 'drizzle-orm/mysql-core';
3
+ import { MySqlTableWithColumns } from 'drizzle-orm/mysql-core';
4
+ import { RbacAdapter } from '@holeauth/plugin-rbac';
5
+
6
+ type MysqlUsersTable = MySqlTableWithColumns<any> & {
7
+ id: any;
8
+ };
9
+ interface CreateRbacTablesOptions<U extends MysqlUsersTable> {
10
+ usersTable: U;
11
+ prefix?: string;
12
+ persistGroups?: boolean;
13
+ }
14
+ declare function createRbacTables<U extends MysqlUsersTable>(opts: CreateRbacTablesOptions<U>): {
15
+ tables: {
16
+ userGroups: MySqlTableWithColumns<{
17
+ name: string;
18
+ schema: undefined;
19
+ columns: {
20
+ userId: drizzle_orm_mysql_core.MySqlColumn<{
21
+ name: "user_id";
22
+ tableName: string;
23
+ dataType: "string";
24
+ columnType: "MySqlVarChar";
25
+ data: string;
26
+ driverParam: string | number;
27
+ notNull: true;
28
+ hasDefault: false;
29
+ isPrimaryKey: false;
30
+ isAutoincrement: false;
31
+ hasRuntimeDefault: false;
32
+ enumValues: [string, ...string[]];
33
+ baseColumn: never;
34
+ identity: undefined;
35
+ generated: undefined;
36
+ }, object>;
37
+ groupId: drizzle_orm_mysql_core.MySqlColumn<{
38
+ name: "group_id";
39
+ tableName: string;
40
+ dataType: "string";
41
+ columnType: "MySqlVarChar";
42
+ data: string;
43
+ driverParam: string | number;
44
+ notNull: true;
45
+ hasDefault: false;
46
+ isPrimaryKey: false;
47
+ isAutoincrement: false;
48
+ hasRuntimeDefault: false;
49
+ enumValues: [string, ...string[]];
50
+ baseColumn: never;
51
+ identity: undefined;
52
+ generated: undefined;
53
+ }, object>;
54
+ assignedAt: drizzle_orm_mysql_core.MySqlColumn<{
55
+ name: "assigned_at";
56
+ tableName: string;
57
+ dataType: "date";
58
+ columnType: "MySqlTimestamp";
59
+ data: Date;
60
+ driverParam: string | number;
61
+ notNull: true;
62
+ hasDefault: true;
63
+ isPrimaryKey: false;
64
+ isAutoincrement: false;
65
+ hasRuntimeDefault: false;
66
+ enumValues: undefined;
67
+ baseColumn: never;
68
+ identity: undefined;
69
+ generated: undefined;
70
+ }, object>;
71
+ };
72
+ dialect: "mysql";
73
+ }>;
74
+ userPermissions: MySqlTableWithColumns<{
75
+ name: string;
76
+ schema: undefined;
77
+ columns: {
78
+ userId: drizzle_orm_mysql_core.MySqlColumn<{
79
+ name: "user_id";
80
+ tableName: string;
81
+ dataType: "string";
82
+ columnType: "MySqlVarChar";
83
+ data: string;
84
+ driverParam: string | number;
85
+ notNull: true;
86
+ hasDefault: false;
87
+ isPrimaryKey: false;
88
+ isAutoincrement: false;
89
+ hasRuntimeDefault: false;
90
+ enumValues: [string, ...string[]];
91
+ baseColumn: never;
92
+ identity: undefined;
93
+ generated: undefined;
94
+ }, object>;
95
+ node: drizzle_orm_mysql_core.MySqlColumn<{
96
+ name: "node";
97
+ tableName: string;
98
+ dataType: "string";
99
+ columnType: "MySqlVarChar";
100
+ data: string;
101
+ driverParam: string | number;
102
+ notNull: true;
103
+ hasDefault: false;
104
+ isPrimaryKey: false;
105
+ isAutoincrement: false;
106
+ hasRuntimeDefault: false;
107
+ enumValues: [string, ...string[]];
108
+ baseColumn: never;
109
+ identity: undefined;
110
+ generated: undefined;
111
+ }, object>;
112
+ assignedAt: drizzle_orm_mysql_core.MySqlColumn<{
113
+ name: "assigned_at";
114
+ tableName: string;
115
+ dataType: "date";
116
+ columnType: "MySqlTimestamp";
117
+ data: Date;
118
+ driverParam: string | number;
119
+ notNull: true;
120
+ hasDefault: true;
121
+ isPrimaryKey: false;
122
+ isAutoincrement: false;
123
+ hasRuntimeDefault: false;
124
+ enumValues: undefined;
125
+ baseColumn: never;
126
+ identity: undefined;
127
+ generated: undefined;
128
+ }, object>;
129
+ };
130
+ dialect: "mysql";
131
+ }>;
132
+ groups?: NonNullable<MySqlTableWithColumns<{
133
+ name: string;
134
+ schema: undefined;
135
+ columns: {
136
+ id: drizzle_orm_mysql_core.MySqlColumn<{
137
+ name: "id";
138
+ tableName: string;
139
+ dataType: "string";
140
+ columnType: "MySqlVarChar";
141
+ data: string;
142
+ driverParam: string | number;
143
+ notNull: true;
144
+ hasDefault: false;
145
+ isPrimaryKey: true;
146
+ isAutoincrement: false;
147
+ hasRuntimeDefault: false;
148
+ enumValues: [string, ...string[]];
149
+ baseColumn: never;
150
+ identity: undefined;
151
+ generated: undefined;
152
+ }, object>;
153
+ displayName: drizzle_orm_mysql_core.MySqlColumn<{
154
+ name: "display_name";
155
+ tableName: string;
156
+ dataType: "string";
157
+ columnType: "MySqlVarChar";
158
+ data: string;
159
+ driverParam: string | number;
160
+ notNull: false;
161
+ hasDefault: false;
162
+ isPrimaryKey: false;
163
+ isAutoincrement: false;
164
+ hasRuntimeDefault: false;
165
+ enumValues: [string, ...string[]];
166
+ baseColumn: never;
167
+ identity: undefined;
168
+ generated: undefined;
169
+ }, object>;
170
+ description: drizzle_orm_mysql_core.MySqlColumn<{
171
+ name: "description";
172
+ tableName: string;
173
+ dataType: "string";
174
+ columnType: "MySqlVarChar";
175
+ data: string;
176
+ driverParam: string | number;
177
+ notNull: false;
178
+ hasDefault: false;
179
+ isPrimaryKey: false;
180
+ isAutoincrement: false;
181
+ hasRuntimeDefault: false;
182
+ enumValues: [string, ...string[]];
183
+ baseColumn: never;
184
+ identity: undefined;
185
+ generated: undefined;
186
+ }, object>;
187
+ priority: drizzle_orm_mysql_core.MySqlColumn<{
188
+ name: "priority";
189
+ tableName: string;
190
+ dataType: "number";
191
+ columnType: "MySqlInt";
192
+ data: number;
193
+ driverParam: string | number;
194
+ notNull: false;
195
+ hasDefault: false;
196
+ isPrimaryKey: false;
197
+ isAutoincrement: false;
198
+ hasRuntimeDefault: false;
199
+ enumValues: undefined;
200
+ baseColumn: never;
201
+ identity: undefined;
202
+ generated: undefined;
203
+ }, object>;
204
+ isDefault: drizzle_orm_mysql_core.MySqlColumn<{
205
+ name: "is_default";
206
+ tableName: string;
207
+ dataType: "boolean";
208
+ columnType: "MySqlBoolean";
209
+ data: boolean;
210
+ driverParam: number | boolean;
211
+ notNull: true;
212
+ hasDefault: true;
213
+ isPrimaryKey: false;
214
+ isAutoincrement: false;
215
+ hasRuntimeDefault: false;
216
+ enumValues: undefined;
217
+ baseColumn: never;
218
+ identity: undefined;
219
+ generated: undefined;
220
+ }, object>;
221
+ effective: drizzle_orm_mysql_core.MySqlColumn<{
222
+ name: "effective";
223
+ tableName: string;
224
+ dataType: "json";
225
+ columnType: "MySqlJson";
226
+ data: string[];
227
+ driverParam: string;
228
+ notNull: true;
229
+ hasDefault: false;
230
+ isPrimaryKey: false;
231
+ isAutoincrement: false;
232
+ hasRuntimeDefault: false;
233
+ enumValues: undefined;
234
+ baseColumn: never;
235
+ identity: undefined;
236
+ generated: undefined;
237
+ }, object>;
238
+ permissions: drizzle_orm_mysql_core.MySqlColumn<{
239
+ name: "permissions";
240
+ tableName: string;
241
+ dataType: "json";
242
+ columnType: "MySqlJson";
243
+ data: string[];
244
+ driverParam: string;
245
+ notNull: true;
246
+ hasDefault: false;
247
+ isPrimaryKey: false;
248
+ isAutoincrement: false;
249
+ hasRuntimeDefault: false;
250
+ enumValues: undefined;
251
+ baseColumn: never;
252
+ identity: undefined;
253
+ generated: undefined;
254
+ }, object>;
255
+ };
256
+ dialect: "mysql";
257
+ }> | undefined>;
258
+ };
259
+ relations: {
260
+ userGroupsRelations: drizzle_orm.Relations<string, {
261
+ user: drizzle_orm.One<U["_"]["name"], true>;
262
+ }>;
263
+ userPermissionsRelations: drizzle_orm.Relations<string, {
264
+ user: drizzle_orm.One<U["_"]["name"], true>;
265
+ }>;
266
+ };
267
+ };
268
+ type RbacTables = ReturnType<typeof createRbacTables>['tables'];
269
+ interface CreateRbacAdapterOptions {
270
+ db: any;
271
+ tables: RbacTables;
272
+ }
273
+ declare function createRbacAdapter(opts: CreateRbacAdapterOptions): RbacAdapter;
274
+
275
+ export { type CreateRbacAdapterOptions, type CreateRbacTablesOptions, type MysqlUsersTable, createRbacAdapter, createRbacTables };
@@ -0,0 +1,96 @@
1
+ import { mysqlTable, timestamp, varchar, index, primaryKey, json, boolean, int } from 'drizzle-orm/mysql-core';
2
+ import { relations, eq, and } from 'drizzle-orm';
3
+
4
+ // src/mysql/index.ts
5
+ function createRbacTables(opts) {
6
+ const { usersTable, prefix = "holeauth_rbac_", persistGroups = false } = opts;
7
+ const p = (s) => `${prefix}${s}`;
8
+ const userGroups = mysqlTable(
9
+ p("user_group"),
10
+ {
11
+ userId: varchar("user_id", { length: 191 }).notNull().references(() => usersTable.id, { onDelete: "cascade" }),
12
+ groupId: varchar("group_id", { length: 191 }).notNull(),
13
+ assignedAt: timestamp("assigned_at", { fsp: 3 }).notNull().defaultNow()
14
+ },
15
+ (t) => ({
16
+ pk: primaryKey({ columns: [t.userId, t.groupId] }),
17
+ groupIdx: index(`${p("user_group")}_group_idx`).on(t.groupId)
18
+ })
19
+ );
20
+ const userPermissions = mysqlTable(
21
+ p("user_permission"),
22
+ {
23
+ userId: varchar("user_id", { length: 191 }).notNull().references(() => usersTable.id, { onDelete: "cascade" }),
24
+ node: varchar("node", { length: 191 }).notNull(),
25
+ assignedAt: timestamp("assigned_at", { fsp: 3 }).notNull().defaultNow()
26
+ },
27
+ (t) => ({ pk: primaryKey({ columns: [t.userId, t.node] }) })
28
+ );
29
+ const userGroupsRelations = relations(userGroups, ({ one }) => ({
30
+ user: one(usersTable, { fields: [userGroups.userId], references: [usersTable.id] })
31
+ }));
32
+ const userPermissionsRelations = relations(userPermissions, ({ one }) => ({
33
+ user: one(usersTable, { fields: [userPermissions.userId], references: [usersTable.id] })
34
+ }));
35
+ const groups = persistGroups ? mysqlTable(p("group"), {
36
+ id: varchar("id", { length: 191 }).primaryKey(),
37
+ displayName: varchar("display_name", { length: 191 }),
38
+ description: varchar("description", { length: 512 }),
39
+ priority: int("priority"),
40
+ isDefault: boolean("is_default").notNull().default(false),
41
+ effective: json("effective").$type().notNull(),
42
+ permissions: json("permissions").$type().notNull()
43
+ }) : void 0;
44
+ return {
45
+ tables: {
46
+ userGroups,
47
+ userPermissions,
48
+ ...groups ? { groups } : {}
49
+ },
50
+ relations: { userGroupsRelations, userPermissionsRelations }
51
+ };
52
+ }
53
+ function createRbacAdapter(opts) {
54
+ const { db, tables } = opts;
55
+ const { userGroups, userPermissions } = tables;
56
+ return {
57
+ async listUserGroups(userId) {
58
+ const rows = await db.select({ groupId: userGroups.groupId }).from(userGroups).where(eq(userGroups.userId, userId));
59
+ return rows.map((r) => r.groupId);
60
+ },
61
+ async assignGroup(userId, groupId) {
62
+ await db.insert(userGroups).values({ userId, groupId }).onDuplicateKeyUpdate({ set: { groupId } });
63
+ },
64
+ async removeGroup(userId, groupId) {
65
+ await db.delete(userGroups).where(and(eq(userGroups.userId, userId), eq(userGroups.groupId, groupId)));
66
+ },
67
+ async listUserPermissions(userId) {
68
+ const rows = await db.select({ node: userPermissions.node }).from(userPermissions).where(eq(userPermissions.userId, userId));
69
+ return rows.map((r) => r.node);
70
+ },
71
+ async grantPermission(userId, node) {
72
+ await db.insert(userPermissions).values({ userId, node }).onDuplicateKeyUpdate({ set: { node } });
73
+ },
74
+ async revokePermission(userId, node) {
75
+ await db.delete(userPermissions).where(and(eq(userPermissions.userId, userId), eq(userPermissions.node, node)));
76
+ },
77
+ async listAllGroupAssignments() {
78
+ const rows = await db.select().from(userGroups);
79
+ return rows.map(
80
+ (r) => ({
81
+ userId: r.userId,
82
+ groupId: r.groupId,
83
+ assignedAt: r.assignedAt
84
+ })
85
+ );
86
+ },
87
+ async purgeUser(userId) {
88
+ await db.delete(userPermissions).where(eq(userPermissions.userId, userId));
89
+ await db.delete(userGroups).where(eq(userGroups.userId, userId));
90
+ }
91
+ };
92
+ }
93
+
94
+ export { createRbacAdapter, createRbacTables };
95
+ //# sourceMappingURL=index.js.map
96
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/mysql/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import {\n mysqlTable,\n varchar,\n timestamp,\n int,\n boolean,\n json,\n primaryKey,\n index,\n type MySqlTableWithColumns,\n} from 'drizzle-orm/mysql-core';\nimport { relations, eq, and } from 'drizzle-orm';\nimport type { RbacAdapter, UserGroupAssignment } from '@holeauth/plugin-rbac';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type MysqlUsersTable = MySqlTableWithColumns<any> & { id: any };\n\nexport interface CreateRbacTablesOptions<U extends MysqlUsersTable> {\n usersTable: U;\n prefix?: string;\n persistGroups?: boolean;\n}\n\nexport function createRbacTables<U extends MysqlUsersTable>(opts: CreateRbacTablesOptions<U>) {\n const { usersTable, prefix = 'holeauth_rbac_', persistGroups = false } = opts;\n const p = (s: string) => `${prefix}${s}`;\n\n const userGroups = mysqlTable(\n p('user_group'),\n {\n userId: varchar('user_id', { length: 191 })\n .notNull()\n .references(() => usersTable.id, { onDelete: 'cascade' }),\n groupId: varchar('group_id', { length: 191 }).notNull(),\n assignedAt: timestamp('assigned_at', { fsp: 3 }).notNull().defaultNow(),\n },\n (t) => ({\n pk: primaryKey({ columns: [t.userId, t.groupId] }),\n groupIdx: index(`${p('user_group')}_group_idx`).on(t.groupId),\n }),\n );\n\n const userPermissions = mysqlTable(\n p('user_permission'),\n {\n userId: varchar('user_id', { length: 191 })\n .notNull()\n .references(() => usersTable.id, { onDelete: 'cascade' }),\n node: varchar('node', { length: 191 }).notNull(),\n assignedAt: timestamp('assigned_at', { fsp: 3 }).notNull().defaultNow(),\n },\n (t) => ({ pk: primaryKey({ columns: [t.userId, t.node] }) }),\n );\n\n const userGroupsRelations = relations(userGroups, ({ one }) => ({\n user: one(usersTable, { fields: [userGroups.userId], references: [usersTable.id] }),\n }));\n const userPermissionsRelations = relations(userPermissions, ({ one }) => ({\n user: one(usersTable, { fields: [userPermissions.userId], references: [usersTable.id] }),\n }));\n\n const groups = persistGroups\n ? mysqlTable(p('group'), {\n id: varchar('id', { length: 191 }).primaryKey(),\n displayName: varchar('display_name', { length: 191 }),\n description: varchar('description', { length: 512 }),\n priority: int('priority'),\n isDefault: boolean('is_default').notNull().default(false),\n effective: json('effective').$type<string[]>().notNull(),\n permissions: json('permissions').$type<string[]>().notNull(),\n })\n : undefined;\n\n return {\n tables: {\n userGroups,\n userPermissions,\n ...(groups ? { groups } : {}),\n } as {\n userGroups: typeof userGroups;\n userPermissions: typeof userPermissions;\n groups?: NonNullable<typeof groups>;\n },\n relations: { userGroupsRelations, userPermissionsRelations },\n };\n}\n\ntype RbacTables = ReturnType<typeof createRbacTables>['tables'];\n\nexport interface CreateRbacAdapterOptions {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n db: any;\n tables: RbacTables;\n}\n\nexport function createRbacAdapter(opts: CreateRbacAdapterOptions): RbacAdapter {\n const { db, tables } = opts;\n const { userGroups, userPermissions } = tables;\n // MySQL uses onDuplicateKeyUpdate for idempotent inserts.\n return {\n async listUserGroups(userId) {\n const rows = await db\n .select({ groupId: userGroups.groupId })\n .from(userGroups)\n .where(eq(userGroups.userId, userId));\n return (rows as { groupId: string }[]).map((r) => r.groupId);\n },\n async assignGroup(userId, groupId) {\n await db\n .insert(userGroups)\n .values({ userId, groupId })\n .onDuplicateKeyUpdate({ set: { groupId } });\n },\n async removeGroup(userId, groupId) {\n await db\n .delete(userGroups)\n .where(and(eq(userGroups.userId, userId), eq(userGroups.groupId, groupId)));\n },\n async listUserPermissions(userId) {\n const rows = await db\n .select({ node: userPermissions.node })\n .from(userPermissions)\n .where(eq(userPermissions.userId, userId));\n return (rows as { node: string }[]).map((r) => r.node);\n },\n async grantPermission(userId, node) {\n await db\n .insert(userPermissions)\n .values({ userId, node })\n .onDuplicateKeyUpdate({ set: { node } });\n },\n async revokePermission(userId, node) {\n await db\n .delete(userPermissions)\n .where(and(eq(userPermissions.userId, userId), eq(userPermissions.node, node)));\n },\n async listAllGroupAssignments() {\n const rows = await db.select().from(userGroups);\n return (rows as { userId: string; groupId: string; assignedAt: Date }[]).map(\n (r): UserGroupAssignment => ({\n userId: r.userId,\n groupId: r.groupId,\n assignedAt: r.assignedAt,\n }),\n );\n },\n async purgeUser(userId) {\n await db.delete(userPermissions).where(eq(userPermissions.userId, userId));\n await db.delete(userGroups).where(eq(userGroups.userId, userId));\n },\n };\n}\n"]}
@@ -0,0 +1,101 @@
1
+ 'use strict';
2
+
3
+ var pgCore = require('drizzle-orm/pg-core');
4
+ var drizzleOrm = require('drizzle-orm');
5
+
6
+ // src/pg/index.ts
7
+ function createRbacTables(opts) {
8
+ const { usersTable, prefix = "holeauth_rbac_", persistGroups = false } = opts;
9
+ const p = (s) => `${prefix}${s}`;
10
+ const userGroups = pgCore.pgTable(
11
+ p("user_group"),
12
+ {
13
+ userId: pgCore.text("user_id").notNull().references(() => usersTable.id, { onDelete: "cascade" }),
14
+ groupId: pgCore.text("group_id").notNull(),
15
+ assignedAt: pgCore.timestamp("assigned_at", { withTimezone: true, mode: "date" }).notNull().defaultNow()
16
+ },
17
+ (t) => ({
18
+ pk: pgCore.primaryKey({ columns: [t.userId, t.groupId] }),
19
+ groupIdx: pgCore.index().on(t.groupId)
20
+ })
21
+ );
22
+ const userPermissions = pgCore.pgTable(
23
+ p("user_permission"),
24
+ {
25
+ userId: pgCore.text("user_id").notNull().references(() => usersTable.id, { onDelete: "cascade" }),
26
+ node: pgCore.text("node").notNull(),
27
+ assignedAt: pgCore.timestamp("assigned_at", { withTimezone: true, mode: "date" }).notNull().defaultNow()
28
+ },
29
+ (t) => ({
30
+ pk: pgCore.primaryKey({ columns: [t.userId, t.node] })
31
+ })
32
+ );
33
+ const userGroupsRelations = drizzleOrm.relations(userGroups, ({ one }) => ({
34
+ user: one(usersTable, { fields: [userGroups.userId], references: [usersTable.id] })
35
+ }));
36
+ const userPermissionsRelations = drizzleOrm.relations(userPermissions, ({ one }) => ({
37
+ user: one(usersTable, { fields: [userPermissions.userId], references: [usersTable.id] })
38
+ }));
39
+ const groups = persistGroups ? pgCore.pgTable(p("group"), {
40
+ id: pgCore.text("id").primaryKey(),
41
+ displayName: pgCore.text("display_name"),
42
+ description: pgCore.text("description"),
43
+ priority: pgCore.integer("priority"),
44
+ isDefault: pgCore.boolean("is_default").notNull().default(false),
45
+ effective: pgCore.text("effective").array().notNull().default([]),
46
+ permissions: pgCore.text("permissions").array().notNull().default([])
47
+ }) : void 0;
48
+ return {
49
+ tables: {
50
+ userGroups,
51
+ userPermissions,
52
+ ...groups ? { groups } : {}
53
+ },
54
+ relations: { userGroupsRelations, userPermissionsRelations }
55
+ };
56
+ }
57
+ function createRbacAdapter(opts) {
58
+ const { db, tables } = opts;
59
+ const { userGroups, userPermissions } = tables;
60
+ return {
61
+ async listUserGroups(userId) {
62
+ const rows = await db.select({ groupId: userGroups.groupId }).from(userGroups).where(drizzleOrm.eq(userGroups.userId, userId));
63
+ return rows.map((r) => r.groupId);
64
+ },
65
+ async assignGroup(userId, groupId) {
66
+ await db.insert(userGroups).values({ userId, groupId }).onConflictDoNothing();
67
+ },
68
+ async removeGroup(userId, groupId) {
69
+ await db.delete(userGroups).where(drizzleOrm.and(drizzleOrm.eq(userGroups.userId, userId), drizzleOrm.eq(userGroups.groupId, groupId)));
70
+ },
71
+ async listUserPermissions(userId) {
72
+ const rows = await db.select({ node: userPermissions.node }).from(userPermissions).where(drizzleOrm.eq(userPermissions.userId, userId));
73
+ return rows.map((r) => r.node);
74
+ },
75
+ async grantPermission(userId, node) {
76
+ await db.insert(userPermissions).values({ userId, node }).onConflictDoNothing();
77
+ },
78
+ async revokePermission(userId, node) {
79
+ await db.delete(userPermissions).where(drizzleOrm.and(drizzleOrm.eq(userPermissions.userId, userId), drizzleOrm.eq(userPermissions.node, node)));
80
+ },
81
+ async listAllGroupAssignments() {
82
+ const rows = await db.select().from(userGroups);
83
+ return rows.map(
84
+ (r) => ({
85
+ userId: r.userId,
86
+ groupId: r.groupId,
87
+ assignedAt: r.assignedAt
88
+ })
89
+ );
90
+ },
91
+ async purgeUser(userId) {
92
+ await db.delete(userPermissions).where(drizzleOrm.eq(userPermissions.userId, userId));
93
+ await db.delete(userGroups).where(drizzleOrm.eq(userGroups.userId, userId));
94
+ }
95
+ };
96
+ }
97
+
98
+ exports.createRbacAdapter = createRbacAdapter;
99
+ exports.createRbacTables = createRbacTables;
100
+ //# sourceMappingURL=index.cjs.map
101
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/pg/index.ts"],"names":["pgTable","text","timestamp","primaryKey","index","relations","integer","boolean","eq","and"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n pgTable,\n text,\n timestamp,\n integer,\n boolean,\n primaryKey,\n index,\n type PgTableWithColumns,\n} from 'drizzle-orm/pg-core';\nimport { relations, eq, and } from 'drizzle-orm';\nimport type { RbacAdapter, UserGroupAssignment } from '@holeauth/plugin-rbac';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type PgUsersTable = PgTableWithColumns<any> & { id: any };\n\nexport interface CreateRbacTablesOptions<U extends PgUsersTable> {\n usersTable: U;\n /** Prefix for rbac tables. Default `holeauth_rbac_`. */\n prefix?: string;\n /** Also persist group definitions (opt-in). Default `false` — groups come from YAML. */\n persistGroups?: boolean;\n}\n\nexport function createRbacTables<U extends PgUsersTable>(opts: CreateRbacTablesOptions<U>) {\n const { usersTable, prefix = 'holeauth_rbac_', persistGroups = false } = opts;\n const p = (s: string) => `${prefix}${s}`;\n\n const userGroups = pgTable(\n p('user_group'),\n {\n userId: text('user_id')\n .notNull()\n .references(() => usersTable.id, { onDelete: 'cascade' }),\n groupId: text('group_id').notNull(),\n assignedAt: timestamp('assigned_at', { withTimezone: true, mode: 'date' })\n .notNull()\n .defaultNow(),\n },\n (t) => ({\n pk: primaryKey({ columns: [t.userId, t.groupId] }),\n groupIdx: index().on(t.groupId),\n }),\n );\n\n const userPermissions = pgTable(\n p('user_permission'),\n {\n userId: text('user_id')\n .notNull()\n .references(() => usersTable.id, { onDelete: 'cascade' }),\n node: text('node').notNull(),\n assignedAt: timestamp('assigned_at', { withTimezone: true, mode: 'date' })\n .notNull()\n .defaultNow(),\n },\n (t) => ({\n pk: primaryKey({ columns: [t.userId, t.node] }),\n }),\n );\n\n const userGroupsRelations = relations(userGroups, ({ one }) => ({\n user: one(usersTable, { fields: [userGroups.userId], references: [usersTable.id] }),\n }));\n const userPermissionsRelations = relations(userPermissions, ({ one }) => ({\n user: one(usersTable, { fields: [userPermissions.userId], references: [usersTable.id] }),\n }));\n\n const groups = persistGroups\n ? pgTable(p('group'), {\n id: text('id').primaryKey(),\n displayName: text('display_name'),\n description: text('description'),\n priority: integer('priority'),\n isDefault: boolean('is_default').notNull().default(false),\n effective: text('effective').array().notNull().default([]),\n permissions: text('permissions').array().notNull().default([]),\n })\n : undefined;\n\n return {\n tables: {\n userGroups,\n userPermissions,\n ...(groups ? { groups } : {}),\n } as {\n userGroups: typeof userGroups;\n userPermissions: typeof userPermissions;\n groups?: NonNullable<typeof groups>;\n },\n relations: { userGroupsRelations, userPermissionsRelations },\n };\n}\n\ntype RbacTables = ReturnType<typeof createRbacTables>['tables'];\n\nexport interface CreateRbacAdapterOptions {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n db: any;\n tables: RbacTables;\n}\n\nexport function createRbacAdapter(opts: CreateRbacAdapterOptions): RbacAdapter {\n const { db, tables } = opts;\n const { userGroups, userPermissions } = tables;\n\n return {\n async listUserGroups(userId) {\n const rows = await db\n .select({ groupId: userGroups.groupId })\n .from(userGroups)\n .where(eq(userGroups.userId, userId));\n return (rows as { groupId: string }[]).map((r) => r.groupId);\n },\n async assignGroup(userId, groupId) {\n await db.insert(userGroups).values({ userId, groupId }).onConflictDoNothing();\n },\n async removeGroup(userId, groupId) {\n await db\n .delete(userGroups)\n .where(and(eq(userGroups.userId, userId), eq(userGroups.groupId, groupId)));\n },\n async listUserPermissions(userId) {\n const rows = await db\n .select({ node: userPermissions.node })\n .from(userPermissions)\n .where(eq(userPermissions.userId, userId));\n return (rows as { node: string }[]).map((r) => r.node);\n },\n async grantPermission(userId, node) {\n await db.insert(userPermissions).values({ userId, node }).onConflictDoNothing();\n },\n async revokePermission(userId, node) {\n await db\n .delete(userPermissions)\n .where(and(eq(userPermissions.userId, userId), eq(userPermissions.node, node)));\n },\n async listAllGroupAssignments() {\n const rows = await db.select().from(userGroups);\n return (rows as { userId: string; groupId: string; assignedAt: Date }[]).map(\n (r): UserGroupAssignment => ({\n userId: r.userId,\n groupId: r.groupId,\n assignedAt: r.assignedAt,\n }),\n );\n },\n async purgeUser(userId) {\n await db.delete(userPermissions).where(eq(userPermissions.userId, userId));\n await db.delete(userGroups).where(eq(userGroups.userId, userId));\n },\n };\n}\n"]}