@rebasepro/server-postgresql 0.3.0 → 0.4.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/dist/common/src/collections/default-collections.d.ts +5 -8
- package/dist/common/src/data/query_builder.d.ts +6 -2
- package/dist/index.es.js +301 -500
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +297 -496
- package/dist/index.umd.js.map +1 -1
- package/dist/server-postgresql/src/PostgresBackendDriver.d.ts +2 -0
- package/dist/server-postgresql/src/auth/ensure-tables.d.ts +7 -4
- package/dist/server-postgresql/src/auth/services.d.ts +6 -31
- package/dist/server-postgresql/src/schema/auth-schema.d.ts +87 -340
- package/dist/server-postgresql/src/services/EntityFetchService.d.ts +2 -1
- package/dist/server-postgresql/src/services/EntityPersistService.d.ts +4 -0
- package/dist/server-postgresql/src/services/entityService.d.ts +4 -0
- package/dist/server-postgresql/src/utils/drizzle-conditions.d.ts +5 -1
- package/dist/types/src/controllers/auth.d.ts +2 -2
- package/dist/types/src/controllers/client.d.ts +25 -40
- package/dist/types/src/controllers/data.d.ts +21 -3
- package/dist/types/src/controllers/data_driver.d.ts +5 -0
- package/dist/types/src/controllers/email.d.ts +2 -0
- package/dist/types/src/types/auth_adapter.d.ts +3 -56
- package/dist/types/src/types/backend.d.ts +2 -2
- package/dist/types/src/types/backend_hooks.d.ts +2 -17
- package/dist/types/src/types/collections.d.ts +9 -5
- package/dist/types/src/types/entity_views.d.ts +19 -28
- package/dist/types/src/types/properties.d.ts +9 -7
- package/dist/types/src/types/user_management_delegate.d.ts +16 -53
- package/dist/types/src/users/index.d.ts +0 -1
- package/dist/types/src/users/user.d.ts +0 -1
- package/package.json +6 -6
- package/src/PostgresBackendDriver.ts +10 -0
- package/src/PostgresBootstrapper.ts +25 -21
- package/src/auth/ensure-tables.ts +82 -129
- package/src/auth/services.ts +71 -170
- package/src/schema/auth-schema.ts +13 -69
- package/src/schema/doctor.ts +44 -3
- package/src/schema/generate-drizzle-schema-logic.ts +33 -3
- package/src/schema/generate-drizzle-schema.ts +2 -6
- package/src/schema/introspect-db-logic.ts +7 -0
- package/src/services/EntityFetchService.ts +13 -1
- package/src/services/EntityPersistService.ts +9 -0
- package/src/services/entityService.ts +7 -0
- package/src/utils/drizzle-conditions.ts +40 -5
- package/src/websocket.ts +1 -3
- package/test/auth-services.test.ts +7 -150
- package/test/doctor.test.ts +6 -2
- package/test/relation-pipeline-gaps.test.ts +315 -0
- package/dist/server-postgresql/src/schema/default-collections.d.ts +0 -2
- package/dist/types/src/users/roles.d.ts +0 -14
- package/src/schema/default-collections.ts +0 -69
package/dist/index.umd.js
CHANGED
|
@@ -2719,114 +2719,6 @@
|
|
|
2719
2719
|
};
|
|
2720
2720
|
}
|
|
2721
2721
|
}
|
|
2722
|
-
const defaultUsersCollection = {
|
|
2723
|
-
name: "Users",
|
|
2724
|
-
singularName: "User",
|
|
2725
|
-
slug: "users",
|
|
2726
|
-
table: "users",
|
|
2727
|
-
schema: "rebase",
|
|
2728
|
-
icon: "Users",
|
|
2729
|
-
group: "Settings",
|
|
2730
|
-
properties: {
|
|
2731
|
-
id: {
|
|
2732
|
-
name: "ID",
|
|
2733
|
-
type: "string",
|
|
2734
|
-
isId: "uuid"
|
|
2735
|
-
},
|
|
2736
|
-
email: {
|
|
2737
|
-
name: "Email",
|
|
2738
|
-
type: "string",
|
|
2739
|
-
validation: {
|
|
2740
|
-
required: true,
|
|
2741
|
-
unique: true
|
|
2742
|
-
}
|
|
2743
|
-
},
|
|
2744
|
-
password_hash: {
|
|
2745
|
-
name: "Password Hash",
|
|
2746
|
-
type: "string",
|
|
2747
|
-
ui: {
|
|
2748
|
-
hideFromCollection: true
|
|
2749
|
-
}
|
|
2750
|
-
},
|
|
2751
|
-
display_name: {
|
|
2752
|
-
name: "Display Name",
|
|
2753
|
-
type: "string"
|
|
2754
|
-
},
|
|
2755
|
-
photo_url: {
|
|
2756
|
-
name: "Photo URL",
|
|
2757
|
-
type: "string"
|
|
2758
|
-
},
|
|
2759
|
-
email_verified: {
|
|
2760
|
-
name: "Email Verified",
|
|
2761
|
-
type: "boolean",
|
|
2762
|
-
defaultValue: false
|
|
2763
|
-
},
|
|
2764
|
-
email_verification_token: {
|
|
2765
|
-
name: "Email Verification Token",
|
|
2766
|
-
type: "string",
|
|
2767
|
-
ui: {
|
|
2768
|
-
hideFromCollection: true
|
|
2769
|
-
}
|
|
2770
|
-
},
|
|
2771
|
-
email_verification_sent_at: {
|
|
2772
|
-
name: "Email Verification Sent At",
|
|
2773
|
-
type: "date",
|
|
2774
|
-
ui: {
|
|
2775
|
-
hideFromCollection: true
|
|
2776
|
-
}
|
|
2777
|
-
},
|
|
2778
|
-
metadata: {
|
|
2779
|
-
name: "Metadata",
|
|
2780
|
-
type: "map",
|
|
2781
|
-
defaultValue: {},
|
|
2782
|
-
ui: {
|
|
2783
|
-
hideFromCollection: true
|
|
2784
|
-
}
|
|
2785
|
-
},
|
|
2786
|
-
created_at: {
|
|
2787
|
-
name: "Created At",
|
|
2788
|
-
type: "date",
|
|
2789
|
-
autoValue: "on_create",
|
|
2790
|
-
ui: {
|
|
2791
|
-
readOnly: true,
|
|
2792
|
-
hideFromCollection: true
|
|
2793
|
-
}
|
|
2794
|
-
},
|
|
2795
|
-
updated_at: {
|
|
2796
|
-
name: "Updated At",
|
|
2797
|
-
type: "date",
|
|
2798
|
-
autoValue: "on_update",
|
|
2799
|
-
ui: {
|
|
2800
|
-
readOnly: true,
|
|
2801
|
-
hideFromCollection: true
|
|
2802
|
-
}
|
|
2803
|
-
}
|
|
2804
|
-
}
|
|
2805
|
-
};
|
|
2806
|
-
function mapOperator(op) {
|
|
2807
|
-
switch (op) {
|
|
2808
|
-
case "==":
|
|
2809
|
-
return "eq";
|
|
2810
|
-
case "!=":
|
|
2811
|
-
return "neq";
|
|
2812
|
-
case ">":
|
|
2813
|
-
return "gt";
|
|
2814
|
-
case ">=":
|
|
2815
|
-
return "gte";
|
|
2816
|
-
case "<":
|
|
2817
|
-
return "lt";
|
|
2818
|
-
case "<=":
|
|
2819
|
-
return "lte";
|
|
2820
|
-
case "array-contains":
|
|
2821
|
-
return "cs";
|
|
2822
|
-
case "array-contains-any":
|
|
2823
|
-
return "csa";
|
|
2824
|
-
case "not-in":
|
|
2825
|
-
return "nin";
|
|
2826
|
-
default:
|
|
2827
|
-
return op;
|
|
2828
|
-
}
|
|
2829
|
-
}
|
|
2830
2722
|
class QueryBuilder {
|
|
2831
2723
|
constructor(collection) {
|
|
2832
2724
|
this.collection = collection;
|
|
@@ -2834,23 +2726,30 @@
|
|
|
2834
2726
|
params = {
|
|
2835
2727
|
where: {}
|
|
2836
2728
|
};
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
where(column, operator, value) {
|
|
2729
|
+
where(columnOrCondition, operator, value) {
|
|
2730
|
+
if (typeof columnOrCondition === "object" && columnOrCondition !== null && "type" in columnOrCondition) {
|
|
2731
|
+
this.params.logical = columnOrCondition;
|
|
2732
|
+
return this;
|
|
2733
|
+
}
|
|
2843
2734
|
if (!this.params.where) {
|
|
2844
2735
|
this.params.where = {};
|
|
2845
2736
|
}
|
|
2846
|
-
const
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2737
|
+
const column = columnOrCondition;
|
|
2738
|
+
const condition = [operator, value];
|
|
2739
|
+
const existing = this.params.where[column];
|
|
2740
|
+
if (existing === void 0) {
|
|
2741
|
+
this.params.where[column] = condition;
|
|
2742
|
+
} else if (Array.isArray(existing) && existing.length > 0 && Array.isArray(existing[0])) {
|
|
2743
|
+
this.params.where[column].push(condition);
|
|
2744
|
+
} else {
|
|
2745
|
+
let firstCondition;
|
|
2746
|
+
if (Array.isArray(existing) && existing.length === 2 && typeof existing[0] === "string") {
|
|
2747
|
+
firstCondition = existing;
|
|
2748
|
+
} else {
|
|
2749
|
+
firstCondition = ["==", existing];
|
|
2750
|
+
}
|
|
2751
|
+
this.params.where[column] = [firstCondition, condition];
|
|
2852
2752
|
}
|
|
2853
|
-
this.params.where[column] = mappedOp === "eq" ? String(formattedValue) : `${mappedOp}.${formattedValue}`;
|
|
2854
2753
|
return this;
|
|
2855
2754
|
}
|
|
2856
2755
|
/**
|
|
@@ -2952,10 +2851,13 @@
|
|
|
2952
2851
|
filter[field] = ["==", rawValue];
|
|
2953
2852
|
continue;
|
|
2954
2853
|
}
|
|
2955
|
-
if (Array.isArray(rawValue)
|
|
2956
|
-
const [
|
|
2957
|
-
const
|
|
2958
|
-
|
|
2854
|
+
if (Array.isArray(rawValue)) {
|
|
2855
|
+
const conditions = Array.isArray(rawValue[0]) ? rawValue : [rawValue];
|
|
2856
|
+
const mappedConditions = conditions.map(([rawOp, val]) => {
|
|
2857
|
+
const mappedOp = operatorMap[rawOp] ?? "==";
|
|
2858
|
+
return [mappedOp, val];
|
|
2859
|
+
});
|
|
2860
|
+
filter[field] = Array.isArray(rawValue[0]) ? mappedConditions : mappedConditions[0];
|
|
2959
2861
|
continue;
|
|
2960
2862
|
}
|
|
2961
2863
|
if (typeof rawValue === "string") {
|
|
@@ -3049,6 +2951,9 @@
|
|
|
3049
2951
|
}
|
|
3050
2952
|
});
|
|
3051
2953
|
},
|
|
2954
|
+
deleteAll: driver.deleteAll ? async () => {
|
|
2955
|
+
return driver.deleteAll(slug);
|
|
2956
|
+
} : void 0,
|
|
3052
2957
|
count: driver.countEntities ? async (params) => {
|
|
3053
2958
|
return driver.countEntities({
|
|
3054
2959
|
path: slug,
|
|
@@ -3090,8 +2995,12 @@
|
|
|
3090
2995
|
});
|
|
3091
2996
|
} : void 0,
|
|
3092
2997
|
// Fluent Query Builder
|
|
3093
|
-
where(
|
|
3094
|
-
|
|
2998
|
+
where(columnOrCondition, operator, value) {
|
|
2999
|
+
const builder = new QueryBuilder(accessor);
|
|
3000
|
+
if (typeof columnOrCondition === "object") {
|
|
3001
|
+
return builder.where(columnOrCondition);
|
|
3002
|
+
}
|
|
3003
|
+
return builder.where(columnOrCondition, operator, value);
|
|
3095
3004
|
},
|
|
3096
3005
|
orderBy(column, ascending) {
|
|
3097
3006
|
return new QueryBuilder(accessor).orderBy(column, ascending);
|
|
@@ -3142,7 +3051,6 @@
|
|
|
3142
3051
|
const conditions = [];
|
|
3143
3052
|
for (const [field, filterParam] of Object.entries(filter)) {
|
|
3144
3053
|
if (!filterParam) continue;
|
|
3145
|
-
const [op, value] = filterParam;
|
|
3146
3054
|
let fieldColumn = table[field];
|
|
3147
3055
|
if (!fieldColumn) {
|
|
3148
3056
|
const relationKey = `${field}_id`;
|
|
@@ -3154,13 +3062,39 @@
|
|
|
3154
3062
|
console.warn(`Filtering by field '${field}', but it does not exist in table for collection '${collectionPath}'`);
|
|
3155
3063
|
continue;
|
|
3156
3064
|
}
|
|
3157
|
-
const
|
|
3158
|
-
|
|
3159
|
-
|
|
3065
|
+
const paramsList = Array.isArray(filterParam) && filterParam.length > 0 && Array.isArray(filterParam[0]) ? filterParam : [filterParam];
|
|
3066
|
+
for (const [op, value] of paramsList) {
|
|
3067
|
+
const condition = this.buildSingleFilterCondition(fieldColumn, op, value);
|
|
3068
|
+
if (condition) {
|
|
3069
|
+
conditions.push(condition);
|
|
3070
|
+
}
|
|
3160
3071
|
}
|
|
3161
3072
|
}
|
|
3162
3073
|
return conditions;
|
|
3163
3074
|
}
|
|
3075
|
+
/**
|
|
3076
|
+
* Build logical conditions recursively from LogicalCondition or FilterCondition
|
|
3077
|
+
*/
|
|
3078
|
+
static buildLogicalConditions(cond, table, collectionPath) {
|
|
3079
|
+
if ("type" in cond) {
|
|
3080
|
+
const subSQLs = cond.conditions.map((c) => this.buildLogicalConditions(c, table, collectionPath)).filter((sql2) => sql2 !== null);
|
|
3081
|
+
if (subSQLs.length === 0) return null;
|
|
3082
|
+
return (cond.type === "or" ? drizzleOrm.or(...subSQLs) : drizzleOrm.and(...subSQLs)) ?? null;
|
|
3083
|
+
} else {
|
|
3084
|
+
let fieldColumn = table[cond.column];
|
|
3085
|
+
if (!fieldColumn) {
|
|
3086
|
+
const relationKey = `${cond.column}_id`;
|
|
3087
|
+
if (relationKey in table) {
|
|
3088
|
+
fieldColumn = table[relationKey];
|
|
3089
|
+
}
|
|
3090
|
+
}
|
|
3091
|
+
if (!fieldColumn) {
|
|
3092
|
+
console.warn(`Filtering by field '${cond.column}', but it does not exist in table for collection '${collectionPath}'`);
|
|
3093
|
+
return null;
|
|
3094
|
+
}
|
|
3095
|
+
return this.buildSingleFilterCondition(fieldColumn, cond.operator, cond.value);
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3164
3098
|
/**
|
|
3165
3099
|
* Build a single filter condition for a specific operator and value
|
|
3166
3100
|
*/
|
|
@@ -5557,6 +5491,10 @@
|
|
|
5557
5491
|
const filterConditions = this.buildFilterConditions(options.filter, table, collectionPath);
|
|
5558
5492
|
if (filterConditions.length > 0) allConditions.push(...filterConditions);
|
|
5559
5493
|
}
|
|
5494
|
+
if (options.logical) {
|
|
5495
|
+
const logicalCondition = DrizzleConditionBuilder.buildLogicalConditions(options.logical, table, collectionPath);
|
|
5496
|
+
if (logicalCondition) allConditions.push(logicalCondition);
|
|
5497
|
+
}
|
|
5560
5498
|
if (options.startAfter) {
|
|
5561
5499
|
const cursorConditions = this.buildCursorConditions(table, idField, idInfo, options, collectionPath);
|
|
5562
5500
|
if (cursorConditions.length > 0) allConditions.push(...cursorConditions);
|
|
@@ -5728,6 +5666,10 @@
|
|
|
5728
5666
|
const filterConditions = this.buildFilterConditions(options.filter, table, collectionPath);
|
|
5729
5667
|
if (filterConditions.length > 0) allConditions.push(...filterConditions);
|
|
5730
5668
|
}
|
|
5669
|
+
if (options.logical) {
|
|
5670
|
+
const logicalCondition = DrizzleConditionBuilder.buildLogicalConditions(options.logical, table, collectionPath);
|
|
5671
|
+
if (logicalCondition) allConditions.push(logicalCondition);
|
|
5672
|
+
}
|
|
5731
5673
|
if (vectorMeta?.filter) {
|
|
5732
5674
|
allConditions.push(vectorMeta.filter);
|
|
5733
5675
|
}
|
|
@@ -6313,6 +6255,14 @@
|
|
|
6313
6255
|
const parsedId = parsedIdObj[idInfo.fieldName];
|
|
6314
6256
|
await this.db.delete(table).where(drizzleOrm.eq(idField, parsedId));
|
|
6315
6257
|
}
|
|
6258
|
+
/**
|
|
6259
|
+
* Delete all entities from a collection
|
|
6260
|
+
*/
|
|
6261
|
+
async deleteAll(collectionPath, _databaseId) {
|
|
6262
|
+
const collection = getCollectionByPath(collectionPath, this.registry);
|
|
6263
|
+
const table = getTableForCollection(collection, this.registry);
|
|
6264
|
+
await this.db.delete(table);
|
|
6265
|
+
}
|
|
6316
6266
|
/**
|
|
6317
6267
|
* Save an entity (create or update)
|
|
6318
6268
|
*/
|
|
@@ -6644,6 +6594,12 @@
|
|
|
6644
6594
|
async deleteEntity(collectionPath, entityId, databaseId) {
|
|
6645
6595
|
return this.persistService.deleteEntity(collectionPath, entityId, databaseId);
|
|
6646
6596
|
}
|
|
6597
|
+
/**
|
|
6598
|
+
* Delete all entities from a collection
|
|
6599
|
+
*/
|
|
6600
|
+
async deleteAll(collectionPath, databaseId) {
|
|
6601
|
+
return this.persistService.deleteAll(collectionPath, databaseId);
|
|
6602
|
+
}
|
|
6647
6603
|
/**
|
|
6648
6604
|
* Execute raw SQL
|
|
6649
6605
|
*/
|
|
@@ -7344,6 +7300,10 @@
|
|
|
7344
7300
|
await this.realtimeService.notifyEntityUpdate(entity.path, entity.id.toString(), null, entity.databaseId || resolvedCollection?.databaseId);
|
|
7345
7301
|
}
|
|
7346
7302
|
}
|
|
7303
|
+
async deleteAll(path2) {
|
|
7304
|
+
await this.entityService.deleteAll(path2);
|
|
7305
|
+
await this.realtimeService.notifyEntityUpdate(path2, "*", null);
|
|
7306
|
+
}
|
|
7347
7307
|
async checkUniqueField(path2, name, value, entityId, collection) {
|
|
7348
7308
|
return this.entityService.checkUniqueField(path2, name, value, entityId, collection?.databaseId);
|
|
7349
7309
|
}
|
|
@@ -7613,11 +7573,11 @@
|
|
|
7613
7573
|
console.warn("[DataDriver] User ID (uid) is missing for authenticated delegate. Using 'anonymous'. User object:", this.user);
|
|
7614
7574
|
userId = "anonymous";
|
|
7615
7575
|
}
|
|
7616
|
-
const
|
|
7576
|
+
const userRoles = this.user?.roles ?? [];
|
|
7617
7577
|
if (!this.user?.roles) {
|
|
7618
7578
|
console.warn("[DataDriver] User roles are missing for authenticated delegate. Using empty array. User object:", this.user);
|
|
7619
7579
|
}
|
|
7620
|
-
const normalizedRoles =
|
|
7580
|
+
const normalizedRoles = userRoles.map((r) => typeof r === "string" ? r : r?.id ?? String(r));
|
|
7621
7581
|
const rolesString = normalizedRoles.join(",");
|
|
7622
7582
|
await tx.execute(drizzleOrm.sql`
|
|
7623
7583
|
SELECT
|
|
@@ -7625,7 +7585,7 @@
|
|
|
7625
7585
|
set_config('app.user_roles', ${rolesString}, true),
|
|
7626
7586
|
set_config('app.jwt', ${JSON.stringify({
|
|
7627
7587
|
sub: userId,
|
|
7628
|
-
roles:
|
|
7588
|
+
roles: userRoles
|
|
7629
7589
|
})}, true)
|
|
7630
7590
|
`);
|
|
7631
7591
|
const txEntityService = new EntityService(tx, this.delegate.registry);
|
|
@@ -7680,6 +7640,9 @@
|
|
|
7680
7640
|
async deleteEntity(props) {
|
|
7681
7641
|
return this.withTransaction((delegate) => delegate.deleteEntity(props));
|
|
7682
7642
|
}
|
|
7643
|
+
async deleteAll(path2) {
|
|
7644
|
+
return this.delegate.deleteAll(path2);
|
|
7645
|
+
}
|
|
7683
7646
|
async checkUniqueField(path2, name, value, entityId, collection) {
|
|
7684
7647
|
return this.withTransaction((delegate) => delegate.checkUniqueField(path2, name, value, entityId, collection));
|
|
7685
7648
|
}
|
|
@@ -7759,11 +7722,10 @@
|
|
|
7759
7722
|
this.pools.clear();
|
|
7760
7723
|
}
|
|
7761
7724
|
}
|
|
7762
|
-
function createAuthSchema(
|
|
7763
|
-
const rolesSchema = rolesSchemaName === "public" ? null : pgCore.pgSchema(rolesSchemaName);
|
|
7725
|
+
function createAuthSchema(usersSchemaName = "rebase") {
|
|
7764
7726
|
const usersSchema2 = usersSchemaName === "public" ? null : pgCore.pgSchema(usersSchemaName);
|
|
7765
|
-
const
|
|
7766
|
-
const usersTableCreator =
|
|
7727
|
+
const tableCreator = usersSchema2 ? usersSchema2.table.bind(usersSchema2) : pgCore.pgTable;
|
|
7728
|
+
const usersTableCreator = tableCreator;
|
|
7767
7729
|
const users2 = usersTableCreator("users", {
|
|
7768
7730
|
id: pgCore.uuid("id").defaultRandom().primaryKey(),
|
|
7769
7731
|
email: pgCore.varchar("email", {
|
|
@@ -7785,37 +7747,12 @@
|
|
|
7785
7747
|
}),
|
|
7786
7748
|
emailVerificationSentAt: pgCore.timestamp("email_verification_sent_at"),
|
|
7787
7749
|
isAnonymous: pgCore.boolean("is_anonymous").default(false).notNull(),
|
|
7750
|
+
roles: pgCore.text("roles").array().default([]).notNull(),
|
|
7788
7751
|
metadata: pgCore.jsonb("metadata").$type().default({}).notNull(),
|
|
7789
7752
|
createdAt: pgCore.timestamp("created_at").defaultNow().notNull(),
|
|
7790
7753
|
updatedAt: pgCore.timestamp("updated_at").defaultNow().notNull()
|
|
7791
7754
|
});
|
|
7792
|
-
const
|
|
7793
|
-
id: pgCore.varchar("id", {
|
|
7794
|
-
length: 50
|
|
7795
|
-
}).primaryKey(),
|
|
7796
|
-
// 'admin', 'editor', 'viewer'
|
|
7797
|
-
name: pgCore.varchar("name", {
|
|
7798
|
-
length: 100
|
|
7799
|
-
}).notNull(),
|
|
7800
|
-
isAdmin: pgCore.boolean("is_admin").default(false).notNull(),
|
|
7801
|
-
defaultPermissions: pgCore.jsonb("default_permissions").$type(),
|
|
7802
|
-
collectionPermissions: pgCore.jsonb("collection_permissions").$type()
|
|
7803
|
-
});
|
|
7804
|
-
const userRoles2 = rolesTableCreator("user_roles", {
|
|
7805
|
-
userId: pgCore.uuid("user_id").notNull().references(() => users2.id, {
|
|
7806
|
-
onDelete: "cascade"
|
|
7807
|
-
}),
|
|
7808
|
-
roleId: pgCore.varchar("role_id", {
|
|
7809
|
-
length: 50
|
|
7810
|
-
}).notNull().references(() => roles2.id, {
|
|
7811
|
-
onDelete: "cascade"
|
|
7812
|
-
})
|
|
7813
|
-
}, (table) => ({
|
|
7814
|
-
pk: pgCore.primaryKey({
|
|
7815
|
-
columns: [table.userId, table.roleId]
|
|
7816
|
-
})
|
|
7817
|
-
}));
|
|
7818
|
-
const refreshTokens2 = rolesTableCreator("refresh_tokens", {
|
|
7755
|
+
const refreshTokens2 = tableCreator("refresh_tokens", {
|
|
7819
7756
|
id: pgCore.uuid("id").defaultRandom().primaryKey(),
|
|
7820
7757
|
userId: pgCore.uuid("user_id").notNull().references(() => users2.id, {
|
|
7821
7758
|
onDelete: "cascade"
|
|
@@ -7834,7 +7771,7 @@
|
|
|
7834
7771
|
}, (table) => ({
|
|
7835
7772
|
uniqueDeviceSession: pgCore.unique("unique_device_session").on(table.userId, table.userAgent, table.ipAddress)
|
|
7836
7773
|
}));
|
|
7837
|
-
const passwordResetTokens2 =
|
|
7774
|
+
const passwordResetTokens2 = tableCreator("password_reset_tokens", {
|
|
7838
7775
|
id: pgCore.uuid("id").defaultRandom().primaryKey(),
|
|
7839
7776
|
userId: pgCore.uuid("user_id").notNull().references(() => users2.id, {
|
|
7840
7777
|
onDelete: "cascade"
|
|
@@ -7846,14 +7783,14 @@
|
|
|
7846
7783
|
usedAt: pgCore.timestamp("used_at"),
|
|
7847
7784
|
createdAt: pgCore.timestamp("created_at").defaultNow().notNull()
|
|
7848
7785
|
});
|
|
7849
|
-
const appConfig2 =
|
|
7786
|
+
const appConfig2 = tableCreator("app_config", {
|
|
7850
7787
|
key: pgCore.varchar("key", {
|
|
7851
7788
|
length: 100
|
|
7852
7789
|
}).primaryKey(),
|
|
7853
7790
|
value: pgCore.jsonb("value").notNull(),
|
|
7854
7791
|
updatedAt: pgCore.timestamp("updated_at").defaultNow().notNull()
|
|
7855
7792
|
});
|
|
7856
|
-
const userIdentities2 =
|
|
7793
|
+
const userIdentities2 = tableCreator("user_identities", {
|
|
7857
7794
|
id: pgCore.uuid("id").defaultRandom().primaryKey(),
|
|
7858
7795
|
userId: pgCore.uuid("user_id").notNull().references(() => users2.id, {
|
|
7859
7796
|
onDelete: "cascade"
|
|
@@ -7871,7 +7808,7 @@
|
|
|
7871
7808
|
}, (table) => ({
|
|
7872
7809
|
uniqueProviderId: pgCore.unique("unique_provider_id").on(table.provider, table.providerId)
|
|
7873
7810
|
}));
|
|
7874
|
-
const mfaFactors2 =
|
|
7811
|
+
const mfaFactors2 = tableCreator("mfa_factors", {
|
|
7875
7812
|
id: pgCore.uuid("id").defaultRandom().primaryKey(),
|
|
7876
7813
|
userId: pgCore.uuid("user_id").notNull().references(() => users2.id, {
|
|
7877
7814
|
onDelete: "cascade"
|
|
@@ -7890,7 +7827,7 @@
|
|
|
7890
7827
|
createdAt: pgCore.timestamp("created_at").defaultNow().notNull(),
|
|
7891
7828
|
updatedAt: pgCore.timestamp("updated_at").defaultNow().notNull()
|
|
7892
7829
|
});
|
|
7893
|
-
const mfaChallenges2 =
|
|
7830
|
+
const mfaChallenges2 = tableCreator("mfa_challenges", {
|
|
7894
7831
|
id: pgCore.uuid("id").defaultRandom().primaryKey(),
|
|
7895
7832
|
factorId: pgCore.uuid("factor_id").notNull().references(() => mfaFactors2.id, {
|
|
7896
7833
|
onDelete: "cascade"
|
|
@@ -7902,7 +7839,7 @@
|
|
|
7902
7839
|
}),
|
|
7903
7840
|
expiresAt: pgCore.timestamp("expires_at").notNull()
|
|
7904
7841
|
});
|
|
7905
|
-
const recoveryCodes2 =
|
|
7842
|
+
const recoveryCodes2 = tableCreator("recovery_codes", {
|
|
7906
7843
|
id: pgCore.uuid("id").defaultRandom().primaryKey(),
|
|
7907
7844
|
userId: pgCore.uuid("user_id").notNull().references(() => users2.id, {
|
|
7908
7845
|
onDelete: "cascade"
|
|
@@ -7914,11 +7851,8 @@
|
|
|
7914
7851
|
createdAt: pgCore.timestamp("created_at").defaultNow().notNull()
|
|
7915
7852
|
});
|
|
7916
7853
|
return {
|
|
7917
|
-
rolesSchema,
|
|
7918
7854
|
usersSchema: usersSchema2,
|
|
7919
7855
|
users: users2,
|
|
7920
|
-
roles: roles2,
|
|
7921
|
-
userRoles: userRoles2,
|
|
7922
7856
|
refreshTokens: refreshTokens2,
|
|
7923
7857
|
passwordResetTokens: passwordResetTokens2,
|
|
7924
7858
|
appConfig: appConfig2,
|
|
@@ -7928,12 +7862,9 @@
|
|
|
7928
7862
|
recoveryCodes: recoveryCodes2
|
|
7929
7863
|
};
|
|
7930
7864
|
}
|
|
7931
|
-
const defaultAuthSchema = createAuthSchema("rebase"
|
|
7932
|
-
const rebaseSchema = defaultAuthSchema.rolesSchema;
|
|
7865
|
+
const defaultAuthSchema = createAuthSchema("rebase");
|
|
7933
7866
|
const usersSchema = defaultAuthSchema.usersSchema;
|
|
7934
7867
|
const users = defaultAuthSchema.users;
|
|
7935
|
-
const roles = defaultAuthSchema.roles;
|
|
7936
|
-
const userRoles = defaultAuthSchema.userRoles;
|
|
7937
7868
|
const refreshTokens = defaultAuthSchema.refreshTokens;
|
|
7938
7869
|
const passwordResetTokens = defaultAuthSchema.passwordResetTokens;
|
|
7939
7870
|
const appConfig = defaultAuthSchema.appConfig;
|
|
@@ -7944,30 +7875,12 @@
|
|
|
7944
7875
|
const usersRelations = drizzleOrm.relations(users, ({
|
|
7945
7876
|
many
|
|
7946
7877
|
}) => ({
|
|
7947
|
-
userRoles: many(userRoles),
|
|
7948
7878
|
refreshTokens: many(refreshTokens),
|
|
7949
7879
|
passwordResetTokens: many(passwordResetTokens),
|
|
7950
7880
|
userIdentities: many(userIdentities),
|
|
7951
7881
|
mfaFactors: many(mfaFactors),
|
|
7952
7882
|
recoveryCodes: many(recoveryCodes)
|
|
7953
7883
|
}));
|
|
7954
|
-
const rolesRelations = drizzleOrm.relations(roles, ({
|
|
7955
|
-
many
|
|
7956
|
-
}) => ({
|
|
7957
|
-
userRoles: many(userRoles)
|
|
7958
|
-
}));
|
|
7959
|
-
const userRolesRelations = drizzleOrm.relations(userRoles, ({
|
|
7960
|
-
one
|
|
7961
|
-
}) => ({
|
|
7962
|
-
user: one(users, {
|
|
7963
|
-
fields: [userRoles.userId],
|
|
7964
|
-
references: [users.id]
|
|
7965
|
-
}),
|
|
7966
|
-
role: one(roles, {
|
|
7967
|
-
fields: [userRoles.roleId],
|
|
7968
|
-
references: [roles.id]
|
|
7969
|
-
})
|
|
7970
|
-
}));
|
|
7971
7884
|
const refreshTokensRelations = drizzleOrm.relations(refreshTokens, ({
|
|
7972
7885
|
one
|
|
7973
7886
|
}) => ({
|
|
@@ -8074,6 +7987,8 @@
|
|
|
8074
7987
|
columnDefinition = `${enumName}("${colName}")`;
|
|
8075
7988
|
} else if ("isId" in stringProp && stringProp.isId === "uuid") {
|
|
8076
7989
|
columnDefinition = `uuid("${colName}")`;
|
|
7990
|
+
} else if (stringProp.columnType === "uuid") {
|
|
7991
|
+
columnDefinition = `uuid("${colName}")`;
|
|
8077
7992
|
} else if (stringProp.columnType === "text") {
|
|
8078
7993
|
columnDefinition = `text("${colName}")`;
|
|
8079
7994
|
} else if (stringProp.columnType === "char") {
|
|
@@ -8141,11 +8056,38 @@
|
|
|
8141
8056
|
}
|
|
8142
8057
|
break;
|
|
8143
8058
|
}
|
|
8144
|
-
case "map":
|
|
8059
|
+
case "map": {
|
|
8060
|
+
const mapProp = prop;
|
|
8061
|
+
if (mapProp.columnType === "json") {
|
|
8062
|
+
columnDefinition = `json("${colName}")`;
|
|
8063
|
+
} else {
|
|
8064
|
+
columnDefinition = `jsonb("${colName}")`;
|
|
8065
|
+
}
|
|
8066
|
+
break;
|
|
8067
|
+
}
|
|
8145
8068
|
case "array": {
|
|
8146
|
-
const
|
|
8147
|
-
|
|
8069
|
+
const arrayProp = prop;
|
|
8070
|
+
let colType = arrayProp.columnType;
|
|
8071
|
+
if (!colType && arrayProp.of && !Array.isArray(arrayProp.of)) {
|
|
8072
|
+
const ofProp = arrayProp.of;
|
|
8073
|
+
if (ofProp.type === "string") {
|
|
8074
|
+
colType = "text[]";
|
|
8075
|
+
} else if (ofProp.type === "number") {
|
|
8076
|
+
colType = ofProp.validation?.integer ? "integer[]" : "numeric[]";
|
|
8077
|
+
} else if (ofProp.type === "boolean") {
|
|
8078
|
+
colType = "boolean[]";
|
|
8079
|
+
}
|
|
8080
|
+
}
|
|
8081
|
+
if (colType === "json") {
|
|
8148
8082
|
columnDefinition = `json("${colName}")`;
|
|
8083
|
+
} else if (colType === "text[]") {
|
|
8084
|
+
columnDefinition = `text("${colName}").array()`;
|
|
8085
|
+
} else if (colType === "integer[]") {
|
|
8086
|
+
columnDefinition = `integer("${colName}").array()`;
|
|
8087
|
+
} else if (colType === "boolean[]") {
|
|
8088
|
+
columnDefinition = `boolean("${colName}").array()`;
|
|
8089
|
+
} else if (colType === "numeric[]") {
|
|
8090
|
+
columnDefinition = `numeric("${colName}").array()`;
|
|
8149
8091
|
} else {
|
|
8150
8092
|
columnDefinition = `jsonb("${colName}")`;
|
|
8151
8093
|
}
|
|
@@ -8229,8 +8171,8 @@
|
|
|
8229
8171
|
const resolved = expression.replace(/\{(\w+)\}/g, (_, col) => col);
|
|
8230
8172
|
return `sql\`${resolved}\``;
|
|
8231
8173
|
};
|
|
8232
|
-
const wrapWithRoleCheck = (clause,
|
|
8233
|
-
const rolesArrayString = `ARRAY[${
|
|
8174
|
+
const wrapWithRoleCheck = (clause, roles) => {
|
|
8175
|
+
const rolesArrayString = `ARRAY[${roles.map((r) => `'${r}'`).join(",")}]`;
|
|
8234
8176
|
const roleCondition = `string_to_array(auth.roles(), ',') @> ${rolesArrayString}`;
|
|
8235
8177
|
return `sql\`(${unwrapSql(clause)}) AND (${roleCondition})\``;
|
|
8236
8178
|
};
|
|
@@ -8283,22 +8225,22 @@
|
|
|
8283
8225
|
};
|
|
8284
8226
|
const generateSinglePolicyCode = (collection, rule, operation, policyName) => {
|
|
8285
8227
|
const mode = rule.mode ?? "permissive";
|
|
8286
|
-
const
|
|
8228
|
+
const roles = rule.roles ? [...rule.roles].sort() : void 0;
|
|
8287
8229
|
const needsUsing = operation !== "insert";
|
|
8288
8230
|
const needsWithCheck = operation !== "select" && operation !== "delete";
|
|
8289
8231
|
let usingClause = needsUsing ? buildUsingClause(rule, collection) : null;
|
|
8290
8232
|
let withCheckClause = needsWithCheck ? buildWithCheckClause(rule, collection) : null;
|
|
8291
|
-
if (
|
|
8233
|
+
if (roles && roles.length > 0) {
|
|
8292
8234
|
if (usingClause) {
|
|
8293
|
-
usingClause = wrapWithRoleCheck(usingClause,
|
|
8235
|
+
usingClause = wrapWithRoleCheck(usingClause, roles);
|
|
8294
8236
|
} else if (needsUsing) {
|
|
8295
|
-
const rolesArrayString = `ARRAY[${
|
|
8237
|
+
const rolesArrayString = `ARRAY[${roles.map((r) => `'${r}'`).join(",")}]`;
|
|
8296
8238
|
usingClause = `sql\`string_to_array(auth.roles(), ',') @> ${rolesArrayString}\``;
|
|
8297
8239
|
}
|
|
8298
8240
|
if (withCheckClause) {
|
|
8299
|
-
withCheckClause = wrapWithRoleCheck(withCheckClause,
|
|
8241
|
+
withCheckClause = wrapWithRoleCheck(withCheckClause, roles);
|
|
8300
8242
|
} else if (needsWithCheck) {
|
|
8301
|
-
const rolesArrayString = `ARRAY[${
|
|
8243
|
+
const rolesArrayString = `ARRAY[${roles.map((r) => `'${r}'`).join(",")}]`;
|
|
8302
8244
|
withCheckClause = `sql\`string_to_array(auth.roles(), ',') @> ${rolesArrayString}\``;
|
|
8303
8245
|
}
|
|
8304
8246
|
}
|
|
@@ -8686,7 +8628,6 @@ ${tableRelations.join(",\n")}
|
|
|
8686
8628
|
if (!collections || !Array.isArray(collections)) {
|
|
8687
8629
|
collections = [];
|
|
8688
8630
|
}
|
|
8689
|
-
collections = Array.from(new Map([defaultUsersCollection, ...collections].map((c) => [c.slug, c])).values());
|
|
8690
8631
|
collections.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
8691
8632
|
const schemaContent = await generateSchema(collections);
|
|
8692
8633
|
if (outputPath) {
|
|
@@ -10032,15 +9973,15 @@ ${tableRelations.join(",\n")}
|
|
|
10032
9973
|
wsDebug("👤 [WebSocket Server] Processing FETCH_ROLES request");
|
|
10033
9974
|
const delegate = await getScopedDelegate();
|
|
10034
9975
|
const admin = delegate.admin;
|
|
10035
|
-
let
|
|
9976
|
+
let roles = [];
|
|
10036
9977
|
if (isSQLAdmin(admin) && admin.fetchAvailableRoles) {
|
|
10037
|
-
|
|
9978
|
+
roles = await admin.fetchAvailableRoles();
|
|
10038
9979
|
}
|
|
10039
|
-
wsDebug(`👤 [WebSocket Server] Fetched ${
|
|
9980
|
+
wsDebug(`👤 [WebSocket Server] Fetched ${roles.length} roles.`);
|
|
10040
9981
|
const response = {
|
|
10041
9982
|
type: "FETCH_ROLES_SUCCESS",
|
|
10042
9983
|
payload: {
|
|
10043
|
-
roles
|
|
9984
|
+
roles
|
|
10044
9985
|
},
|
|
10045
9986
|
requestId
|
|
10046
9987
|
};
|
|
@@ -10294,85 +10235,35 @@ ${tableRelations.join(",\n")}
|
|
|
10294
10235
|
return collection.relations.map((r) => r.relationName || r.localKey || "").filter(Boolean);
|
|
10295
10236
|
}
|
|
10296
10237
|
}
|
|
10297
|
-
|
|
10298
|
-
id: "admin",
|
|
10299
|
-
name: "Admin",
|
|
10300
|
-
is_admin: true,
|
|
10301
|
-
default_permissions: {
|
|
10302
|
-
read: true,
|
|
10303
|
-
create: true,
|
|
10304
|
-
edit: true,
|
|
10305
|
-
delete: true
|
|
10306
|
-
}
|
|
10307
|
-
}, {
|
|
10308
|
-
id: "editor",
|
|
10309
|
-
name: "Editor",
|
|
10310
|
-
is_admin: false,
|
|
10311
|
-
default_permissions: {
|
|
10312
|
-
read: true,
|
|
10313
|
-
create: true,
|
|
10314
|
-
edit: true,
|
|
10315
|
-
delete: true
|
|
10316
|
-
}
|
|
10317
|
-
}, {
|
|
10318
|
-
id: "viewer",
|
|
10319
|
-
name: "Viewer",
|
|
10320
|
-
is_admin: false,
|
|
10321
|
-
default_permissions: {
|
|
10322
|
-
read: true,
|
|
10323
|
-
create: false,
|
|
10324
|
-
edit: false,
|
|
10325
|
-
delete: false
|
|
10326
|
-
}
|
|
10327
|
-
}];
|
|
10328
|
-
async function ensureAuthTablesExist(db, registry) {
|
|
10238
|
+
async function ensureAuthTablesExist(db, collection) {
|
|
10329
10239
|
serverCore.logger.info("🔍 Checking auth tables...");
|
|
10330
10240
|
try {
|
|
10331
|
-
let usersTableName = '"users"';
|
|
10241
|
+
let usersTableName = '"rebase"."users"';
|
|
10332
10242
|
let userIdType = "TEXT";
|
|
10333
|
-
let usersSchema2 = "
|
|
10334
|
-
if (
|
|
10335
|
-
const
|
|
10336
|
-
|
|
10337
|
-
|
|
10338
|
-
|
|
10339
|
-
|
|
10340
|
-
|
|
10341
|
-
|
|
10342
|
-
|
|
10343
|
-
|
|
10344
|
-
|
|
10345
|
-
const columnType = meta.columnType;
|
|
10346
|
-
if (columnType === "PgUUID") {
|
|
10347
|
-
userIdType = "UUID";
|
|
10348
|
-
} else if (columnType === "PgSerial" || columnType === "PgInteger") {
|
|
10349
|
-
userIdType = "INTEGER";
|
|
10350
|
-
} else if (columnType === "PgBigInt" || columnType === "PgBigSerial") {
|
|
10351
|
-
userIdType = "BIGINT";
|
|
10352
|
-
}
|
|
10243
|
+
let usersSchema2 = "rebase";
|
|
10244
|
+
if (collection) {
|
|
10245
|
+
const rawTable = "table" in collection && typeof collection.table === "string" ? collection.table : collection.slug;
|
|
10246
|
+
usersSchema2 = "schema" in collection && typeof collection.schema === "string" ? collection.schema : "public";
|
|
10247
|
+
usersTableName = usersSchema2 === "public" ? `"${rawTable}"` : `"${usersSchema2}"."${rawTable}"`;
|
|
10248
|
+
const idProp = collection.properties?.id;
|
|
10249
|
+
if (idProp) {
|
|
10250
|
+
const isId = "isId" in idProp ? idProp.isId : void 0;
|
|
10251
|
+
if (isId === "uuid") {
|
|
10252
|
+
userIdType = "UUID";
|
|
10253
|
+
} else if (isId === "autoincrement") {
|
|
10254
|
+
userIdType = "INTEGER";
|
|
10353
10255
|
}
|
|
10354
10256
|
}
|
|
10355
10257
|
}
|
|
10356
|
-
let rolesSchema = "rebase";
|
|
10357
|
-
if (registry) {
|
|
10358
|
-
const rolesTable = registry.getTable("roles");
|
|
10359
|
-
if (rolesTable) {
|
|
10360
|
-
rolesSchema = pgCore.getTableConfig(rolesTable).schema || "public";
|
|
10361
|
-
}
|
|
10362
|
-
}
|
|
10363
10258
|
if (usersSchema2 !== "public") {
|
|
10364
10259
|
await db.execute(drizzleOrm.sql`CREATE SCHEMA IF NOT EXISTS ${drizzleOrm.sql.raw(usersSchema2)}`);
|
|
10365
10260
|
}
|
|
10366
|
-
if (rolesSchema !== "public" && rolesSchema !== usersSchema2) {
|
|
10367
|
-
await db.execute(drizzleOrm.sql`CREATE SCHEMA IF NOT EXISTS ${drizzleOrm.sql.raw(rolesSchema)}`);
|
|
10368
|
-
}
|
|
10369
10261
|
await db.execute(drizzleOrm.sql`CREATE SCHEMA IF NOT EXISTS rebase`);
|
|
10370
|
-
const
|
|
10371
|
-
const
|
|
10372
|
-
const
|
|
10373
|
-
const
|
|
10374
|
-
const
|
|
10375
|
-
const appConfigTableName = `"${rolesSchema}"."app_config"`;
|
|
10262
|
+
const authSchema = usersSchema2 === "public" ? "rebase" : usersSchema2;
|
|
10263
|
+
const userIdentitiesTable = `"${authSchema}"."user_identities"`;
|
|
10264
|
+
const refreshTokensTableName = `"${authSchema}"."refresh_tokens"`;
|
|
10265
|
+
const passwordResetTokensTableName = `"${authSchema}"."password_reset_tokens"`;
|
|
10266
|
+
const appConfigTableName = `"${authSchema}"."app_config"`;
|
|
10376
10267
|
await db.execute(drizzleOrm.sql`
|
|
10377
10268
|
CREATE TABLE IF NOT EXISTS ${drizzleOrm.sql.raw(userIdentitiesTable)} (
|
|
10378
10269
|
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
@@ -10389,27 +10280,6 @@ ${tableRelations.join(",\n")}
|
|
|
10389
10280
|
CREATE INDEX IF NOT EXISTS idx_user_identities_user
|
|
10390
10281
|
ON ${drizzleOrm.sql.raw(userIdentitiesTable)}(user_id)
|
|
10391
10282
|
`);
|
|
10392
|
-
await db.execute(drizzleOrm.sql`
|
|
10393
|
-
CREATE TABLE IF NOT EXISTS ${drizzleOrm.sql.raw(rolesTableName)} (
|
|
10394
|
-
id TEXT PRIMARY KEY,
|
|
10395
|
-
name TEXT NOT NULL,
|
|
10396
|
-
is_admin BOOLEAN DEFAULT FALSE,
|
|
10397
|
-
default_permissions JSONB,
|
|
10398
|
-
collection_permissions JSONB,
|
|
10399
|
-
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
|
10400
|
-
)
|
|
10401
|
-
`);
|
|
10402
|
-
await db.execute(drizzleOrm.sql`
|
|
10403
|
-
CREATE TABLE IF NOT EXISTS ${drizzleOrm.sql.raw(userRolesTableName)} (
|
|
10404
|
-
user_id ${drizzleOrm.sql.raw(userIdType)} NOT NULL REFERENCES ${drizzleOrm.sql.raw(usersTableName)}(id) ON DELETE CASCADE,
|
|
10405
|
-
role_id TEXT NOT NULL REFERENCES ${drizzleOrm.sql.raw(rolesTableName)}(id) ON DELETE CASCADE,
|
|
10406
|
-
PRIMARY KEY (user_id, role_id)
|
|
10407
|
-
)
|
|
10408
|
-
`);
|
|
10409
|
-
await db.execute(drizzleOrm.sql`
|
|
10410
|
-
CREATE INDEX IF NOT EXISTS idx_user_roles_user
|
|
10411
|
-
ON ${drizzleOrm.sql.raw(userRolesTableName)}(user_id)
|
|
10412
|
-
`);
|
|
10413
10283
|
await db.execute(drizzleOrm.sql`
|
|
10414
10284
|
CREATE TABLE IF NOT EXISTS ${drizzleOrm.sql.raw(refreshTokensTableName)} (
|
|
10415
10285
|
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
@@ -10477,14 +10347,43 @@ ${tableRelations.join(",\n")}
|
|
|
10477
10347
|
$$ LANGUAGE sql STABLE
|
|
10478
10348
|
`);
|
|
10479
10349
|
});
|
|
10480
|
-
await seedDefaultRoles(db, rolesTableName);
|
|
10481
10350
|
await db.execute(drizzleOrm.sql`
|
|
10482
10351
|
ALTER TABLE ${drizzleOrm.sql.raw(usersTableName)}
|
|
10483
10352
|
ADD COLUMN IF NOT EXISTS is_anonymous BOOLEAN DEFAULT FALSE
|
|
10484
10353
|
`);
|
|
10485
|
-
|
|
10486
|
-
|
|
10487
|
-
|
|
10354
|
+
await db.execute(drizzleOrm.sql`
|
|
10355
|
+
ALTER TABLE ${drizzleOrm.sql.raw(usersTableName)}
|
|
10356
|
+
ADD COLUMN IF NOT EXISTS roles TEXT[] DEFAULT '{}' NOT NULL
|
|
10357
|
+
`);
|
|
10358
|
+
try {
|
|
10359
|
+
const legacyCheck = await db.execute(drizzleOrm.sql`
|
|
10360
|
+
SELECT EXISTS (
|
|
10361
|
+
SELECT 1 FROM information_schema.tables
|
|
10362
|
+
WHERE table_schema = 'rebase' AND table_name = 'user_roles'
|
|
10363
|
+
) AS has_user_roles
|
|
10364
|
+
`);
|
|
10365
|
+
const hasLegacyTables = legacyCheck.rows[0].has_user_roles;
|
|
10366
|
+
if (hasLegacyTables) {
|
|
10367
|
+
serverCore.logger.info("🔄 Migrating roles from legacy user_roles table...");
|
|
10368
|
+
await db.execute(drizzleOrm.sql`
|
|
10369
|
+
UPDATE ${drizzleOrm.sql.raw(usersTableName)} u
|
|
10370
|
+
SET roles = COALESCE((
|
|
10371
|
+
SELECT array_agg(ur.role_id)
|
|
10372
|
+
FROM "rebase"."user_roles" ur
|
|
10373
|
+
WHERE ur.user_id = u.id
|
|
10374
|
+
), '{}')
|
|
10375
|
+
WHERE u.roles = '{}' OR u.roles IS NULL
|
|
10376
|
+
`);
|
|
10377
|
+
await db.execute(drizzleOrm.sql`DROP TABLE IF EXISTS "rebase"."user_roles" CASCADE`);
|
|
10378
|
+
await db.execute(drizzleOrm.sql`DROP TABLE IF EXISTS "rebase"."roles" CASCADE`);
|
|
10379
|
+
serverCore.logger.info("✅ Legacy roles tables migrated and dropped");
|
|
10380
|
+
}
|
|
10381
|
+
} catch (migrationError) {
|
|
10382
|
+
serverCore.logger.warn(`⚠️ Legacy roles migration skipped: ${migrationError instanceof Error ? migrationError.message : String(migrationError)}`);
|
|
10383
|
+
}
|
|
10384
|
+
const mfaFactorsTableName = `"${authSchema}"."mfa_factors"`;
|
|
10385
|
+
const mfaChallengesTableName = `"${authSchema}"."mfa_challenges"`;
|
|
10386
|
+
const recoveryCodesTableName = `"${authSchema}"."recovery_codes"`;
|
|
10488
10387
|
await db.execute(drizzleOrm.sql`
|
|
10489
10388
|
CREATE TABLE IF NOT EXISTS ${drizzleOrm.sql.raw(mfaFactorsTableName)} (
|
|
10490
10389
|
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
@@ -10536,28 +10435,6 @@ ${tableRelations.join(",\n")}
|
|
|
10536
10435
|
serverCore.logger.warn("⚠️ Continuing without creating auth tables.");
|
|
10537
10436
|
}
|
|
10538
10437
|
}
|
|
10539
|
-
async function seedDefaultRoles(db, rolesTableName) {
|
|
10540
|
-
const result = await db.execute(drizzleOrm.sql`SELECT COUNT(*) as count FROM ${drizzleOrm.sql.raw(rolesTableName)}`);
|
|
10541
|
-
const count = parseInt(result.rows[0]?.count || "0", 10);
|
|
10542
|
-
if (count > 0) {
|
|
10543
|
-
serverCore.logger.info(`📋 Found ${count} existing roles`);
|
|
10544
|
-
return;
|
|
10545
|
-
}
|
|
10546
|
-
serverCore.logger.info("🌱 Seeding default roles...");
|
|
10547
|
-
for (const role of DEFAULT_ROLES) {
|
|
10548
|
-
await db.execute(drizzleOrm.sql`
|
|
10549
|
-
INSERT INTO ${drizzleOrm.sql.raw(rolesTableName)} (id, name, is_admin, default_permissions)
|
|
10550
|
-
VALUES (
|
|
10551
|
-
${role.id},
|
|
10552
|
-
${role.name},
|
|
10553
|
-
${role.is_admin},
|
|
10554
|
-
${JSON.stringify(role.default_permissions)}::jsonb
|
|
10555
|
-
)
|
|
10556
|
-
ON CONFLICT (id) DO NOTHING
|
|
10557
|
-
`);
|
|
10558
|
-
}
|
|
10559
|
-
serverCore.logger.info("✅ Default roles created: admin, editor, viewer");
|
|
10560
|
-
}
|
|
10561
10438
|
function getColumnKey(table, ...keys2) {
|
|
10562
10439
|
if (!table) return void 0;
|
|
10563
10440
|
for (const key of keys2) {
|
|
@@ -10577,24 +10454,18 @@ ${tableRelations.join(",\n")}
|
|
|
10577
10454
|
class UserService {
|
|
10578
10455
|
constructor(db, tableOrTables) {
|
|
10579
10456
|
this.db = db;
|
|
10580
|
-
if (tableOrTables &&
|
|
10457
|
+
if (tableOrTables && tableOrTables.users) {
|
|
10581
10458
|
const tables = tableOrTables;
|
|
10582
10459
|
this.usersTable = tables.users || users;
|
|
10583
10460
|
this.userIdentitiesTable = tables.userIdentities || userIdentities;
|
|
10584
|
-
this.userRolesTable = tables.userRoles || userRoles;
|
|
10585
|
-
this.rolesTable = tables.roles || roles;
|
|
10586
10461
|
} else {
|
|
10587
10462
|
const table = tableOrTables;
|
|
10588
10463
|
this.usersTable = table || users;
|
|
10589
10464
|
this.userIdentitiesTable = userIdentities;
|
|
10590
|
-
this.userRolesTable = userRoles;
|
|
10591
|
-
this.rolesTable = roles;
|
|
10592
10465
|
}
|
|
10593
10466
|
}
|
|
10594
10467
|
usersTable;
|
|
10595
10468
|
userIdentitiesTable;
|
|
10596
|
-
userRolesTable;
|
|
10597
|
-
rolesTable;
|
|
10598
10469
|
getQualifiedUsersTableName() {
|
|
10599
10470
|
const name = drizzleOrm.getTableName(this.usersTable);
|
|
10600
10471
|
const schema = pgCore.getTableConfig(this.usersTable).schema || "public";
|
|
@@ -10616,7 +10487,7 @@ ${tableRelations.join(",\n")}
|
|
|
10616
10487
|
const metadata = {
|
|
10617
10488
|
...row.metadata || {}
|
|
10618
10489
|
};
|
|
10619
|
-
const knownKeys = /* @__PURE__ */ new Set(["id", "uid", "email", "password_hash", "passwordHash", "display_name", "displayName", "photo_url", "photoUrl", "photoURL", "email_verified", "emailVerified", "email_verification_token", "emailVerificationToken", "email_verification_sent_at", "emailVerificationSentAt", "is_anonymous", "isAnonymous", "created_at", "createdAt", "updated_at", "updatedAt", "metadata"]);
|
|
10490
|
+
const knownKeys = /* @__PURE__ */ new Set(["id", "uid", "email", "password_hash", "passwordHash", "display_name", "displayName", "photo_url", "photoUrl", "photoURL", "email_verified", "emailVerified", "email_verification_token", "emailVerificationToken", "email_verification_sent_at", "emailVerificationSentAt", "is_anonymous", "isAnonymous", "roles", "created_at", "createdAt", "updated_at", "updatedAt", "metadata"]);
|
|
10620
10491
|
for (const [key, val] of Object.entries(row)) {
|
|
10621
10492
|
if (!knownKeys.has(key)) {
|
|
10622
10493
|
const camelKey = camelCase(key);
|
|
@@ -10767,19 +10638,18 @@ ${tableRelations.join(",\n")}
|
|
|
10767
10638
|
const displayNameCol = getColumn(this.usersTable, "displayName", "display_name");
|
|
10768
10639
|
const displayNameColumn = displayNameCol ? displayNameCol.name : "display_name";
|
|
10769
10640
|
const idCol = getColumn(this.usersTable, "id");
|
|
10770
|
-
|
|
10641
|
+
idCol ? idCol.name : "id";
|
|
10771
10642
|
const usersTableName = this.getQualifiedUsersTableName();
|
|
10772
|
-
const rolesSchema = pgCore.getTableConfig(this.userRolesTable).schema || "public";
|
|
10773
10643
|
const conditions = [];
|
|
10774
10644
|
if (roleId) {
|
|
10775
|
-
conditions.push(drizzleOrm.sql
|
|
10645
|
+
conditions.push(drizzleOrm.sql`${roleId} = ANY(${drizzleOrm.sql.raw(usersTableName)}.roles)`);
|
|
10776
10646
|
}
|
|
10777
10647
|
if (search) {
|
|
10778
10648
|
const pattern = `%${search}%`;
|
|
10779
10649
|
conditions.push(drizzleOrm.sql`(${drizzleOrm.sql.raw(usersTableName)}.${drizzleOrm.sql.raw(emailColumn)} ILIKE ${pattern} OR ${drizzleOrm.sql.raw(usersTableName)}.${drizzleOrm.sql.raw(displayNameColumn)} ILIKE ${pattern})`);
|
|
10780
10650
|
}
|
|
10781
10651
|
const whereClause = conditions.length > 0 ? drizzleOrm.sql`WHERE ${drizzleOrm.sql.join(conditions, drizzleOrm.sql` AND `)}` : drizzleOrm.sql``;
|
|
10782
|
-
const orderByClause = roleId ? drizzleOrm.sql`ORDER BY ${drizzleOrm.sql.raw(usersTableName)}.${drizzleOrm.sql.raw(orderColumn)} ${direction}` : drizzleOrm.sql`ORDER BY (
|
|
10652
|
+
const orderByClause = roleId ? drizzleOrm.sql`ORDER BY ${drizzleOrm.sql.raw(usersTableName)}.${drizzleOrm.sql.raw(orderColumn)} ${direction}` : drizzleOrm.sql`ORDER BY array_length(${drizzleOrm.sql.raw(usersTableName)}.roles, 1) DESC NULLS LAST, ${drizzleOrm.sql.raw(usersTableName)}.${drizzleOrm.sql.raw(orderColumn)} ${direction}`;
|
|
10783
10653
|
const countResult = await this.db.execute(drizzleOrm.sql`
|
|
10784
10654
|
SELECT count(*)::int as total FROM ${drizzleOrm.sql.raw(usersTableName)}
|
|
10785
10655
|
${whereClause}
|
|
@@ -10853,54 +10723,57 @@ ${tableRelations.join(",\n")}
|
|
|
10853
10723
|
return row ? this.mapRowToUser(row) : null;
|
|
10854
10724
|
}
|
|
10855
10725
|
/**
|
|
10856
|
-
* Get roles for a user from database
|
|
10726
|
+
* Get roles for a user from database (inline TEXT[] column)
|
|
10857
10727
|
*/
|
|
10858
10728
|
async getUserRoles(userId) {
|
|
10859
|
-
const
|
|
10729
|
+
const usersTableName = this.getQualifiedUsersTableName();
|
|
10860
10730
|
const result = await this.db.execute(drizzleOrm.sql`
|
|
10861
|
-
SELECT
|
|
10862
|
-
FROM ${drizzleOrm.sql.raw(`"${rolesSchema}"."roles"`)} r
|
|
10863
|
-
INNER JOIN ${drizzleOrm.sql.raw(`"${rolesSchema}"."user_roles"`)} ur ON r.id = ur.role_id
|
|
10864
|
-
WHERE ur.user_id = ${userId}
|
|
10731
|
+
SELECT roles FROM ${drizzleOrm.sql.raw(usersTableName)} WHERE id = ${userId}
|
|
10865
10732
|
`);
|
|
10866
|
-
|
|
10867
|
-
|
|
10868
|
-
|
|
10869
|
-
|
|
10870
|
-
|
|
10871
|
-
|
|
10733
|
+
if (result.rows.length === 0) return [];
|
|
10734
|
+
const row = result.rows[0];
|
|
10735
|
+
const roleIds = row.roles ?? [];
|
|
10736
|
+
return roleIds.map((id) => ({
|
|
10737
|
+
id,
|
|
10738
|
+
name: id,
|
|
10739
|
+
isAdmin: id === "admin",
|
|
10740
|
+
defaultPermissions: null,
|
|
10741
|
+
collectionPermissions: null
|
|
10872
10742
|
}));
|
|
10873
10743
|
}
|
|
10874
10744
|
/**
|
|
10875
10745
|
* Get role IDs for a user
|
|
10876
10746
|
*/
|
|
10877
10747
|
async getUserRoleIds(userId) {
|
|
10878
|
-
const
|
|
10879
|
-
|
|
10748
|
+
const usersTableName = this.getQualifiedUsersTableName();
|
|
10749
|
+
const result = await this.db.execute(drizzleOrm.sql`
|
|
10750
|
+
SELECT roles FROM ${drizzleOrm.sql.raw(usersTableName)} WHERE id = ${userId}
|
|
10751
|
+
`);
|
|
10752
|
+
if (result.rows.length === 0) return [];
|
|
10753
|
+
const row = result.rows[0];
|
|
10754
|
+
return row.roles ?? [];
|
|
10880
10755
|
}
|
|
10881
10756
|
/**
|
|
10882
|
-
* Set roles for a user
|
|
10757
|
+
* Set roles for a user (replaces existing roles)
|
|
10883
10758
|
*/
|
|
10884
10759
|
async setUserRoles(userId, roleIds) {
|
|
10885
|
-
const
|
|
10886
|
-
|
|
10887
|
-
|
|
10888
|
-
|
|
10889
|
-
|
|
10890
|
-
|
|
10891
|
-
|
|
10892
|
-
`);
|
|
10893
|
-
}
|
|
10760
|
+
const usersTableName = this.getQualifiedUsersTableName();
|
|
10761
|
+
const rolesArray = `{${roleIds.join(",")}}`;
|
|
10762
|
+
await this.db.execute(drizzleOrm.sql`
|
|
10763
|
+
UPDATE ${drizzleOrm.sql.raw(usersTableName)}
|
|
10764
|
+
SET roles = ${rolesArray}::text[], updated_at = NOW()
|
|
10765
|
+
WHERE id = ${userId}
|
|
10766
|
+
`);
|
|
10894
10767
|
}
|
|
10895
10768
|
/**
|
|
10896
|
-
* Assign a specific role to new user
|
|
10769
|
+
* Assign a specific role to new user (appends if not present)
|
|
10897
10770
|
*/
|
|
10898
10771
|
async assignDefaultRole(userId, roleId) {
|
|
10899
|
-
const
|
|
10772
|
+
const usersTableName = this.getQualifiedUsersTableName();
|
|
10900
10773
|
await this.db.execute(drizzleOrm.sql`
|
|
10901
|
-
|
|
10902
|
-
|
|
10903
|
-
|
|
10774
|
+
UPDATE ${drizzleOrm.sql.raw(usersTableName)}
|
|
10775
|
+
SET roles = array_append(roles, ${roleId}), updated_at = NOW()
|
|
10776
|
+
WHERE id = ${userId} AND NOT (${roleId} = ANY(roles))
|
|
10904
10777
|
`);
|
|
10905
10778
|
}
|
|
10906
10779
|
/**
|
|
@@ -10909,101 +10782,12 @@ ${tableRelations.join(",\n")}
|
|
|
10909
10782
|
async getUserWithRoles(userId) {
|
|
10910
10783
|
const user = await this.getUserById(userId);
|
|
10911
10784
|
if (!user) return null;
|
|
10912
|
-
const
|
|
10785
|
+
const roles = await this.getUserRoles(userId);
|
|
10913
10786
|
return {
|
|
10914
10787
|
user,
|
|
10915
|
-
roles
|
|
10916
|
-
};
|
|
10917
|
-
}
|
|
10918
|
-
}
|
|
10919
|
-
class RoleService {
|
|
10920
|
-
constructor(db, tableOrTables) {
|
|
10921
|
-
this.db = db;
|
|
10922
|
-
if (tableOrTables && (tableOrTables.roles || tableOrTables.users)) {
|
|
10923
|
-
this.rolesTable = tableOrTables.roles || roles;
|
|
10924
|
-
} else {
|
|
10925
|
-
this.rolesTable = tableOrTables || roles;
|
|
10926
|
-
}
|
|
10927
|
-
}
|
|
10928
|
-
rolesTable;
|
|
10929
|
-
getQualifiedRolesTableName() {
|
|
10930
|
-
const name = drizzleOrm.getTableName(this.rolesTable);
|
|
10931
|
-
const schema = pgCore.getTableConfig(this.rolesTable).schema || "public";
|
|
10932
|
-
return `"${schema}"."${name}"`;
|
|
10933
|
-
}
|
|
10934
|
-
async getRoleById(id) {
|
|
10935
|
-
const tableName = this.getQualifiedRolesTableName();
|
|
10936
|
-
const result = await this.db.execute(drizzleOrm.sql`
|
|
10937
|
-
SELECT id, name, is_admin, default_permissions, collection_permissions
|
|
10938
|
-
FROM ${drizzleOrm.sql.raw(tableName)}
|
|
10939
|
-
WHERE id = ${id}
|
|
10940
|
-
`);
|
|
10941
|
-
if (result.rows.length === 0) return null;
|
|
10942
|
-
const row = result.rows[0];
|
|
10943
|
-
return {
|
|
10944
|
-
id: row.id,
|
|
10945
|
-
name: row.name,
|
|
10946
|
-
isAdmin: row.is_admin,
|
|
10947
|
-
defaultPermissions: row.default_permissions,
|
|
10948
|
-
collectionPermissions: row.collection_permissions
|
|
10949
|
-
};
|
|
10950
|
-
}
|
|
10951
|
-
async listRoles() {
|
|
10952
|
-
const tableName = this.getQualifiedRolesTableName();
|
|
10953
|
-
const result = await this.db.execute(drizzleOrm.sql`
|
|
10954
|
-
SELECT id, name, is_admin, default_permissions, collection_permissions
|
|
10955
|
-
FROM ${drizzleOrm.sql.raw(tableName)}
|
|
10956
|
-
ORDER BY name
|
|
10957
|
-
`);
|
|
10958
|
-
return result.rows.map((row) => ({
|
|
10959
|
-
id: row.id,
|
|
10960
|
-
name: row.name,
|
|
10961
|
-
isAdmin: row.is_admin,
|
|
10962
|
-
defaultPermissions: row.default_permissions,
|
|
10963
|
-
collectionPermissions: row.collection_permissions
|
|
10964
|
-
}));
|
|
10965
|
-
}
|
|
10966
|
-
async createRole(data) {
|
|
10967
|
-
const tableName = this.getQualifiedRolesTableName();
|
|
10968
|
-
const result = await this.db.execute(drizzleOrm.sql`
|
|
10969
|
-
INSERT INTO ${drizzleOrm.sql.raw(tableName)} (id, name, is_admin, default_permissions, collection_permissions)
|
|
10970
|
-
VALUES (
|
|
10971
|
-
${data.id},
|
|
10972
|
-
${data.name},
|
|
10973
|
-
${data.isAdmin ?? false},
|
|
10974
|
-
${data.defaultPermissions ? JSON.stringify(data.defaultPermissions) : null}::jsonb,
|
|
10975
|
-
${data.collectionPermissions ? JSON.stringify(data.collectionPermissions) : null}::jsonb
|
|
10976
|
-
)
|
|
10977
|
-
RETURNING id, name, is_admin, default_permissions, collection_permissions
|
|
10978
|
-
`);
|
|
10979
|
-
const row = result.rows[0];
|
|
10980
|
-
return {
|
|
10981
|
-
id: row.id,
|
|
10982
|
-
name: row.name,
|
|
10983
|
-
isAdmin: row.is_admin,
|
|
10984
|
-
defaultPermissions: row.default_permissions,
|
|
10985
|
-
collectionPermissions: row.collection_permissions
|
|
10788
|
+
roles
|
|
10986
10789
|
};
|
|
10987
10790
|
}
|
|
10988
|
-
async updateRole(id, data) {
|
|
10989
|
-
const existing = await this.getRoleById(id);
|
|
10990
|
-
if (!existing) return null;
|
|
10991
|
-
const tableName = this.getQualifiedRolesTableName();
|
|
10992
|
-
await this.db.execute(drizzleOrm.sql`
|
|
10993
|
-
UPDATE ${drizzleOrm.sql.raw(tableName)}
|
|
10994
|
-
SET
|
|
10995
|
-
name = ${data.name ?? existing.name},
|
|
10996
|
-
is_admin = ${data.isAdmin ?? existing.isAdmin},
|
|
10997
|
-
default_permissions = ${data.defaultPermissions ? JSON.stringify(data.defaultPermissions) : JSON.stringify(existing.defaultPermissions)}::jsonb,
|
|
10998
|
-
collection_permissions = ${data.collectionPermissions !== void 0 ? data.collectionPermissions ? JSON.stringify(data.collectionPermissions) : null : existing.collectionPermissions ? JSON.stringify(existing.collectionPermissions) : null}::jsonb
|
|
10999
|
-
WHERE id = ${id}
|
|
11000
|
-
`);
|
|
11001
|
-
return this.getRoleById(id);
|
|
11002
|
-
}
|
|
11003
|
-
async deleteRole(id) {
|
|
11004
|
-
const tableName = this.getQualifiedRolesTableName();
|
|
11005
|
-
await this.db.execute(drizzleOrm.sql`DELETE FROM ${drizzleOrm.sql.raw(tableName)} WHERE id = ${id}`);
|
|
11006
|
-
}
|
|
11007
10791
|
}
|
|
11008
10792
|
class RefreshTokenService {
|
|
11009
10793
|
constructor(db, tableOrTables) {
|
|
@@ -11199,11 +10983,9 @@ ${tableRelations.join(",\n")}
|
|
|
11199
10983
|
constructor(db, tableOrTables) {
|
|
11200
10984
|
this.db = db;
|
|
11201
10985
|
this.userService = new UserService(db, tableOrTables);
|
|
11202
|
-
this.roleService = new RoleService(db, tableOrTables);
|
|
11203
10986
|
this.tokenRepository = new PostgresTokenRepository(db, tableOrTables);
|
|
11204
10987
|
}
|
|
11205
10988
|
userService;
|
|
11206
|
-
roleService;
|
|
11207
10989
|
tokenRepository;
|
|
11208
10990
|
// User operations (delegate to UserService)
|
|
11209
10991
|
async createUser(data) {
|
|
@@ -11263,25 +11045,56 @@ ${tableRelations.join(",\n")}
|
|
|
11263
11045
|
async getUserWithRoles(userId) {
|
|
11264
11046
|
return this.userService.getUserWithRoles(userId);
|
|
11265
11047
|
}
|
|
11266
|
-
// Role operations (
|
|
11048
|
+
// Role operations (roles are inline on users, synthesized from string IDs)
|
|
11267
11049
|
async getRoleById(id) {
|
|
11268
|
-
return
|
|
11050
|
+
return {
|
|
11051
|
+
id,
|
|
11052
|
+
name: id,
|
|
11053
|
+
isAdmin: id === "admin",
|
|
11054
|
+
defaultPermissions: null,
|
|
11055
|
+
collectionPermissions: null
|
|
11056
|
+
};
|
|
11269
11057
|
}
|
|
11270
11058
|
async listRoles() {
|
|
11271
|
-
return
|
|
11059
|
+
return [{
|
|
11060
|
+
id: "admin",
|
|
11061
|
+
name: "Admin",
|
|
11062
|
+
isAdmin: true,
|
|
11063
|
+
defaultPermissions: null,
|
|
11064
|
+
collectionPermissions: null
|
|
11065
|
+
}, {
|
|
11066
|
+
id: "editor",
|
|
11067
|
+
name: "Editor",
|
|
11068
|
+
isAdmin: false,
|
|
11069
|
+
defaultPermissions: null,
|
|
11070
|
+
collectionPermissions: null
|
|
11071
|
+
}, {
|
|
11072
|
+
id: "viewer",
|
|
11073
|
+
name: "Viewer",
|
|
11074
|
+
isAdmin: false,
|
|
11075
|
+
defaultPermissions: null,
|
|
11076
|
+
collectionPermissions: null
|
|
11077
|
+
}];
|
|
11078
|
+
}
|
|
11079
|
+
async createRole(_data) {
|
|
11080
|
+
return {
|
|
11081
|
+
id: _data.id,
|
|
11082
|
+
name: _data.name,
|
|
11083
|
+
isAdmin: _data.isAdmin ?? false,
|
|
11084
|
+
defaultPermissions: _data.defaultPermissions ?? null,
|
|
11085
|
+
collectionPermissions: _data.collectionPermissions ?? null
|
|
11086
|
+
};
|
|
11272
11087
|
}
|
|
11273
|
-
async
|
|
11274
|
-
return
|
|
11275
|
-
|
|
11088
|
+
async updateRole(id, data) {
|
|
11089
|
+
return {
|
|
11090
|
+
id,
|
|
11091
|
+
name: data.name ?? id,
|
|
11092
|
+
isAdmin: data.isAdmin ?? id === "admin",
|
|
11276
11093
|
defaultPermissions: data.defaultPermissions ?? null,
|
|
11277
11094
|
collectionPermissions: data.collectionPermissions ?? null
|
|
11278
|
-
}
|
|
11279
|
-
}
|
|
11280
|
-
async updateRole(id, data) {
|
|
11281
|
-
return this.roleService.updateRole(id, data);
|
|
11095
|
+
};
|
|
11282
11096
|
}
|
|
11283
|
-
async deleteRole(
|
|
11284
|
-
await this.roleService.deleteRole(id);
|
|
11097
|
+
async deleteRole(_id) {
|
|
11285
11098
|
}
|
|
11286
11099
|
// Token operations (delegate to PostgresTokenRepository)
|
|
11287
11100
|
async createRefreshToken(userId, tokenHash, expiresAt, userAgent, ipAddress) {
|
|
@@ -11831,34 +11644,27 @@ ${tableRelations.join(",\n")}
|
|
|
11831
11644
|
const internals = driverResult.internals;
|
|
11832
11645
|
const db = internals.db;
|
|
11833
11646
|
const registry = internals.registry;
|
|
11834
|
-
|
|
11647
|
+
const authCollection = authConfig.collection;
|
|
11648
|
+
await ensureAuthTablesExist(db, authCollection);
|
|
11835
11649
|
let emailService;
|
|
11836
11650
|
if (authConfig.email) {
|
|
11837
11651
|
emailService = serverCore.createEmailService(authConfig.email);
|
|
11838
11652
|
}
|
|
11839
|
-
const
|
|
11840
|
-
const
|
|
11653
|
+
const tableName = authCollection ? "table" in authCollection && typeof authCollection.table === "string" ? authCollection.table : authCollection.slug : void 0;
|
|
11654
|
+
const usersTable = tableName ? registry.getTable(tableName) : void 0;
|
|
11841
11655
|
let usersSchemaName = "rebase";
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
usersSchemaName = pgCore.getTableConfig(customUsersTable).schema || "public";
|
|
11656
|
+
if (authCollection && "schema" in authCollection && typeof authCollection.schema === "string") {
|
|
11657
|
+
usersSchemaName = authCollection.schema;
|
|
11845
11658
|
}
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
const authTables = createAuthSchema(rolesSchemaName, usersSchemaName);
|
|
11850
|
-
if (customUsersTable) {
|
|
11851
|
-
authTables.users = customUsersTable;
|
|
11852
|
-
}
|
|
11853
|
-
if (customRolesTable) {
|
|
11854
|
-
authTables.roles = customRolesTable;
|
|
11659
|
+
const authTables = createAuthSchema(usersSchemaName);
|
|
11660
|
+
if (usersTable) {
|
|
11661
|
+
authTables.users = usersTable;
|
|
11855
11662
|
}
|
|
11856
11663
|
const userService = new UserService(db, authTables);
|
|
11857
|
-
const roleService = new RoleService(db, authTables);
|
|
11858
11664
|
const authRepository = new PostgresAuthRepository(db, authTables);
|
|
11859
11665
|
return {
|
|
11860
11666
|
userService,
|
|
11861
|
-
roleService,
|
|
11667
|
+
roleService: userService,
|
|
11862
11668
|
emailService,
|
|
11863
11669
|
authRepository
|
|
11864
11670
|
};
|
|
@@ -11962,17 +11768,12 @@ ${tableRelations.join(",\n")}
|
|
|
11962
11768
|
exports2.mfaFactorsRelations = mfaFactorsRelations;
|
|
11963
11769
|
exports2.passwordResetTokens = passwordResetTokens;
|
|
11964
11770
|
exports2.passwordResetTokensRelations = passwordResetTokensRelations;
|
|
11965
|
-
exports2.rebaseSchema = rebaseSchema;
|
|
11966
11771
|
exports2.recoveryCodes = recoveryCodes;
|
|
11967
11772
|
exports2.recoveryCodesRelations = recoveryCodesRelations;
|
|
11968
11773
|
exports2.refreshTokens = refreshTokens;
|
|
11969
11774
|
exports2.refreshTokensRelations = refreshTokensRelations;
|
|
11970
|
-
exports2.roles = roles;
|
|
11971
|
-
exports2.rolesRelations = rolesRelations;
|
|
11972
11775
|
exports2.userIdentities = userIdentities;
|
|
11973
11776
|
exports2.userIdentitiesRelations = userIdentitiesRelations;
|
|
11974
|
-
exports2.userRoles = userRoles;
|
|
11975
|
-
exports2.userRolesRelations = userRolesRelations;
|
|
11976
11777
|
exports2.users = users;
|
|
11977
11778
|
exports2.usersRelations = usersRelations;
|
|
11978
11779
|
exports2.usersSchema = usersSchema;
|