@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.es.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Pool, Client } from "pg";
2
2
  import { drizzle } from "drizzle-orm/node-postgres";
3
- import { sql, inArray, eq, and, or, ilike, asc, desc, gt, lt, getTableName as getTableName$1, count, relations, isTable } from "drizzle-orm";
4
- import { PgVarchar, PgText, PgChar, pgSchema, pgTable, timestamp, jsonb, boolean, varchar, uuid, primaryKey, unique, getTableConfig } from "drizzle-orm/pg-core";
3
+ import { or, and, sql, inArray, eq, ilike, asc, desc, gt, lt, getTableName as getTableName$1, count, relations, isTable } from "drizzle-orm";
4
+ import { PgVarchar, PgText, PgChar, pgSchema, pgTable, timestamp, jsonb, text, boolean, varchar, uuid, unique, getTableConfig } from "drizzle-orm/pg-core";
5
5
  import { createHash, randomUUID } from "crypto";
6
6
  import * as fs from "fs";
7
7
  import { promises } from "fs";
@@ -2711,114 +2711,6 @@ class CollectionRegistry {
2711
2711
  };
2712
2712
  }
2713
2713
  }
2714
- const defaultUsersCollection = {
2715
- name: "Users",
2716
- singularName: "User",
2717
- slug: "users",
2718
- table: "users",
2719
- schema: "rebase",
2720
- icon: "Users",
2721
- group: "Settings",
2722
- properties: {
2723
- id: {
2724
- name: "ID",
2725
- type: "string",
2726
- isId: "uuid"
2727
- },
2728
- email: {
2729
- name: "Email",
2730
- type: "string",
2731
- validation: {
2732
- required: true,
2733
- unique: true
2734
- }
2735
- },
2736
- password_hash: {
2737
- name: "Password Hash",
2738
- type: "string",
2739
- ui: {
2740
- hideFromCollection: true
2741
- }
2742
- },
2743
- display_name: {
2744
- name: "Display Name",
2745
- type: "string"
2746
- },
2747
- photo_url: {
2748
- name: "Photo URL",
2749
- type: "string"
2750
- },
2751
- email_verified: {
2752
- name: "Email Verified",
2753
- type: "boolean",
2754
- defaultValue: false
2755
- },
2756
- email_verification_token: {
2757
- name: "Email Verification Token",
2758
- type: "string",
2759
- ui: {
2760
- hideFromCollection: true
2761
- }
2762
- },
2763
- email_verification_sent_at: {
2764
- name: "Email Verification Sent At",
2765
- type: "date",
2766
- ui: {
2767
- hideFromCollection: true
2768
- }
2769
- },
2770
- metadata: {
2771
- name: "Metadata",
2772
- type: "map",
2773
- defaultValue: {},
2774
- ui: {
2775
- hideFromCollection: true
2776
- }
2777
- },
2778
- created_at: {
2779
- name: "Created At",
2780
- type: "date",
2781
- autoValue: "on_create",
2782
- ui: {
2783
- readOnly: true,
2784
- hideFromCollection: true
2785
- }
2786
- },
2787
- updated_at: {
2788
- name: "Updated At",
2789
- type: "date",
2790
- autoValue: "on_update",
2791
- ui: {
2792
- readOnly: true,
2793
- hideFromCollection: true
2794
- }
2795
- }
2796
- }
2797
- };
2798
- function mapOperator(op) {
2799
- switch (op) {
2800
- case "==":
2801
- return "eq";
2802
- case "!=":
2803
- return "neq";
2804
- case ">":
2805
- return "gt";
2806
- case ">=":
2807
- return "gte";
2808
- case "<":
2809
- return "lt";
2810
- case "<=":
2811
- return "lte";
2812
- case "array-contains":
2813
- return "cs";
2814
- case "array-contains-any":
2815
- return "csa";
2816
- case "not-in":
2817
- return "nin";
2818
- default:
2819
- return op;
2820
- }
2821
- }
2822
2714
  class QueryBuilder {
2823
2715
  constructor(collection) {
2824
2716
  this.collection = collection;
@@ -2826,23 +2718,30 @@ class QueryBuilder {
2826
2718
  params = {
2827
2719
  where: {}
2828
2720
  };
2829
- /**
2830
- * Add a filter condition to your query.
2831
- * @example
2832
- * client.collection('users').where('age', '>=', 18).find()
2833
- */
2834
- where(column, operator, value) {
2721
+ where(columnOrCondition, operator, value) {
2722
+ if (typeof columnOrCondition === "object" && columnOrCondition !== null && "type" in columnOrCondition) {
2723
+ this.params.logical = columnOrCondition;
2724
+ return this;
2725
+ }
2835
2726
  if (!this.params.where) {
2836
2727
  this.params.where = {};
2837
2728
  }
2838
- const mappedOp = mapOperator(operator);
2839
- let formattedValue = value;
2840
- if (Array.isArray(value) && ["in", "nin", "cs", "csa"].includes(mappedOp)) {
2841
- formattedValue = `(${value.join(",")})`;
2842
- } else if (value === null) {
2843
- formattedValue = "null";
2729
+ const column = columnOrCondition;
2730
+ const condition = [operator, value];
2731
+ const existing = this.params.where[column];
2732
+ if (existing === void 0) {
2733
+ this.params.where[column] = condition;
2734
+ } else if (Array.isArray(existing) && existing.length > 0 && Array.isArray(existing[0])) {
2735
+ this.params.where[column].push(condition);
2736
+ } else {
2737
+ let firstCondition;
2738
+ if (Array.isArray(existing) && existing.length === 2 && typeof existing[0] === "string") {
2739
+ firstCondition = existing;
2740
+ } else {
2741
+ firstCondition = ["==", existing];
2742
+ }
2743
+ this.params.where[column] = [firstCondition, condition];
2844
2744
  }
2845
- this.params.where[column] = mappedOp === "eq" ? String(formattedValue) : `${mappedOp}.${formattedValue}`;
2846
2745
  return this;
2847
2746
  }
2848
2747
  /**
@@ -2944,10 +2843,13 @@ function convertWhereToFilter(where) {
2944
2843
  filter[field] = ["==", rawValue];
2945
2844
  continue;
2946
2845
  }
2947
- if (Array.isArray(rawValue) && rawValue.length === 2) {
2948
- const [rawOp, val] = rawValue;
2949
- const mappedOp = operatorMap[rawOp] ?? "==";
2950
- filter[field] = [mappedOp, val];
2846
+ if (Array.isArray(rawValue)) {
2847
+ const conditions = Array.isArray(rawValue[0]) ? rawValue : [rawValue];
2848
+ const mappedConditions = conditions.map(([rawOp, val]) => {
2849
+ const mappedOp = operatorMap[rawOp] ?? "==";
2850
+ return [mappedOp, val];
2851
+ });
2852
+ filter[field] = Array.isArray(rawValue[0]) ? mappedConditions : mappedConditions[0];
2951
2853
  continue;
2952
2854
  }
2953
2855
  if (typeof rawValue === "string") {
@@ -3041,6 +2943,9 @@ function createDriverAccessor(driver, slug) {
3041
2943
  }
3042
2944
  });
3043
2945
  },
2946
+ deleteAll: driver.deleteAll ? async () => {
2947
+ return driver.deleteAll(slug);
2948
+ } : void 0,
3044
2949
  count: driver.countEntities ? async (params) => {
3045
2950
  return driver.countEntities({
3046
2951
  path: slug,
@@ -3082,8 +2987,12 @@ function createDriverAccessor(driver, slug) {
3082
2987
  });
3083
2988
  } : void 0,
3084
2989
  // Fluent Query Builder
3085
- where(column, operator, value) {
3086
- return new QueryBuilder(accessor).where(column, operator, value);
2990
+ where(columnOrCondition, operator, value) {
2991
+ const builder = new QueryBuilder(accessor);
2992
+ if (typeof columnOrCondition === "object") {
2993
+ return builder.where(columnOrCondition);
2994
+ }
2995
+ return builder.where(columnOrCondition, operator, value);
3087
2996
  },
3088
2997
  orderBy(column, ascending) {
3089
2998
  return new QueryBuilder(accessor).orderBy(column, ascending);
@@ -3134,7 +3043,6 @@ class DrizzleConditionBuilder {
3134
3043
  const conditions = [];
3135
3044
  for (const [field, filterParam] of Object.entries(filter)) {
3136
3045
  if (!filterParam) continue;
3137
- const [op, value] = filterParam;
3138
3046
  let fieldColumn = table[field];
3139
3047
  if (!fieldColumn) {
3140
3048
  const relationKey = `${field}_id`;
@@ -3146,13 +3054,39 @@ class DrizzleConditionBuilder {
3146
3054
  console.warn(`Filtering by field '${field}', but it does not exist in table for collection '${collectionPath}'`);
3147
3055
  continue;
3148
3056
  }
3149
- const condition = this.buildSingleFilterCondition(fieldColumn, op, value);
3150
- if (condition) {
3151
- conditions.push(condition);
3057
+ const paramsList = Array.isArray(filterParam) && filterParam.length > 0 && Array.isArray(filterParam[0]) ? filterParam : [filterParam];
3058
+ for (const [op, value] of paramsList) {
3059
+ const condition = this.buildSingleFilterCondition(fieldColumn, op, value);
3060
+ if (condition) {
3061
+ conditions.push(condition);
3062
+ }
3152
3063
  }
3153
3064
  }
3154
3065
  return conditions;
3155
3066
  }
3067
+ /**
3068
+ * Build logical conditions recursively from LogicalCondition or FilterCondition
3069
+ */
3070
+ static buildLogicalConditions(cond, table, collectionPath) {
3071
+ if ("type" in cond) {
3072
+ const subSQLs = cond.conditions.map((c) => this.buildLogicalConditions(c, table, collectionPath)).filter((sql2) => sql2 !== null);
3073
+ if (subSQLs.length === 0) return null;
3074
+ return (cond.type === "or" ? or(...subSQLs) : and(...subSQLs)) ?? null;
3075
+ } else {
3076
+ let fieldColumn = table[cond.column];
3077
+ if (!fieldColumn) {
3078
+ const relationKey = `${cond.column}_id`;
3079
+ if (relationKey in table) {
3080
+ fieldColumn = table[relationKey];
3081
+ }
3082
+ }
3083
+ if (!fieldColumn) {
3084
+ console.warn(`Filtering by field '${cond.column}', but it does not exist in table for collection '${collectionPath}'`);
3085
+ return null;
3086
+ }
3087
+ return this.buildSingleFilterCondition(fieldColumn, cond.operator, cond.value);
3088
+ }
3089
+ }
3156
3090
  /**
3157
3091
  * Build a single filter condition for a specific operator and value
3158
3092
  */
@@ -4030,39 +3964,18 @@ function serializePropertyToServer(value, property) {
4030
3964
  }
4031
3965
  return value;
4032
3966
  }
4033
- case "binary":
4034
- if (typeof value === "string") {
4035
- if (value.startsWith("data:application/octet-stream;base64,")) {
4036
- const base64Data = value.split(",")[1];
4037
- if (base64Data) {
4038
- return Buffer.from(base64Data, "base64");
4039
- }
4040
- }
4041
- }
4042
- if (Buffer.isBuffer(value)) {
4043
- return value;
4044
- }
3967
+ case "binary": {
3968
+ const decoded = tryDecodeBase64DataUrl(value);
3969
+ if (decoded) return decoded;
3970
+ if (Buffer.isBuffer(value)) return value;
4045
3971
  return value;
3972
+ }
4046
3973
  case "string":
4047
- if (typeof value === "string") {
4048
- if (value.startsWith("data:application/octet-stream;base64,")) {
4049
- const base64Data = value.split(",")[1];
4050
- if (base64Data) {
4051
- return Buffer.from(base64Data, "base64");
4052
- }
4053
- }
4054
- }
4055
- return value;
4056
- default:
4057
- if (typeof value === "string") {
4058
- if (value.startsWith("data:application/octet-stream;base64,")) {
4059
- const base64Data = value.split(",")[1];
4060
- if (base64Data) {
4061
- return Buffer.from(base64Data, "base64");
4062
- }
4063
- }
4064
- }
3974
+ default: {
3975
+ const decoded = tryDecodeBase64DataUrl(value);
3976
+ if (decoded) return decoded;
4065
3977
  return value;
3978
+ }
4066
3979
  }
4067
3980
  }
4068
3981
  async function parseDataFromServer(data, collection, db, registry) {
@@ -4182,21 +4095,36 @@ async function parseDataFromServer(data, collection, db, registry) {
4182
4095
  }
4183
4096
  return result;
4184
4097
  }
4185
- function parsePropertyFromServer(value, property, collection, propertyKey) {
4186
- if (value === null || value === void 0) {
4187
- return value;
4098
+ function tryDecodeBase64DataUrl(value) {
4099
+ if (typeof value !== "string") return null;
4100
+ if (!value.startsWith("data:application/octet-stream;base64,")) return null;
4101
+ const base64Data = value.split(",")[1];
4102
+ return base64Data ? Buffer.from(base64Data, "base64") : null;
4103
+ }
4104
+ function tryResolveBuffer(value) {
4105
+ if (Buffer.isBuffer(value)) return value;
4106
+ if (typeof value === "object" && value !== null) {
4107
+ const rawVal = value;
4108
+ if (rawVal.type === "Buffer" && Array.isArray(rawVal.data)) {
4109
+ return Buffer.from(rawVal.data);
4110
+ }
4111
+ }
4112
+ return null;
4113
+ }
4114
+ function bufferToStringOrBase64(buf) {
4115
+ for (let i = 0; i < buf.length; i++) {
4116
+ const b = buf[i];
4117
+ if ((b < 32 || b > 126) && b !== 9 && b !== 10 && b !== 13) {
4118
+ return `data:application/octet-stream;base64,${buf.toString("base64")}`;
4119
+ }
4188
4120
  }
4121
+ return buf.toString("utf8");
4122
+ }
4123
+ function parsePropertyFromServer(value, property, collection, propertyKey) {
4124
+ if (value === null || value === void 0) return value;
4189
4125
  switch (property.type) {
4190
4126
  case "binary": {
4191
- let buf = null;
4192
- if (Buffer.isBuffer(value)) {
4193
- buf = value;
4194
- } else if (typeof value === "object" && value !== null) {
4195
- const rawVal = value;
4196
- if (rawVal.type === "Buffer" && Array.isArray(rawVal.data)) {
4197
- buf = Buffer.from(rawVal.data);
4198
- }
4199
- }
4127
+ const buf = tryResolveBuffer(value);
4200
4128
  if (buf) {
4201
4129
  return `data:application/octet-stream;base64,${buf.toString("base64")}`;
4202
4130
  }
@@ -4204,28 +4132,9 @@ function parsePropertyFromServer(value, property, collection, propertyKey) {
4204
4132
  }
4205
4133
  case "string": {
4206
4134
  if (typeof value === "string") return value;
4207
- let isBuffer = false;
4208
- let buf = null;
4209
- if (Buffer.isBuffer(value)) {
4210
- isBuffer = true;
4211
- buf = value;
4212
- } else if (typeof value === "object" && value !== null) {
4213
- const rawVal = value;
4214
- if (rawVal.type === "Buffer" && Array.isArray(rawVal.data)) {
4215
- isBuffer = true;
4216
- buf = Buffer.from(rawVal.data);
4217
- }
4218
- }
4219
- if (isBuffer && buf) {
4220
- let isPrintable = true;
4221
- for (let i = 0; i < buf.length; i++) {
4222
- const b = buf[i];
4223
- if ((b < 32 || b > 126) && b !== 9 && b !== 10 && b !== 13) {
4224
- isPrintable = false;
4225
- break;
4226
- }
4227
- }
4228
- return isPrintable ? buf.toString("utf8") : `data:application/octet-stream;base64,${buf.toString("base64")}`;
4135
+ const buf = tryResolveBuffer(value);
4136
+ if (buf) {
4137
+ return bufferToStringOrBase64(buf);
4229
4138
  }
4230
4139
  if (typeof value === "object" && value !== null) {
4231
4140
  try {
@@ -4339,28 +4248,9 @@ function parsePropertyFromServer(value, property, collection, propertyKey) {
4339
4248
  return null;
4340
4249
  }
4341
4250
  default: {
4342
- let isBuffer = false;
4343
- let buf = null;
4344
- if (Buffer.isBuffer(value)) {
4345
- isBuffer = true;
4346
- buf = value;
4347
- } else if (typeof value === "object" && value !== null) {
4348
- const rawVal = value;
4349
- if (rawVal.type === "Buffer" && Array.isArray(rawVal.data)) {
4350
- isBuffer = true;
4351
- buf = Buffer.from(rawVal.data);
4352
- }
4353
- }
4354
- if (isBuffer && buf) {
4355
- let isPrintable = true;
4356
- for (let i = 0; i < buf.length; i++) {
4357
- const b = buf[i];
4358
- if ((b < 32 || b > 126) && b !== 9 && b !== 10 && b !== 13) {
4359
- isPrintable = false;
4360
- break;
4361
- }
4362
- }
4363
- return isPrintable ? buf.toString("utf8") : `data:application/octet-stream;base64,${buf.toString("base64")}`;
4251
+ const buf = tryResolveBuffer(value);
4252
+ if (buf) {
4253
+ return bufferToStringOrBase64(buf);
4364
4254
  }
4365
4255
  return value;
4366
4256
  }
@@ -5549,6 +5439,10 @@ class EntityFetchService {
5549
5439
  const filterConditions = this.buildFilterConditions(options.filter, table, collectionPath);
5550
5440
  if (filterConditions.length > 0) allConditions.push(...filterConditions);
5551
5441
  }
5442
+ if (options.logical) {
5443
+ const logicalCondition = DrizzleConditionBuilder.buildLogicalConditions(options.logical, table, collectionPath);
5444
+ if (logicalCondition) allConditions.push(logicalCondition);
5445
+ }
5552
5446
  if (options.startAfter) {
5553
5447
  const cursorConditions = this.buildCursorConditions(table, idField, idInfo, options, collectionPath);
5554
5448
  if (cursorConditions.length > 0) allConditions.push(...cursorConditions);
@@ -5720,6 +5614,10 @@ class EntityFetchService {
5720
5614
  const filterConditions = this.buildFilterConditions(options.filter, table, collectionPath);
5721
5615
  if (filterConditions.length > 0) allConditions.push(...filterConditions);
5722
5616
  }
5617
+ if (options.logical) {
5618
+ const logicalCondition = DrizzleConditionBuilder.buildLogicalConditions(options.logical, table, collectionPath);
5619
+ if (logicalCondition) allConditions.push(logicalCondition);
5620
+ }
5723
5621
  if (vectorMeta?.filter) {
5724
5622
  allConditions.push(vectorMeta.filter);
5725
5623
  }
@@ -6305,6 +6203,14 @@ class EntityPersistService {
6305
6203
  const parsedId = parsedIdObj[idInfo.fieldName];
6306
6204
  await this.db.delete(table).where(eq(idField, parsedId));
6307
6205
  }
6206
+ /**
6207
+ * Delete all entities from a collection
6208
+ */
6209
+ async deleteAll(collectionPath, _databaseId) {
6210
+ const collection = getCollectionByPath(collectionPath, this.registry);
6211
+ const table = getTableForCollection(collection, this.registry);
6212
+ await this.db.delete(table);
6213
+ }
6308
6214
  /**
6309
6215
  * Save an entity (create or update)
6310
6216
  */
@@ -6537,12 +6443,12 @@ class EntityPersistService {
6537
6443
  */
6538
6444
  extractCauseMessage(error) {
6539
6445
  if (!error || typeof error !== "object") return null;
6540
- const err = error;
6541
- if (err.cause && typeof err.cause === "object") {
6542
- const deeper = this.extractCauseMessage(err.cause);
6446
+ if (!(error instanceof Error)) return null;
6447
+ if (error.cause && typeof error.cause === "object") {
6448
+ const deeper = this.extractCauseMessage(error.cause);
6543
6449
  if (deeper) return deeper;
6544
- if (err.cause instanceof Error && err.cause.message) {
6545
- return err.cause.message;
6450
+ if (error.cause instanceof Error && error.cause.message) {
6451
+ return error.cause.message;
6546
6452
  }
6547
6453
  }
6548
6454
  return null;
@@ -6563,12 +6469,17 @@ class EntityPersistService {
6563
6469
  */
6564
6470
  extractPgError(error) {
6565
6471
  if (!error || typeof error !== "object") return null;
6566
- const err = error;
6567
- if (err.code && /^[0-9A-Z]{5}$/.test(err.code)) {
6568
- return err;
6472
+ if (!(error instanceof Error)) {
6473
+ if ("cause" in error && error.cause && typeof error.cause === "object") {
6474
+ return this.extractPgError(error.cause);
6475
+ }
6476
+ return null;
6477
+ }
6478
+ if ("code" in error && typeof error.code === "string" && /^[0-9A-Z]{5}$/.test(error.code)) {
6479
+ return error;
6569
6480
  }
6570
- if (err.cause && typeof err.cause === "object") {
6571
- return this.extractPgError(err.cause);
6481
+ if (error.cause && typeof error.cause === "object") {
6482
+ return this.extractPgError(error.cause);
6572
6483
  }
6573
6484
  return null;
6574
6485
  }
@@ -6636,6 +6547,12 @@ class EntityService {
6636
6547
  async deleteEntity(collectionPath, entityId, databaseId) {
6637
6548
  return this.persistService.deleteEntity(collectionPath, entityId, databaseId);
6638
6549
  }
6550
+ /**
6551
+ * Delete all entities from a collection
6552
+ */
6553
+ async deleteAll(collectionPath, databaseId) {
6554
+ return this.persistService.deleteAll(collectionPath, databaseId);
6555
+ }
6639
6556
  /**
6640
6557
  * Execute raw SQL
6641
6558
  */
@@ -7336,6 +7253,10 @@ class PostgresBackendDriver {
7336
7253
  await this.realtimeService.notifyEntityUpdate(entity.path, entity.id.toString(), null, entity.databaseId || resolvedCollection?.databaseId);
7337
7254
  }
7338
7255
  }
7256
+ async deleteAll(path2) {
7257
+ await this.entityService.deleteAll(path2);
7258
+ await this.realtimeService.notifyEntityUpdate(path2, "*", null);
7259
+ }
7339
7260
  async checkUniqueField(path2, name, value, entityId, collection) {
7340
7261
  return this.entityService.checkUniqueField(path2, name, value, entityId, collection?.databaseId);
7341
7262
  }
@@ -7605,11 +7526,11 @@ class AuthenticatedPostgresBackendDriver {
7605
7526
  console.warn("[DataDriver] User ID (uid) is missing for authenticated delegate. Using 'anonymous'. User object:", this.user);
7606
7527
  userId = "anonymous";
7607
7528
  }
7608
- const userRoles2 = this.user?.roles ?? [];
7529
+ const userRoles = this.user?.roles ?? [];
7609
7530
  if (!this.user?.roles) {
7610
7531
  console.warn("[DataDriver] User roles are missing for authenticated delegate. Using empty array. User object:", this.user);
7611
7532
  }
7612
- const normalizedRoles = userRoles2.map((r) => typeof r === "string" ? r : r?.id ?? String(r));
7533
+ const normalizedRoles = userRoles.map((r) => typeof r === "string" ? r : r?.id ?? String(r));
7613
7534
  const rolesString = normalizedRoles.join(",");
7614
7535
  await tx.execute(sql`
7615
7536
  SELECT
@@ -7617,7 +7538,7 @@ class AuthenticatedPostgresBackendDriver {
7617
7538
  set_config('app.user_roles', ${rolesString}, true),
7618
7539
  set_config('app.jwt', ${JSON.stringify({
7619
7540
  sub: userId,
7620
- roles: userRoles2
7541
+ roles: userRoles
7621
7542
  })}, true)
7622
7543
  `);
7623
7544
  const txEntityService = new EntityService(tx, this.delegate.registry);
@@ -7672,6 +7593,9 @@ class AuthenticatedPostgresBackendDriver {
7672
7593
  async deleteEntity(props) {
7673
7594
  return this.withTransaction((delegate) => delegate.deleteEntity(props));
7674
7595
  }
7596
+ async deleteAll(path2) {
7597
+ return this.withTransaction((delegate) => delegate.deleteAll(path2));
7598
+ }
7675
7599
  async checkUniqueField(path2, name, value, entityId, collection) {
7676
7600
  return this.withTransaction((delegate) => delegate.checkUniqueField(path2, name, value, entityId, collection));
7677
7601
  }
@@ -7749,13 +7673,13 @@ class DatabasePoolManager {
7749
7673
  }
7750
7674
  await Promise.all(promises2);
7751
7675
  this.pools.clear();
7676
+ this.drizzleInstances.clear();
7752
7677
  }
7753
7678
  }
7754
- function createAuthSchema(rolesSchemaName = "rebase", usersSchemaName = "rebase") {
7755
- const rolesSchema = rolesSchemaName === "public" ? null : pgSchema(rolesSchemaName);
7679
+ function createAuthSchema(usersSchemaName = "rebase") {
7756
7680
  const usersSchema2 = usersSchemaName === "public" ? null : pgSchema(usersSchemaName);
7757
- const rolesTableCreator = rolesSchema ? rolesSchema.table.bind(rolesSchema) : pgTable;
7758
- const usersTableCreator = usersSchema2 ? usersSchema2.table.bind(usersSchema2) : pgTable;
7681
+ const tableCreator = usersSchema2 ? usersSchema2.table.bind(usersSchema2) : pgTable;
7682
+ const usersTableCreator = tableCreator;
7759
7683
  const users2 = usersTableCreator("users", {
7760
7684
  id: uuid("id").defaultRandom().primaryKey(),
7761
7685
  email: varchar("email", {
@@ -7777,37 +7701,12 @@ function createAuthSchema(rolesSchemaName = "rebase", usersSchemaName = "rebase"
7777
7701
  }),
7778
7702
  emailVerificationSentAt: timestamp("email_verification_sent_at"),
7779
7703
  isAnonymous: boolean("is_anonymous").default(false).notNull(),
7704
+ roles: text("roles").array().default([]).notNull(),
7780
7705
  metadata: jsonb("metadata").$type().default({}).notNull(),
7781
7706
  createdAt: timestamp("created_at").defaultNow().notNull(),
7782
7707
  updatedAt: timestamp("updated_at").defaultNow().notNull()
7783
7708
  });
7784
- const roles2 = rolesTableCreator("roles", {
7785
- id: varchar("id", {
7786
- length: 50
7787
- }).primaryKey(),
7788
- // 'admin', 'editor', 'viewer'
7789
- name: varchar("name", {
7790
- length: 100
7791
- }).notNull(),
7792
- isAdmin: boolean("is_admin").default(false).notNull(),
7793
- defaultPermissions: jsonb("default_permissions").$type(),
7794
- collectionPermissions: jsonb("collection_permissions").$type()
7795
- });
7796
- const userRoles2 = rolesTableCreator("user_roles", {
7797
- userId: uuid("user_id").notNull().references(() => users2.id, {
7798
- onDelete: "cascade"
7799
- }),
7800
- roleId: varchar("role_id", {
7801
- length: 50
7802
- }).notNull().references(() => roles2.id, {
7803
- onDelete: "cascade"
7804
- })
7805
- }, (table) => ({
7806
- pk: primaryKey({
7807
- columns: [table.userId, table.roleId]
7808
- })
7809
- }));
7810
- const refreshTokens2 = rolesTableCreator("refresh_tokens", {
7709
+ const refreshTokens2 = tableCreator("refresh_tokens", {
7811
7710
  id: uuid("id").defaultRandom().primaryKey(),
7812
7711
  userId: uuid("user_id").notNull().references(() => users2.id, {
7813
7712
  onDelete: "cascade"
@@ -7826,7 +7725,7 @@ function createAuthSchema(rolesSchemaName = "rebase", usersSchemaName = "rebase"
7826
7725
  }, (table) => ({
7827
7726
  uniqueDeviceSession: unique("unique_device_session").on(table.userId, table.userAgent, table.ipAddress)
7828
7727
  }));
7829
- const passwordResetTokens2 = rolesTableCreator("password_reset_tokens", {
7728
+ const passwordResetTokens2 = tableCreator("password_reset_tokens", {
7830
7729
  id: uuid("id").defaultRandom().primaryKey(),
7831
7730
  userId: uuid("user_id").notNull().references(() => users2.id, {
7832
7731
  onDelete: "cascade"
@@ -7838,14 +7737,14 @@ function createAuthSchema(rolesSchemaName = "rebase", usersSchemaName = "rebase"
7838
7737
  usedAt: timestamp("used_at"),
7839
7738
  createdAt: timestamp("created_at").defaultNow().notNull()
7840
7739
  });
7841
- const appConfig2 = rolesTableCreator("app_config", {
7740
+ const appConfig2 = tableCreator("app_config", {
7842
7741
  key: varchar("key", {
7843
7742
  length: 100
7844
7743
  }).primaryKey(),
7845
7744
  value: jsonb("value").notNull(),
7846
7745
  updatedAt: timestamp("updated_at").defaultNow().notNull()
7847
7746
  });
7848
- const userIdentities2 = rolesTableCreator("user_identities", {
7747
+ const userIdentities2 = tableCreator("user_identities", {
7849
7748
  id: uuid("id").defaultRandom().primaryKey(),
7850
7749
  userId: uuid("user_id").notNull().references(() => users2.id, {
7851
7750
  onDelete: "cascade"
@@ -7863,7 +7762,7 @@ function createAuthSchema(rolesSchemaName = "rebase", usersSchemaName = "rebase"
7863
7762
  }, (table) => ({
7864
7763
  uniqueProviderId: unique("unique_provider_id").on(table.provider, table.providerId)
7865
7764
  }));
7866
- const mfaFactors2 = rolesTableCreator("mfa_factors", {
7765
+ const mfaFactors2 = tableCreator("mfa_factors", {
7867
7766
  id: uuid("id").defaultRandom().primaryKey(),
7868
7767
  userId: uuid("user_id").notNull().references(() => users2.id, {
7869
7768
  onDelete: "cascade"
@@ -7882,7 +7781,7 @@ function createAuthSchema(rolesSchemaName = "rebase", usersSchemaName = "rebase"
7882
7781
  createdAt: timestamp("created_at").defaultNow().notNull(),
7883
7782
  updatedAt: timestamp("updated_at").defaultNow().notNull()
7884
7783
  });
7885
- const mfaChallenges2 = rolesTableCreator("mfa_challenges", {
7784
+ const mfaChallenges2 = tableCreator("mfa_challenges", {
7886
7785
  id: uuid("id").defaultRandom().primaryKey(),
7887
7786
  factorId: uuid("factor_id").notNull().references(() => mfaFactors2.id, {
7888
7787
  onDelete: "cascade"
@@ -7894,7 +7793,7 @@ function createAuthSchema(rolesSchemaName = "rebase", usersSchemaName = "rebase"
7894
7793
  }),
7895
7794
  expiresAt: timestamp("expires_at").notNull()
7896
7795
  });
7897
- const recoveryCodes2 = rolesTableCreator("recovery_codes", {
7796
+ const recoveryCodes2 = tableCreator("recovery_codes", {
7898
7797
  id: uuid("id").defaultRandom().primaryKey(),
7899
7798
  userId: uuid("user_id").notNull().references(() => users2.id, {
7900
7799
  onDelete: "cascade"
@@ -7906,11 +7805,8 @@ function createAuthSchema(rolesSchemaName = "rebase", usersSchemaName = "rebase"
7906
7805
  createdAt: timestamp("created_at").defaultNow().notNull()
7907
7806
  });
7908
7807
  return {
7909
- rolesSchema,
7910
7808
  usersSchema: usersSchema2,
7911
7809
  users: users2,
7912
- roles: roles2,
7913
- userRoles: userRoles2,
7914
7810
  refreshTokens: refreshTokens2,
7915
7811
  passwordResetTokens: passwordResetTokens2,
7916
7812
  appConfig: appConfig2,
@@ -7920,12 +7816,9 @@ function createAuthSchema(rolesSchemaName = "rebase", usersSchemaName = "rebase"
7920
7816
  recoveryCodes: recoveryCodes2
7921
7817
  };
7922
7818
  }
7923
- const defaultAuthSchema = createAuthSchema("rebase", "rebase");
7924
- const rebaseSchema = defaultAuthSchema.rolesSchema;
7819
+ const defaultAuthSchema = createAuthSchema("rebase");
7925
7820
  const usersSchema = defaultAuthSchema.usersSchema;
7926
7821
  const users = defaultAuthSchema.users;
7927
- const roles = defaultAuthSchema.roles;
7928
- const userRoles = defaultAuthSchema.userRoles;
7929
7822
  const refreshTokens = defaultAuthSchema.refreshTokens;
7930
7823
  const passwordResetTokens = defaultAuthSchema.passwordResetTokens;
7931
7824
  const appConfig = defaultAuthSchema.appConfig;
@@ -7936,30 +7829,12 @@ const recoveryCodes = defaultAuthSchema.recoveryCodes;
7936
7829
  const usersRelations = relations(users, ({
7937
7830
  many
7938
7831
  }) => ({
7939
- userRoles: many(userRoles),
7940
7832
  refreshTokens: many(refreshTokens),
7941
7833
  passwordResetTokens: many(passwordResetTokens),
7942
7834
  userIdentities: many(userIdentities),
7943
7835
  mfaFactors: many(mfaFactors),
7944
7836
  recoveryCodes: many(recoveryCodes)
7945
7837
  }));
7946
- const rolesRelations = relations(roles, ({
7947
- many
7948
- }) => ({
7949
- userRoles: many(userRoles)
7950
- }));
7951
- const userRolesRelations = relations(userRoles, ({
7952
- one
7953
- }) => ({
7954
- user: one(users, {
7955
- fields: [userRoles.userId],
7956
- references: [users.id]
7957
- }),
7958
- role: one(roles, {
7959
- fields: [userRoles.roleId],
7960
- references: [roles.id]
7961
- })
7962
- }));
7963
7838
  const refreshTokensRelations = relations(refreshTokens, ({
7964
7839
  one
7965
7840
  }) => ({
@@ -8066,6 +7941,8 @@ const getDrizzleColumn = (propName, prop, collection, collections) => {
8066
7941
  columnDefinition = `${enumName}("${colName}")`;
8067
7942
  } else if ("isId" in stringProp && stringProp.isId === "uuid") {
8068
7943
  columnDefinition = `uuid("${colName}")`;
7944
+ } else if (stringProp.columnType === "uuid") {
7945
+ columnDefinition = `uuid("${colName}")`;
8069
7946
  } else if (stringProp.columnType === "text") {
8070
7947
  columnDefinition = `text("${colName}")`;
8071
7948
  } else if (stringProp.columnType === "char") {
@@ -8133,11 +8010,38 @@ const getDrizzleColumn = (propName, prop, collection, collections) => {
8133
8010
  }
8134
8011
  break;
8135
8012
  }
8136
- case "map":
8013
+ case "map": {
8014
+ const mapProp = prop;
8015
+ if (mapProp.columnType === "json") {
8016
+ columnDefinition = `json("${colName}")`;
8017
+ } else {
8018
+ columnDefinition = `jsonb("${colName}")`;
8019
+ }
8020
+ break;
8021
+ }
8137
8022
  case "array": {
8138
- const arrayOrMapProp = prop;
8139
- if (arrayOrMapProp.columnType === "json") {
8023
+ const arrayProp = prop;
8024
+ let colType = arrayProp.columnType;
8025
+ if (!colType && arrayProp.of && !Array.isArray(arrayProp.of)) {
8026
+ const ofProp = arrayProp.of;
8027
+ if (ofProp.type === "string") {
8028
+ colType = "text[]";
8029
+ } else if (ofProp.type === "number") {
8030
+ colType = ofProp.validation?.integer ? "integer[]" : "numeric[]";
8031
+ } else if (ofProp.type === "boolean") {
8032
+ colType = "boolean[]";
8033
+ }
8034
+ }
8035
+ if (colType === "json") {
8140
8036
  columnDefinition = `json("${colName}")`;
8037
+ } else if (colType === "text[]") {
8038
+ columnDefinition = `text("${colName}").array()`;
8039
+ } else if (colType === "integer[]") {
8040
+ columnDefinition = `integer("${colName}").array()`;
8041
+ } else if (colType === "boolean[]") {
8042
+ columnDefinition = `boolean("${colName}").array()`;
8043
+ } else if (colType === "numeric[]") {
8044
+ columnDefinition = `numeric("${colName}").array()`;
8141
8045
  } else {
8142
8046
  columnDefinition = `jsonb("${colName}")`;
8143
8047
  }
@@ -8221,8 +8125,8 @@ const resolveRawSql = (expression) => {
8221
8125
  const resolved = expression.replace(/\{(\w+)\}/g, (_, col) => col);
8222
8126
  return `sql\`${resolved}\``;
8223
8127
  };
8224
- const wrapWithRoleCheck = (clause, roles2) => {
8225
- const rolesArrayString = `ARRAY[${roles2.map((r) => `'${r}'`).join(",")}]`;
8128
+ const wrapWithRoleCheck = (clause, roles) => {
8129
+ const rolesArrayString = `ARRAY[${roles.map((r) => `'${r}'`).join(",")}]`;
8226
8130
  const roleCondition = `string_to_array(auth.roles(), ',') @> ${rolesArrayString}`;
8227
8131
  return `sql\`(${unwrapSql(clause)}) AND (${roleCondition})\``;
8228
8132
  };
@@ -8275,22 +8179,22 @@ const generatePolicyCode = (collection, rule, index) => {
8275
8179
  };
8276
8180
  const generateSinglePolicyCode = (collection, rule, operation, policyName) => {
8277
8181
  const mode = rule.mode ?? "permissive";
8278
- const roles2 = rule.roles ? [...rule.roles].sort() : void 0;
8182
+ const roles = rule.roles ? [...rule.roles].sort() : void 0;
8279
8183
  const needsUsing = operation !== "insert";
8280
8184
  const needsWithCheck = operation !== "select" && operation !== "delete";
8281
8185
  let usingClause = needsUsing ? buildUsingClause(rule, collection) : null;
8282
8186
  let withCheckClause = needsWithCheck ? buildWithCheckClause(rule, collection) : null;
8283
- if (roles2 && roles2.length > 0) {
8187
+ if (roles && roles.length > 0) {
8284
8188
  if (usingClause) {
8285
- usingClause = wrapWithRoleCheck(usingClause, roles2);
8189
+ usingClause = wrapWithRoleCheck(usingClause, roles);
8286
8190
  } else if (needsUsing) {
8287
- const rolesArrayString = `ARRAY[${roles2.map((r) => `'${r}'`).join(",")}]`;
8191
+ const rolesArrayString = `ARRAY[${roles.map((r) => `'${r}'`).join(",")}]`;
8288
8192
  usingClause = `sql\`string_to_array(auth.roles(), ',') @> ${rolesArrayString}\``;
8289
8193
  }
8290
8194
  if (withCheckClause) {
8291
- withCheckClause = wrapWithRoleCheck(withCheckClause, roles2);
8195
+ withCheckClause = wrapWithRoleCheck(withCheckClause, roles);
8292
8196
  } else if (needsWithCheck) {
8293
- const rolesArrayString = `ARRAY[${roles2.map((r) => `'${r}'`).join(",")}]`;
8197
+ const rolesArrayString = `ARRAY[${roles.map((r) => `'${r}'`).join(",")}]`;
8294
8198
  withCheckClause = `sql\`string_to_array(auth.roles(), ',') @> ${rolesArrayString}\``;
8295
8199
  }
8296
8200
  }
@@ -8613,7 +8517,7 @@ ${tableRelations.join(",\n")}
8613
8517
  schemaContent += tablesExport + enumsExport + relationsExport;
8614
8518
  return schemaContent;
8615
8519
  };
8616
- const formatTerminalText = (text, options = {}) => {
8520
+ const formatTerminalText = (text2, options = {}) => {
8617
8521
  let codes = "";
8618
8522
  if (options.bold) codes += "\x1B[1m";
8619
8523
  if (options.backgroundColor) {
@@ -8640,7 +8544,7 @@ const formatTerminalText = (text, options = {}) => {
8640
8544
  };
8641
8545
  codes += textColors[options.textColor];
8642
8546
  }
8643
- return `${codes}${text}\x1B[0m`;
8547
+ return `${codes}${text2}\x1B[0m`;
8644
8548
  };
8645
8549
  const runGeneration = async (collectionsFilePath, outputPath) => {
8646
8550
  try {
@@ -8678,7 +8582,6 @@ const runGeneration = async (collectionsFilePath, outputPath) => {
8678
8582
  if (!collections || !Array.isArray(collections)) {
8679
8583
  collections = [];
8680
8584
  }
8681
- collections = Array.from(new Map([defaultUsersCollection, ...collections].map((c) => [c.slug, c])).values());
8682
8585
  collections.sort((a, b) => a.slug.localeCompare(b.slug));
8683
8586
  const schemaContent = await generateSchema(collections);
8684
8587
  if (outputPath) {
@@ -9664,20 +9567,19 @@ class RealtimeService extends EventEmitter {
9664
9567
  }
9665
9568
  }
9666
9569
  const PostgresRealtimeProvider = RealtimeService;
9667
- const clientSessions = /* @__PURE__ */ new Map();
9668
9570
  const WS_RATE_LIMIT = 2e3;
9669
9571
  const WS_RATE_WINDOW_MS = 6e4;
9670
9572
  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"]);
9671
9573
  function extractErrorMessage(error) {
9672
9574
  if (!error) return "Unknown error";
9673
- if (typeof error === "object") {
9674
- const err = error;
9675
- if (err.cause) {
9676
- return extractErrorMessage(err.cause);
9677
- }
9678
- if (typeof err.message === "string") {
9679
- return err.message;
9575
+ if (error instanceof Error) {
9576
+ if ("cause" in error && error.cause) {
9577
+ return extractErrorMessage(error.cause);
9680
9578
  }
9579
+ return error.message;
9580
+ }
9581
+ if (typeof error === "object" && "message" in error && typeof error.message === "string") {
9582
+ return error.message;
9681
9583
  }
9682
9584
  return String(error);
9683
9585
  }
@@ -9685,14 +9587,10 @@ function isAdminSession(session) {
9685
9587
  if (!session?.user) return false;
9686
9588
  if (session.user.isAdmin) return true;
9687
9589
  if (!session.user.roles) return false;
9688
- return session.user.roles.some((r) => {
9689
- if (typeof r === "string") return r === "admin";
9690
- if (r && typeof r === "object" && "isAdmin" in r) return r.isAdmin;
9691
- if (r && typeof r === "object" && "id" in r) return r.id === "admin";
9692
- return false;
9693
- });
9590
+ return session.user.roles.some((r) => r === "admin");
9694
9591
  }
9695
9592
  function createPostgresWebSocket(server, realtimeService, driver, authConfig, authAdapter) {
9593
+ const clientSessions = /* @__PURE__ */ new Map();
9696
9594
  const isProduction = process.env.NODE_ENV === "production";
9697
9595
  const wsDebug = (...args) => {
9698
9596
  if (!isProduction) console.debug(...args);
@@ -9831,13 +9729,23 @@ function createPostgresWebSocket(server, realtimeService, driver, authConfig, au
9831
9729
  }
9832
9730
  const getScopedDelegate = async () => {
9833
9731
  const session = clientSessions.get(clientId);
9834
- if ("withAuth" in driver && typeof driver.withAuth === "function") {
9732
+ if (typeof driver.withAuth === "function") {
9835
9733
  try {
9836
9734
  const userForAuth = session?.user ? {
9837
9735
  uid: session.user.userId,
9736
+ displayName: null,
9737
+ email: null,
9738
+ photoURL: null,
9739
+ providerId: "websocket",
9740
+ isAnonymous: false,
9838
9741
  roles: session.user.roles ?? []
9839
9742
  } : {
9840
9743
  uid: "anon",
9744
+ displayName: null,
9745
+ email: null,
9746
+ photoURL: null,
9747
+ providerId: "websocket",
9748
+ isAnonymous: true,
9841
9749
  roles: ["anon"]
9842
9750
  };
9843
9751
  return await driver.withAuth(userForAuth);
@@ -10024,15 +9932,15 @@ function createPostgresWebSocket(server, realtimeService, driver, authConfig, au
10024
9932
  wsDebug("👤 [WebSocket Server] Processing FETCH_ROLES request");
10025
9933
  const delegate = await getScopedDelegate();
10026
9934
  const admin = delegate.admin;
10027
- let roles2 = [];
9935
+ let roles = [];
10028
9936
  if (isSQLAdmin(admin) && admin.fetchAvailableRoles) {
10029
- roles2 = await admin.fetchAvailableRoles();
9937
+ roles = await admin.fetchAvailableRoles();
10030
9938
  }
10031
- wsDebug(`👤 [WebSocket Server] Fetched ${roles2.length} roles.`);
9939
+ wsDebug(`👤 [WebSocket Server] Fetched ${roles.length} roles.`);
10032
9940
  const response = {
10033
9941
  type: "FETCH_ROLES_SUCCESS",
10034
9942
  payload: {
10035
- roles: roles2
9943
+ roles
10036
9944
  },
10037
9945
  requestId
10038
9946
  };
@@ -10286,85 +10194,35 @@ class PostgresCollectionRegistry extends CollectionRegistry {
10286
10194
  return collection.relations.map((r) => r.relationName || r.localKey || "").filter(Boolean);
10287
10195
  }
10288
10196
  }
10289
- const DEFAULT_ROLES = [{
10290
- id: "admin",
10291
- name: "Admin",
10292
- is_admin: true,
10293
- default_permissions: {
10294
- read: true,
10295
- create: true,
10296
- edit: true,
10297
- delete: true
10298
- }
10299
- }, {
10300
- id: "editor",
10301
- name: "Editor",
10302
- is_admin: false,
10303
- default_permissions: {
10304
- read: true,
10305
- create: true,
10306
- edit: true,
10307
- delete: true
10308
- }
10309
- }, {
10310
- id: "viewer",
10311
- name: "Viewer",
10312
- is_admin: false,
10313
- default_permissions: {
10314
- read: true,
10315
- create: false,
10316
- edit: false,
10317
- delete: false
10318
- }
10319
- }];
10320
- async function ensureAuthTablesExist(db, registry) {
10197
+ async function ensureAuthTablesExist(db, collection) {
10321
10198
  logger.info("🔍 Checking auth tables...");
10322
10199
  try {
10323
- let usersTableName = '"users"';
10200
+ let usersTableName = '"rebase"."users"';
10324
10201
  let userIdType = "TEXT";
10325
- let usersSchema2 = "public";
10326
- if (registry) {
10327
- const usersTable = registry.getTable("users");
10328
- if (usersTable) {
10329
- const {
10330
- getTableName: getTableName2
10331
- } = await import("drizzle-orm");
10332
- usersSchema2 = getTableConfig(usersTable).schema || "public";
10333
- usersTableName = usersSchema2 === "public" ? `"${getTableName2(usersTable)}"` : `"${usersSchema2}"."${getTableName2(usersTable)}"`;
10334
- if (usersTable.id) {
10335
- const col = usersTable.id;
10336
- const meta = getColumnMeta(col);
10337
- const columnType = meta.columnType;
10338
- if (columnType === "PgUUID") {
10339
- userIdType = "UUID";
10340
- } else if (columnType === "PgSerial" || columnType === "PgInteger") {
10341
- userIdType = "INTEGER";
10342
- } else if (columnType === "PgBigInt" || columnType === "PgBigSerial") {
10343
- userIdType = "BIGINT";
10344
- }
10202
+ let usersSchema2 = "rebase";
10203
+ if (collection) {
10204
+ const rawTable = "table" in collection && typeof collection.table === "string" ? collection.table : collection.slug;
10205
+ usersSchema2 = "schema" in collection && typeof collection.schema === "string" ? collection.schema : "public";
10206
+ usersTableName = usersSchema2 === "public" ? `"${rawTable}"` : `"${usersSchema2}"."${rawTable}"`;
10207
+ const idProp = collection.properties?.id;
10208
+ if (idProp) {
10209
+ const isId = "isId" in idProp ? idProp.isId : void 0;
10210
+ if (isId === "uuid") {
10211
+ userIdType = "UUID";
10212
+ } else if (isId === "autoincrement") {
10213
+ userIdType = "INTEGER";
10345
10214
  }
10346
10215
  }
10347
10216
  }
10348
- let rolesSchema = "rebase";
10349
- if (registry) {
10350
- const rolesTable = registry.getTable("roles");
10351
- if (rolesTable) {
10352
- rolesSchema = getTableConfig(rolesTable).schema || "public";
10353
- }
10354
- }
10355
10217
  if (usersSchema2 !== "public") {
10356
10218
  await db.execute(sql`CREATE SCHEMA IF NOT EXISTS ${sql.raw(usersSchema2)}`);
10357
10219
  }
10358
- if (rolesSchema !== "public" && rolesSchema !== usersSchema2) {
10359
- await db.execute(sql`CREATE SCHEMA IF NOT EXISTS ${sql.raw(rolesSchema)}`);
10360
- }
10361
10220
  await db.execute(sql`CREATE SCHEMA IF NOT EXISTS rebase`);
10362
- const userIdentitiesTable = `"${rolesSchema}"."user_identities"`;
10363
- const rolesTableName = `"${rolesSchema}"."roles"`;
10364
- const userRolesTableName = `"${rolesSchema}"."user_roles"`;
10365
- const refreshTokensTableName = `"${rolesSchema}"."refresh_tokens"`;
10366
- const passwordResetTokensTableName = `"${rolesSchema}"."password_reset_tokens"`;
10367
- const appConfigTableName = `"${rolesSchema}"."app_config"`;
10221
+ const authSchema = usersSchema2 === "public" ? "rebase" : usersSchema2;
10222
+ const userIdentitiesTable = `"${authSchema}"."user_identities"`;
10223
+ const refreshTokensTableName = `"${authSchema}"."refresh_tokens"`;
10224
+ const passwordResetTokensTableName = `"${authSchema}"."password_reset_tokens"`;
10225
+ const appConfigTableName = `"${authSchema}"."app_config"`;
10368
10226
  await db.execute(sql`
10369
10227
  CREATE TABLE IF NOT EXISTS ${sql.raw(userIdentitiesTable)} (
10370
10228
  id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
@@ -10381,27 +10239,6 @@ async function ensureAuthTablesExist(db, registry) {
10381
10239
  CREATE INDEX IF NOT EXISTS idx_user_identities_user
10382
10240
  ON ${sql.raw(userIdentitiesTable)}(user_id)
10383
10241
  `);
10384
- await db.execute(sql`
10385
- CREATE TABLE IF NOT EXISTS ${sql.raw(rolesTableName)} (
10386
- id TEXT PRIMARY KEY,
10387
- name TEXT NOT NULL,
10388
- is_admin BOOLEAN DEFAULT FALSE,
10389
- default_permissions JSONB,
10390
- collection_permissions JSONB,
10391
- created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
10392
- )
10393
- `);
10394
- await db.execute(sql`
10395
- CREATE TABLE IF NOT EXISTS ${sql.raw(userRolesTableName)} (
10396
- user_id ${sql.raw(userIdType)} NOT NULL REFERENCES ${sql.raw(usersTableName)}(id) ON DELETE CASCADE,
10397
- role_id TEXT NOT NULL REFERENCES ${sql.raw(rolesTableName)}(id) ON DELETE CASCADE,
10398
- PRIMARY KEY (user_id, role_id)
10399
- )
10400
- `);
10401
- await db.execute(sql`
10402
- CREATE INDEX IF NOT EXISTS idx_user_roles_user
10403
- ON ${sql.raw(userRolesTableName)}(user_id)
10404
- `);
10405
10242
  await db.execute(sql`
10406
10243
  CREATE TABLE IF NOT EXISTS ${sql.raw(refreshTokensTableName)} (
10407
10244
  id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
@@ -10469,14 +10306,43 @@ async function ensureAuthTablesExist(db, registry) {
10469
10306
  $$ LANGUAGE sql STABLE
10470
10307
  `);
10471
10308
  });
10472
- await seedDefaultRoles(db, rolesTableName);
10473
10309
  await db.execute(sql`
10474
10310
  ALTER TABLE ${sql.raw(usersTableName)}
10475
10311
  ADD COLUMN IF NOT EXISTS is_anonymous BOOLEAN DEFAULT FALSE
10476
10312
  `);
10477
- const mfaFactorsTableName = `"${rolesSchema}"."mfa_factors"`;
10478
- const mfaChallengesTableName = `"${rolesSchema}"."mfa_challenges"`;
10479
- const recoveryCodesTableName = `"${rolesSchema}"."recovery_codes"`;
10313
+ await db.execute(sql`
10314
+ ALTER TABLE ${sql.raw(usersTableName)}
10315
+ ADD COLUMN IF NOT EXISTS roles TEXT[] DEFAULT '{}' NOT NULL
10316
+ `);
10317
+ try {
10318
+ const legacyCheck = await db.execute(sql`
10319
+ SELECT EXISTS (
10320
+ SELECT 1 FROM information_schema.tables
10321
+ WHERE table_schema = 'rebase' AND table_name = 'user_roles'
10322
+ ) AS has_user_roles
10323
+ `);
10324
+ const hasLegacyTables = legacyCheck.rows[0].has_user_roles;
10325
+ if (hasLegacyTables) {
10326
+ logger.info("🔄 Migrating roles from legacy user_roles table...");
10327
+ await db.execute(sql`
10328
+ UPDATE ${sql.raw(usersTableName)} u
10329
+ SET roles = COALESCE((
10330
+ SELECT array_agg(ur.role_id)
10331
+ FROM "rebase"."user_roles" ur
10332
+ WHERE ur.user_id = u.id
10333
+ ), '{}')
10334
+ WHERE u.roles = '{}' OR u.roles IS NULL
10335
+ `);
10336
+ await db.execute(sql`DROP TABLE IF EXISTS "rebase"."user_roles" CASCADE`);
10337
+ await db.execute(sql`DROP TABLE IF EXISTS "rebase"."roles" CASCADE`);
10338
+ logger.info("✅ Legacy roles tables migrated and dropped");
10339
+ }
10340
+ } catch (migrationError) {
10341
+ logger.warn(`⚠️ Legacy roles migration skipped: ${migrationError instanceof Error ? migrationError.message : String(migrationError)}`);
10342
+ }
10343
+ const mfaFactorsTableName = `"${authSchema}"."mfa_factors"`;
10344
+ const mfaChallengesTableName = `"${authSchema}"."mfa_challenges"`;
10345
+ const recoveryCodesTableName = `"${authSchema}"."recovery_codes"`;
10480
10346
  await db.execute(sql`
10481
10347
  CREATE TABLE IF NOT EXISTS ${sql.raw(mfaFactorsTableName)} (
10482
10348
  id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
@@ -10528,28 +10394,6 @@ async function ensureAuthTablesExist(db, registry) {
10528
10394
  logger.warn("⚠️ Continuing without creating auth tables.");
10529
10395
  }
10530
10396
  }
10531
- async function seedDefaultRoles(db, rolesTableName) {
10532
- const result = await db.execute(sql`SELECT COUNT(*) as count FROM ${sql.raw(rolesTableName)}`);
10533
- const count2 = parseInt(result.rows[0]?.count || "0", 10);
10534
- if (count2 > 0) {
10535
- logger.info(`📋 Found ${count2} existing roles`);
10536
- return;
10537
- }
10538
- logger.info("🌱 Seeding default roles...");
10539
- for (const role of DEFAULT_ROLES) {
10540
- await db.execute(sql`
10541
- INSERT INTO ${sql.raw(rolesTableName)} (id, name, is_admin, default_permissions)
10542
- VALUES (
10543
- ${role.id},
10544
- ${role.name},
10545
- ${role.is_admin},
10546
- ${JSON.stringify(role.default_permissions)}::jsonb
10547
- )
10548
- ON CONFLICT (id) DO NOTHING
10549
- `);
10550
- }
10551
- logger.info("✅ Default roles created: admin, editor, viewer");
10552
- }
10553
10397
  function getColumnKey(table, ...keys2) {
10554
10398
  if (!table) return void 0;
10555
10399
  for (const key of keys2) {
@@ -10569,24 +10413,18 @@ function getColumn(table, ...keys2) {
10569
10413
  class UserService {
10570
10414
  constructor(db, tableOrTables) {
10571
10415
  this.db = db;
10572
- if (tableOrTables && (tableOrTables.users || tableOrTables.roles)) {
10416
+ if (tableOrTables && tableOrTables.users) {
10573
10417
  const tables = tableOrTables;
10574
10418
  this.usersTable = tables.users || users;
10575
10419
  this.userIdentitiesTable = tables.userIdentities || userIdentities;
10576
- this.userRolesTable = tables.userRoles || userRoles;
10577
- this.rolesTable = tables.roles || roles;
10578
10420
  } else {
10579
10421
  const table = tableOrTables;
10580
10422
  this.usersTable = table || users;
10581
10423
  this.userIdentitiesTable = userIdentities;
10582
- this.userRolesTable = userRoles;
10583
- this.rolesTable = roles;
10584
10424
  }
10585
10425
  }
10586
10426
  usersTable;
10587
10427
  userIdentitiesTable;
10588
- userRolesTable;
10589
- rolesTable;
10590
10428
  getQualifiedUsersTableName() {
10591
10429
  const name = getTableName$1(this.usersTable);
10592
10430
  const schema = getTableConfig(this.usersTable).schema || "public";
@@ -10608,7 +10446,7 @@ class UserService {
10608
10446
  const metadata = {
10609
10447
  ...row.metadata || {}
10610
10448
  };
10611
- 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"]);
10449
+ 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"]);
10612
10450
  for (const [key, val] of Object.entries(row)) {
10613
10451
  if (!knownKeys.has(key)) {
10614
10452
  const camelKey = camelCase(key);
@@ -10759,19 +10597,18 @@ class UserService {
10759
10597
  const displayNameCol = getColumn(this.usersTable, "displayName", "display_name");
10760
10598
  const displayNameColumn = displayNameCol ? displayNameCol.name : "display_name";
10761
10599
  const idCol = getColumn(this.usersTable, "id");
10762
- const idColumn = idCol ? idCol.name : "id";
10600
+ idCol ? idCol.name : "id";
10763
10601
  const usersTableName = this.getQualifiedUsersTableName();
10764
- const rolesSchema = getTableConfig(this.userRolesTable).schema || "public";
10765
10602
  const conditions = [];
10766
10603
  if (roleId) {
10767
- conditions.push(sql`EXISTS (SELECT 1 FROM ${sql.raw(`"${rolesSchema}"."user_roles"`)} ur WHERE ur.user_id = ${sql.raw(usersTableName)}.${sql.raw(idColumn)} AND ur.role_id = ${roleId})`);
10604
+ conditions.push(sql`${roleId} = ANY(${sql.raw(usersTableName)}.roles)`);
10768
10605
  }
10769
10606
  if (search) {
10770
10607
  const pattern = `%${search}%`;
10771
10608
  conditions.push(sql`(${sql.raw(usersTableName)}.${sql.raw(emailColumn)} ILIKE ${pattern} OR ${sql.raw(usersTableName)}.${sql.raw(displayNameColumn)} ILIKE ${pattern})`);
10772
10609
  }
10773
10610
  const whereClause = conditions.length > 0 ? sql`WHERE ${sql.join(conditions, sql` AND `)}` : sql``;
10774
- const orderByClause = roleId ? sql`ORDER BY ${sql.raw(usersTableName)}.${sql.raw(orderColumn)} ${direction}` : sql`ORDER BY (SELECT count(*) FROM ${sql.raw(`"${rolesSchema}"."user_roles"`)} ur WHERE ur.user_id = ${sql.raw(usersTableName)}.${sql.raw(idColumn)}) DESC, ${sql.raw(usersTableName)}.${sql.raw(orderColumn)} ${direction}`;
10611
+ const orderByClause = roleId ? sql`ORDER BY ${sql.raw(usersTableName)}.${sql.raw(orderColumn)} ${direction}` : sql`ORDER BY array_length(${sql.raw(usersTableName)}.roles, 1) DESC NULLS LAST, ${sql.raw(usersTableName)}.${sql.raw(orderColumn)} ${direction}`;
10775
10612
  const countResult = await this.db.execute(sql`
10776
10613
  SELECT count(*)::int as total FROM ${sql.raw(usersTableName)}
10777
10614
  ${whereClause}
@@ -10845,54 +10682,57 @@ class UserService {
10845
10682
  return row ? this.mapRowToUser(row) : null;
10846
10683
  }
10847
10684
  /**
10848
- * Get roles for a user from database
10685
+ * Get roles for a user from database (inline TEXT[] column)
10849
10686
  */
10850
10687
  async getUserRoles(userId) {
10851
- const rolesSchema = getTableConfig(this.rolesTable).schema || "public";
10688
+ const usersTableName = this.getQualifiedUsersTableName();
10852
10689
  const result = await this.db.execute(sql`
10853
- SELECT r.id, r.name, r.is_admin, r.default_permissions, r.collection_permissions
10854
- FROM ${sql.raw(`"${rolesSchema}"."roles"`)} r
10855
- INNER JOIN ${sql.raw(`"${rolesSchema}"."user_roles"`)} ur ON r.id = ur.role_id
10856
- WHERE ur.user_id = ${userId}
10690
+ SELECT roles FROM ${sql.raw(usersTableName)} WHERE id = ${userId}
10857
10691
  `);
10858
- return result.rows.map((row) => ({
10859
- id: row.id,
10860
- name: row.name,
10861
- isAdmin: row.is_admin,
10862
- defaultPermissions: row.default_permissions,
10863
- collectionPermissions: row.collection_permissions
10692
+ if (result.rows.length === 0) return [];
10693
+ const row = result.rows[0];
10694
+ const roleIds = row.roles ?? [];
10695
+ return roleIds.map((id) => ({
10696
+ id,
10697
+ name: id,
10698
+ isAdmin: id === "admin",
10699
+ defaultPermissions: null,
10700
+ collectionPermissions: null
10864
10701
  }));
10865
10702
  }
10866
10703
  /**
10867
10704
  * Get role IDs for a user
10868
10705
  */
10869
10706
  async getUserRoleIds(userId) {
10870
- const roles2 = await this.getUserRoles(userId);
10871
- return roles2.map((r) => r.id);
10707
+ const usersTableName = this.getQualifiedUsersTableName();
10708
+ const result = await this.db.execute(sql`
10709
+ SELECT roles FROM ${sql.raw(usersTableName)} WHERE id = ${userId}
10710
+ `);
10711
+ if (result.rows.length === 0) return [];
10712
+ const row = result.rows[0];
10713
+ return row.roles ?? [];
10872
10714
  }
10873
10715
  /**
10874
- * Set roles for a user
10716
+ * Set roles for a user (replaces existing roles)
10875
10717
  */
10876
10718
  async setUserRoles(userId, roleIds) {
10877
- const rolesSchema = getTableConfig(this.userRolesTable).schema || "public";
10878
- await this.db.execute(sql`DELETE FROM ${sql.raw(`"${rolesSchema}"."user_roles"`)} WHERE user_id = ${userId}`);
10879
- for (const roleId of roleIds) {
10880
- await this.db.execute(sql`
10881
- INSERT INTO ${sql.raw(`"${rolesSchema}"."user_roles"`)} (user_id, role_id)
10882
- VALUES (${userId}, ${roleId})
10883
- ON CONFLICT DO NOTHING
10884
- `);
10885
- }
10719
+ const usersTableName = this.getQualifiedUsersTableName();
10720
+ const rolesArray = `{${roleIds.join(",")}}`;
10721
+ await this.db.execute(sql`
10722
+ UPDATE ${sql.raw(usersTableName)}
10723
+ SET roles = ${rolesArray}::text[], updated_at = NOW()
10724
+ WHERE id = ${userId}
10725
+ `);
10886
10726
  }
10887
10727
  /**
10888
- * Assign a specific role to new user
10728
+ * Assign a specific role to new user (appends if not present)
10889
10729
  */
10890
10730
  async assignDefaultRole(userId, roleId) {
10891
- const rolesSchema = getTableConfig(this.userRolesTable).schema || "public";
10731
+ const usersTableName = this.getQualifiedUsersTableName();
10892
10732
  await this.db.execute(sql`
10893
- INSERT INTO ${sql.raw(`"${rolesSchema}"."user_roles"`)} (user_id, role_id)
10894
- VALUES (${userId}, ${roleId})
10895
- ON CONFLICT DO NOTHING
10733
+ UPDATE ${sql.raw(usersTableName)}
10734
+ SET roles = array_append(roles, ${roleId}), updated_at = NOW()
10735
+ WHERE id = ${userId} AND NOT (${roleId} = ANY(roles))
10896
10736
  `);
10897
10737
  }
10898
10738
  /**
@@ -10901,101 +10741,12 @@ class UserService {
10901
10741
  async getUserWithRoles(userId) {
10902
10742
  const user = await this.getUserById(userId);
10903
10743
  if (!user) return null;
10904
- const roles2 = await this.getUserRoles(userId);
10744
+ const roles = await this.getUserRoles(userId);
10905
10745
  return {
10906
10746
  user,
10907
- roles: roles2
10908
- };
10909
- }
10910
- }
10911
- class RoleService {
10912
- constructor(db, tableOrTables) {
10913
- this.db = db;
10914
- if (tableOrTables && (tableOrTables.roles || tableOrTables.users)) {
10915
- this.rolesTable = tableOrTables.roles || roles;
10916
- } else {
10917
- this.rolesTable = tableOrTables || roles;
10918
- }
10919
- }
10920
- rolesTable;
10921
- getQualifiedRolesTableName() {
10922
- const name = getTableName$1(this.rolesTable);
10923
- const schema = getTableConfig(this.rolesTable).schema || "public";
10924
- return `"${schema}"."${name}"`;
10925
- }
10926
- async getRoleById(id) {
10927
- const tableName = this.getQualifiedRolesTableName();
10928
- const result = await this.db.execute(sql`
10929
- SELECT id, name, is_admin, default_permissions, collection_permissions
10930
- FROM ${sql.raw(tableName)}
10931
- WHERE id = ${id}
10932
- `);
10933
- if (result.rows.length === 0) return null;
10934
- const row = result.rows[0];
10935
- return {
10936
- id: row.id,
10937
- name: row.name,
10938
- isAdmin: row.is_admin,
10939
- defaultPermissions: row.default_permissions,
10940
- collectionPermissions: row.collection_permissions
10941
- };
10942
- }
10943
- async listRoles() {
10944
- const tableName = this.getQualifiedRolesTableName();
10945
- const result = await this.db.execute(sql`
10946
- SELECT id, name, is_admin, default_permissions, collection_permissions
10947
- FROM ${sql.raw(tableName)}
10948
- ORDER BY name
10949
- `);
10950
- return result.rows.map((row) => ({
10951
- id: row.id,
10952
- name: row.name,
10953
- isAdmin: row.is_admin,
10954
- defaultPermissions: row.default_permissions,
10955
- collectionPermissions: row.collection_permissions
10956
- }));
10957
- }
10958
- async createRole(data) {
10959
- const tableName = this.getQualifiedRolesTableName();
10960
- const result = await this.db.execute(sql`
10961
- INSERT INTO ${sql.raw(tableName)} (id, name, is_admin, default_permissions, collection_permissions)
10962
- VALUES (
10963
- ${data.id},
10964
- ${data.name},
10965
- ${data.isAdmin ?? false},
10966
- ${data.defaultPermissions ? JSON.stringify(data.defaultPermissions) : null}::jsonb,
10967
- ${data.collectionPermissions ? JSON.stringify(data.collectionPermissions) : null}::jsonb
10968
- )
10969
- RETURNING id, name, is_admin, default_permissions, collection_permissions
10970
- `);
10971
- const row = result.rows[0];
10972
- return {
10973
- id: row.id,
10974
- name: row.name,
10975
- isAdmin: row.is_admin,
10976
- defaultPermissions: row.default_permissions,
10977
- collectionPermissions: row.collection_permissions
10747
+ roles
10978
10748
  };
10979
10749
  }
10980
- async updateRole(id, data) {
10981
- const existing = await this.getRoleById(id);
10982
- if (!existing) return null;
10983
- const tableName = this.getQualifiedRolesTableName();
10984
- await this.db.execute(sql`
10985
- UPDATE ${sql.raw(tableName)}
10986
- SET
10987
- name = ${data.name ?? existing.name},
10988
- is_admin = ${data.isAdmin ?? existing.isAdmin},
10989
- default_permissions = ${data.defaultPermissions ? JSON.stringify(data.defaultPermissions) : JSON.stringify(existing.defaultPermissions)}::jsonb,
10990
- collection_permissions = ${data.collectionPermissions !== void 0 ? data.collectionPermissions ? JSON.stringify(data.collectionPermissions) : null : existing.collectionPermissions ? JSON.stringify(existing.collectionPermissions) : null}::jsonb
10991
- WHERE id = ${id}
10992
- `);
10993
- return this.getRoleById(id);
10994
- }
10995
- async deleteRole(id) {
10996
- const tableName = this.getQualifiedRolesTableName();
10997
- await this.db.execute(sql`DELETE FROM ${sql.raw(tableName)} WHERE id = ${id}`);
10998
- }
10999
10750
  }
11000
10751
  class RefreshTokenService {
11001
10752
  constructor(db, tableOrTables) {
@@ -11191,11 +10942,9 @@ class PostgresAuthRepository {
11191
10942
  constructor(db, tableOrTables) {
11192
10943
  this.db = db;
11193
10944
  this.userService = new UserService(db, tableOrTables);
11194
- this.roleService = new RoleService(db, tableOrTables);
11195
10945
  this.tokenRepository = new PostgresTokenRepository(db, tableOrTables);
11196
10946
  }
11197
10947
  userService;
11198
- roleService;
11199
10948
  tokenRepository;
11200
10949
  // User operations (delegate to UserService)
11201
10950
  async createUser(data) {
@@ -11255,25 +11004,56 @@ class PostgresAuthRepository {
11255
11004
  async getUserWithRoles(userId) {
11256
11005
  return this.userService.getUserWithRoles(userId);
11257
11006
  }
11258
- // Role operations (delegate to RoleService)
11007
+ // Role operations (roles are inline on users, synthesized from string IDs)
11259
11008
  async getRoleById(id) {
11260
- return this.roleService.getRoleById(id);
11009
+ return {
11010
+ id,
11011
+ name: id,
11012
+ isAdmin: id === "admin",
11013
+ defaultPermissions: null,
11014
+ collectionPermissions: null
11015
+ };
11261
11016
  }
11262
11017
  async listRoles() {
11263
- return this.roleService.listRoles();
11018
+ return [{
11019
+ id: "admin",
11020
+ name: "Admin",
11021
+ isAdmin: true,
11022
+ defaultPermissions: null,
11023
+ collectionPermissions: null
11024
+ }, {
11025
+ id: "editor",
11026
+ name: "Editor",
11027
+ isAdmin: false,
11028
+ defaultPermissions: null,
11029
+ collectionPermissions: null
11030
+ }, {
11031
+ id: "viewer",
11032
+ name: "Viewer",
11033
+ isAdmin: false,
11034
+ defaultPermissions: null,
11035
+ collectionPermissions: null
11036
+ }];
11037
+ }
11038
+ async createRole(_data) {
11039
+ return {
11040
+ id: _data.id,
11041
+ name: _data.name,
11042
+ isAdmin: _data.isAdmin ?? false,
11043
+ defaultPermissions: _data.defaultPermissions ?? null,
11044
+ collectionPermissions: _data.collectionPermissions ?? null
11045
+ };
11264
11046
  }
11265
- async createRole(data) {
11266
- return this.roleService.createRole({
11267
- ...data,
11047
+ async updateRole(id, data) {
11048
+ return {
11049
+ id,
11050
+ name: data.name ?? id,
11051
+ isAdmin: data.isAdmin ?? id === "admin",
11268
11052
  defaultPermissions: data.defaultPermissions ?? null,
11269
11053
  collectionPermissions: data.collectionPermissions ?? null
11270
- });
11271
- }
11272
- async updateRole(id, data) {
11273
- return this.roleService.updateRole(id, data);
11054
+ };
11274
11055
  }
11275
- async deleteRole(id) {
11276
- await this.roleService.deleteRole(id);
11056
+ async deleteRole(_id) {
11277
11057
  }
11278
11058
  // Token operations (delegate to PostgresTokenRepository)
11279
11059
  async createRefreshToken(userId, tokenHash, expiresAt, userAgent, ipAddress) {
@@ -11823,34 +11603,27 @@ function createPostgresBootstrapper(pgConfig) {
11823
11603
  const internals = driverResult.internals;
11824
11604
  const db = internals.db;
11825
11605
  const registry = internals.registry;
11826
- await ensureAuthTablesExist(db, registry);
11606
+ const authCollection = authConfig.collection;
11607
+ await ensureAuthTablesExist(db, authCollection);
11827
11608
  let emailService;
11828
11609
  if (authConfig.email) {
11829
11610
  emailService = createEmailService(authConfig.email);
11830
11611
  }
11831
- const customUsersTable = registry?.getTable("users");
11832
- const customRolesTable = registry?.getTable("roles");
11612
+ const tableName = authCollection ? "table" in authCollection && typeof authCollection.table === "string" ? authCollection.table : authCollection.slug : void 0;
11613
+ const usersTable = tableName ? registry.getTable(tableName) : void 0;
11833
11614
  let usersSchemaName = "rebase";
11834
- let rolesSchemaName = "rebase";
11835
- if (customUsersTable) {
11836
- usersSchemaName = getTableConfig(customUsersTable).schema || "public";
11615
+ if (authCollection && "schema" in authCollection && typeof authCollection.schema === "string") {
11616
+ usersSchemaName = authCollection.schema;
11837
11617
  }
11838
- if (customRolesTable) {
11839
- rolesSchemaName = getTableConfig(customRolesTable).schema || "public";
11840
- }
11841
- const authTables = createAuthSchema(rolesSchemaName, usersSchemaName);
11842
- if (customUsersTable) {
11843
- authTables.users = customUsersTable;
11844
- }
11845
- if (customRolesTable) {
11846
- authTables.roles = customRolesTable;
11618
+ const authTables = createAuthSchema(usersSchemaName);
11619
+ if (usersTable) {
11620
+ authTables.users = usersTable;
11847
11621
  }
11848
11622
  const userService = new UserService(db, authTables);
11849
- const roleService = new RoleService(db, authTables);
11850
11623
  const authRepository = new PostgresAuthRepository(db, authTables);
11851
11624
  return {
11852
11625
  userService,
11853
- roleService,
11626
+ roleService: userService,
11854
11627
  emailService,
11855
11628
  authRepository
11856
11629
  };
@@ -11955,17 +11728,12 @@ export {
11955
11728
  mfaFactorsRelations,
11956
11729
  passwordResetTokens,
11957
11730
  passwordResetTokensRelations,
11958
- rebaseSchema,
11959
11731
  recoveryCodes,
11960
11732
  recoveryCodesRelations,
11961
11733
  refreshTokens,
11962
11734
  refreshTokensRelations,
11963
- roles,
11964
- rolesRelations,
11965
11735
  userIdentities,
11966
11736
  userIdentitiesRelations,
11967
- userRoles,
11968
- userRolesRelations,
11969
11737
  users,
11970
11738
  usersRelations,
11971
11739
  usersSchema