@rebasepro/server-postgres 0.12.0 → 0.12.1-canary.g009ed95

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 (91) hide show
  1. package/dist/PostgresBackendDriver.d.ts +1 -1
  2. package/dist/PostgresBootstrapper.d.ts +25 -1
  3. package/dist/auth/services.d.ts +21 -0
  4. package/dist/backup/backup-service.d.ts +10 -1
  5. package/dist/backup/pg-tools.d.ts +47 -0
  6. package/dist/backup-service-CD8o_1Sl.js +8999 -0
  7. package/dist/backup-service-CD8o_1Sl.js.map +1 -0
  8. package/dist/cli-helpers.d.ts +39 -0
  9. package/dist/connection-BuZ97wsr.js +250 -0
  10. package/dist/connection-BuZ97wsr.js.map +1 -0
  11. package/dist/connection.d.ts +42 -0
  12. package/dist/ensure-collection-policies-BrUVgjz3.js +57 -0
  13. package/dist/ensure-collection-policies-BrUVgjz3.js.map +1 -0
  14. package/dist/ensure-collection-tables-Da2oGkX2.js +650 -0
  15. package/dist/ensure-collection-tables-Da2oGkX2.js.map +1 -0
  16. package/dist/index.es.js +816 -9679
  17. package/dist/index.es.js.map +1 -1
  18. package/dist/policy-CeA1JcxP.js +105 -0
  19. package/dist/policy-CeA1JcxP.js.map +1 -0
  20. package/dist/schema/auth-schema.d.ts +83 -144
  21. package/dist/schema/ensure-collection-policies.d.ts +60 -0
  22. package/dist/schema/ensure-collection-tables.d.ts +44 -2
  23. package/dist/schema/generate-postgres-ddl-logic.d.ts +135 -1
  24. package/dist/schema/introspect-db-constraints.d.ts +57 -0
  25. package/dist/schema/introspect-db-logic.d.ts +94 -5
  26. package/dist/schema/introspect-db-queries.d.ts +119 -0
  27. package/dist/schema/introspect-db-structure.d.ts +263 -0
  28. package/dist/schema/introspect-db-types.d.ts +11 -0
  29. package/dist/services/FetchService.d.ts +4 -1
  30. package/dist/services/RelationService.d.ts +24 -1
  31. package/dist/services/channel-bus/index.d.ts +1 -7
  32. package/dist/services/collection-helpers.d.ts +24 -1
  33. package/dist/services/dataService.d.ts +3 -1
  34. package/dist/services/row-pipeline.d.ts +1 -1
  35. package/dist/{src-BbFOPJ1S.js → src-CzbghKwf.js} +271 -173
  36. package/dist/src-CzbghKwf.js.map +1 -0
  37. package/dist/{src-Zqwaw3P5.js → src-DoU9yPqq.js} +3 -159
  38. package/dist/src-DoU9yPqq.js.map +1 -0
  39. package/dist/utils/connection-string.d.ts +29 -0
  40. package/dist/utils/drizzle-conditions.d.ts +5 -4
  41. package/dist/utils/pg-error-utils.d.ts +19 -0
  42. package/dist/websocket-B2LsrINK.js +530 -0
  43. package/dist/websocket-B2LsrINK.js.map +1 -0
  44. package/package.json +14 -14
  45. package/src/PostgresAdapter.ts +21 -2
  46. package/src/PostgresBackendDriver.ts +4 -0
  47. package/src/PostgresBootstrapper.ts +192 -33
  48. package/src/auth/ensure-tables.ts +164 -9
  49. package/src/auth/services.ts +24 -2
  50. package/src/backup/backup-cli.ts +41 -2
  51. package/src/backup/backup-service.ts +38 -5
  52. package/src/backup/pg-tools.ts +96 -3
  53. package/src/cli-helpers.ts +70 -0
  54. package/src/cli.ts +44 -26
  55. package/src/collections/validate-relations.ts +15 -0
  56. package/src/connection.ts +73 -0
  57. package/src/data-transformer.ts +9 -3
  58. package/src/databasePoolManager.ts +5 -2
  59. package/src/schema/auth-schema.ts +30 -19
  60. package/src/schema/ensure-collection-policies.ts +105 -0
  61. package/src/schema/ensure-collection-tables.test.ts +105 -9
  62. package/src/schema/ensure-collection-tables.ts +220 -32
  63. package/src/schema/generate-drizzle-schema-logic.ts +23 -6
  64. package/src/schema/generate-postgres-ddl-logic.ts +382 -19
  65. package/src/schema/introspect-db-constraints.ts +385 -0
  66. package/src/schema/introspect-db-inference.ts +18 -8
  67. package/src/schema/introspect-db-logic.ts +385 -71
  68. package/src/schema/introspect-db-queries.ts +326 -0
  69. package/src/schema/introspect-db-structure.ts +670 -0
  70. package/src/schema/introspect-db-types.ts +56 -0
  71. package/src/schema/introspect-db.ts +37 -80
  72. package/src/schema/introspect-runtime.test.ts +56 -8
  73. package/src/schema/introspect-runtime.ts +31 -9
  74. package/src/security/policy-drift.test.ts +11 -3
  75. package/src/services/FetchService.ts +76 -14
  76. package/src/services/PersistService.ts +20 -6
  77. package/src/services/RelationService.ts +249 -48
  78. package/src/services/channel-bus/index.ts +0 -9
  79. package/src/services/collection-helpers.ts +40 -1
  80. package/src/services/dataService.ts +3 -1
  81. package/src/services/realtimeService.ts +3 -3
  82. package/src/services/row-pipeline.ts +1 -1
  83. package/src/utils/connection-string.ts +58 -0
  84. package/src/utils/drizzle-conditions.ts +31 -6
  85. package/src/utils/pg-error-utils.ts +46 -0
  86. package/src/websocket.ts +18 -9
  87. package/dist/chunk-DSJWtz9O.js +0 -40
  88. package/dist/ensure-collection-tables-CNTcZGvn.js +0 -304
  89. package/dist/ensure-collection-tables-CNTcZGvn.js.map +0 -1
  90. package/dist/src-BbFOPJ1S.js.map +0 -1
  91. package/dist/src-Zqwaw3P5.js.map +0 -1
@@ -1,8 +1,61 @@
1
1
  import { createRequire as __createRequire } from "module";
2
2
  import "process";
3
3
  __createRequire(import.meta.url);
4
- import { r as __require, t as __commonJSMin } from "./chunk-DSJWtz9O.js";
5
- import { a as policy, c as getDeclaredSubcollections, f as getDataSourceCapabilities, g as EntityRelation, h as toCanonicalOp, i as ANONYMOUS_USER_ID, l as isPostgresCollectionConfig, m as REST_TO_CANONICAL, p as NULL_OPS, s as isManyToMany, u as isRelationalCollectionConfig } from "./src-Zqwaw3P5.js";
4
+ import { l as __require, s as __commonJSMin } from "./connection-BuZ97wsr.js";
5
+ import { a as getDataSourceCapabilities, c as toCanonicalOp, n as isPostgresCollectionConfig, o as NULL_OPS, r as isRelationalCollectionConfig, s as REST_TO_CANONICAL, t as getDeclaredSubcollections } from "./src-DoU9yPqq.js";
6
+ import { n as ANONYMOUS_USER_IDS, r as policy, t as ANONYMOUS_USER_ID } from "./policy-CeA1JcxP.js";
7
+ //#region ../types/src/types/entities.ts
8
+ /**
9
+ * Class used to create a reference to a entity in a different path
10
+ */
11
+ var EntityRelation = class {
12
+ __type = "relation";
13
+ /**
14
+ * ID of the entity
15
+ */
16
+ id;
17
+ /**
18
+ * A string representing the path of the referenced document (relative
19
+ * to the root of the database).
20
+ */
21
+ path;
22
+ /**
23
+ * Pre-fetched data payload to eliminate N+1 queries.
24
+ * When present, clients can use this directly instead of fetching.
25
+ */
26
+ data;
27
+ constructor(id, path, data) {
28
+ this.id = id;
29
+ this.path = path;
30
+ this.data = data;
31
+ }
32
+ get pathWithId() {
33
+ return `${this.path}/${this.id}`;
34
+ }
35
+ isEntityReference() {
36
+ return false;
37
+ }
38
+ isEntityRelation() {
39
+ return true;
40
+ }
41
+ };
42
+ var Vector = class {
43
+ value;
44
+ constructor(value) {
45
+ this.value = value;
46
+ }
47
+ };
48
+ //#endregion
49
+ //#region ../types/src/types/relations.ts
50
+ /** @group Models */
51
+ function hasForeignKeyOnTarget(relation) {
52
+ return relation.kind === "hasOne" || relation.kind === "hasMany";
53
+ }
54
+ /** @group Models */
55
+ function isManyToMany(relation) {
56
+ return relation.kind === "manyToMany";
57
+ }
58
+ //#endregion
6
59
  //#region ../common/src/util/common.ts
7
60
  var DEFAULT_ONE_OF_TYPE = "type";
8
61
  var DEFAULT_ONE_OF_VALUE = "value";
@@ -1014,16 +1067,12 @@ function removeFunctions(o) {
1014
1067
  if (o === void 0) return void 0;
1015
1068
  if (o === null) return null;
1016
1069
  if (typeof o === "object") {
1017
- if (Array.isArray(o)) return o.map((v) => removeFunctions(v));
1070
+ if (Array.isArray(o)) return o.filter((v) => typeof v !== "function").map((v) => removeFunctions(v));
1018
1071
  if (!isPlainObject(o)) return o;
1019
- return Object.entries(o).filter(([_, value]) => typeof value !== "function").map(([key, value]) => {
1020
- if (Array.isArray(value)) return { [key]: value.map((v) => removeFunctions(v)) };
1021
- else if (typeof value === "object") return { [key]: removeFunctions(value) };
1022
- else return { [key]: value };
1023
- }).reduce((a, b) => ({
1024
- ...a,
1025
- ...b
1026
- }), {});
1072
+ return Object.entries(o).filter(([_, value]) => typeof value !== "function").reduce((acc, [key, value]) => {
1073
+ acc[key] = removeFunctions(value);
1074
+ return acc;
1075
+ }, {});
1027
1076
  }
1028
1077
  return o;
1029
1078
  }
@@ -1162,11 +1211,101 @@ function getPolicyNamesForRule(rule, tableName) {
1162
1211
  return ops.map((op, opIdx) => rule.name ? ops.length > 1 ? `${rule.name}_${op}` : rule.name : `${tableName}_${op}_${ruleHash}${ops.length > 1 ? `_${opIdx}` : ""}`);
1163
1212
  }
1164
1213
  //#endregion
1214
+ //#region ../utils/src/plurals.ts
1215
+ /**
1216
+ * Returns the singular of an English word.
1217
+ *
1218
+ * @param {string} word
1219
+ * @param {number} [amount]
1220
+ * @returns {string}
1221
+ */
1222
+ function singular(word, amount) {
1223
+ if (amount !== void 0 && amount !== 1) return word;
1224
+ const singulars = {
1225
+ "(quiz)zes$": "$1",
1226
+ "(matr)ices$": "$1ix",
1227
+ "(vert|ind)ices$": "$1ex",
1228
+ "^(ox)en$": "$1",
1229
+ "(alias)es$": "$1",
1230
+ "(octop|vir)i$": "$1us",
1231
+ "(cris|ax|test)es$": "$1is",
1232
+ "(shoe)s$": "$1",
1233
+ "(o)es$": "$1",
1234
+ "(bus)es$": "$1",
1235
+ "([m|l])ice$": "$1ouse",
1236
+ "(x|ch|ss|sh)es$": "$1",
1237
+ "(m)ovies$": "$1ovie",
1238
+ "(s)eries$": "$1eries",
1239
+ "([^aeiouy]|qu)ies$": "$1y",
1240
+ "([lr])ves$": "$1f",
1241
+ "(tive)s$": "$1",
1242
+ "(hive)s$": "$1",
1243
+ "(li|wi|kni)ves$": "$1fe",
1244
+ "(shea|loa|lea|thie)ves$": "$1f",
1245
+ "(^analy)ses$": "$1sis",
1246
+ "((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$": "$1$2sis",
1247
+ "([ti])a$": "$1um",
1248
+ "(n)ews$": "$1ews",
1249
+ "(h|bl)ouses$": "$1ouse",
1250
+ "(corpse)s$": "$1",
1251
+ "(us)es$": "$1",
1252
+ s$: ""
1253
+ };
1254
+ const irregular = {
1255
+ move: "moves",
1256
+ foot: "feet",
1257
+ goose: "geese",
1258
+ sex: "sexes",
1259
+ child: "children",
1260
+ man: "men",
1261
+ tooth: "teeth",
1262
+ person: "people"
1263
+ };
1264
+ if ([
1265
+ "sheep",
1266
+ "fish",
1267
+ "deer",
1268
+ "moose",
1269
+ "series",
1270
+ "species",
1271
+ "money",
1272
+ "rice",
1273
+ "information",
1274
+ "equipment",
1275
+ "bison",
1276
+ "cod",
1277
+ "offspring",
1278
+ "pike",
1279
+ "salmon",
1280
+ "shrimp",
1281
+ "swine",
1282
+ "trout",
1283
+ "aircraft",
1284
+ "hovercraft",
1285
+ "spacecraft",
1286
+ "sugar",
1287
+ "tuna",
1288
+ "you",
1289
+ "wood"
1290
+ ].indexOf(word.toLowerCase()) >= 0) return word;
1291
+ for (const w in irregular) {
1292
+ const pattern = new RegExp(`${irregular[w]}$`, "i");
1293
+ if (pattern.test(word)) return word.replace(pattern, w);
1294
+ }
1295
+ for (const reg in singulars) {
1296
+ const pattern = new RegExp(reg, "i");
1297
+ if (pattern.test(word)) return word.replace(pattern, singulars[reg]);
1298
+ }
1299
+ return word;
1300
+ }
1301
+ //#endregion
1165
1302
  //#region ../utils/src/names.ts
1166
1303
  /**
1167
1304
  * Generates a foreign key column name from a given string, typically a collection slug or name.
1168
- * It converts the name to snake_case, attempts to singularize it by removing a trailing 's'
1169
- * (a common convention for collection names), and appends '_id'.
1305
+ * It singularizes the name, converts it to snake_case and appends '_id'.
1306
+ *
1307
+ * Singularization runs *before* snake-casing so that acronyms survive: `toSnakeCase`
1308
+ * splits on every capital, which turned "URLs" into "ur_ls" and then "ur_l_id".
1170
1309
  *
1171
1310
  * @param name The base name to convert to a foreign key.
1172
1311
  * @returns A foreign key name in the format 'singular_name_id'.
@@ -1176,8 +1315,8 @@ function getPolicyNamesForRule(rule, tableName) {
1176
1315
  * generateForeignKeyName("users")
1177
1316
  *
1178
1317
  * @example
1179
- * // returns "post_id"
1180
- * generateForeignKeyName("posts")
1318
+ * // returns "category_id"
1319
+ * generateForeignKeyName("categories")
1181
1320
  *
1182
1321
  * @example
1183
1322
  * // returns "product_id"
@@ -1185,8 +1324,41 @@ function getPolicyNamesForRule(rule, tableName) {
1185
1324
  *
1186
1325
  */
1187
1326
  function generateForeignKeyName(name) {
1188
- const snakeCaseName = toSnakeCase(name);
1189
- return `${snakeCaseName.endsWith("s") ? snakeCaseName.slice(0, -1) : snakeCaseName}_id`;
1327
+ return `${toSnakeCase(singularizeForKey(name))}_id`;
1328
+ }
1329
+ /**
1330
+ * `singular()` handles real English plurals, but its final catch-all rule strips
1331
+ * any trailing "s", which mangles words that only look plural. Guard the two
1332
+ * cases that produce a column name nobody would recognise:
1333
+ *
1334
+ * - a double "s" ending is never a plural marker ("address", "class", "process"),
1335
+ * so stripping it yields "addres";
1336
+ * - a name that singularizes to nothing (the literal "s") would yield "_id".
1337
+ */
1338
+ function singularizeForKey(name) {
1339
+ if (/ss$/i.test(name)) return name;
1340
+ const result = singular(name);
1341
+ return result.length > 0 ? result : name;
1342
+ }
1343
+ /**
1344
+ * What `generateForeignKeyName` returned before it learned to singularize:
1345
+ * snake-case the name, then chop one trailing "s".
1346
+ *
1347
+ * This is here to be *detected*, never to be generated. A database provisioned
1348
+ * under the old rule carries `categorie_id`, `addresse_id`, `children_id` or
1349
+ * `ur_l_id` where the current rule expects `category_id`, `address_id`,
1350
+ * `child_id` and `url_id` — and the boot-time schema ensure is additive, so it
1351
+ * would create the new column empty beside the populated old one and leave the
1352
+ * relation reading nothing. No error, no missing table: the failure is silent,
1353
+ * which is the only reason this function still exists.
1354
+ *
1355
+ * `ensureCollectionSchema` calls it to recognise that shape and say so.
1356
+ * Returns the same string as `generateForeignKeyName` for every regular plural,
1357
+ * so a caller can compare the two and act only when they differ.
1358
+ */
1359
+ function legacyForeignKeyName(name) {
1360
+ const snake = toSnakeCase(name);
1361
+ return `${snake.endsWith("s") ? snake.slice(0, -1) : snake}_id`;
1190
1362
  }
1191
1363
  //#endregion
1192
1364
  //#region ../common/src/util/entities.ts
@@ -1426,8 +1598,7 @@ function enumToObjectEntries(enumValues) {
1426
1598
  function resolveRelation(relation, sourceCollection, propertyKey) {
1427
1599
  const target = relation.target;
1428
1600
  if (typeof target !== "function") throw new Error(`Relation${relation.relationName ? ` '${relation.relationName}'` : ""} on '${sourceCollection.slug}' has no \`target\`. Give it a thunk: \`target: () => otherCollection\`.`);
1429
- const targetCollection = target();
1430
- if (!targetCollection?.slug) throw new Error(`Relation${relation.relationName ? ` '${relation.relationName}'` : ""} on '${sourceCollection.slug}' has a \`target\` that did not resolve to a collection.`);
1601
+ const targetCollection = callTarget(relation, sourceCollection, propertyKey, target);
1431
1602
  const relationName = relation.relationName ?? propertyKey ?? toSnakeCase(targetCollection.slug);
1432
1603
  const shared = {
1433
1604
  relationName,
@@ -1454,7 +1625,8 @@ function resolveRelation(relation, sourceCollection, propertyKey) {
1454
1625
  cardinality: "one",
1455
1626
  writable: true,
1456
1627
  shared: false,
1457
- foreignKeyOnTarget: relation.foreignKeyOnTarget ?? generateForeignKeyName(sourceName)
1628
+ foreignKeyOnTarget: relation.foreignKeyOnTarget ?? generateForeignKeyName(sourceName),
1629
+ sourceKey: relation.sourceKey
1458
1630
  };
1459
1631
  case "hasMany": return {
1460
1632
  ...shared,
@@ -1462,7 +1634,8 @@ function resolveRelation(relation, sourceCollection, propertyKey) {
1462
1634
  cardinality: "many",
1463
1635
  writable: true,
1464
1636
  shared: false,
1465
- foreignKeyOnTarget: relation.foreignKeyOnTarget ?? generateForeignKeyName(sourceName)
1637
+ foreignKeyOnTarget: relation.foreignKeyOnTarget ?? generateForeignKeyName(sourceName),
1638
+ sourceKey: relation.sourceKey
1466
1639
  };
1467
1640
  case "manyToMany": {
1468
1641
  const sourceTable = getTableName(sourceCollection);
@@ -1491,6 +1664,43 @@ function resolveRelation(relation, sourceCollection, propertyKey) {
1491
1664
  default: throw new Error(`Unknown relation kind: ${JSON.stringify(relation)}`);
1492
1665
  }
1493
1666
  }
1667
+ /** How this relation is addressed in an error message, before it has a resolved name. */
1668
+ function describe(relation, sourceCollection, propertyKey) {
1669
+ const name = relation.relationName ?? propertyKey;
1670
+ return `Relation${name ? ` '${name}'` : ""} on '${sourceCollection.slug}'`;
1671
+ }
1672
+ /**
1673
+ * Call the `target` thunk, and translate the two ways an import cycle breaks it
1674
+ * into an error that names the cause.
1675
+ *
1676
+ * The thunk exists to defer the reference until every module has finished
1677
+ * evaluating, and for a cycle that closes at import time it does. What it cannot
1678
+ * defer is a cycle that leaves the binding permanently unusable, and there are
1679
+ * two shapes of that:
1680
+ *
1681
+ * - **ESM/TDZ.** `const` and `class` bindings in a not-yet-evaluated module are
1682
+ * in the temporal dead zone, so reading one throws `ReferenceError: x is not
1683
+ * defined`. The stack points at the thunk — a one-line arrow function that is
1684
+ * obviously fine — and says nothing about the cycle that made it throw.
1685
+ * - **CJS interop.** The half-initialised module object has no `default` yet,
1686
+ * the import resolves to `undefined`, and the thunk returns it without
1687
+ * complaint. That one used to surface here as "did not resolve to a
1688
+ * collection", which is true and unhelpful.
1689
+ *
1690
+ * Both mean the same thing, and the fix for both is the same: break the cycle,
1691
+ * or move the relation into the collection that does not close it.
1692
+ */
1693
+ function callTarget(relation, sourceCollection, propertyKey, target) {
1694
+ let targetCollection;
1695
+ try {
1696
+ targetCollection = target();
1697
+ } catch (error) {
1698
+ if (error instanceof ReferenceError) throw new Error(`${describe(relation, sourceCollection, propertyKey)} targets a collection that is not initialized yet — almost always an import cycle between the two collection files. Break the cycle (move the shared piece into a third module, or import the target lazily) so the target's module finishes evaluating before the registry is built.`, { cause: error });
1699
+ throw error;
1700
+ }
1701
+ if (!targetCollection?.slug) throw new Error(`${describe(relation, sourceCollection, propertyKey)} has a \`target\` that resolved to ${targetCollection === void 0 ? "`undefined`" : "something that is not a collection"}. ` + (targetCollection === void 0 ? "Under CommonJS interop an import cycle resolves the default import to `undefined`, so check whether this collection and its target import each other. Otherwise the thunk is returning the wrong value — it must return the collection itself, not a promise or a module." : "The thunk must return a collection config with a `slug`."));
1702
+ return targetCollection;
1703
+ }
1494
1704
  //#endregion
1495
1705
  //#region ../common/src/util/relations.ts
1496
1706
  /**
@@ -1811,7 +2021,12 @@ var UID_NOT_NULL = /auth\.uid\(\)\s+IS\s+NOT\s+NULL/i;
1811
2021
  * is how the trusted *server* context is recognised), so:
1812
2022
  *
1813
2023
  * - `auth.uid() IS NOT NULL` is a tautology on the user path, and
1814
- * - `auth.uid() != 'anon'` compares against a string no caller ever has.
2024
+ * - `auth.uid() != 'anon'` excludes one spelling of anonymous and admits the
2025
+ * other. This one is not hypothetical and was not only a foreign habit:
2026
+ * rebase's own request path reported `'anon'` while everything that compiled
2027
+ * or checked a policy used `'anonymous'`, so whichever literal an author
2028
+ * picked, half the anonymous callers walked through. See
2029
+ * {@link ANONYMOUS_USER_IDS}.
1815
2030
  *
1816
2031
  * Either one turns a lockdown into a full grant, and neither looks wrong. No
1817
2032
  * real user id is ever one of these literals, and a user-context request is
@@ -1849,7 +2064,7 @@ function findAnonymousGrants(expr) {
1849
2064
  found.push({
1850
2065
  pattern: "foreign-uid-literal",
1851
2066
  detail: literal.value,
1852
- explanation: `'${literal.value}' is a ${platform} convention. Rebase reports an anonymous request as '${ANONYMOUS_USER_ID}', so comparing against '${literal.value}' passes for every caller. Use \`condition: policy.authenticated()\` to mean "signed in".`
2067
+ explanation: `'${literal.value}' is a ${platform} convention. Rebase reports an anonymous request as '${ANONYMOUS_USER_ID}', so comparing against '${literal.value}' passes for every caller. Use \`condition: policy.authenticated()\` to mean "signed in" — it compiles to NOT IN (${ANONYMOUS_USER_IDS.map((v) => `'${v}'`).join(", ")}), covering every spelling rebase has reported rather than whichever one you remember.`
1853
2068
  });
1854
2069
  return;
1855
2070
  }
@@ -1944,7 +2159,7 @@ function compile(expr, scope) {
1944
2159
  }
1945
2160
  case "rolesOverlap": return `string_to_array(auth.roles(), ',') && ${rolesArraySql(expr.roles)}`;
1946
2161
  case "rolesContain": return `string_to_array(auth.roles(), ',') @> ${rolesArraySql(expr.roles)}`;
1947
- case "authenticated": return `auth.uid() IS NOT NULL AND auth.uid() <> ${quoteLiteral(ANONYMOUS_USER_ID)}`;
2162
+ case "authenticated": return `auth.uid() IS NOT NULL AND auth.uid() NOT IN (${ANONYMOUS_USER_IDS.map(quoteLiteral).join(", ")})`;
1948
2163
  case "serverContext": return "auth.uid() IS NULL";
1949
2164
  case "existsIn": return compileExistsIn(expr, scope);
1950
2165
  case "raw": return expr.sql.replace(/\{(\w+)\}/g, (_, col) => `${outerQualifier(scope)}${resolveColumnName(col, scope.outerCollection)}`);
@@ -2016,75 +2231,6 @@ function rolesArraySql(roles) {
2016
2231
  return `ARRAY[${[...roles].sort().map((r) => `'${r}'`).join(",")}]`;
2017
2232
  }
2018
2233
  //#endregion
2019
- //#region ../common/src/util/callbacks.ts
2020
- /**
2021
- * Helper function to recursively check if there are any callbacks in the properties.
2022
- */
2023
- function hasPropertyCallbacks(properties, callbackName) {
2024
- if (!properties) return false;
2025
- for (const property of Object.values(properties)) {
2026
- if (property.callbacks?.[callbackName]) return true;
2027
- if (property.type === "map" && property.properties) {
2028
- if (hasPropertyCallbacks(property.properties, callbackName)) return true;
2029
- } else if (property.type === "array" && property.of) {
2030
- const ofs = Array.isArray(property.of) ? property.of : [property.of];
2031
- for (const of of ofs) {
2032
- if (of.callbacks?.[callbackName]) return true;
2033
- if (of.type === "map" && of.properties && hasPropertyCallbacks(of.properties, callbackName)) return true;
2034
- }
2035
- }
2036
- }
2037
- return false;
2038
- }
2039
- /**
2040
- * Recursively process properties to apply field-level hooks.
2041
- */
2042
- async function processProperties(properties, values, previousValues, propsContext, callbackName) {
2043
- if (!values || typeof values !== "object") return values;
2044
- const result = { ...values };
2045
- for (const [key, property] of Object.entries(properties)) {
2046
- if (result[key] === void 0) continue;
2047
- let currentValue = result[key];
2048
- const previousValue = previousValues?.[key];
2049
- if (property.type === "array" && Array.isArray(currentValue)) {
2050
- if (property.of && !Array.isArray(property.of)) currentValue = await Promise.all(currentValue.map(async (item, index) => {
2051
- const prevItem = Array.isArray(previousValue) ? previousValue[index] : void 0;
2052
- return (await processProperties({ "_tmp": property.of }, { "_tmp": item }, { "_tmp": prevItem }, propsContext, callbackName))["_tmp"];
2053
- }));
2054
- } else if (property.type === "map" && property.properties && typeof currentValue === "object") currentValue = await processProperties(property.properties, currentValue, previousValue ?? {}, propsContext, callbackName);
2055
- if (property.callbacks?.[callbackName]) {
2056
- const cbRes = await Promise.resolve(property.callbacks[callbackName]({
2057
- ...propsContext,
2058
- value: currentValue,
2059
- previousValue
2060
- }));
2061
- if (cbRes !== void 0) currentValue = cbRes;
2062
- }
2063
- result[key] = currentValue;
2064
- }
2065
- return result;
2066
- }
2067
- /**
2068
- * Helper function to extract field-level PropertyCallbacks from a properties schema
2069
- * and wrap them into an CollectionCallbacks object recursively.
2070
- */
2071
- var buildPropertyCallbacks = (properties) => {
2072
- if (!properties) return void 0;
2073
- const propertyCallbacks = {};
2074
- if (hasPropertyCallbacks(properties, "afterRead")) propertyCallbacks.afterRead = async (props) => {
2075
- const row = props.row;
2076
- const processedValues = await processProperties(properties, row, row, props, "afterRead");
2077
- return {
2078
- ...props.row,
2079
- ...processedValues
2080
- };
2081
- };
2082
- if (hasPropertyCallbacks(properties, "beforeSave")) propertyCallbacks.beforeSave = async (props) => {
2083
- return await processProperties(properties, props.values, props.previousValues ?? {}, props, "beforeSave");
2084
- };
2085
- return Object.keys(propertyCallbacks).length > 0 ? propertyCallbacks : void 0;
2086
- };
2087
- //#endregion
2088
2234
  //#region ../common/src/util/auth-default-policies.ts
2089
2235
  /**
2090
2236
  * Default RLS policies injected by the schema generator.
@@ -2659,10 +2805,27 @@ function getJunctionSecurityRules(spec) {
2659
2805
  });
2660
2806
  })))();
2661
2807
  /**
2662
- * Apply PropertyConditions to a resolved property, evaluating all JSON Logic rules.
2808
+ * How wide a `varchar`/`char` column should be for a given property.
2809
+ *
2810
+ * One definition, three call sites, because they used to disagree. For the same
2811
+ * `columnType: "varchar"` property the DDL generator emitted `VARCHAR(255)`
2812
+ * while the Drizzle generator emitted a bare `varchar("col")` — which Postgres
2813
+ * reads as *unbounded* — so which of the two you ran decided whether the column
2814
+ * had a limit at all. Introspection then dropped the length entirely, so reading
2815
+ * an existing `character varying(500)` column back and regenerating it produced
2816
+ * a `VARCHAR(255)`: a silent narrowing of a column with data already in it.
2817
+ *
2818
+ * `validation.max` is the property's own statement about how long the value may
2819
+ * be, so it is the only sensible source for the column's width — and it keeps
2820
+ * the constraint the database enforces in step with the one the app enforces,
2821
+ * rather than inventing a second, different limit underneath it.
2663
2822
  */
2823
+ function resolveStringColumnLength(prop) {
2824
+ const max = prop.validation?.max;
2825
+ return typeof max === "number" && Number.isInteger(max) && max > 0 ? max : 255;
2826
+ }
2664
2827
  //#endregion
2665
- //#region ../../node_modules/.pnpm/fast-equals@6.0.0/node_modules/fast-equals/dist/es/index.mjs
2828
+ //#region ../../node_modules/.pnpm/fast-equals@6.0.2/node_modules/fast-equals/dist/es/index.mjs
2666
2829
  var { getOwnPropertyNames, getOwnPropertySymbols } = Object;
2667
2830
  var { hasOwnProperty } = Object.prototype;
2668
2831
  /**
@@ -2698,7 +2861,8 @@ function createIsCircular(areItemsEqual) {
2698
2861
  * not enumerable and symbol properties.
2699
2862
  */
2700
2863
  function getStrictProperties(object) {
2701
- return getOwnPropertyNames(object).concat(getOwnPropertySymbols(object));
2864
+ const symbols = getOwnPropertySymbols(object);
2865
+ return symbols.length ? getOwnPropertyNames(object).concat(symbols) : getOwnPropertyNames(object);
2702
2866
  }
2703
2867
  /**
2704
2868
  * Whether the object contains the property passed as an own property.
@@ -2771,7 +2935,7 @@ function areMapsEqual(a, b, state) {
2771
2935
  const size = a.size;
2772
2936
  if (size !== b.size) return false;
2773
2937
  if (!size) return true;
2774
- const matchedIndices = new Array(size);
2938
+ const matchedIndices = new Uint8Array(size);
2775
2939
  const aIterable = a.entries();
2776
2940
  let aResult;
2777
2941
  let bResult;
@@ -2779,7 +2943,7 @@ function areMapsEqual(a, b, state) {
2779
2943
  while (aResult = aIterable.next()) {
2780
2944
  if (aResult.done) break;
2781
2945
  const bIterable = b.entries();
2782
- let hasMatch = false;
2946
+ let hasMatch = 0;
2783
2947
  let matchIndex = 0;
2784
2948
  while (bResult = bIterable.next()) {
2785
2949
  if (bResult.done) break;
@@ -2790,7 +2954,7 @@ function areMapsEqual(a, b, state) {
2790
2954
  const aEntry = aResult.value;
2791
2955
  const bEntry = bResult.value;
2792
2956
  if (state.equals(aEntry[0], bEntry[0], index, matchIndex, a, b, state) && state.equals(aEntry[1], bEntry[1], aEntry[0], bEntry[0], a, b, state)) {
2793
- hasMatch = matchedIndices[matchIndex] = true;
2957
+ hasMatch = matchedIndices[matchIndex] = 1;
2794
2958
  break;
2795
2959
  }
2796
2960
  matchIndex++;
@@ -2848,19 +3012,19 @@ function areSetsEqual(a, b, state) {
2848
3012
  const size = a.size;
2849
3013
  if (size !== b.size) return false;
2850
3014
  if (!size) return true;
2851
- const matchedIndices = new Array(size);
3015
+ const matchedIndices = new Uint8Array(size);
2852
3016
  const aIterable = a.values();
2853
3017
  let aResult;
2854
3018
  let bResult;
2855
3019
  while (aResult = aIterable.next()) {
2856
3020
  if (aResult.done) break;
2857
3021
  const bIterable = b.values();
2858
- let hasMatch = false;
3022
+ let hasMatch = 0;
2859
3023
  let matchIndex = 0;
2860
3024
  while (bResult = bIterable.next()) {
2861
3025
  if (bResult.done) break;
2862
3026
  if (!matchedIndices[matchIndex] && state.equals(aResult.value, bResult.value, aResult.value, bResult.value, a, b, state)) {
2863
- hasMatch = matchedIndices[matchIndex] = true;
3027
+ hasMatch = matchedIndices[matchIndex] = 1;
2864
3028
  break;
2865
3029
  }
2866
3030
  matchIndex++;
@@ -2873,8 +3037,8 @@ function areSetsEqual(a, b, state) {
2873
3037
  * Whether the TypedArray instances are equal in value.
2874
3038
  */
2875
3039
  function areTypedArraysEqual(a, b) {
2876
- let index = a.byteLength;
2877
- if (b.byteLength !== index || a.byteOffset !== b.byteOffset) return false;
3040
+ let index = a.length;
3041
+ if (b.length !== index || a.byteOffset !== b.byteOffset) return false;
2878
3042
  while (index-- > 0) if (a[index] !== b[index]) return false;
2879
3043
  return true;
2880
3044
  }
@@ -3724,7 +3888,7 @@ function rowToEntity(row, slug, primaryKeys = []) {
3724
3888
  };
3725
3889
  }
3726
3890
  /**
3727
- * The relation envelope `toCmsRow` writes where a relation was:
3891
+ * The relation envelope `toFlatRow` writes where a relation was:
3728
3892
  * `{ id, path, __type: "relation", data: { id, path, values } }`. It is the
3729
3893
  * admin's view-model, and the only pipeline that produces one is postgres'.
3730
3894
  */
@@ -4102,72 +4266,6 @@ function buildSdkData(driver) {
4102
4266
  return wrapAsSdkData(buildRebaseData(driver));
4103
4267
  }
4104
4268
  //#endregion
4105
- //#region ../common/src/table-classification.ts
4106
- /** Schemas that are always considered Rebase-internal. */
4107
- var REBASE_INTERNAL_SCHEMAS = ["rebase", "auth"];
4108
- /** Table-name prefixes that mark a table as Rebase-internal regardless of schema. */
4109
- var REBASE_INTERNAL_PREFIXES = [
4110
- "_rebase_",
4111
- "_auth_",
4112
- "drizzle_"
4113
- ];
4114
- /**
4115
- * Synchronously classify a table based on naming conventions.
4116
- *
4117
- * @param tableName - The unqualified name of the table.
4118
- * @param schemaName - The schema the table belongs to (e.g. `"public"`, `"rebase"`).
4119
- * @returns `"rebase-internal"` when the table belongs to a reserved schema or
4120
- * carries a reserved prefix; `"user"` otherwise.
4121
- *
4122
- * @remarks
4123
- * Junction-table detection requires an async database query and is therefore
4124
- * **not** handled by this function. Use {@link detectJunctionTables} to obtain
4125
- * the set of junction tables, then reclassify as needed.
4126
- */
4127
- function classifyTable(tableName, schemaName) {
4128
- if (REBASE_INTERNAL_SCHEMAS.includes(schemaName) || REBASE_INTERNAL_PREFIXES.some((prefix) => tableName.startsWith(prefix))) return "rebase-internal";
4129
- return "user";
4130
- }
4131
- /** SQL query that detects junction tables in the `public` schema. */
4132
- var JUNCTION_TABLES_SQL = `
4133
- SELECT t.table_name
4134
- FROM information_schema.tables t
4135
- WHERE t.table_schema = 'public'
4136
- AND t.table_type = 'BASE TABLE'
4137
- AND NOT EXISTS (
4138
- SELECT 1
4139
- FROM information_schema.columns c
4140
- WHERE c.table_schema = t.table_schema
4141
- AND c.table_name = t.table_name
4142
- AND c.column_name NOT IN (
4143
- SELECT kcu.column_name
4144
- FROM information_schema.key_column_usage kcu
4145
- JOIN information_schema.table_constraints tc
4146
- ON tc.constraint_name = kcu.constraint_name
4147
- AND tc.table_schema = kcu.table_schema
4148
- WHERE tc.constraint_type = 'FOREIGN KEY'
4149
- AND kcu.table_schema = t.table_schema
4150
- AND kcu.table_name = t.table_name
4151
- )
4152
- )
4153
- `;
4154
- /**
4155
- * Asynchronously detect junction (link) tables in the `public` schema.
4156
- *
4157
- * A junction table is defined as a table where **every** column participates in
4158
- * at least one foreign-key constraint.
4159
- *
4160
- * @param executeSql - A callback that executes a raw SQL string and returns the
4161
- * resulting rows.
4162
- * @returns A `Set` containing the names of all detected junction tables.
4163
- */
4164
- async function detectJunctionTables(executeSql) {
4165
- const rows = await executeSql(JUNCTION_TABLES_SQL);
4166
- const junctionTables = /* @__PURE__ */ new Set();
4167
- for (const row of rows) if (typeof row.table_name === "string") junctionTables.add(row.table_name);
4168
- return junctionTables;
4169
- }
4170
- //#endregion
4171
- export { toSnakeCase as A, createRelationRefWithData as C, getPolicyNamesForRule as D, generateForeignKeyName as E, DEFAULT_ONE_OF_VALUE as M, mergeDeep as O, createRelationRef as S, updateDateAutoValues as T, getTableVarName as _, getJunctionCollectionConfig as a, getDeclaredPrimaryKeys as b, getEffectiveSecurityRules as c, securityRuleToConditions as d, findAnonymousGrants as f, getTableName as g, getEnumVarName as h, CollectionRegistry as i, DEFAULT_ONE_OF_TYPE as j, camelCase as k, buildPropertyCallbacks as l, getColumnName as m, detectJunctionTables as n, getJunctionSecurityRules as o, findRelation as p, buildSdkData as r, resolveJunctionSpecs as s, classifyTable as t, policyToPostgres as u, resolveCollectionRelations as v, normalizeToEntityRelation as w, parseIdValues as x, buildCompositeId as y };
4269
+ export { DEFAULT_ONE_OF_TYPE as A, updateDateAutoValues as C, mergeDeep as D, getPolicyNamesForRule as E, hasForeignKeyOnTarget as M, isManyToMany as N, camelCase as O, Vector as P, normalizeToEntityRelation as S, legacyForeignKeyName as T, buildCompositeId as _, getJunctionSecurityRules as a, createRelationRef as b, policyToPostgres as c, findRelation as d, getColumnName as f, resolveCollectionRelations as g, getTableVarName as h, getJunctionCollectionConfig as i, DEFAULT_ONE_OF_VALUE as j, toSnakeCase as k, securityRuleToConditions as l, getTableName as m, CollectionRegistry as n, resolveJunctionSpecs as o, getEnumVarName as p, resolveStringColumnLength as r, getEffectiveSecurityRules as s, buildSdkData as t, findAnonymousGrants as u, getDeclaredPrimaryKeys as v, generateForeignKeyName as w, createRelationRefWithData as x, parseIdValues as y };
4172
4270
 
4173
- //# sourceMappingURL=src-BbFOPJ1S.js.map
4271
+ //# sourceMappingURL=src-CzbghKwf.js.map