@rebasepro/server-postgresql 0.2.4 → 0.2.5

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 (37) hide show
  1. package/dist/common/src/collections/default-collections.d.ts +5 -8
  2. package/dist/index.es.js +286 -365
  3. package/dist/index.es.js.map +1 -1
  4. package/dist/index.umd.js +283 -362
  5. package/dist/index.umd.js.map +1 -1
  6. package/dist/server-postgresql/src/PostgresBackendDriver.d.ts +2 -0
  7. package/dist/server-postgresql/src/auth/services.d.ts +6 -31
  8. package/dist/server-postgresql/src/schema/auth-schema.d.ts +87 -340
  9. package/dist/server-postgresql/src/services/EntityPersistService.d.ts +4 -0
  10. package/dist/server-postgresql/src/services/entityService.d.ts +4 -0
  11. package/dist/types/src/controllers/auth.d.ts +2 -2
  12. package/dist/types/src/controllers/client.d.ts +25 -40
  13. package/dist/types/src/controllers/data.d.ts +4 -0
  14. package/dist/types/src/controllers/data_driver.d.ts +5 -0
  15. package/dist/types/src/types/auth_adapter.d.ts +3 -56
  16. package/dist/types/src/types/backend.d.ts +2 -2
  17. package/dist/types/src/types/backend_hooks.d.ts +2 -17
  18. package/dist/types/src/types/properties.d.ts +7 -5
  19. package/dist/types/src/types/user_management_delegate.d.ts +16 -53
  20. package/dist/types/src/users/index.d.ts +0 -1
  21. package/dist/types/src/users/user.d.ts +0 -1
  22. package/package.json +6 -6
  23. package/src/PostgresBackendDriver.ts +10 -0
  24. package/src/PostgresBootstrapper.ts +3 -12
  25. package/src/auth/ensure-tables.ts +52 -101
  26. package/src/auth/services.ts +71 -170
  27. package/src/schema/auth-schema.ts +13 -69
  28. package/src/schema/doctor.ts +44 -3
  29. package/src/schema/generate-drizzle-schema-logic.ts +33 -3
  30. package/src/schema/introspect-db-logic.ts +7 -0
  31. package/src/services/EntityPersistService.ts +9 -0
  32. package/src/services/entityService.ts +7 -0
  33. package/test/auth-services.test.ts +7 -150
  34. package/test/doctor.test.ts +6 -2
  35. package/dist/server-postgresql/src/schema/default-collections.d.ts +0 -2
  36. package/dist/types/src/users/roles.d.ts +0 -14
  37. package/src/schema/default-collections.ts +0 -69
package/dist/index.umd.js CHANGED
@@ -2727,11 +2727,17 @@
2727
2727
  schema: "rebase",
2728
2728
  icon: "Users",
2729
2729
  group: "Settings",
2730
+ openEntityMode: "dialog",
2731
+ disableDefaultActions: ["copy"],
2732
+ sort: ["createdAt", "desc"],
2730
2733
  properties: {
2731
2734
  id: {
2732
2735
  name: "ID",
2733
2736
  type: "string",
2734
- isId: "uuid"
2737
+ isId: "uuid",
2738
+ ui: {
2739
+ readOnly: true
2740
+ }
2735
2741
  },
2736
2742
  email: {
2737
2743
  name: "Email",
@@ -2741,38 +2747,77 @@
2741
2747
  unique: true
2742
2748
  }
2743
2749
  },
2744
- password_hash: {
2745
- name: "Password Hash",
2750
+ displayName: {
2751
+ name: "Name",
2746
2752
  type: "string",
2747
- ui: {
2748
- hideFromCollection: true
2753
+ columnName: "display_name",
2754
+ validation: {
2755
+ required: true
2749
2756
  }
2750
2757
  },
2751
- display_name: {
2752
- name: "Display Name",
2753
- type: "string"
2754
- },
2755
- photo_url: {
2758
+ photoURL: {
2756
2759
  name: "Photo URL",
2757
- type: "string"
2760
+ type: "string",
2761
+ columnName: "photo_url",
2762
+ url: "image"
2758
2763
  },
2759
- email_verified: {
2764
+ roles: {
2765
+ name: "Roles",
2766
+ type: "array",
2767
+ columnType: "text[]",
2768
+ of: {
2769
+ name: "Role",
2770
+ type: "string",
2771
+ enum: {
2772
+ admin: "Admin",
2773
+ editor: "Editor",
2774
+ viewer: "Viewer"
2775
+ }
2776
+ }
2777
+ },
2778
+ passwordHash: {
2779
+ name: "Password Hash",
2780
+ type: "string",
2781
+ columnName: "password_hash",
2782
+ ui: {
2783
+ hideFromCollection: true,
2784
+ disabled: {
2785
+ hidden: true
2786
+ }
2787
+ }
2788
+ },
2789
+ emailVerified: {
2760
2790
  name: "Email Verified",
2761
2791
  type: "boolean",
2762
- defaultValue: false
2792
+ columnName: "email_verified",
2793
+ defaultValue: false,
2794
+ ui: {
2795
+ hideFromCollection: true,
2796
+ disabled: {
2797
+ hidden: true
2798
+ }
2799
+ }
2763
2800
  },
2764
- email_verification_token: {
2801
+ emailVerificationToken: {
2765
2802
  name: "Email Verification Token",
2766
2803
  type: "string",
2804
+ columnName: "email_verification_token",
2767
2805
  ui: {
2768
- hideFromCollection: true
2806
+ hideFromCollection: true,
2807
+ disabled: {
2808
+ hidden: true
2809
+ }
2769
2810
  }
2770
2811
  },
2771
- email_verification_sent_at: {
2812
+ emailVerificationSentAt: {
2772
2813
  name: "Email Verification Sent At",
2773
2814
  type: "date",
2815
+ columnName: "email_verification_sent_at",
2774
2816
  ui: {
2775
- hideFromCollection: true
2817
+ hideFromCollection: true,
2818
+ disabled: {
2819
+ hidden: true
2820
+ }
2776
2821
  }
2777
2822
  },
2778
2823
  metadata: {
@@ -2780,28 +2825,35 @@
2780
2825
  type: "map",
2781
2826
  defaultValue: {},
2782
2827
  ui: {
2783
- hideFromCollection: true
2828
+ hideFromCollection: true,
2829
+ disabled: {
2830
+ hidden: true
2831
+ }
2784
2832
  }
2785
2833
  },
2786
- created_at: {
2834
+ createdAt: {
2787
2835
  name: "Created At",
2788
2836
  type: "date",
2789
- autoValue: "on_create",
2837
+ columnName: "created_at",
2790
2838
  ui: {
2791
- readOnly: true,
2792
- hideFromCollection: true
2839
+ readOnly: true
2793
2840
  }
2794
2841
  },
2795
- updated_at: {
2842
+ updatedAt: {
2796
2843
  name: "Updated At",
2797
2844
  type: "date",
2845
+ columnName: "updated_at",
2798
2846
  autoValue: "on_update",
2799
2847
  ui: {
2800
- readOnly: true,
2801
- hideFromCollection: true
2848
+ hideFromCollection: true,
2849
+ disabled: {
2850
+ hidden: true
2851
+ }
2802
2852
  }
2803
2853
  }
2804
- }
2854
+ },
2855
+ listProperties: ["displayName", "email", "roles", "createdAt"],
2856
+ propertiesOrder: ["id", "email", "displayName", "roles", "createdAt"]
2805
2857
  };
2806
2858
  function mapOperator(op) {
2807
2859
  switch (op) {
@@ -3049,6 +3101,9 @@
3049
3101
  }
3050
3102
  });
3051
3103
  },
3104
+ deleteAll: driver.deleteAll ? async () => {
3105
+ return driver.deleteAll(slug);
3106
+ } : void 0,
3052
3107
  count: driver.countEntities ? async (params) => {
3053
3108
  return driver.countEntities({
3054
3109
  path: slug,
@@ -6313,6 +6368,14 @@
6313
6368
  const parsedId = parsedIdObj[idInfo.fieldName];
6314
6369
  await this.db.delete(table).where(drizzleOrm.eq(idField, parsedId));
6315
6370
  }
6371
+ /**
6372
+ * Delete all entities from a collection
6373
+ */
6374
+ async deleteAll(collectionPath, _databaseId) {
6375
+ const collection = getCollectionByPath(collectionPath, this.registry);
6376
+ const table = getTableForCollection(collection, this.registry);
6377
+ await this.db.delete(table);
6378
+ }
6316
6379
  /**
6317
6380
  * Save an entity (create or update)
6318
6381
  */
@@ -6644,6 +6707,12 @@
6644
6707
  async deleteEntity(collectionPath, entityId, databaseId) {
6645
6708
  return this.persistService.deleteEntity(collectionPath, entityId, databaseId);
6646
6709
  }
6710
+ /**
6711
+ * Delete all entities from a collection
6712
+ */
6713
+ async deleteAll(collectionPath, databaseId) {
6714
+ return this.persistService.deleteAll(collectionPath, databaseId);
6715
+ }
6647
6716
  /**
6648
6717
  * Execute raw SQL
6649
6718
  */
@@ -7344,6 +7413,10 @@
7344
7413
  await this.realtimeService.notifyEntityUpdate(entity.path, entity.id.toString(), null, entity.databaseId || resolvedCollection?.databaseId);
7345
7414
  }
7346
7415
  }
7416
+ async deleteAll(path2) {
7417
+ await this.entityService.deleteAll(path2);
7418
+ await this.realtimeService.notifyEntityUpdate(path2, "*", null);
7419
+ }
7347
7420
  async checkUniqueField(path2, name, value, entityId, collection) {
7348
7421
  return this.entityService.checkUniqueField(path2, name, value, entityId, collection?.databaseId);
7349
7422
  }
@@ -7613,11 +7686,11 @@
7613
7686
  console.warn("[DataDriver] User ID (uid) is missing for authenticated delegate. Using 'anonymous'. User object:", this.user);
7614
7687
  userId = "anonymous";
7615
7688
  }
7616
- const userRoles2 = this.user?.roles ?? [];
7689
+ const userRoles = this.user?.roles ?? [];
7617
7690
  if (!this.user?.roles) {
7618
7691
  console.warn("[DataDriver] User roles are missing for authenticated delegate. Using empty array. User object:", this.user);
7619
7692
  }
7620
- const normalizedRoles = userRoles2.map((r) => typeof r === "string" ? r : r?.id ?? String(r));
7693
+ const normalizedRoles = userRoles.map((r) => typeof r === "string" ? r : r?.id ?? String(r));
7621
7694
  const rolesString = normalizedRoles.join(",");
7622
7695
  await tx.execute(drizzleOrm.sql`
7623
7696
  SELECT
@@ -7625,7 +7698,7 @@
7625
7698
  set_config('app.user_roles', ${rolesString}, true),
7626
7699
  set_config('app.jwt', ${JSON.stringify({
7627
7700
  sub: userId,
7628
- roles: userRoles2
7701
+ roles: userRoles
7629
7702
  })}, true)
7630
7703
  `);
7631
7704
  const txEntityService = new EntityService(tx, this.delegate.registry);
@@ -7680,6 +7753,9 @@
7680
7753
  async deleteEntity(props) {
7681
7754
  return this.withTransaction((delegate) => delegate.deleteEntity(props));
7682
7755
  }
7756
+ async deleteAll(path2) {
7757
+ return this.delegate.deleteAll(path2);
7758
+ }
7683
7759
  async checkUniqueField(path2, name, value, entityId, collection) {
7684
7760
  return this.withTransaction((delegate) => delegate.checkUniqueField(path2, name, value, entityId, collection));
7685
7761
  }
@@ -7759,11 +7835,10 @@
7759
7835
  this.pools.clear();
7760
7836
  }
7761
7837
  }
7762
- function createAuthSchema(rolesSchemaName = "rebase", usersSchemaName = "rebase") {
7763
- const rolesSchema = rolesSchemaName === "public" ? null : pgCore.pgSchema(rolesSchemaName);
7838
+ function createAuthSchema(usersSchemaName = "rebase") {
7764
7839
  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;
7840
+ const tableCreator = usersSchema2 ? usersSchema2.table.bind(usersSchema2) : pgCore.pgTable;
7841
+ const usersTableCreator = tableCreator;
7767
7842
  const users2 = usersTableCreator("users", {
7768
7843
  id: pgCore.uuid("id").defaultRandom().primaryKey(),
7769
7844
  email: pgCore.varchar("email", {
@@ -7785,37 +7860,12 @@
7785
7860
  }),
7786
7861
  emailVerificationSentAt: pgCore.timestamp("email_verification_sent_at"),
7787
7862
  isAnonymous: pgCore.boolean("is_anonymous").default(false).notNull(),
7863
+ roles: pgCore.text("roles").array().default([]).notNull(),
7788
7864
  metadata: pgCore.jsonb("metadata").$type().default({}).notNull(),
7789
7865
  createdAt: pgCore.timestamp("created_at").defaultNow().notNull(),
7790
7866
  updatedAt: pgCore.timestamp("updated_at").defaultNow().notNull()
7791
7867
  });
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", {
7868
+ const refreshTokens2 = tableCreator("refresh_tokens", {
7819
7869
  id: pgCore.uuid("id").defaultRandom().primaryKey(),
7820
7870
  userId: pgCore.uuid("user_id").notNull().references(() => users2.id, {
7821
7871
  onDelete: "cascade"
@@ -7834,7 +7884,7 @@
7834
7884
  }, (table) => ({
7835
7885
  uniqueDeviceSession: pgCore.unique("unique_device_session").on(table.userId, table.userAgent, table.ipAddress)
7836
7886
  }));
7837
- const passwordResetTokens2 = rolesTableCreator("password_reset_tokens", {
7887
+ const passwordResetTokens2 = tableCreator("password_reset_tokens", {
7838
7888
  id: pgCore.uuid("id").defaultRandom().primaryKey(),
7839
7889
  userId: pgCore.uuid("user_id").notNull().references(() => users2.id, {
7840
7890
  onDelete: "cascade"
@@ -7846,14 +7896,14 @@
7846
7896
  usedAt: pgCore.timestamp("used_at"),
7847
7897
  createdAt: pgCore.timestamp("created_at").defaultNow().notNull()
7848
7898
  });
7849
- const appConfig2 = rolesTableCreator("app_config", {
7899
+ const appConfig2 = tableCreator("app_config", {
7850
7900
  key: pgCore.varchar("key", {
7851
7901
  length: 100
7852
7902
  }).primaryKey(),
7853
7903
  value: pgCore.jsonb("value").notNull(),
7854
7904
  updatedAt: pgCore.timestamp("updated_at").defaultNow().notNull()
7855
7905
  });
7856
- const userIdentities2 = rolesTableCreator("user_identities", {
7906
+ const userIdentities2 = tableCreator("user_identities", {
7857
7907
  id: pgCore.uuid("id").defaultRandom().primaryKey(),
7858
7908
  userId: pgCore.uuid("user_id").notNull().references(() => users2.id, {
7859
7909
  onDelete: "cascade"
@@ -7871,7 +7921,7 @@
7871
7921
  }, (table) => ({
7872
7922
  uniqueProviderId: pgCore.unique("unique_provider_id").on(table.provider, table.providerId)
7873
7923
  }));
7874
- const mfaFactors2 = rolesTableCreator("mfa_factors", {
7924
+ const mfaFactors2 = tableCreator("mfa_factors", {
7875
7925
  id: pgCore.uuid("id").defaultRandom().primaryKey(),
7876
7926
  userId: pgCore.uuid("user_id").notNull().references(() => users2.id, {
7877
7927
  onDelete: "cascade"
@@ -7890,7 +7940,7 @@
7890
7940
  createdAt: pgCore.timestamp("created_at").defaultNow().notNull(),
7891
7941
  updatedAt: pgCore.timestamp("updated_at").defaultNow().notNull()
7892
7942
  });
7893
- const mfaChallenges2 = rolesTableCreator("mfa_challenges", {
7943
+ const mfaChallenges2 = tableCreator("mfa_challenges", {
7894
7944
  id: pgCore.uuid("id").defaultRandom().primaryKey(),
7895
7945
  factorId: pgCore.uuid("factor_id").notNull().references(() => mfaFactors2.id, {
7896
7946
  onDelete: "cascade"
@@ -7902,7 +7952,7 @@
7902
7952
  }),
7903
7953
  expiresAt: pgCore.timestamp("expires_at").notNull()
7904
7954
  });
7905
- const recoveryCodes2 = rolesTableCreator("recovery_codes", {
7955
+ const recoveryCodes2 = tableCreator("recovery_codes", {
7906
7956
  id: pgCore.uuid("id").defaultRandom().primaryKey(),
7907
7957
  userId: pgCore.uuid("user_id").notNull().references(() => users2.id, {
7908
7958
  onDelete: "cascade"
@@ -7914,11 +7964,8 @@
7914
7964
  createdAt: pgCore.timestamp("created_at").defaultNow().notNull()
7915
7965
  });
7916
7966
  return {
7917
- rolesSchema,
7918
7967
  usersSchema: usersSchema2,
7919
7968
  users: users2,
7920
- roles: roles2,
7921
- userRoles: userRoles2,
7922
7969
  refreshTokens: refreshTokens2,
7923
7970
  passwordResetTokens: passwordResetTokens2,
7924
7971
  appConfig: appConfig2,
@@ -7928,12 +7975,9 @@
7928
7975
  recoveryCodes: recoveryCodes2
7929
7976
  };
7930
7977
  }
7931
- const defaultAuthSchema = createAuthSchema("rebase", "rebase");
7932
- const rebaseSchema = defaultAuthSchema.rolesSchema;
7978
+ const defaultAuthSchema = createAuthSchema("rebase");
7933
7979
  const usersSchema = defaultAuthSchema.usersSchema;
7934
7980
  const users = defaultAuthSchema.users;
7935
- const roles = defaultAuthSchema.roles;
7936
- const userRoles = defaultAuthSchema.userRoles;
7937
7981
  const refreshTokens = defaultAuthSchema.refreshTokens;
7938
7982
  const passwordResetTokens = defaultAuthSchema.passwordResetTokens;
7939
7983
  const appConfig = defaultAuthSchema.appConfig;
@@ -7944,30 +7988,12 @@
7944
7988
  const usersRelations = drizzleOrm.relations(users, ({
7945
7989
  many
7946
7990
  }) => ({
7947
- userRoles: many(userRoles),
7948
7991
  refreshTokens: many(refreshTokens),
7949
7992
  passwordResetTokens: many(passwordResetTokens),
7950
7993
  userIdentities: many(userIdentities),
7951
7994
  mfaFactors: many(mfaFactors),
7952
7995
  recoveryCodes: many(recoveryCodes)
7953
7996
  }));
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
7997
  const refreshTokensRelations = drizzleOrm.relations(refreshTokens, ({
7972
7998
  one
7973
7999
  }) => ({
@@ -8074,6 +8100,8 @@
8074
8100
  columnDefinition = `${enumName}("${colName}")`;
8075
8101
  } else if ("isId" in stringProp && stringProp.isId === "uuid") {
8076
8102
  columnDefinition = `uuid("${colName}")`;
8103
+ } else if (stringProp.columnType === "uuid") {
8104
+ columnDefinition = `uuid("${colName}")`;
8077
8105
  } else if (stringProp.columnType === "text") {
8078
8106
  columnDefinition = `text("${colName}")`;
8079
8107
  } else if (stringProp.columnType === "char") {
@@ -8141,11 +8169,38 @@
8141
8169
  }
8142
8170
  break;
8143
8171
  }
8144
- case "map":
8172
+ case "map": {
8173
+ const mapProp = prop;
8174
+ if (mapProp.columnType === "json") {
8175
+ columnDefinition = `json("${colName}")`;
8176
+ } else {
8177
+ columnDefinition = `jsonb("${colName}")`;
8178
+ }
8179
+ break;
8180
+ }
8145
8181
  case "array": {
8146
- const arrayOrMapProp = prop;
8147
- if (arrayOrMapProp.columnType === "json") {
8182
+ const arrayProp = prop;
8183
+ let colType = arrayProp.columnType;
8184
+ if (!colType && arrayProp.of && !Array.isArray(arrayProp.of)) {
8185
+ const ofProp = arrayProp.of;
8186
+ if (ofProp.type === "string") {
8187
+ colType = "text[]";
8188
+ } else if (ofProp.type === "number") {
8189
+ colType = ofProp.validation?.integer ? "integer[]" : "numeric[]";
8190
+ } else if (ofProp.type === "boolean") {
8191
+ colType = "boolean[]";
8192
+ }
8193
+ }
8194
+ if (colType === "json") {
8148
8195
  columnDefinition = `json("${colName}")`;
8196
+ } else if (colType === "text[]") {
8197
+ columnDefinition = `text("${colName}").array()`;
8198
+ } else if (colType === "integer[]") {
8199
+ columnDefinition = `integer("${colName}").array()`;
8200
+ } else if (colType === "boolean[]") {
8201
+ columnDefinition = `boolean("${colName}").array()`;
8202
+ } else if (colType === "numeric[]") {
8203
+ columnDefinition = `numeric("${colName}").array()`;
8149
8204
  } else {
8150
8205
  columnDefinition = `jsonb("${colName}")`;
8151
8206
  }
@@ -8229,8 +8284,8 @@
8229
8284
  const resolved = expression.replace(/\{(\w+)\}/g, (_, col) => col);
8230
8285
  return `sql\`${resolved}\``;
8231
8286
  };
8232
- const wrapWithRoleCheck = (clause, roles2) => {
8233
- const rolesArrayString = `ARRAY[${roles2.map((r) => `'${r}'`).join(",")}]`;
8287
+ const wrapWithRoleCheck = (clause, roles) => {
8288
+ const rolesArrayString = `ARRAY[${roles.map((r) => `'${r}'`).join(",")}]`;
8234
8289
  const roleCondition = `string_to_array(auth.roles(), ',') @> ${rolesArrayString}`;
8235
8290
  return `sql\`(${unwrapSql(clause)}) AND (${roleCondition})\``;
8236
8291
  };
@@ -8283,22 +8338,22 @@
8283
8338
  };
8284
8339
  const generateSinglePolicyCode = (collection, rule, operation, policyName) => {
8285
8340
  const mode = rule.mode ?? "permissive";
8286
- const roles2 = rule.roles ? [...rule.roles].sort() : void 0;
8341
+ const roles = rule.roles ? [...rule.roles].sort() : void 0;
8287
8342
  const needsUsing = operation !== "insert";
8288
8343
  const needsWithCheck = operation !== "select" && operation !== "delete";
8289
8344
  let usingClause = needsUsing ? buildUsingClause(rule, collection) : null;
8290
8345
  let withCheckClause = needsWithCheck ? buildWithCheckClause(rule, collection) : null;
8291
- if (roles2 && roles2.length > 0) {
8346
+ if (roles && roles.length > 0) {
8292
8347
  if (usingClause) {
8293
- usingClause = wrapWithRoleCheck(usingClause, roles2);
8348
+ usingClause = wrapWithRoleCheck(usingClause, roles);
8294
8349
  } else if (needsUsing) {
8295
- const rolesArrayString = `ARRAY[${roles2.map((r) => `'${r}'`).join(",")}]`;
8350
+ const rolesArrayString = `ARRAY[${roles.map((r) => `'${r}'`).join(",")}]`;
8296
8351
  usingClause = `sql\`string_to_array(auth.roles(), ',') @> ${rolesArrayString}\``;
8297
8352
  }
8298
8353
  if (withCheckClause) {
8299
- withCheckClause = wrapWithRoleCheck(withCheckClause, roles2);
8354
+ withCheckClause = wrapWithRoleCheck(withCheckClause, roles);
8300
8355
  } else if (needsWithCheck) {
8301
- const rolesArrayString = `ARRAY[${roles2.map((r) => `'${r}'`).join(",")}]`;
8356
+ const rolesArrayString = `ARRAY[${roles.map((r) => `'${r}'`).join(",")}]`;
8302
8357
  withCheckClause = `sql\`string_to_array(auth.roles(), ',') @> ${rolesArrayString}\``;
8303
8358
  }
8304
8359
  }
@@ -10032,15 +10087,15 @@ ${tableRelations.join(",\n")}
10032
10087
  wsDebug("👤 [WebSocket Server] Processing FETCH_ROLES request");
10033
10088
  const delegate = await getScopedDelegate();
10034
10089
  const admin = delegate.admin;
10035
- let roles2 = [];
10090
+ let roles = [];
10036
10091
  if (isSQLAdmin(admin) && admin.fetchAvailableRoles) {
10037
- roles2 = await admin.fetchAvailableRoles();
10092
+ roles = await admin.fetchAvailableRoles();
10038
10093
  }
10039
- wsDebug(`👤 [WebSocket Server] Fetched ${roles2.length} roles.`);
10094
+ wsDebug(`👤 [WebSocket Server] Fetched ${roles.length} roles.`);
10040
10095
  const response = {
10041
10096
  type: "FETCH_ROLES_SUCCESS",
10042
10097
  payload: {
10043
- roles: roles2
10098
+ roles
10044
10099
  },
10045
10100
  requestId
10046
10101
  };
@@ -10294,37 +10349,6 @@ ${tableRelations.join(",\n")}
10294
10349
  return collection.relations.map((r) => r.relationName || r.localKey || "").filter(Boolean);
10295
10350
  }
10296
10351
  }
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
10352
  async function ensureAuthTablesExist(db, registry) {
10329
10353
  serverCore.logger.info("🔍 Checking auth tables...");
10330
10354
  try {
@@ -10353,26 +10377,15 @@ ${tableRelations.join(",\n")}
10353
10377
  }
10354
10378
  }
10355
10379
  }
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
10380
  if (usersSchema2 !== "public") {
10364
10381
  await db.execute(drizzleOrm.sql`CREATE SCHEMA IF NOT EXISTS ${drizzleOrm.sql.raw(usersSchema2)}`);
10365
10382
  }
10366
- if (rolesSchema !== "public" && rolesSchema !== usersSchema2) {
10367
- await db.execute(drizzleOrm.sql`CREATE SCHEMA IF NOT EXISTS ${drizzleOrm.sql.raw(rolesSchema)}`);
10368
- }
10369
10383
  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"`;
10384
+ const authSchema = usersSchema2 === "public" ? "rebase" : usersSchema2;
10385
+ const userIdentitiesTable = `"${authSchema}"."user_identities"`;
10386
+ const refreshTokensTableName = `"${authSchema}"."refresh_tokens"`;
10387
+ const passwordResetTokensTableName = `"${authSchema}"."password_reset_tokens"`;
10388
+ const appConfigTableName = `"${authSchema}"."app_config"`;
10376
10389
  await db.execute(drizzleOrm.sql`
10377
10390
  CREATE TABLE IF NOT EXISTS ${drizzleOrm.sql.raw(userIdentitiesTable)} (
10378
10391
  id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
@@ -10389,27 +10402,6 @@ ${tableRelations.join(",\n")}
10389
10402
  CREATE INDEX IF NOT EXISTS idx_user_identities_user
10390
10403
  ON ${drizzleOrm.sql.raw(userIdentitiesTable)}(user_id)
10391
10404
  `);
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
10405
  await db.execute(drizzleOrm.sql`
10414
10406
  CREATE TABLE IF NOT EXISTS ${drizzleOrm.sql.raw(refreshTokensTableName)} (
10415
10407
  id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
@@ -10477,14 +10469,43 @@ ${tableRelations.join(",\n")}
10477
10469
  $$ LANGUAGE sql STABLE
10478
10470
  `);
10479
10471
  });
10480
- await seedDefaultRoles(db, rolesTableName);
10481
10472
  await db.execute(drizzleOrm.sql`
10482
10473
  ALTER TABLE ${drizzleOrm.sql.raw(usersTableName)}
10483
10474
  ADD COLUMN IF NOT EXISTS is_anonymous BOOLEAN DEFAULT FALSE
10484
10475
  `);
10485
- const mfaFactorsTableName = `"${rolesSchema}"."mfa_factors"`;
10486
- const mfaChallengesTableName = `"${rolesSchema}"."mfa_challenges"`;
10487
- const recoveryCodesTableName = `"${rolesSchema}"."recovery_codes"`;
10476
+ await db.execute(drizzleOrm.sql`
10477
+ ALTER TABLE ${drizzleOrm.sql.raw(usersTableName)}
10478
+ ADD COLUMN IF NOT EXISTS roles TEXT[] DEFAULT '{}' NOT NULL
10479
+ `);
10480
+ try {
10481
+ const legacyCheck = await db.execute(drizzleOrm.sql`
10482
+ SELECT EXISTS (
10483
+ SELECT 1 FROM information_schema.tables
10484
+ WHERE table_schema = 'rebase' AND table_name = 'user_roles'
10485
+ ) AS has_user_roles
10486
+ `);
10487
+ const hasLegacyTables = legacyCheck.rows[0].has_user_roles;
10488
+ if (hasLegacyTables) {
10489
+ serverCore.logger.info("🔄 Migrating roles from legacy user_roles table...");
10490
+ await db.execute(drizzleOrm.sql`
10491
+ UPDATE ${drizzleOrm.sql.raw(usersTableName)} u
10492
+ SET roles = COALESCE((
10493
+ SELECT array_agg(ur.role_id)
10494
+ FROM "rebase"."user_roles" ur
10495
+ WHERE ur.user_id = u.id
10496
+ ), '{}')
10497
+ WHERE u.roles = '{}' OR u.roles IS NULL
10498
+ `);
10499
+ await db.execute(drizzleOrm.sql`DROP TABLE IF EXISTS "rebase"."user_roles" CASCADE`);
10500
+ await db.execute(drizzleOrm.sql`DROP TABLE IF EXISTS "rebase"."roles" CASCADE`);
10501
+ serverCore.logger.info("✅ Legacy roles tables migrated and dropped");
10502
+ }
10503
+ } catch (migrationError) {
10504
+ serverCore.logger.warn(`⚠️ Legacy roles migration skipped: ${migrationError instanceof Error ? migrationError.message : String(migrationError)}`);
10505
+ }
10506
+ const mfaFactorsTableName = `"${authSchema}"."mfa_factors"`;
10507
+ const mfaChallengesTableName = `"${authSchema}"."mfa_challenges"`;
10508
+ const recoveryCodesTableName = `"${authSchema}"."recovery_codes"`;
10488
10509
  await db.execute(drizzleOrm.sql`
10489
10510
  CREATE TABLE IF NOT EXISTS ${drizzleOrm.sql.raw(mfaFactorsTableName)} (
10490
10511
  id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
@@ -10536,28 +10557,6 @@ ${tableRelations.join(",\n")}
10536
10557
  serverCore.logger.warn("⚠️ Continuing without creating auth tables.");
10537
10558
  }
10538
10559
  }
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
10560
  function getColumnKey(table, ...keys2) {
10562
10561
  if (!table) return void 0;
10563
10562
  for (const key of keys2) {
@@ -10577,24 +10576,18 @@ ${tableRelations.join(",\n")}
10577
10576
  class UserService {
10578
10577
  constructor(db, tableOrTables) {
10579
10578
  this.db = db;
10580
- if (tableOrTables && (tableOrTables.users || tableOrTables.roles)) {
10579
+ if (tableOrTables && tableOrTables.users) {
10581
10580
  const tables = tableOrTables;
10582
10581
  this.usersTable = tables.users || users;
10583
10582
  this.userIdentitiesTable = tables.userIdentities || userIdentities;
10584
- this.userRolesTable = tables.userRoles || userRoles;
10585
- this.rolesTable = tables.roles || roles;
10586
10583
  } else {
10587
10584
  const table = tableOrTables;
10588
10585
  this.usersTable = table || users;
10589
10586
  this.userIdentitiesTable = userIdentities;
10590
- this.userRolesTable = userRoles;
10591
- this.rolesTable = roles;
10592
10587
  }
10593
10588
  }
10594
10589
  usersTable;
10595
10590
  userIdentitiesTable;
10596
- userRolesTable;
10597
- rolesTable;
10598
10591
  getQualifiedUsersTableName() {
10599
10592
  const name = drizzleOrm.getTableName(this.usersTable);
10600
10593
  const schema = pgCore.getTableConfig(this.usersTable).schema || "public";
@@ -10616,7 +10609,7 @@ ${tableRelations.join(",\n")}
10616
10609
  const metadata = {
10617
10610
  ...row.metadata || {}
10618
10611
  };
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"]);
10612
+ 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
10613
  for (const [key, val] of Object.entries(row)) {
10621
10614
  if (!knownKeys.has(key)) {
10622
10615
  const camelKey = camelCase(key);
@@ -10767,19 +10760,18 @@ ${tableRelations.join(",\n")}
10767
10760
  const displayNameCol = getColumn(this.usersTable, "displayName", "display_name");
10768
10761
  const displayNameColumn = displayNameCol ? displayNameCol.name : "display_name";
10769
10762
  const idCol = getColumn(this.usersTable, "id");
10770
- const idColumn = idCol ? idCol.name : "id";
10763
+ idCol ? idCol.name : "id";
10771
10764
  const usersTableName = this.getQualifiedUsersTableName();
10772
- const rolesSchema = pgCore.getTableConfig(this.userRolesTable).schema || "public";
10773
10765
  const conditions = [];
10774
10766
  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})`);
10767
+ conditions.push(drizzleOrm.sql`${roleId} = ANY(${drizzleOrm.sql.raw(usersTableName)}.roles)`);
10776
10768
  }
10777
10769
  if (search) {
10778
10770
  const pattern = `%${search}%`;
10779
10771
  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
10772
  }
10781
10773
  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}`;
10774
+ 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
10775
  const countResult = await this.db.execute(drizzleOrm.sql`
10784
10776
  SELECT count(*)::int as total FROM ${drizzleOrm.sql.raw(usersTableName)}
10785
10777
  ${whereClause}
@@ -10853,54 +10845,57 @@ ${tableRelations.join(",\n")}
10853
10845
  return row ? this.mapRowToUser(row) : null;
10854
10846
  }
10855
10847
  /**
10856
- * Get roles for a user from database
10848
+ * Get roles for a user from database (inline TEXT[] column)
10857
10849
  */
10858
10850
  async getUserRoles(userId) {
10859
- const rolesSchema = pgCore.getTableConfig(this.rolesTable).schema || "public";
10851
+ const usersTableName = this.getQualifiedUsersTableName();
10860
10852
  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}
10853
+ SELECT roles FROM ${drizzleOrm.sql.raw(usersTableName)} WHERE id = ${userId}
10865
10854
  `);
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
10855
+ if (result.rows.length === 0) return [];
10856
+ const row = result.rows[0];
10857
+ const roleIds = row.roles ?? [];
10858
+ return roleIds.map((id) => ({
10859
+ id,
10860
+ name: id,
10861
+ isAdmin: id === "admin",
10862
+ defaultPermissions: null,
10863
+ collectionPermissions: null
10872
10864
  }));
10873
10865
  }
10874
10866
  /**
10875
10867
  * Get role IDs for a user
10876
10868
  */
10877
10869
  async getUserRoleIds(userId) {
10878
- const roles2 = await this.getUserRoles(userId);
10879
- return roles2.map((r) => r.id);
10870
+ const usersTableName = this.getQualifiedUsersTableName();
10871
+ const result = await this.db.execute(drizzleOrm.sql`
10872
+ SELECT roles FROM ${drizzleOrm.sql.raw(usersTableName)} WHERE id = ${userId}
10873
+ `);
10874
+ if (result.rows.length === 0) return [];
10875
+ const row = result.rows[0];
10876
+ return row.roles ?? [];
10880
10877
  }
10881
10878
  /**
10882
- * Set roles for a user
10879
+ * Set roles for a user (replaces existing roles)
10883
10880
  */
10884
10881
  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
- }
10882
+ const usersTableName = this.getQualifiedUsersTableName();
10883
+ const rolesArray = `{${roleIds.join(",")}}`;
10884
+ await this.db.execute(drizzleOrm.sql`
10885
+ UPDATE ${drizzleOrm.sql.raw(usersTableName)}
10886
+ SET roles = ${rolesArray}::text[], updated_at = NOW()
10887
+ WHERE id = ${userId}
10888
+ `);
10894
10889
  }
10895
10890
  /**
10896
- * Assign a specific role to new user
10891
+ * Assign a specific role to new user (appends if not present)
10897
10892
  */
10898
10893
  async assignDefaultRole(userId, roleId) {
10899
- const rolesSchema = pgCore.getTableConfig(this.userRolesTable).schema || "public";
10894
+ const usersTableName = this.getQualifiedUsersTableName();
10900
10895
  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
10896
+ UPDATE ${drizzleOrm.sql.raw(usersTableName)}
10897
+ SET roles = array_append(roles, ${roleId}), updated_at = NOW()
10898
+ WHERE id = ${userId} AND NOT (${roleId} = ANY(roles))
10904
10899
  `);
10905
10900
  }
10906
10901
  /**
@@ -10909,101 +10904,12 @@ ${tableRelations.join(",\n")}
10909
10904
  async getUserWithRoles(userId) {
10910
10905
  const user = await this.getUserById(userId);
10911
10906
  if (!user) return null;
10912
- const roles2 = await this.getUserRoles(userId);
10907
+ const roles = await this.getUserRoles(userId);
10913
10908
  return {
10914
10909
  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
10910
+ roles
10986
10911
  };
10987
10912
  }
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
10913
  }
11008
10914
  class RefreshTokenService {
11009
10915
  constructor(db, tableOrTables) {
@@ -11199,11 +11105,9 @@ ${tableRelations.join(",\n")}
11199
11105
  constructor(db, tableOrTables) {
11200
11106
  this.db = db;
11201
11107
  this.userService = new UserService(db, tableOrTables);
11202
- this.roleService = new RoleService(db, tableOrTables);
11203
11108
  this.tokenRepository = new PostgresTokenRepository(db, tableOrTables);
11204
11109
  }
11205
11110
  userService;
11206
- roleService;
11207
11111
  tokenRepository;
11208
11112
  // User operations (delegate to UserService)
11209
11113
  async createUser(data) {
@@ -11263,25 +11167,56 @@ ${tableRelations.join(",\n")}
11263
11167
  async getUserWithRoles(userId) {
11264
11168
  return this.userService.getUserWithRoles(userId);
11265
11169
  }
11266
- // Role operations (delegate to RoleService)
11170
+ // Role operations (roles are inline on users, synthesized from string IDs)
11267
11171
  async getRoleById(id) {
11268
- return this.roleService.getRoleById(id);
11172
+ return {
11173
+ id,
11174
+ name: id,
11175
+ isAdmin: id === "admin",
11176
+ defaultPermissions: null,
11177
+ collectionPermissions: null
11178
+ };
11269
11179
  }
11270
11180
  async listRoles() {
11271
- return this.roleService.listRoles();
11181
+ return [{
11182
+ id: "admin",
11183
+ name: "Admin",
11184
+ isAdmin: true,
11185
+ defaultPermissions: null,
11186
+ collectionPermissions: null
11187
+ }, {
11188
+ id: "editor",
11189
+ name: "Editor",
11190
+ isAdmin: false,
11191
+ defaultPermissions: null,
11192
+ collectionPermissions: null
11193
+ }, {
11194
+ id: "viewer",
11195
+ name: "Viewer",
11196
+ isAdmin: false,
11197
+ defaultPermissions: null,
11198
+ collectionPermissions: null
11199
+ }];
11200
+ }
11201
+ async createRole(_data) {
11202
+ return {
11203
+ id: _data.id,
11204
+ name: _data.name,
11205
+ isAdmin: _data.isAdmin ?? false,
11206
+ defaultPermissions: _data.defaultPermissions ?? null,
11207
+ collectionPermissions: _data.collectionPermissions ?? null
11208
+ };
11272
11209
  }
11273
- async createRole(data) {
11274
- return this.roleService.createRole({
11275
- ...data,
11210
+ async updateRole(id, data) {
11211
+ return {
11212
+ id,
11213
+ name: data.name ?? id,
11214
+ isAdmin: data.isAdmin ?? id === "admin",
11276
11215
  defaultPermissions: data.defaultPermissions ?? null,
11277
11216
  collectionPermissions: data.collectionPermissions ?? null
11278
- });
11279
- }
11280
- async updateRole(id, data) {
11281
- return this.roleService.updateRole(id, data);
11217
+ };
11282
11218
  }
11283
- async deleteRole(id) {
11284
- await this.roleService.deleteRole(id);
11219
+ async deleteRole(_id) {
11285
11220
  }
11286
11221
  // Token operations (delegate to PostgresTokenRepository)
11287
11222
  async createRefreshToken(userId, tokenHash, expiresAt, userAgent, ipAddress) {
@@ -11837,28 +11772,19 @@ ${tableRelations.join(",\n")}
11837
11772
  emailService = serverCore.createEmailService(authConfig.email);
11838
11773
  }
11839
11774
  const customUsersTable = registry?.getTable("users");
11840
- const customRolesTable = registry?.getTable("roles");
11841
11775
  let usersSchemaName = "rebase";
11842
- let rolesSchemaName = "rebase";
11843
11776
  if (customUsersTable) {
11844
11777
  usersSchemaName = pgCore.getTableConfig(customUsersTable).schema || "public";
11845
11778
  }
11846
- if (customRolesTable) {
11847
- rolesSchemaName = pgCore.getTableConfig(customRolesTable).schema || "public";
11848
- }
11849
- const authTables = createAuthSchema(rolesSchemaName, usersSchemaName);
11779
+ const authTables = createAuthSchema(usersSchemaName);
11850
11780
  if (customUsersTable) {
11851
11781
  authTables.users = customUsersTable;
11852
11782
  }
11853
- if (customRolesTable) {
11854
- authTables.roles = customRolesTable;
11855
- }
11856
11783
  const userService = new UserService(db, authTables);
11857
- const roleService = new RoleService(db, authTables);
11858
11784
  const authRepository = new PostgresAuthRepository(db, authTables);
11859
11785
  return {
11860
11786
  userService,
11861
- roleService,
11787
+ roleService: userService,
11862
11788
  emailService,
11863
11789
  authRepository
11864
11790
  };
@@ -11962,17 +11888,12 @@ ${tableRelations.join(",\n")}
11962
11888
  exports2.mfaFactorsRelations = mfaFactorsRelations;
11963
11889
  exports2.passwordResetTokens = passwordResetTokens;
11964
11890
  exports2.passwordResetTokensRelations = passwordResetTokensRelations;
11965
- exports2.rebaseSchema = rebaseSchema;
11966
11891
  exports2.recoveryCodes = recoveryCodes;
11967
11892
  exports2.recoveryCodesRelations = recoveryCodesRelations;
11968
11893
  exports2.refreshTokens = refreshTokens;
11969
11894
  exports2.refreshTokensRelations = refreshTokensRelations;
11970
- exports2.roles = roles;
11971
- exports2.rolesRelations = rolesRelations;
11972
11895
  exports2.userIdentities = userIdentities;
11973
11896
  exports2.userIdentitiesRelations = userIdentitiesRelations;
11974
- exports2.userRoles = userRoles;
11975
- exports2.userRolesRelations = userRolesRelations;
11976
11897
  exports2.users = users;
11977
11898
  exports2.usersRelations = usersRelations;
11978
11899
  exports2.usersSchema = usersSchema;