@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_sqlite_core from 'drizzle-orm/sqlite-core';
3
+ import { SQLiteTableWithColumns } from 'drizzle-orm/sqlite-core';
4
+ import { RbacAdapter } from '@holeauth/plugin-rbac';
5
+
6
+ type SqliteUsersTable = SQLiteTableWithColumns<any> & {
7
+ id: any;
8
+ };
9
+ interface CreateRbacTablesOptions<U extends SqliteUsersTable> {
10
+ usersTable: U;
11
+ prefix?: string;
12
+ persistGroups?: boolean;
13
+ }
14
+ declare function createRbacTables<U extends SqliteUsersTable>(opts: CreateRbacTablesOptions<U>): {
15
+ tables: {
16
+ userGroups: SQLiteTableWithColumns<{
17
+ name: string;
18
+ schema: undefined;
19
+ columns: {
20
+ userId: drizzle_orm_sqlite_core.SQLiteColumn<{
21
+ name: "user_id";
22
+ tableName: string;
23
+ dataType: "string";
24
+ columnType: "SQLiteText";
25
+ data: string;
26
+ driverParam: string;
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_sqlite_core.SQLiteColumn<{
38
+ name: "group_id";
39
+ tableName: string;
40
+ dataType: "string";
41
+ columnType: "SQLiteText";
42
+ data: string;
43
+ driverParam: string;
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_sqlite_core.SQLiteColumn<{
55
+ name: "assigned_at";
56
+ tableName: string;
57
+ dataType: "date";
58
+ columnType: "SQLiteTimestamp";
59
+ data: Date;
60
+ driverParam: number;
61
+ notNull: true;
62
+ hasDefault: true;
63
+ isPrimaryKey: false;
64
+ isAutoincrement: false;
65
+ hasRuntimeDefault: true;
66
+ enumValues: undefined;
67
+ baseColumn: never;
68
+ identity: undefined;
69
+ generated: undefined;
70
+ }, object>;
71
+ };
72
+ dialect: "sqlite";
73
+ }>;
74
+ userPermissions: SQLiteTableWithColumns<{
75
+ name: string;
76
+ schema: undefined;
77
+ columns: {
78
+ userId: drizzle_orm_sqlite_core.SQLiteColumn<{
79
+ name: "user_id";
80
+ tableName: string;
81
+ dataType: "string";
82
+ columnType: "SQLiteText";
83
+ data: string;
84
+ driverParam: string;
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_sqlite_core.SQLiteColumn<{
96
+ name: "node";
97
+ tableName: string;
98
+ dataType: "string";
99
+ columnType: "SQLiteText";
100
+ data: string;
101
+ driverParam: string;
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_sqlite_core.SQLiteColumn<{
113
+ name: "assigned_at";
114
+ tableName: string;
115
+ dataType: "date";
116
+ columnType: "SQLiteTimestamp";
117
+ data: Date;
118
+ driverParam: number;
119
+ notNull: true;
120
+ hasDefault: true;
121
+ isPrimaryKey: false;
122
+ isAutoincrement: false;
123
+ hasRuntimeDefault: true;
124
+ enumValues: undefined;
125
+ baseColumn: never;
126
+ identity: undefined;
127
+ generated: undefined;
128
+ }, object>;
129
+ };
130
+ dialect: "sqlite";
131
+ }>;
132
+ groups?: NonNullable<SQLiteTableWithColumns<{
133
+ name: string;
134
+ schema: undefined;
135
+ columns: {
136
+ id: drizzle_orm_sqlite_core.SQLiteColumn<{
137
+ name: "id";
138
+ tableName: string;
139
+ dataType: "string";
140
+ columnType: "SQLiteText";
141
+ data: string;
142
+ driverParam: string;
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_sqlite_core.SQLiteColumn<{
154
+ name: "display_name";
155
+ tableName: string;
156
+ dataType: "string";
157
+ columnType: "SQLiteText";
158
+ data: string;
159
+ driverParam: string;
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_sqlite_core.SQLiteColumn<{
171
+ name: "description";
172
+ tableName: string;
173
+ dataType: "string";
174
+ columnType: "SQLiteText";
175
+ data: string;
176
+ driverParam: string;
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_sqlite_core.SQLiteColumn<{
188
+ name: "priority";
189
+ tableName: string;
190
+ dataType: "number";
191
+ columnType: "SQLiteInteger";
192
+ data: number;
193
+ driverParam: 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_sqlite_core.SQLiteColumn<{
205
+ name: "is_default";
206
+ tableName: string;
207
+ dataType: "boolean";
208
+ columnType: "SQLiteBoolean";
209
+ data: boolean;
210
+ driverParam: number;
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_sqlite_core.SQLiteColumn<{
222
+ name: "effective";
223
+ tableName: string;
224
+ dataType: "json";
225
+ columnType: "SQLiteTextJson";
226
+ data: string[];
227
+ driverParam: string;
228
+ notNull: true;
229
+ hasDefault: true;
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_sqlite_core.SQLiteColumn<{
239
+ name: "permissions";
240
+ tableName: string;
241
+ dataType: "json";
242
+ columnType: "SQLiteTextJson";
243
+ data: string[];
244
+ driverParam: string;
245
+ notNull: true;
246
+ hasDefault: true;
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: "sqlite";
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 SqliteUsersTable, createRbacAdapter, createRbacTables };
@@ -0,0 +1,96 @@
1
+ import { sqliteTable, integer, text, index, primaryKey } from 'drizzle-orm/sqlite-core';
2
+ import { relations, eq, and } from 'drizzle-orm';
3
+
4
+ // src/sqlite/index.ts
5
+ function createRbacTables(opts) {
6
+ const { usersTable, prefix = "holeauth_rbac_", persistGroups = false } = opts;
7
+ const p = (s) => `${prefix}${s}`;
8
+ const userGroups = sqliteTable(
9
+ p("user_group"),
10
+ {
11
+ userId: text("user_id").notNull().references(() => usersTable.id, { onDelete: "cascade" }),
12
+ groupId: text("group_id").notNull(),
13
+ assignedAt: integer("assigned_at", { mode: "timestamp_ms" }).notNull().$defaultFn(() => /* @__PURE__ */ new Date())
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 = sqliteTable(
21
+ p("user_permission"),
22
+ {
23
+ userId: text("user_id").notNull().references(() => usersTable.id, { onDelete: "cascade" }),
24
+ node: text("node").notNull(),
25
+ assignedAt: integer("assigned_at", { mode: "timestamp_ms" }).notNull().$defaultFn(() => /* @__PURE__ */ new Date())
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 ? sqliteTable(p("group"), {
36
+ id: text("id").primaryKey(),
37
+ displayName: text("display_name"),
38
+ description: text("description"),
39
+ priority: integer("priority"),
40
+ isDefault: integer("is_default", { mode: "boolean" }).notNull().default(false),
41
+ effective: text("effective", { mode: "json" }).$type().notNull().default([]),
42
+ permissions: text("permissions", { mode: "json" }).$type().notNull().default([])
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 }).onConflictDoNothing();
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 }).onConflictDoNothing();
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/sqlite/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import {\n sqliteTable,\n text,\n integer,\n primaryKey,\n index,\n type SQLiteTableWithColumns,\n} from 'drizzle-orm/sqlite-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 SqliteUsersTable = SQLiteTableWithColumns<any> & { id: any };\n\nexport interface CreateRbacTablesOptions<U extends SqliteUsersTable> {\n usersTable: U;\n prefix?: string;\n persistGroups?: boolean;\n}\n\nexport function createRbacTables<U extends SqliteUsersTable>(opts: CreateRbacTablesOptions<U>) {\n const { usersTable, prefix = 'holeauth_rbac_', persistGroups = false } = opts;\n const p = (s: string) => `${prefix}${s}`;\n\n const userGroups = sqliteTable(\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: integer('assigned_at', { mode: 'timestamp_ms' })\n .notNull()\n .$defaultFn(() => new Date()),\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 = sqliteTable(\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: integer('assigned_at', { mode: 'timestamp_ms' })\n .notNull()\n .$defaultFn(() => new Date()),\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 ? sqliteTable(p('group'), {\n id: text('id').primaryKey(),\n displayName: text('display_name'),\n description: text('description'),\n priority: integer('priority'),\n isDefault: integer('is_default', { mode: 'boolean' }).notNull().default(false),\n effective: text('effective', { mode: 'json' }).$type<string[]>().notNull().default([]),\n permissions: text('permissions', { mode: 'json' }).$type<string[]>().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 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"]}
package/package.json ADDED
@@ -0,0 +1,79 @@
1
+ {
2
+ "name": "@holeauth/rbac-drizzle",
3
+ "version": "0.0.1-alpha.0",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/robert-kratz/holeauth.git",
7
+ "directory": "packages/rbac-drizzle"
8
+ },
9
+ "description": "Drizzle RBAC adapter for @holeauth/plugin-rbac (user-group and user-permission assignments, optional group persistence).",
10
+ "license": "MIT",
11
+ "author": "Robert Kratz",
12
+ "type": "module",
13
+ "sideEffects": false,
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js",
19
+ "require": "./dist/index.cjs"
20
+ },
21
+ "./pg": {
22
+ "types": "./dist/pg/index.d.ts",
23
+ "import": "./dist/pg/index.js",
24
+ "require": "./dist/pg/index.cjs"
25
+ },
26
+ "./mysql": {
27
+ "types": "./dist/mysql/index.d.ts",
28
+ "import": "./dist/mysql/index.js",
29
+ "require": "./dist/mysql/index.cjs"
30
+ },
31
+ "./sqlite": {
32
+ "types": "./dist/sqlite/index.d.ts",
33
+ "import": "./dist/sqlite/index.js",
34
+ "require": "./dist/sqlite/index.cjs"
35
+ },
36
+ "./package.json": "./package.json"
37
+ },
38
+ "files": [
39
+ "dist",
40
+ "README.md",
41
+ "LICENSE"
42
+ ],
43
+ "publishConfig": {
44
+ "access": "public",
45
+ "provenance": true
46
+ },
47
+ "peerDependencies": {
48
+ "drizzle-orm": ">=0.33.0",
49
+ "@holeauth/plugin-rbac": "0.0.1-alpha.0"
50
+ },
51
+ "devDependencies": {
52
+ "@testcontainers/mysql": "^11.14.0",
53
+ "@testcontainers/postgresql": "^11.14.0",
54
+ "@types/better-sqlite3": "^7.6.13",
55
+ "@types/node": "^20.16.10",
56
+ "@types/pg": "^8.11.10",
57
+ "@vitest/coverage-v8": "^2.1.9",
58
+ "better-sqlite3": "^12.9.0",
59
+ "drizzle-orm": "^0.36.0",
60
+ "mysql2": "^3.22.2",
61
+ "pg": "^8.13.0",
62
+ "testcontainers": "^11.14.0",
63
+ "tsup": "^8.3.0",
64
+ "typescript": "^5.6.2",
65
+ "vitest": "^2.1.2",
66
+ "@holeauth/eslint-config": "0.0.0",
67
+ "@holeauth/plugin-rbac": "0.0.1-alpha.0",
68
+ "@holeauth/tsconfig": "0.0.0"
69
+ },
70
+ "scripts": {
71
+ "build": "tsup",
72
+ "dev": "tsup --watch",
73
+ "clean": "rm -rf dist .turbo",
74
+ "lint": "echo 'lint skipped'",
75
+ "typecheck": "tsc --noEmit",
76
+ "test": "vitest run --passWithNoTests",
77
+ "test:coverage": "vitest run --coverage"
78
+ }
79
+ }