@rebasepro/server-postgresql 0.3.0 → 0.5.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.
Files changed (60) hide show
  1. package/README.md +69 -89
  2. package/dist/common/src/collections/default-collections.d.ts +5 -8
  3. package/dist/common/src/data/query_builder.d.ts +6 -2
  4. package/dist/common/src/util/permissions.d.ts +14 -6
  5. package/dist/index.es.js +379 -611
  6. package/dist/index.es.js.map +1 -1
  7. package/dist/index.umd.js +375 -607
  8. package/dist/index.umd.js.map +1 -1
  9. package/dist/server-postgresql/src/PostgresBackendDriver.d.ts +2 -0
  10. package/dist/server-postgresql/src/auth/ensure-tables.d.ts +7 -4
  11. package/dist/server-postgresql/src/auth/services.d.ts +17 -42
  12. package/dist/server-postgresql/src/data-transformer.d.ts +0 -3
  13. package/dist/server-postgresql/src/databasePoolManager.d.ts +1 -1
  14. package/dist/server-postgresql/src/schema/auth-schema.d.ts +87 -340
  15. package/dist/server-postgresql/src/services/EntityFetchService.d.ts +2 -1
  16. package/dist/server-postgresql/src/services/EntityPersistService.d.ts +4 -0
  17. package/dist/server-postgresql/src/services/entityService.d.ts +4 -0
  18. package/dist/server-postgresql/src/types.d.ts +3 -0
  19. package/dist/server-postgresql/src/utils/drizzle-conditions.d.ts +5 -1
  20. package/dist/server-postgresql/src/websocket.d.ts +8 -3
  21. package/dist/types/src/controllers/auth.d.ts +2 -2
  22. package/dist/types/src/controllers/client.d.ts +25 -40
  23. package/dist/types/src/controllers/data.d.ts +21 -3
  24. package/dist/types/src/controllers/data_driver.d.ts +5 -0
  25. package/dist/types/src/controllers/email.d.ts +2 -0
  26. package/dist/types/src/types/auth_adapter.d.ts +3 -56
  27. package/dist/types/src/types/backend.d.ts +38 -3
  28. package/dist/types/src/types/backend_hooks.d.ts +2 -17
  29. package/dist/types/src/types/collections.d.ts +30 -6
  30. package/dist/types/src/types/entity_views.d.ts +19 -28
  31. package/dist/types/src/types/properties.d.ts +9 -15
  32. package/dist/types/src/types/user_management_delegate.d.ts +16 -53
  33. package/dist/types/src/users/index.d.ts +0 -1
  34. package/dist/types/src/users/user.d.ts +0 -1
  35. package/package.json +6 -6
  36. package/src/PostgresBackendDriver.ts +10 -0
  37. package/src/PostgresBootstrapper.ts +27 -22
  38. package/src/auth/ensure-tables.ts +82 -129
  39. package/src/auth/services.ts +99 -197
  40. package/src/cli.ts +50 -23
  41. package/src/data-transformer.ts +57 -95
  42. package/src/databasePoolManager.ts +2 -1
  43. package/src/schema/auth-schema.ts +13 -69
  44. package/src/schema/doctor.ts +44 -3
  45. package/src/schema/generate-drizzle-schema-logic.ts +33 -3
  46. package/src/schema/generate-drizzle-schema.ts +2 -6
  47. package/src/schema/introspect-db-logic.ts +7 -0
  48. package/src/services/EntityFetchService.ts +13 -1
  49. package/src/services/EntityPersistService.ts +38 -12
  50. package/src/services/entityService.ts +7 -0
  51. package/src/types.ts +4 -0
  52. package/src/utils/drizzle-conditions.ts +40 -5
  53. package/src/websocket.ts +38 -25
  54. package/test/auth-services.test.ts +7 -150
  55. package/test/doctor.test.ts +6 -2
  56. package/test/relation-pipeline-gaps.test.ts +315 -0
  57. package/dist/server-postgresql/src/schema/default-collections.d.ts +0 -2
  58. package/dist/types/src/users/roles.d.ts +0 -14
  59. package/drizzle.test.config.ts +0 -10
  60. 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
- * Add a filter condition to your query.
2839
- * @example
2840
- * client.collection('users').where('age', '>=', 18).find()
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 mappedOp = mapOperator(operator);
2847
- let formattedValue = value;
2848
- if (Array.isArray(value) && ["in", "nin", "cs", "csa"].includes(mappedOp)) {
2849
- formattedValue = `(${value.join(",")})`;
2850
- } else if (value === null) {
2851
- formattedValue = "null";
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) && rawValue.length === 2) {
2956
- const [rawOp, val] = rawValue;
2957
- const mappedOp = operatorMap[rawOp] ?? "==";
2958
- filter[field] = [mappedOp, val];
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(column, operator, value) {
3094
- return new QueryBuilder(accessor).where(column, operator, value);
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 condition = this.buildSingleFilterCondition(fieldColumn, op, value);
3158
- if (condition) {
3159
- conditions.push(condition);
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
  */
@@ -4038,39 +3972,18 @@
4038
3972
  }
4039
3973
  return value;
4040
3974
  }
4041
- case "binary":
4042
- if (typeof value === "string") {
4043
- if (value.startsWith("data:application/octet-stream;base64,")) {
4044
- const base64Data = value.split(",")[1];
4045
- if (base64Data) {
4046
- return Buffer.from(base64Data, "base64");
4047
- }
4048
- }
4049
- }
4050
- if (Buffer.isBuffer(value)) {
4051
- return value;
4052
- }
3975
+ case "binary": {
3976
+ const decoded = tryDecodeBase64DataUrl(value);
3977
+ if (decoded) return decoded;
3978
+ if (Buffer.isBuffer(value)) return value;
4053
3979
  return value;
3980
+ }
4054
3981
  case "string":
4055
- if (typeof value === "string") {
4056
- if (value.startsWith("data:application/octet-stream;base64,")) {
4057
- const base64Data = value.split(",")[1];
4058
- if (base64Data) {
4059
- return Buffer.from(base64Data, "base64");
4060
- }
4061
- }
4062
- }
4063
- return value;
4064
- default:
4065
- if (typeof value === "string") {
4066
- if (value.startsWith("data:application/octet-stream;base64,")) {
4067
- const base64Data = value.split(",")[1];
4068
- if (base64Data) {
4069
- return Buffer.from(base64Data, "base64");
4070
- }
4071
- }
4072
- }
3982
+ default: {
3983
+ const decoded = tryDecodeBase64DataUrl(value);
3984
+ if (decoded) return decoded;
4073
3985
  return value;
3986
+ }
4074
3987
  }
4075
3988
  }
4076
3989
  async function parseDataFromServer(data, collection, db, registry) {
@@ -4190,21 +4103,36 @@
4190
4103
  }
4191
4104
  return result;
4192
4105
  }
4193
- function parsePropertyFromServer(value, property, collection, propertyKey) {
4194
- if (value === null || value === void 0) {
4195
- return value;
4106
+ function tryDecodeBase64DataUrl(value) {
4107
+ if (typeof value !== "string") return null;
4108
+ if (!value.startsWith("data:application/octet-stream;base64,")) return null;
4109
+ const base64Data = value.split(",")[1];
4110
+ return base64Data ? Buffer.from(base64Data, "base64") : null;
4111
+ }
4112
+ function tryResolveBuffer(value) {
4113
+ if (Buffer.isBuffer(value)) return value;
4114
+ if (typeof value === "object" && value !== null) {
4115
+ const rawVal = value;
4116
+ if (rawVal.type === "Buffer" && Array.isArray(rawVal.data)) {
4117
+ return Buffer.from(rawVal.data);
4118
+ }
4119
+ }
4120
+ return null;
4121
+ }
4122
+ function bufferToStringOrBase64(buf) {
4123
+ for (let i = 0; i < buf.length; i++) {
4124
+ const b = buf[i];
4125
+ if ((b < 32 || b > 126) && b !== 9 && b !== 10 && b !== 13) {
4126
+ return `data:application/octet-stream;base64,${buf.toString("base64")}`;
4127
+ }
4196
4128
  }
4129
+ return buf.toString("utf8");
4130
+ }
4131
+ function parsePropertyFromServer(value, property, collection, propertyKey) {
4132
+ if (value === null || value === void 0) return value;
4197
4133
  switch (property.type) {
4198
4134
  case "binary": {
4199
- let buf = null;
4200
- if (Buffer.isBuffer(value)) {
4201
- buf = value;
4202
- } else if (typeof value === "object" && value !== null) {
4203
- const rawVal = value;
4204
- if (rawVal.type === "Buffer" && Array.isArray(rawVal.data)) {
4205
- buf = Buffer.from(rawVal.data);
4206
- }
4207
- }
4135
+ const buf = tryResolveBuffer(value);
4208
4136
  if (buf) {
4209
4137
  return `data:application/octet-stream;base64,${buf.toString("base64")}`;
4210
4138
  }
@@ -4212,28 +4140,9 @@
4212
4140
  }
4213
4141
  case "string": {
4214
4142
  if (typeof value === "string") return value;
4215
- let isBuffer = false;
4216
- let buf = null;
4217
- if (Buffer.isBuffer(value)) {
4218
- isBuffer = true;
4219
- buf = value;
4220
- } else if (typeof value === "object" && value !== null) {
4221
- const rawVal = value;
4222
- if (rawVal.type === "Buffer" && Array.isArray(rawVal.data)) {
4223
- isBuffer = true;
4224
- buf = Buffer.from(rawVal.data);
4225
- }
4226
- }
4227
- if (isBuffer && buf) {
4228
- let isPrintable = true;
4229
- for (let i = 0; i < buf.length; i++) {
4230
- const b = buf[i];
4231
- if ((b < 32 || b > 126) && b !== 9 && b !== 10 && b !== 13) {
4232
- isPrintable = false;
4233
- break;
4234
- }
4235
- }
4236
- return isPrintable ? buf.toString("utf8") : `data:application/octet-stream;base64,${buf.toString("base64")}`;
4143
+ const buf = tryResolveBuffer(value);
4144
+ if (buf) {
4145
+ return bufferToStringOrBase64(buf);
4237
4146
  }
4238
4147
  if (typeof value === "object" && value !== null) {
4239
4148
  try {
@@ -4347,28 +4256,9 @@
4347
4256
  return null;
4348
4257
  }
4349
4258
  default: {
4350
- let isBuffer = false;
4351
- let buf = null;
4352
- if (Buffer.isBuffer(value)) {
4353
- isBuffer = true;
4354
- buf = value;
4355
- } else if (typeof value === "object" && value !== null) {
4356
- const rawVal = value;
4357
- if (rawVal.type === "Buffer" && Array.isArray(rawVal.data)) {
4358
- isBuffer = true;
4359
- buf = Buffer.from(rawVal.data);
4360
- }
4361
- }
4362
- if (isBuffer && buf) {
4363
- let isPrintable = true;
4364
- for (let i = 0; i < buf.length; i++) {
4365
- const b = buf[i];
4366
- if ((b < 32 || b > 126) && b !== 9 && b !== 10 && b !== 13) {
4367
- isPrintable = false;
4368
- break;
4369
- }
4370
- }
4371
- return isPrintable ? buf.toString("utf8") : `data:application/octet-stream;base64,${buf.toString("base64")}`;
4259
+ const buf = tryResolveBuffer(value);
4260
+ if (buf) {
4261
+ return bufferToStringOrBase64(buf);
4372
4262
  }
4373
4263
  return value;
4374
4264
  }
@@ -5557,6 +5447,10 @@
5557
5447
  const filterConditions = this.buildFilterConditions(options.filter, table, collectionPath);
5558
5448
  if (filterConditions.length > 0) allConditions.push(...filterConditions);
5559
5449
  }
5450
+ if (options.logical) {
5451
+ const logicalCondition = DrizzleConditionBuilder.buildLogicalConditions(options.logical, table, collectionPath);
5452
+ if (logicalCondition) allConditions.push(logicalCondition);
5453
+ }
5560
5454
  if (options.startAfter) {
5561
5455
  const cursorConditions = this.buildCursorConditions(table, idField, idInfo, options, collectionPath);
5562
5456
  if (cursorConditions.length > 0) allConditions.push(...cursorConditions);
@@ -5728,6 +5622,10 @@
5728
5622
  const filterConditions = this.buildFilterConditions(options.filter, table, collectionPath);
5729
5623
  if (filterConditions.length > 0) allConditions.push(...filterConditions);
5730
5624
  }
5625
+ if (options.logical) {
5626
+ const logicalCondition = DrizzleConditionBuilder.buildLogicalConditions(options.logical, table, collectionPath);
5627
+ if (logicalCondition) allConditions.push(logicalCondition);
5628
+ }
5731
5629
  if (vectorMeta?.filter) {
5732
5630
  allConditions.push(vectorMeta.filter);
5733
5631
  }
@@ -6313,6 +6211,14 @@
6313
6211
  const parsedId = parsedIdObj[idInfo.fieldName];
6314
6212
  await this.db.delete(table).where(drizzleOrm.eq(idField, parsedId));
6315
6213
  }
6214
+ /**
6215
+ * Delete all entities from a collection
6216
+ */
6217
+ async deleteAll(collectionPath, _databaseId) {
6218
+ const collection = getCollectionByPath(collectionPath, this.registry);
6219
+ const table = getTableForCollection(collection, this.registry);
6220
+ await this.db.delete(table);
6221
+ }
6316
6222
  /**
6317
6223
  * Save an entity (create or update)
6318
6224
  */
@@ -6545,12 +6451,12 @@
6545
6451
  */
6546
6452
  extractCauseMessage(error) {
6547
6453
  if (!error || typeof error !== "object") return null;
6548
- const err = error;
6549
- if (err.cause && typeof err.cause === "object") {
6550
- const deeper = this.extractCauseMessage(err.cause);
6454
+ if (!(error instanceof Error)) return null;
6455
+ if (error.cause && typeof error.cause === "object") {
6456
+ const deeper = this.extractCauseMessage(error.cause);
6551
6457
  if (deeper) return deeper;
6552
- if (err.cause instanceof Error && err.cause.message) {
6553
- return err.cause.message;
6458
+ if (error.cause instanceof Error && error.cause.message) {
6459
+ return error.cause.message;
6554
6460
  }
6555
6461
  }
6556
6462
  return null;
@@ -6571,12 +6477,17 @@
6571
6477
  */
6572
6478
  extractPgError(error) {
6573
6479
  if (!error || typeof error !== "object") return null;
6574
- const err = error;
6575
- if (err.code && /^[0-9A-Z]{5}$/.test(err.code)) {
6576
- return err;
6480
+ if (!(error instanceof Error)) {
6481
+ if ("cause" in error && error.cause && typeof error.cause === "object") {
6482
+ return this.extractPgError(error.cause);
6483
+ }
6484
+ return null;
6485
+ }
6486
+ if ("code" in error && typeof error.code === "string" && /^[0-9A-Z]{5}$/.test(error.code)) {
6487
+ return error;
6577
6488
  }
6578
- if (err.cause && typeof err.cause === "object") {
6579
- return this.extractPgError(err.cause);
6489
+ if (error.cause && typeof error.cause === "object") {
6490
+ return this.extractPgError(error.cause);
6580
6491
  }
6581
6492
  return null;
6582
6493
  }
@@ -6644,6 +6555,12 @@
6644
6555
  async deleteEntity(collectionPath, entityId, databaseId) {
6645
6556
  return this.persistService.deleteEntity(collectionPath, entityId, databaseId);
6646
6557
  }
6558
+ /**
6559
+ * Delete all entities from a collection
6560
+ */
6561
+ async deleteAll(collectionPath, databaseId) {
6562
+ return this.persistService.deleteAll(collectionPath, databaseId);
6563
+ }
6647
6564
  /**
6648
6565
  * Execute raw SQL
6649
6566
  */
@@ -7344,6 +7261,10 @@
7344
7261
  await this.realtimeService.notifyEntityUpdate(entity.path, entity.id.toString(), null, entity.databaseId || resolvedCollection?.databaseId);
7345
7262
  }
7346
7263
  }
7264
+ async deleteAll(path2) {
7265
+ await this.entityService.deleteAll(path2);
7266
+ await this.realtimeService.notifyEntityUpdate(path2, "*", null);
7267
+ }
7347
7268
  async checkUniqueField(path2, name, value, entityId, collection) {
7348
7269
  return this.entityService.checkUniqueField(path2, name, value, entityId, collection?.databaseId);
7349
7270
  }
@@ -7613,11 +7534,11 @@
7613
7534
  console.warn("[DataDriver] User ID (uid) is missing for authenticated delegate. Using 'anonymous'. User object:", this.user);
7614
7535
  userId = "anonymous";
7615
7536
  }
7616
- const userRoles2 = this.user?.roles ?? [];
7537
+ const userRoles = this.user?.roles ?? [];
7617
7538
  if (!this.user?.roles) {
7618
7539
  console.warn("[DataDriver] User roles are missing for authenticated delegate. Using empty array. User object:", this.user);
7619
7540
  }
7620
- const normalizedRoles = userRoles2.map((r) => typeof r === "string" ? r : r?.id ?? String(r));
7541
+ const normalizedRoles = userRoles.map((r) => typeof r === "string" ? r : r?.id ?? String(r));
7621
7542
  const rolesString = normalizedRoles.join(",");
7622
7543
  await tx.execute(drizzleOrm.sql`
7623
7544
  SELECT
@@ -7625,7 +7546,7 @@
7625
7546
  set_config('app.user_roles', ${rolesString}, true),
7626
7547
  set_config('app.jwt', ${JSON.stringify({
7627
7548
  sub: userId,
7628
- roles: userRoles2
7549
+ roles: userRoles
7629
7550
  })}, true)
7630
7551
  `);
7631
7552
  const txEntityService = new EntityService(tx, this.delegate.registry);
@@ -7680,6 +7601,9 @@
7680
7601
  async deleteEntity(props) {
7681
7602
  return this.withTransaction((delegate) => delegate.deleteEntity(props));
7682
7603
  }
7604
+ async deleteAll(path2) {
7605
+ return this.withTransaction((delegate) => delegate.deleteAll(path2));
7606
+ }
7683
7607
  async checkUniqueField(path2, name, value, entityId, collection) {
7684
7608
  return this.withTransaction((delegate) => delegate.checkUniqueField(path2, name, value, entityId, collection));
7685
7609
  }
@@ -7757,13 +7681,13 @@
7757
7681
  }
7758
7682
  await Promise.all(promises);
7759
7683
  this.pools.clear();
7684
+ this.drizzleInstances.clear();
7760
7685
  }
7761
7686
  }
7762
- function createAuthSchema(rolesSchemaName = "rebase", usersSchemaName = "rebase") {
7763
- const rolesSchema = rolesSchemaName === "public" ? null : pgCore.pgSchema(rolesSchemaName);
7687
+ function createAuthSchema(usersSchemaName = "rebase") {
7764
7688
  const usersSchema2 = usersSchemaName === "public" ? null : pgCore.pgSchema(usersSchemaName);
7765
- const rolesTableCreator = rolesSchema ? rolesSchema.table.bind(rolesSchema) : pgCore.pgTable;
7766
- const usersTableCreator = usersSchema2 ? usersSchema2.table.bind(usersSchema2) : pgCore.pgTable;
7689
+ const tableCreator = usersSchema2 ? usersSchema2.table.bind(usersSchema2) : pgCore.pgTable;
7690
+ const usersTableCreator = tableCreator;
7767
7691
  const users2 = usersTableCreator("users", {
7768
7692
  id: pgCore.uuid("id").defaultRandom().primaryKey(),
7769
7693
  email: pgCore.varchar("email", {
@@ -7785,37 +7709,12 @@
7785
7709
  }),
7786
7710
  emailVerificationSentAt: pgCore.timestamp("email_verification_sent_at"),
7787
7711
  isAnonymous: pgCore.boolean("is_anonymous").default(false).notNull(),
7712
+ roles: pgCore.text("roles").array().default([]).notNull(),
7788
7713
  metadata: pgCore.jsonb("metadata").$type().default({}).notNull(),
7789
7714
  createdAt: pgCore.timestamp("created_at").defaultNow().notNull(),
7790
7715
  updatedAt: pgCore.timestamp("updated_at").defaultNow().notNull()
7791
7716
  });
7792
- const roles2 = rolesTableCreator("roles", {
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", {
7717
+ const refreshTokens2 = tableCreator("refresh_tokens", {
7819
7718
  id: pgCore.uuid("id").defaultRandom().primaryKey(),
7820
7719
  userId: pgCore.uuid("user_id").notNull().references(() => users2.id, {
7821
7720
  onDelete: "cascade"
@@ -7834,7 +7733,7 @@
7834
7733
  }, (table) => ({
7835
7734
  uniqueDeviceSession: pgCore.unique("unique_device_session").on(table.userId, table.userAgent, table.ipAddress)
7836
7735
  }));
7837
- const passwordResetTokens2 = rolesTableCreator("password_reset_tokens", {
7736
+ const passwordResetTokens2 = tableCreator("password_reset_tokens", {
7838
7737
  id: pgCore.uuid("id").defaultRandom().primaryKey(),
7839
7738
  userId: pgCore.uuid("user_id").notNull().references(() => users2.id, {
7840
7739
  onDelete: "cascade"
@@ -7846,14 +7745,14 @@
7846
7745
  usedAt: pgCore.timestamp("used_at"),
7847
7746
  createdAt: pgCore.timestamp("created_at").defaultNow().notNull()
7848
7747
  });
7849
- const appConfig2 = rolesTableCreator("app_config", {
7748
+ const appConfig2 = tableCreator("app_config", {
7850
7749
  key: pgCore.varchar("key", {
7851
7750
  length: 100
7852
7751
  }).primaryKey(),
7853
7752
  value: pgCore.jsonb("value").notNull(),
7854
7753
  updatedAt: pgCore.timestamp("updated_at").defaultNow().notNull()
7855
7754
  });
7856
- const userIdentities2 = rolesTableCreator("user_identities", {
7755
+ const userIdentities2 = tableCreator("user_identities", {
7857
7756
  id: pgCore.uuid("id").defaultRandom().primaryKey(),
7858
7757
  userId: pgCore.uuid("user_id").notNull().references(() => users2.id, {
7859
7758
  onDelete: "cascade"
@@ -7871,7 +7770,7 @@
7871
7770
  }, (table) => ({
7872
7771
  uniqueProviderId: pgCore.unique("unique_provider_id").on(table.provider, table.providerId)
7873
7772
  }));
7874
- const mfaFactors2 = rolesTableCreator("mfa_factors", {
7773
+ const mfaFactors2 = tableCreator("mfa_factors", {
7875
7774
  id: pgCore.uuid("id").defaultRandom().primaryKey(),
7876
7775
  userId: pgCore.uuid("user_id").notNull().references(() => users2.id, {
7877
7776
  onDelete: "cascade"
@@ -7890,7 +7789,7 @@
7890
7789
  createdAt: pgCore.timestamp("created_at").defaultNow().notNull(),
7891
7790
  updatedAt: pgCore.timestamp("updated_at").defaultNow().notNull()
7892
7791
  });
7893
- const mfaChallenges2 = rolesTableCreator("mfa_challenges", {
7792
+ const mfaChallenges2 = tableCreator("mfa_challenges", {
7894
7793
  id: pgCore.uuid("id").defaultRandom().primaryKey(),
7895
7794
  factorId: pgCore.uuid("factor_id").notNull().references(() => mfaFactors2.id, {
7896
7795
  onDelete: "cascade"
@@ -7902,7 +7801,7 @@
7902
7801
  }),
7903
7802
  expiresAt: pgCore.timestamp("expires_at").notNull()
7904
7803
  });
7905
- const recoveryCodes2 = rolesTableCreator("recovery_codes", {
7804
+ const recoveryCodes2 = tableCreator("recovery_codes", {
7906
7805
  id: pgCore.uuid("id").defaultRandom().primaryKey(),
7907
7806
  userId: pgCore.uuid("user_id").notNull().references(() => users2.id, {
7908
7807
  onDelete: "cascade"
@@ -7914,11 +7813,8 @@
7914
7813
  createdAt: pgCore.timestamp("created_at").defaultNow().notNull()
7915
7814
  });
7916
7815
  return {
7917
- rolesSchema,
7918
7816
  usersSchema: usersSchema2,
7919
7817
  users: users2,
7920
- roles: roles2,
7921
- userRoles: userRoles2,
7922
7818
  refreshTokens: refreshTokens2,
7923
7819
  passwordResetTokens: passwordResetTokens2,
7924
7820
  appConfig: appConfig2,
@@ -7928,12 +7824,9 @@
7928
7824
  recoveryCodes: recoveryCodes2
7929
7825
  };
7930
7826
  }
7931
- const defaultAuthSchema = createAuthSchema("rebase", "rebase");
7932
- const rebaseSchema = defaultAuthSchema.rolesSchema;
7827
+ const defaultAuthSchema = createAuthSchema("rebase");
7933
7828
  const usersSchema = defaultAuthSchema.usersSchema;
7934
7829
  const users = defaultAuthSchema.users;
7935
- const roles = defaultAuthSchema.roles;
7936
- const userRoles = defaultAuthSchema.userRoles;
7937
7830
  const refreshTokens = defaultAuthSchema.refreshTokens;
7938
7831
  const passwordResetTokens = defaultAuthSchema.passwordResetTokens;
7939
7832
  const appConfig = defaultAuthSchema.appConfig;
@@ -7944,30 +7837,12 @@
7944
7837
  const usersRelations = drizzleOrm.relations(users, ({
7945
7838
  many
7946
7839
  }) => ({
7947
- userRoles: many(userRoles),
7948
7840
  refreshTokens: many(refreshTokens),
7949
7841
  passwordResetTokens: many(passwordResetTokens),
7950
7842
  userIdentities: many(userIdentities),
7951
7843
  mfaFactors: many(mfaFactors),
7952
7844
  recoveryCodes: many(recoveryCodes)
7953
7845
  }));
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
7846
  const refreshTokensRelations = drizzleOrm.relations(refreshTokens, ({
7972
7847
  one
7973
7848
  }) => ({
@@ -8074,6 +7949,8 @@
8074
7949
  columnDefinition = `${enumName}("${colName}")`;
8075
7950
  } else if ("isId" in stringProp && stringProp.isId === "uuid") {
8076
7951
  columnDefinition = `uuid("${colName}")`;
7952
+ } else if (stringProp.columnType === "uuid") {
7953
+ columnDefinition = `uuid("${colName}")`;
8077
7954
  } else if (stringProp.columnType === "text") {
8078
7955
  columnDefinition = `text("${colName}")`;
8079
7956
  } else if (stringProp.columnType === "char") {
@@ -8141,11 +8018,38 @@
8141
8018
  }
8142
8019
  break;
8143
8020
  }
8144
- case "map":
8021
+ case "map": {
8022
+ const mapProp = prop;
8023
+ if (mapProp.columnType === "json") {
8024
+ columnDefinition = `json("${colName}")`;
8025
+ } else {
8026
+ columnDefinition = `jsonb("${colName}")`;
8027
+ }
8028
+ break;
8029
+ }
8145
8030
  case "array": {
8146
- const arrayOrMapProp = prop;
8147
- if (arrayOrMapProp.columnType === "json") {
8031
+ const arrayProp = prop;
8032
+ let colType = arrayProp.columnType;
8033
+ if (!colType && arrayProp.of && !Array.isArray(arrayProp.of)) {
8034
+ const ofProp = arrayProp.of;
8035
+ if (ofProp.type === "string") {
8036
+ colType = "text[]";
8037
+ } else if (ofProp.type === "number") {
8038
+ colType = ofProp.validation?.integer ? "integer[]" : "numeric[]";
8039
+ } else if (ofProp.type === "boolean") {
8040
+ colType = "boolean[]";
8041
+ }
8042
+ }
8043
+ if (colType === "json") {
8148
8044
  columnDefinition = `json("${colName}")`;
8045
+ } else if (colType === "text[]") {
8046
+ columnDefinition = `text("${colName}").array()`;
8047
+ } else if (colType === "integer[]") {
8048
+ columnDefinition = `integer("${colName}").array()`;
8049
+ } else if (colType === "boolean[]") {
8050
+ columnDefinition = `boolean("${colName}").array()`;
8051
+ } else if (colType === "numeric[]") {
8052
+ columnDefinition = `numeric("${colName}").array()`;
8149
8053
  } else {
8150
8054
  columnDefinition = `jsonb("${colName}")`;
8151
8055
  }
@@ -8229,8 +8133,8 @@
8229
8133
  const resolved = expression.replace(/\{(\w+)\}/g, (_, col) => col);
8230
8134
  return `sql\`${resolved}\``;
8231
8135
  };
8232
- const wrapWithRoleCheck = (clause, roles2) => {
8233
- const rolesArrayString = `ARRAY[${roles2.map((r) => `'${r}'`).join(",")}]`;
8136
+ const wrapWithRoleCheck = (clause, roles) => {
8137
+ const rolesArrayString = `ARRAY[${roles.map((r) => `'${r}'`).join(",")}]`;
8234
8138
  const roleCondition = `string_to_array(auth.roles(), ',') @> ${rolesArrayString}`;
8235
8139
  return `sql\`(${unwrapSql(clause)}) AND (${roleCondition})\``;
8236
8140
  };
@@ -8283,22 +8187,22 @@
8283
8187
  };
8284
8188
  const generateSinglePolicyCode = (collection, rule, operation, policyName) => {
8285
8189
  const mode = rule.mode ?? "permissive";
8286
- const roles2 = rule.roles ? [...rule.roles].sort() : void 0;
8190
+ const roles = rule.roles ? [...rule.roles].sort() : void 0;
8287
8191
  const needsUsing = operation !== "insert";
8288
8192
  const needsWithCheck = operation !== "select" && operation !== "delete";
8289
8193
  let usingClause = needsUsing ? buildUsingClause(rule, collection) : null;
8290
8194
  let withCheckClause = needsWithCheck ? buildWithCheckClause(rule, collection) : null;
8291
- if (roles2 && roles2.length > 0) {
8195
+ if (roles && roles.length > 0) {
8292
8196
  if (usingClause) {
8293
- usingClause = wrapWithRoleCheck(usingClause, roles2);
8197
+ usingClause = wrapWithRoleCheck(usingClause, roles);
8294
8198
  } else if (needsUsing) {
8295
- const rolesArrayString = `ARRAY[${roles2.map((r) => `'${r}'`).join(",")}]`;
8199
+ const rolesArrayString = `ARRAY[${roles.map((r) => `'${r}'`).join(",")}]`;
8296
8200
  usingClause = `sql\`string_to_array(auth.roles(), ',') @> ${rolesArrayString}\``;
8297
8201
  }
8298
8202
  if (withCheckClause) {
8299
- withCheckClause = wrapWithRoleCheck(withCheckClause, roles2);
8203
+ withCheckClause = wrapWithRoleCheck(withCheckClause, roles);
8300
8204
  } else if (needsWithCheck) {
8301
- const rolesArrayString = `ARRAY[${roles2.map((r) => `'${r}'`).join(",")}]`;
8205
+ const rolesArrayString = `ARRAY[${roles.map((r) => `'${r}'`).join(",")}]`;
8302
8206
  withCheckClause = `sql\`string_to_array(auth.roles(), ',') @> ${rolesArrayString}\``;
8303
8207
  }
8304
8208
  }
@@ -8686,7 +8590,6 @@ ${tableRelations.join(",\n")}
8686
8590
  if (!collections || !Array.isArray(collections)) {
8687
8591
  collections = [];
8688
8592
  }
8689
- collections = Array.from(new Map([defaultUsersCollection, ...collections].map((c) => [c.slug, c])).values());
8690
8593
  collections.sort((a, b) => a.slug.localeCompare(b.slug));
8691
8594
  const schemaContent = await generateSchema(collections);
8692
8595
  if (outputPath) {
@@ -9672,20 +9575,19 @@ ${tableRelations.join(",\n")}
9672
9575
  }
9673
9576
  }
9674
9577
  const PostgresRealtimeProvider = RealtimeService;
9675
- const clientSessions = /* @__PURE__ */ new Map();
9676
9578
  const WS_RATE_LIMIT = 2e3;
9677
9579
  const WS_RATE_WINDOW_MS = 6e4;
9678
9580
  const ADMIN_ONLY_TYPES = /* @__PURE__ */ new Set(["EXECUTE_SQL", "FETCH_DATABASES", "FETCH_ROLES", "FETCH_UNMAPPED_TABLES", "FETCH_TABLE_METADATA", "FETCH_CURRENT_DATABASE", "CREATE_BRANCH", "DELETE_BRANCH", "LIST_BRANCHES"]);
9679
9581
  function extractErrorMessage(error) {
9680
9582
  if (!error) return "Unknown error";
9681
- if (typeof error === "object") {
9682
- const err = error;
9683
- if (err.cause) {
9684
- return extractErrorMessage(err.cause);
9685
- }
9686
- if (typeof err.message === "string") {
9687
- return err.message;
9583
+ if (error instanceof Error) {
9584
+ if ("cause" in error && error.cause) {
9585
+ return extractErrorMessage(error.cause);
9688
9586
  }
9587
+ return error.message;
9588
+ }
9589
+ if (typeof error === "object" && "message" in error && typeof error.message === "string") {
9590
+ return error.message;
9689
9591
  }
9690
9592
  return String(error);
9691
9593
  }
@@ -9693,14 +9595,10 @@ ${tableRelations.join(",\n")}
9693
9595
  if (!session?.user) return false;
9694
9596
  if (session.user.isAdmin) return true;
9695
9597
  if (!session.user.roles) return false;
9696
- return session.user.roles.some((r) => {
9697
- if (typeof r === "string") return r === "admin";
9698
- if (r && typeof r === "object" && "isAdmin" in r) return r.isAdmin;
9699
- if (r && typeof r === "object" && "id" in r) return r.id === "admin";
9700
- return false;
9701
- });
9598
+ return session.user.roles.some((r) => r === "admin");
9702
9599
  }
9703
9600
  function createPostgresWebSocket(server, realtimeService, driver, authConfig, authAdapter) {
9601
+ const clientSessions = /* @__PURE__ */ new Map();
9704
9602
  const isProduction = process.env.NODE_ENV === "production";
9705
9603
  const wsDebug = (...args) => {
9706
9604
  if (!isProduction) console.debug(...args);
@@ -9839,13 +9737,23 @@ ${tableRelations.join(",\n")}
9839
9737
  }
9840
9738
  const getScopedDelegate = async () => {
9841
9739
  const session = clientSessions.get(clientId);
9842
- if ("withAuth" in driver && typeof driver.withAuth === "function") {
9740
+ if (typeof driver.withAuth === "function") {
9843
9741
  try {
9844
9742
  const userForAuth = session?.user ? {
9845
9743
  uid: session.user.userId,
9744
+ displayName: null,
9745
+ email: null,
9746
+ photoURL: null,
9747
+ providerId: "websocket",
9748
+ isAnonymous: false,
9846
9749
  roles: session.user.roles ?? []
9847
9750
  } : {
9848
9751
  uid: "anon",
9752
+ displayName: null,
9753
+ email: null,
9754
+ photoURL: null,
9755
+ providerId: "websocket",
9756
+ isAnonymous: true,
9849
9757
  roles: ["anon"]
9850
9758
  };
9851
9759
  return await driver.withAuth(userForAuth);
@@ -10032,15 +9940,15 @@ ${tableRelations.join(",\n")}
10032
9940
  wsDebug("👤 [WebSocket Server] Processing FETCH_ROLES request");
10033
9941
  const delegate = await getScopedDelegate();
10034
9942
  const admin = delegate.admin;
10035
- let roles2 = [];
9943
+ let roles = [];
10036
9944
  if (isSQLAdmin(admin) && admin.fetchAvailableRoles) {
10037
- roles2 = await admin.fetchAvailableRoles();
9945
+ roles = await admin.fetchAvailableRoles();
10038
9946
  }
10039
- wsDebug(`👤 [WebSocket Server] Fetched ${roles2.length} roles.`);
9947
+ wsDebug(`👤 [WebSocket Server] Fetched ${roles.length} roles.`);
10040
9948
  const response = {
10041
9949
  type: "FETCH_ROLES_SUCCESS",
10042
9950
  payload: {
10043
- roles: roles2
9951
+ roles
10044
9952
  },
10045
9953
  requestId
10046
9954
  };
@@ -10294,85 +10202,35 @@ ${tableRelations.join(",\n")}
10294
10202
  return collection.relations.map((r) => r.relationName || r.localKey || "").filter(Boolean);
10295
10203
  }
10296
10204
  }
10297
- const DEFAULT_ROLES = [{
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) {
10205
+ async function ensureAuthTablesExist(db, collection) {
10329
10206
  serverCore.logger.info("🔍 Checking auth tables...");
10330
10207
  try {
10331
- let usersTableName = '"users"';
10208
+ let usersTableName = '"rebase"."users"';
10332
10209
  let userIdType = "TEXT";
10333
- let usersSchema2 = "public";
10334
- if (registry) {
10335
- const usersTable = registry.getTable("users");
10336
- if (usersTable) {
10337
- const {
10338
- getTableName: getTableName2
10339
- } = await import("drizzle-orm");
10340
- usersSchema2 = pgCore.getTableConfig(usersTable).schema || "public";
10341
- usersTableName = usersSchema2 === "public" ? `"${getTableName2(usersTable)}"` : `"${usersSchema2}"."${getTableName2(usersTable)}"`;
10342
- if (usersTable.id) {
10343
- const col = usersTable.id;
10344
- const meta = getColumnMeta(col);
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
- }
10210
+ let usersSchema2 = "rebase";
10211
+ if (collection) {
10212
+ const rawTable = "table" in collection && typeof collection.table === "string" ? collection.table : collection.slug;
10213
+ usersSchema2 = "schema" in collection && typeof collection.schema === "string" ? collection.schema : "public";
10214
+ usersTableName = usersSchema2 === "public" ? `"${rawTable}"` : `"${usersSchema2}"."${rawTable}"`;
10215
+ const idProp = collection.properties?.id;
10216
+ if (idProp) {
10217
+ const isId = "isId" in idProp ? idProp.isId : void 0;
10218
+ if (isId === "uuid") {
10219
+ userIdType = "UUID";
10220
+ } else if (isId === "autoincrement") {
10221
+ userIdType = "INTEGER";
10353
10222
  }
10354
10223
  }
10355
10224
  }
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
10225
  if (usersSchema2 !== "public") {
10364
10226
  await db.execute(drizzleOrm.sql`CREATE SCHEMA IF NOT EXISTS ${drizzleOrm.sql.raw(usersSchema2)}`);
10365
10227
  }
10366
- if (rolesSchema !== "public" && rolesSchema !== usersSchema2) {
10367
- await db.execute(drizzleOrm.sql`CREATE SCHEMA IF NOT EXISTS ${drizzleOrm.sql.raw(rolesSchema)}`);
10368
- }
10369
10228
  await db.execute(drizzleOrm.sql`CREATE SCHEMA IF NOT EXISTS rebase`);
10370
- const userIdentitiesTable = `"${rolesSchema}"."user_identities"`;
10371
- const rolesTableName = `"${rolesSchema}"."roles"`;
10372
- const userRolesTableName = `"${rolesSchema}"."user_roles"`;
10373
- const refreshTokensTableName = `"${rolesSchema}"."refresh_tokens"`;
10374
- const passwordResetTokensTableName = `"${rolesSchema}"."password_reset_tokens"`;
10375
- const appConfigTableName = `"${rolesSchema}"."app_config"`;
10229
+ const authSchema = usersSchema2 === "public" ? "rebase" : usersSchema2;
10230
+ const userIdentitiesTable = `"${authSchema}"."user_identities"`;
10231
+ const refreshTokensTableName = `"${authSchema}"."refresh_tokens"`;
10232
+ const passwordResetTokensTableName = `"${authSchema}"."password_reset_tokens"`;
10233
+ const appConfigTableName = `"${authSchema}"."app_config"`;
10376
10234
  await db.execute(drizzleOrm.sql`
10377
10235
  CREATE TABLE IF NOT EXISTS ${drizzleOrm.sql.raw(userIdentitiesTable)} (
10378
10236
  id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
@@ -10389,27 +10247,6 @@ ${tableRelations.join(",\n")}
10389
10247
  CREATE INDEX IF NOT EXISTS idx_user_identities_user
10390
10248
  ON ${drizzleOrm.sql.raw(userIdentitiesTable)}(user_id)
10391
10249
  `);
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
10250
  await db.execute(drizzleOrm.sql`
10414
10251
  CREATE TABLE IF NOT EXISTS ${drizzleOrm.sql.raw(refreshTokensTableName)} (
10415
10252
  id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
@@ -10477,14 +10314,43 @@ ${tableRelations.join(",\n")}
10477
10314
  $$ LANGUAGE sql STABLE
10478
10315
  `);
10479
10316
  });
10480
- await seedDefaultRoles(db, rolesTableName);
10481
10317
  await db.execute(drizzleOrm.sql`
10482
10318
  ALTER TABLE ${drizzleOrm.sql.raw(usersTableName)}
10483
10319
  ADD COLUMN IF NOT EXISTS is_anonymous BOOLEAN DEFAULT FALSE
10484
10320
  `);
10485
- const mfaFactorsTableName = `"${rolesSchema}"."mfa_factors"`;
10486
- const mfaChallengesTableName = `"${rolesSchema}"."mfa_challenges"`;
10487
- const recoveryCodesTableName = `"${rolesSchema}"."recovery_codes"`;
10321
+ await db.execute(drizzleOrm.sql`
10322
+ ALTER TABLE ${drizzleOrm.sql.raw(usersTableName)}
10323
+ ADD COLUMN IF NOT EXISTS roles TEXT[] DEFAULT '{}' NOT NULL
10324
+ `);
10325
+ try {
10326
+ const legacyCheck = await db.execute(drizzleOrm.sql`
10327
+ SELECT EXISTS (
10328
+ SELECT 1 FROM information_schema.tables
10329
+ WHERE table_schema = 'rebase' AND table_name = 'user_roles'
10330
+ ) AS has_user_roles
10331
+ `);
10332
+ const hasLegacyTables = legacyCheck.rows[0].has_user_roles;
10333
+ if (hasLegacyTables) {
10334
+ serverCore.logger.info("🔄 Migrating roles from legacy user_roles table...");
10335
+ await db.execute(drizzleOrm.sql`
10336
+ UPDATE ${drizzleOrm.sql.raw(usersTableName)} u
10337
+ SET roles = COALESCE((
10338
+ SELECT array_agg(ur.role_id)
10339
+ FROM "rebase"."user_roles" ur
10340
+ WHERE ur.user_id = u.id
10341
+ ), '{}')
10342
+ WHERE u.roles = '{}' OR u.roles IS NULL
10343
+ `);
10344
+ await db.execute(drizzleOrm.sql`DROP TABLE IF EXISTS "rebase"."user_roles" CASCADE`);
10345
+ await db.execute(drizzleOrm.sql`DROP TABLE IF EXISTS "rebase"."roles" CASCADE`);
10346
+ serverCore.logger.info("✅ Legacy roles tables migrated and dropped");
10347
+ }
10348
+ } catch (migrationError) {
10349
+ serverCore.logger.warn(`⚠️ Legacy roles migration skipped: ${migrationError instanceof Error ? migrationError.message : String(migrationError)}`);
10350
+ }
10351
+ const mfaFactorsTableName = `"${authSchema}"."mfa_factors"`;
10352
+ const mfaChallengesTableName = `"${authSchema}"."mfa_challenges"`;
10353
+ const recoveryCodesTableName = `"${authSchema}"."recovery_codes"`;
10488
10354
  await db.execute(drizzleOrm.sql`
10489
10355
  CREATE TABLE IF NOT EXISTS ${drizzleOrm.sql.raw(mfaFactorsTableName)} (
10490
10356
  id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
@@ -10536,28 +10402,6 @@ ${tableRelations.join(",\n")}
10536
10402
  serverCore.logger.warn("⚠️ Continuing without creating auth tables.");
10537
10403
  }
10538
10404
  }
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
10405
  function getColumnKey(table, ...keys2) {
10562
10406
  if (!table) return void 0;
10563
10407
  for (const key of keys2) {
@@ -10577,24 +10421,18 @@ ${tableRelations.join(",\n")}
10577
10421
  class UserService {
10578
10422
  constructor(db, tableOrTables) {
10579
10423
  this.db = db;
10580
- if (tableOrTables && (tableOrTables.users || tableOrTables.roles)) {
10424
+ if (tableOrTables && tableOrTables.users) {
10581
10425
  const tables = tableOrTables;
10582
10426
  this.usersTable = tables.users || users;
10583
10427
  this.userIdentitiesTable = tables.userIdentities || userIdentities;
10584
- this.userRolesTable = tables.userRoles || userRoles;
10585
- this.rolesTable = tables.roles || roles;
10586
10428
  } else {
10587
10429
  const table = tableOrTables;
10588
10430
  this.usersTable = table || users;
10589
10431
  this.userIdentitiesTable = userIdentities;
10590
- this.userRolesTable = userRoles;
10591
- this.rolesTable = roles;
10592
10432
  }
10593
10433
  }
10594
10434
  usersTable;
10595
10435
  userIdentitiesTable;
10596
- userRolesTable;
10597
- rolesTable;
10598
10436
  getQualifiedUsersTableName() {
10599
10437
  const name = drizzleOrm.getTableName(this.usersTable);
10600
10438
  const schema = pgCore.getTableConfig(this.usersTable).schema || "public";
@@ -10616,7 +10454,7 @@ ${tableRelations.join(",\n")}
10616
10454
  const metadata = {
10617
10455
  ...row.metadata || {}
10618
10456
  };
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"]);
10457
+ 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
10458
  for (const [key, val] of Object.entries(row)) {
10621
10459
  if (!knownKeys.has(key)) {
10622
10460
  const camelKey = camelCase(key);
@@ -10767,19 +10605,18 @@ ${tableRelations.join(",\n")}
10767
10605
  const displayNameCol = getColumn(this.usersTable, "displayName", "display_name");
10768
10606
  const displayNameColumn = displayNameCol ? displayNameCol.name : "display_name";
10769
10607
  const idCol = getColumn(this.usersTable, "id");
10770
- const idColumn = idCol ? idCol.name : "id";
10608
+ idCol ? idCol.name : "id";
10771
10609
  const usersTableName = this.getQualifiedUsersTableName();
10772
- const rolesSchema = pgCore.getTableConfig(this.userRolesTable).schema || "public";
10773
10610
  const conditions = [];
10774
10611
  if (roleId) {
10775
- conditions.push(drizzleOrm.sql`EXISTS (SELECT 1 FROM ${drizzleOrm.sql.raw(`"${rolesSchema}"."user_roles"`)} ur WHERE ur.user_id = ${drizzleOrm.sql.raw(usersTableName)}.${drizzleOrm.sql.raw(idColumn)} AND ur.role_id = ${roleId})`);
10612
+ conditions.push(drizzleOrm.sql`${roleId} = ANY(${drizzleOrm.sql.raw(usersTableName)}.roles)`);
10776
10613
  }
10777
10614
  if (search) {
10778
10615
  const pattern = `%${search}%`;
10779
10616
  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
10617
  }
10781
10618
  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 (SELECT count(*) FROM ${drizzleOrm.sql.raw(`"${rolesSchema}"."user_roles"`)} ur WHERE ur.user_id = ${drizzleOrm.sql.raw(usersTableName)}.${drizzleOrm.sql.raw(idColumn)}) DESC, ${drizzleOrm.sql.raw(usersTableName)}.${drizzleOrm.sql.raw(orderColumn)} ${direction}`;
10619
+ 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
10620
  const countResult = await this.db.execute(drizzleOrm.sql`
10784
10621
  SELECT count(*)::int as total FROM ${drizzleOrm.sql.raw(usersTableName)}
10785
10622
  ${whereClause}
@@ -10853,54 +10690,57 @@ ${tableRelations.join(",\n")}
10853
10690
  return row ? this.mapRowToUser(row) : null;
10854
10691
  }
10855
10692
  /**
10856
- * Get roles for a user from database
10693
+ * Get roles for a user from database (inline TEXT[] column)
10857
10694
  */
10858
10695
  async getUserRoles(userId) {
10859
- const rolesSchema = pgCore.getTableConfig(this.rolesTable).schema || "public";
10696
+ const usersTableName = this.getQualifiedUsersTableName();
10860
10697
  const result = await this.db.execute(drizzleOrm.sql`
10861
- SELECT r.id, r.name, r.is_admin, r.default_permissions, r.collection_permissions
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}
10698
+ SELECT roles FROM ${drizzleOrm.sql.raw(usersTableName)} WHERE id = ${userId}
10865
10699
  `);
10866
- return result.rows.map((row) => ({
10867
- id: row.id,
10868
- name: row.name,
10869
- isAdmin: row.is_admin,
10870
- defaultPermissions: row.default_permissions,
10871
- collectionPermissions: row.collection_permissions
10700
+ if (result.rows.length === 0) return [];
10701
+ const row = result.rows[0];
10702
+ const roleIds = row.roles ?? [];
10703
+ return roleIds.map((id) => ({
10704
+ id,
10705
+ name: id,
10706
+ isAdmin: id === "admin",
10707
+ defaultPermissions: null,
10708
+ collectionPermissions: null
10872
10709
  }));
10873
10710
  }
10874
10711
  /**
10875
10712
  * Get role IDs for a user
10876
10713
  */
10877
10714
  async getUserRoleIds(userId) {
10878
- const roles2 = await this.getUserRoles(userId);
10879
- return roles2.map((r) => r.id);
10715
+ const usersTableName = this.getQualifiedUsersTableName();
10716
+ const result = await this.db.execute(drizzleOrm.sql`
10717
+ SELECT roles FROM ${drizzleOrm.sql.raw(usersTableName)} WHERE id = ${userId}
10718
+ `);
10719
+ if (result.rows.length === 0) return [];
10720
+ const row = result.rows[0];
10721
+ return row.roles ?? [];
10880
10722
  }
10881
10723
  /**
10882
- * Set roles for a user
10724
+ * Set roles for a user (replaces existing roles)
10883
10725
  */
10884
10726
  async setUserRoles(userId, roleIds) {
10885
- const rolesSchema = pgCore.getTableConfig(this.userRolesTable).schema || "public";
10886
- await this.db.execute(drizzleOrm.sql`DELETE FROM ${drizzleOrm.sql.raw(`"${rolesSchema}"."user_roles"`)} WHERE user_id = ${userId}`);
10887
- for (const roleId of roleIds) {
10888
- await this.db.execute(drizzleOrm.sql`
10889
- INSERT INTO ${drizzleOrm.sql.raw(`"${rolesSchema}"."user_roles"`)} (user_id, role_id)
10890
- VALUES (${userId}, ${roleId})
10891
- ON CONFLICT DO NOTHING
10892
- `);
10893
- }
10727
+ const usersTableName = this.getQualifiedUsersTableName();
10728
+ const rolesArray = `{${roleIds.join(",")}}`;
10729
+ await this.db.execute(drizzleOrm.sql`
10730
+ UPDATE ${drizzleOrm.sql.raw(usersTableName)}
10731
+ SET roles = ${rolesArray}::text[], updated_at = NOW()
10732
+ WHERE id = ${userId}
10733
+ `);
10894
10734
  }
10895
10735
  /**
10896
- * Assign a specific role to new user
10736
+ * Assign a specific role to new user (appends if not present)
10897
10737
  */
10898
10738
  async assignDefaultRole(userId, roleId) {
10899
- const rolesSchema = pgCore.getTableConfig(this.userRolesTable).schema || "public";
10739
+ const usersTableName = this.getQualifiedUsersTableName();
10900
10740
  await this.db.execute(drizzleOrm.sql`
10901
- INSERT INTO ${drizzleOrm.sql.raw(`"${rolesSchema}"."user_roles"`)} (user_id, role_id)
10902
- VALUES (${userId}, ${roleId})
10903
- ON CONFLICT DO NOTHING
10741
+ UPDATE ${drizzleOrm.sql.raw(usersTableName)}
10742
+ SET roles = array_append(roles, ${roleId}), updated_at = NOW()
10743
+ WHERE id = ${userId} AND NOT (${roleId} = ANY(roles))
10904
10744
  `);
10905
10745
  }
10906
10746
  /**
@@ -10909,101 +10749,12 @@ ${tableRelations.join(",\n")}
10909
10749
  async getUserWithRoles(userId) {
10910
10750
  const user = await this.getUserById(userId);
10911
10751
  if (!user) return null;
10912
- const roles2 = await this.getUserRoles(userId);
10752
+ const roles = await this.getUserRoles(userId);
10913
10753
  return {
10914
10754
  user,
10915
- roles: roles2
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
10755
+ roles
10986
10756
  };
10987
10757
  }
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
10758
  }
11008
10759
  class RefreshTokenService {
11009
10760
  constructor(db, tableOrTables) {
@@ -11199,11 +10950,9 @@ ${tableRelations.join(",\n")}
11199
10950
  constructor(db, tableOrTables) {
11200
10951
  this.db = db;
11201
10952
  this.userService = new UserService(db, tableOrTables);
11202
- this.roleService = new RoleService(db, tableOrTables);
11203
10953
  this.tokenRepository = new PostgresTokenRepository(db, tableOrTables);
11204
10954
  }
11205
10955
  userService;
11206
- roleService;
11207
10956
  tokenRepository;
11208
10957
  // User operations (delegate to UserService)
11209
10958
  async createUser(data) {
@@ -11263,25 +11012,56 @@ ${tableRelations.join(",\n")}
11263
11012
  async getUserWithRoles(userId) {
11264
11013
  return this.userService.getUserWithRoles(userId);
11265
11014
  }
11266
- // Role operations (delegate to RoleService)
11015
+ // Role operations (roles are inline on users, synthesized from string IDs)
11267
11016
  async getRoleById(id) {
11268
- return this.roleService.getRoleById(id);
11017
+ return {
11018
+ id,
11019
+ name: id,
11020
+ isAdmin: id === "admin",
11021
+ defaultPermissions: null,
11022
+ collectionPermissions: null
11023
+ };
11269
11024
  }
11270
11025
  async listRoles() {
11271
- return this.roleService.listRoles();
11026
+ return [{
11027
+ id: "admin",
11028
+ name: "Admin",
11029
+ isAdmin: true,
11030
+ defaultPermissions: null,
11031
+ collectionPermissions: null
11032
+ }, {
11033
+ id: "editor",
11034
+ name: "Editor",
11035
+ isAdmin: false,
11036
+ defaultPermissions: null,
11037
+ collectionPermissions: null
11038
+ }, {
11039
+ id: "viewer",
11040
+ name: "Viewer",
11041
+ isAdmin: false,
11042
+ defaultPermissions: null,
11043
+ collectionPermissions: null
11044
+ }];
11045
+ }
11046
+ async createRole(_data) {
11047
+ return {
11048
+ id: _data.id,
11049
+ name: _data.name,
11050
+ isAdmin: _data.isAdmin ?? false,
11051
+ defaultPermissions: _data.defaultPermissions ?? null,
11052
+ collectionPermissions: _data.collectionPermissions ?? null
11053
+ };
11272
11054
  }
11273
- async createRole(data) {
11274
- return this.roleService.createRole({
11275
- ...data,
11055
+ async updateRole(id, data) {
11056
+ return {
11057
+ id,
11058
+ name: data.name ?? id,
11059
+ isAdmin: data.isAdmin ?? id === "admin",
11276
11060
  defaultPermissions: data.defaultPermissions ?? null,
11277
11061
  collectionPermissions: data.collectionPermissions ?? null
11278
- });
11279
- }
11280
- async updateRole(id, data) {
11281
- return this.roleService.updateRole(id, data);
11062
+ };
11282
11063
  }
11283
- async deleteRole(id) {
11284
- await this.roleService.deleteRole(id);
11064
+ async deleteRole(_id) {
11285
11065
  }
11286
11066
  // Token operations (delegate to PostgresTokenRepository)
11287
11067
  async createRefreshToken(userId, tokenHash, expiresAt, userAgent, ipAddress) {
@@ -11831,34 +11611,27 @@ ${tableRelations.join(",\n")}
11831
11611
  const internals = driverResult.internals;
11832
11612
  const db = internals.db;
11833
11613
  const registry = internals.registry;
11834
- await ensureAuthTablesExist(db, registry);
11614
+ const authCollection = authConfig.collection;
11615
+ await ensureAuthTablesExist(db, authCollection);
11835
11616
  let emailService;
11836
11617
  if (authConfig.email) {
11837
11618
  emailService = serverCore.createEmailService(authConfig.email);
11838
11619
  }
11839
- const customUsersTable = registry?.getTable("users");
11840
- const customRolesTable = registry?.getTable("roles");
11620
+ const tableName = authCollection ? "table" in authCollection && typeof authCollection.table === "string" ? authCollection.table : authCollection.slug : void 0;
11621
+ const usersTable = tableName ? registry.getTable(tableName) : void 0;
11841
11622
  let usersSchemaName = "rebase";
11842
- let rolesSchemaName = "rebase";
11843
- if (customUsersTable) {
11844
- usersSchemaName = pgCore.getTableConfig(customUsersTable).schema || "public";
11623
+ if (authCollection && "schema" in authCollection && typeof authCollection.schema === "string") {
11624
+ usersSchemaName = authCollection.schema;
11845
11625
  }
11846
- if (customRolesTable) {
11847
- rolesSchemaName = pgCore.getTableConfig(customRolesTable).schema || "public";
11848
- }
11849
- const authTables = createAuthSchema(rolesSchemaName, usersSchemaName);
11850
- if (customUsersTable) {
11851
- authTables.users = customUsersTable;
11852
- }
11853
- if (customRolesTable) {
11854
- authTables.roles = customRolesTable;
11626
+ const authTables = createAuthSchema(usersSchemaName);
11627
+ if (usersTable) {
11628
+ authTables.users = usersTable;
11855
11629
  }
11856
11630
  const userService = new UserService(db, authTables);
11857
- const roleService = new RoleService(db, authTables);
11858
11631
  const authRepository = new PostgresAuthRepository(db, authTables);
11859
11632
  return {
11860
11633
  userService,
11861
- roleService,
11634
+ roleService: userService,
11862
11635
  emailService,
11863
11636
  authRepository
11864
11637
  };
@@ -11962,17 +11735,12 @@ ${tableRelations.join(",\n")}
11962
11735
  exports2.mfaFactorsRelations = mfaFactorsRelations;
11963
11736
  exports2.passwordResetTokens = passwordResetTokens;
11964
11737
  exports2.passwordResetTokensRelations = passwordResetTokensRelations;
11965
- exports2.rebaseSchema = rebaseSchema;
11966
11738
  exports2.recoveryCodes = recoveryCodes;
11967
11739
  exports2.recoveryCodesRelations = recoveryCodesRelations;
11968
11740
  exports2.refreshTokens = refreshTokens;
11969
11741
  exports2.refreshTokensRelations = refreshTokensRelations;
11970
- exports2.roles = roles;
11971
- exports2.rolesRelations = rolesRelations;
11972
11742
  exports2.userIdentities = userIdentities;
11973
11743
  exports2.userIdentitiesRelations = userIdentitiesRelations;
11974
- exports2.userRoles = userRoles;
11975
- exports2.userRolesRelations = userRolesRelations;
11976
11744
  exports2.users = users;
11977
11745
  exports2.usersRelations = usersRelations;
11978
11746
  exports2.usersSchema = usersSchema;