@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.
- package/LICENSE +21 -0
- package/README.md +29 -0
- package/dist/index.cjs +4 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/mysql/index.cjs +99 -0
- package/dist/mysql/index.cjs.map +1 -0
- package/dist/mysql/index.d.cts +275 -0
- package/dist/mysql/index.d.ts +275 -0
- package/dist/mysql/index.js +96 -0
- package/dist/mysql/index.js.map +1 -0
- package/dist/pg/index.cjs +101 -0
- package/dist/pg/index.cjs.map +1 -0
- package/dist/pg/index.d.cts +309 -0
- package/dist/pg/index.d.ts +309 -0
- package/dist/pg/index.js +98 -0
- package/dist/pg/index.js.map +1 -0
- package/dist/sqlite/index.cjs +99 -0
- package/dist/sqlite/index.cjs.map +1 -0
- package/dist/sqlite/index.d.cts +275 -0
- package/dist/sqlite/index.d.ts +275 -0
- package/dist/sqlite/index.js +96 -0
- package/dist/sqlite/index.js.map +1 -0
- package/package.json +79 -0
|
@@ -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"]}
|