@rebasepro/server-postgresql 0.6.1 → 0.8.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 (55) hide show
  1. package/dist/PostgresBackendDriver.d.ts +8 -0
  2. package/dist/auth/services.d.ts +21 -1
  3. package/dist/cli-errors.d.ts +29 -0
  4. package/dist/cli-helpers.d.ts +7 -0
  5. package/dist/collections/PostgresCollectionRegistry.d.ts +2 -2
  6. package/dist/index.es.js +2987 -230
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/schema/auth-default-policies.d.ts +12 -0
  9. package/dist/schema/auth-schema.d.ts +227 -0
  10. package/dist/schema/generate-postgres-ddl-logic.d.ts +5 -0
  11. package/dist/schema/generate-postgres-ddl.d.ts +1 -0
  12. package/dist/services/entityService.d.ts +1 -1
  13. package/dist/utils/pg-error-utils.d.ts +10 -0
  14. package/dist/utils/table-classification.d.ts +8 -0
  15. package/package.json +15 -9
  16. package/src/PostgresBackendDriver.ts +200 -68
  17. package/src/PostgresBootstrapper.ts +34 -2
  18. package/src/auth/ensure-tables.ts +56 -1
  19. package/src/auth/services.ts +94 -1
  20. package/src/cli-errors.ts +162 -0
  21. package/src/cli-helpers.ts +183 -0
  22. package/src/cli.ts +264 -245
  23. package/src/collections/PostgresCollectionRegistry.ts +6 -6
  24. package/src/data-transformer.ts +2 -2
  25. package/src/schema/auth-default-policies.ts +97 -0
  26. package/src/schema/auth-schema.ts +25 -2
  27. package/src/schema/doctor.ts +2 -4
  28. package/src/schema/generate-drizzle-schema-logic.ts +20 -82
  29. package/src/schema/generate-drizzle-schema.ts +3 -5
  30. package/src/schema/generate-postgres-ddl-logic.ts +487 -0
  31. package/src/schema/generate-postgres-ddl.ts +116 -0
  32. package/src/services/EntityPersistService.ts +10 -8
  33. package/src/services/entityService.ts +28 -3
  34. package/src/services/realtimeService.ts +26 -2
  35. package/src/utils/pg-error-utils.ts +16 -0
  36. package/src/utils/table-classification.ts +16 -0
  37. package/src/websocket.ts +9 -0
  38. package/test/auth-default-policies.test.ts +89 -0
  39. package/test/cli-helpers-extended.test.ts +324 -0
  40. package/test/cli-helpers.test.ts +59 -0
  41. package/test/connection.test.ts +292 -0
  42. package/test/databasePoolManager.test.ts +289 -0
  43. package/test/doctor-extended.test.ts +443 -0
  44. package/test/e2e/db-e2e.test.ts +293 -0
  45. package/test/e2e/pg-setup.ts +79 -0
  46. package/test/entity-callbacks-redaction.test.ts +86 -0
  47. package/test/entity-persist-composite-keys.test.ts +451 -0
  48. package/test/generate-postgres-ddl-edge-cases.test.ts +716 -0
  49. package/test/generate-postgres-ddl.test.ts +300 -0
  50. package/test/mfa-service.test.ts +544 -0
  51. package/test/pg-error-utils.test.ts +50 -1
  52. package/test/postgresDataDriver.test.ts +2 -1
  53. package/test/realtimeService-channels.test.ts +696 -0
  54. package/test/unmapped-tables-safety.test.ts +55 -342
  55. package/vitest.e2e.config.ts +10 -0
@@ -0,0 +1,12 @@
1
+ import { EntityCollection, SecurityRule } from "@rebasepro/types";
2
+ /**
3
+ * Returns the security rules that should be applied to a collection: the
4
+ * author's explicit `securityRules`, plus, for auth collections, an
5
+ * auto-injected restrictive admin gate and permissive admin grant on every
6
+ * write operation. Together these guarantee only admins (or the trusted server
7
+ * context) can write the row.
8
+ *
9
+ * Non-auth collections, and auth collections that opt out via
10
+ * `disableDefaultAuthPolicies`, are returned unchanged.
11
+ */
12
+ export declare function getEffectiveSecurityRules(collection: EntityCollection): SecurityRule[];
@@ -1056,6 +1056,117 @@ export declare function createAuthSchema(usersSchemaName?: string): {
1056
1056
  };
1057
1057
  dialect: "pg";
1058
1058
  }>;
1059
+ magicLinkTokens: import("drizzle-orm/pg-core").PgTableWithColumns<{
1060
+ name: "magic_link_tokens";
1061
+ schema: undefined;
1062
+ columns: {
1063
+ id: import("drizzle-orm/pg-core").PgColumn<{
1064
+ name: "id";
1065
+ tableName: "magic_link_tokens";
1066
+ dataType: "string";
1067
+ columnType: "PgUUID";
1068
+ data: string;
1069
+ driverParam: string;
1070
+ notNull: true;
1071
+ hasDefault: true;
1072
+ isPrimaryKey: true;
1073
+ isAutoincrement: false;
1074
+ hasRuntimeDefault: false;
1075
+ enumValues: undefined;
1076
+ baseColumn: never;
1077
+ identity: undefined;
1078
+ generated: undefined;
1079
+ }, {}, {}>;
1080
+ userId: import("drizzle-orm/pg-core").PgColumn<{
1081
+ name: "user_id";
1082
+ tableName: "magic_link_tokens";
1083
+ dataType: "string";
1084
+ columnType: "PgUUID";
1085
+ data: string;
1086
+ driverParam: string;
1087
+ notNull: true;
1088
+ hasDefault: false;
1089
+ isPrimaryKey: false;
1090
+ isAutoincrement: false;
1091
+ hasRuntimeDefault: false;
1092
+ enumValues: undefined;
1093
+ baseColumn: never;
1094
+ identity: undefined;
1095
+ generated: undefined;
1096
+ }, {}, {}>;
1097
+ tokenHash: import("drizzle-orm/pg-core").PgColumn<{
1098
+ name: "token_hash";
1099
+ tableName: "magic_link_tokens";
1100
+ dataType: "string";
1101
+ columnType: "PgVarchar";
1102
+ data: string;
1103
+ driverParam: string;
1104
+ notNull: true;
1105
+ hasDefault: false;
1106
+ isPrimaryKey: false;
1107
+ isAutoincrement: false;
1108
+ hasRuntimeDefault: false;
1109
+ enumValues: [string, ...string[]];
1110
+ baseColumn: never;
1111
+ identity: undefined;
1112
+ generated: undefined;
1113
+ }, {}, {
1114
+ length: 255;
1115
+ }>;
1116
+ expiresAt: import("drizzle-orm/pg-core").PgColumn<{
1117
+ name: "expires_at";
1118
+ tableName: "magic_link_tokens";
1119
+ dataType: "date";
1120
+ columnType: "PgTimestamp";
1121
+ data: Date;
1122
+ driverParam: string;
1123
+ notNull: true;
1124
+ hasDefault: false;
1125
+ isPrimaryKey: false;
1126
+ isAutoincrement: false;
1127
+ hasRuntimeDefault: false;
1128
+ enumValues: undefined;
1129
+ baseColumn: never;
1130
+ identity: undefined;
1131
+ generated: undefined;
1132
+ }, {}, {}>;
1133
+ usedAt: import("drizzle-orm/pg-core").PgColumn<{
1134
+ name: "used_at";
1135
+ tableName: "magic_link_tokens";
1136
+ dataType: "date";
1137
+ columnType: "PgTimestamp";
1138
+ data: Date;
1139
+ driverParam: string;
1140
+ notNull: false;
1141
+ hasDefault: false;
1142
+ isPrimaryKey: false;
1143
+ isAutoincrement: false;
1144
+ hasRuntimeDefault: false;
1145
+ enumValues: undefined;
1146
+ baseColumn: never;
1147
+ identity: undefined;
1148
+ generated: undefined;
1149
+ }, {}, {}>;
1150
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
1151
+ name: "created_at";
1152
+ tableName: "magic_link_tokens";
1153
+ dataType: "date";
1154
+ columnType: "PgTimestamp";
1155
+ data: Date;
1156
+ driverParam: string;
1157
+ notNull: true;
1158
+ hasDefault: true;
1159
+ isPrimaryKey: false;
1160
+ isAutoincrement: false;
1161
+ hasRuntimeDefault: false;
1162
+ enumValues: undefined;
1163
+ baseColumn: never;
1164
+ identity: undefined;
1165
+ generated: undefined;
1166
+ }, {}, {}>;
1167
+ };
1168
+ dialect: "pg";
1169
+ }>;
1059
1170
  };
1060
1171
  export declare const usersSchema: import("drizzle-orm/pg-core").PgSchema<string> | null;
1061
1172
  export declare const users: import("drizzle-orm/pg-core").PgTableWithColumns<{
@@ -2111,12 +2222,124 @@ export declare const recoveryCodes: import("drizzle-orm/pg-core").PgTableWithCol
2111
2222
  };
2112
2223
  dialect: "pg";
2113
2224
  }>;
2225
+ export declare const magicLinkTokens: import("drizzle-orm/pg-core").PgTableWithColumns<{
2226
+ name: "magic_link_tokens";
2227
+ schema: undefined;
2228
+ columns: {
2229
+ id: import("drizzle-orm/pg-core").PgColumn<{
2230
+ name: "id";
2231
+ tableName: "magic_link_tokens";
2232
+ dataType: "string";
2233
+ columnType: "PgUUID";
2234
+ data: string;
2235
+ driverParam: string;
2236
+ notNull: true;
2237
+ hasDefault: true;
2238
+ isPrimaryKey: true;
2239
+ isAutoincrement: false;
2240
+ hasRuntimeDefault: false;
2241
+ enumValues: undefined;
2242
+ baseColumn: never;
2243
+ identity: undefined;
2244
+ generated: undefined;
2245
+ }, {}, {}>;
2246
+ userId: import("drizzle-orm/pg-core").PgColumn<{
2247
+ name: "user_id";
2248
+ tableName: "magic_link_tokens";
2249
+ dataType: "string";
2250
+ columnType: "PgUUID";
2251
+ data: string;
2252
+ driverParam: string;
2253
+ notNull: true;
2254
+ hasDefault: false;
2255
+ isPrimaryKey: false;
2256
+ isAutoincrement: false;
2257
+ hasRuntimeDefault: false;
2258
+ enumValues: undefined;
2259
+ baseColumn: never;
2260
+ identity: undefined;
2261
+ generated: undefined;
2262
+ }, {}, {}>;
2263
+ tokenHash: import("drizzle-orm/pg-core").PgColumn<{
2264
+ name: "token_hash";
2265
+ tableName: "magic_link_tokens";
2266
+ dataType: "string";
2267
+ columnType: "PgVarchar";
2268
+ data: string;
2269
+ driverParam: string;
2270
+ notNull: true;
2271
+ hasDefault: false;
2272
+ isPrimaryKey: false;
2273
+ isAutoincrement: false;
2274
+ hasRuntimeDefault: false;
2275
+ enumValues: [string, ...string[]];
2276
+ baseColumn: never;
2277
+ identity: undefined;
2278
+ generated: undefined;
2279
+ }, {}, {
2280
+ length: 255;
2281
+ }>;
2282
+ expiresAt: import("drizzle-orm/pg-core").PgColumn<{
2283
+ name: "expires_at";
2284
+ tableName: "magic_link_tokens";
2285
+ dataType: "date";
2286
+ columnType: "PgTimestamp";
2287
+ data: Date;
2288
+ driverParam: string;
2289
+ notNull: true;
2290
+ hasDefault: false;
2291
+ isPrimaryKey: false;
2292
+ isAutoincrement: false;
2293
+ hasRuntimeDefault: false;
2294
+ enumValues: undefined;
2295
+ baseColumn: never;
2296
+ identity: undefined;
2297
+ generated: undefined;
2298
+ }, {}, {}>;
2299
+ usedAt: import("drizzle-orm/pg-core").PgColumn<{
2300
+ name: "used_at";
2301
+ tableName: "magic_link_tokens";
2302
+ dataType: "date";
2303
+ columnType: "PgTimestamp";
2304
+ data: Date;
2305
+ driverParam: string;
2306
+ notNull: false;
2307
+ hasDefault: false;
2308
+ isPrimaryKey: false;
2309
+ isAutoincrement: false;
2310
+ hasRuntimeDefault: false;
2311
+ enumValues: undefined;
2312
+ baseColumn: never;
2313
+ identity: undefined;
2314
+ generated: undefined;
2315
+ }, {}, {}>;
2316
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
2317
+ name: "created_at";
2318
+ tableName: "magic_link_tokens";
2319
+ dataType: "date";
2320
+ columnType: "PgTimestamp";
2321
+ data: Date;
2322
+ driverParam: string;
2323
+ notNull: true;
2324
+ hasDefault: true;
2325
+ isPrimaryKey: false;
2326
+ isAutoincrement: false;
2327
+ hasRuntimeDefault: false;
2328
+ enumValues: undefined;
2329
+ baseColumn: never;
2330
+ identity: undefined;
2331
+ generated: undefined;
2332
+ }, {}, {}>;
2333
+ };
2334
+ dialect: "pg";
2335
+ }>;
2114
2336
  export declare const usersRelations: import("drizzle-orm").Relations<"users", {
2115
2337
  refreshTokens: import("drizzle-orm").Many<"refresh_tokens">;
2116
2338
  passwordResetTokens: import("drizzle-orm").Many<"password_reset_tokens">;
2117
2339
  userIdentities: import("drizzle-orm").Many<"user_identities">;
2118
2340
  mfaFactors: import("drizzle-orm").Many<"mfa_factors">;
2119
2341
  recoveryCodes: import("drizzle-orm").Many<"recovery_codes">;
2342
+ magicLinkTokens: import("drizzle-orm").Many<"magic_link_tokens">;
2120
2343
  }>;
2121
2344
  export declare const refreshTokensRelations: import("drizzle-orm").Relations<"refresh_tokens", {
2122
2345
  user: import("drizzle-orm").One<"users", true>;
@@ -2137,6 +2360,9 @@ export declare const mfaChallengesRelations: import("drizzle-orm").Relations<"mf
2137
2360
  export declare const recoveryCodesRelations: import("drizzle-orm").Relations<"recovery_codes", {
2138
2361
  user: import("drizzle-orm").One<"users", true>;
2139
2362
  }>;
2363
+ export declare const magicLinkTokensRelations: import("drizzle-orm").Relations<"magic_link_tokens", {
2364
+ user: import("drizzle-orm").One<"users", true>;
2365
+ }>;
2140
2366
  export type User = typeof users.$inferSelect;
2141
2367
  export type NewUser = typeof users.$inferInsert;
2142
2368
  export type RefreshToken = typeof refreshTokens.$inferSelect;
@@ -2147,3 +2373,4 @@ export type NewUserIdentity = typeof userIdentities.$inferInsert;
2147
2373
  export type MfaFactorRow = typeof mfaFactors.$inferSelect;
2148
2374
  export type MfaChallengeRow = typeof mfaChallenges.$inferSelect;
2149
2375
  export type RecoveryCodeRow = typeof recoveryCodes.$inferSelect;
2376
+ export type MagicLinkToken = typeof magicLinkTokens.$inferSelect;
@@ -0,0 +1,5 @@
1
+ import { EntityCollection } from "@rebasepro/types";
2
+ export declare const generatePostgresDdl: (collections: EntityCollection[], options?: {
3
+ includePolicies?: boolean;
4
+ }) => Promise<string>;
5
+ export declare const generatePostgresPoliciesDdl: (collections: EntityCollection[]) => string;
@@ -0,0 +1 @@
1
+ export {};
@@ -94,7 +94,7 @@ export declare class EntityService implements EntityRepository {
94
94
  /**
95
95
  * Execute raw SQL
96
96
  */
97
- executeSql(sqlText: string): Promise<Record<string, unknown>[]>;
97
+ executeSql(sqlText: string, params?: unknown[]): Promise<Record<string, unknown>[]>;
98
98
  /**
99
99
  * Get the underlying EntityFetchService for advanced use
100
100
  */
@@ -28,6 +28,16 @@ export declare function extractPgError(error: unknown): PostgresError | null;
28
28
  * Walk the error cause chain and return the deepest meaningful message.
29
29
  */
30
30
  export declare function extractCauseMessage(error: unknown): string | null;
31
+ /**
32
+ * Detect whether an error is specifically a role-switching permission failure
33
+ * (e.g. "permission denied to set role" or "must be member of role"),
34
+ * as opposed to a table-level permission denial.
35
+ *
36
+ * This is used by the backend driver to auto-disable role switching when the
37
+ * connection user lacks SET ROLE privileges, rather than surfacing a confusing
38
+ * error to the Studio SQL Editor user.
39
+ */
40
+ export declare function isRoleSwitchingPermissionError(error: unknown): boolean;
31
41
  /**
32
42
  * Translate a raw PostgreSQL error into a user-friendly message.
33
43
  *
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Table Classification Utility
3
+ *
4
+ * Re-exports shared classification logic from @rebasepro/common.
5
+ * This module exists for backward compatibility — prefer importing directly
6
+ * from @rebasepro/common in new code.
7
+ */
8
+ export { type TableCategory, REBASE_INTERNAL_SCHEMAS, REBASE_INTERNAL_PREFIXES, classifyTable, isRebaseInternalTable, detectJunctionTables, JUNCTION_TABLES_SQL, } from "@rebasepro/common";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rebasepro/server-postgresql",
3
3
  "type": "module",
4
- "version": "0.6.1",
4
+ "version": "0.8.0",
5
5
  "description": "PostgreSQL data source backend implementation for Rebase with Drizzle ORM",
6
6
  "funding": {
7
7
  "url": "https://github.com/sponsors/rebaseco"
@@ -34,6 +34,10 @@
34
34
  "^.+\\.tsx?$": "ts-jest"
35
35
  },
36
36
  "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
37
+ "testPathIgnorePatterns": [
38
+ "/node_modules/",
39
+ "test/e2e/"
40
+ ],
37
41
  "moduleFileExtensions": [
38
42
  "ts",
39
43
  "tsx",
@@ -62,8 +66,9 @@
62
66
  "./package.json": "./package.json"
63
67
  },
64
68
  "dependencies": {
69
+ "@ariga/atlas": "^1.2.2",
65
70
  "arg": "^5.0.2",
66
- "chalk": "^5.6.2",
71
+ "chalk": "^4.1.2",
67
72
  "chokidar": "5.0.0",
68
73
  "dotenv": "^17.4.2",
69
74
  "drizzle-orm": "^0.45.2",
@@ -71,11 +76,11 @@
71
76
  "hono": "^4.12.25",
72
77
  "pg": "^8.21.0",
73
78
  "ws": "^8.21.0",
74
- "@rebasepro/types": "0.6.1",
75
- "@rebasepro/server-core": "0.6.1",
76
- "@rebasepro/sdk-generator": "0.6.1",
77
- "@rebasepro/common": "0.6.1",
78
- "@rebasepro/utils": "0.6.1"
79
+ "@rebasepro/sdk-generator": "0.8.0",
80
+ "@rebasepro/common": "0.8.0",
81
+ "@rebasepro/server-core": "0.8.0",
82
+ "@rebasepro/utils": "0.8.0",
83
+ "@rebasepro/types": "0.8.0"
79
84
  },
80
85
  "devDependencies": {
81
86
  "@types/jest": "^30.0.0",
@@ -83,11 +88,11 @@
83
88
  "@types/pg": "^8.20.0",
84
89
  "@types/ws": "^8.18.1",
85
90
  "@vitejs/plugin-react": "^6.0.2",
86
- "drizzle-kit": "^0.31.10",
87
91
  "jest": "^30.4.2",
88
92
  "ts-jest": "^29.4.11",
89
93
  "typescript": "^6.0.3",
90
- "vite": "^8.0.16"
94
+ "vite": "^8.0.16",
95
+ "vitest": "^4.1.9"
91
96
  },
92
97
  "gitHead": "d935eefa5aa8d1009a2398cfac2c1e4ee9aeb6b6",
93
98
  "publishConfig": {
@@ -98,6 +103,7 @@
98
103
  "build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json",
99
104
  "test:lint": "eslint \"src/**\" --quiet",
100
105
  "test": "jest --passWithNoTests",
106
+ "test:e2e": "vitest run --config vitest.e2e.config.ts",
101
107
  "clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f"
102
108
  }
103
109
  }