@rebasepro/server-postgres 0.12.1-canary.gdfba2a1 → 0.12.1-canary.ge1bb178
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.
- package/dist/PostgresBackendDriver.d.ts +1 -1
- package/dist/PostgresBootstrapper.d.ts +25 -1
- package/dist/auth/services.d.ts +6 -1
- package/dist/backup/backup-service.d.ts +10 -1
- package/dist/backup/pg-tools.d.ts +47 -0
- package/dist/{backup-service-DH9kPg-E.js → backup-service-CD8o_1Sl.js} +144 -11
- package/dist/backup-service-CD8o_1Sl.js.map +1 -0
- package/dist/cli-helpers.d.ts +39 -0
- package/dist/{connection-B5Wndbr1.js → connection-BuZ97wsr.js} +57 -3
- package/dist/connection-BuZ97wsr.js.map +1 -0
- package/dist/connection.d.ts +42 -0
- package/dist/ensure-collection-policies-BrUVgjz3.js +57 -0
- package/dist/ensure-collection-policies-BrUVgjz3.js.map +1 -0
- package/dist/ensure-collection-tables-Da2oGkX2.js +650 -0
- package/dist/ensure-collection-tables-Da2oGkX2.js.map +1 -0
- package/dist/index.es.js +529 -142
- package/dist/index.es.js.map +1 -1
- package/dist/policy-CeA1JcxP.js +105 -0
- package/dist/policy-CeA1JcxP.js.map +1 -0
- package/dist/schema/ensure-collection-policies.d.ts +60 -0
- package/dist/schema/ensure-collection-tables.d.ts +44 -2
- package/dist/schema/generate-postgres-ddl-logic.d.ts +135 -1
- package/dist/schema/introspect-db-constraints.d.ts +57 -0
- package/dist/schema/introspect-db-logic.d.ts +94 -5
- package/dist/schema/introspect-db-queries.d.ts +119 -0
- package/dist/schema/introspect-db-structure.d.ts +263 -0
- package/dist/schema/introspect-db-types.d.ts +11 -0
- package/dist/services/FetchService.d.ts +4 -1
- package/dist/services/RelationService.d.ts +24 -1
- package/dist/services/channel-bus/index.d.ts +1 -7
- package/dist/services/collection-helpers.d.ts +24 -1
- package/dist/services/dataService.d.ts +3 -1
- package/dist/services/row-pipeline.d.ts +1 -1
- package/dist/{src-DihrDFuP.js → src-CzbghKwf.js} +189 -101
- package/dist/src-CzbghKwf.js.map +1 -0
- package/dist/utils/connection-string.d.ts +29 -0
- package/dist/utils/drizzle-conditions.d.ts +5 -4
- package/dist/utils/pg-error-utils.d.ts +19 -0
- package/dist/{websocket-BKcGvILX.js → websocket-B2LsrINK.js} +8 -6
- package/dist/websocket-B2LsrINK.js.map +1 -0
- package/package.json +6 -6
- package/src/PostgresAdapter.ts +21 -2
- package/src/PostgresBackendDriver.ts +4 -0
- package/src/PostgresBootstrapper.ts +192 -33
- package/src/auth/services.ts +6 -3
- package/src/backup/backup-cli.ts +41 -2
- package/src/backup/backup-service.ts +38 -5
- package/src/backup/pg-tools.ts +96 -3
- package/src/cli-helpers.ts +70 -0
- package/src/cli.ts +44 -26
- package/src/collections/validate-relations.ts +15 -0
- package/src/connection.ts +73 -0
- package/src/data-transformer.ts +9 -3
- package/src/databasePoolManager.ts +5 -2
- package/src/schema/ensure-collection-policies.ts +105 -0
- package/src/schema/ensure-collection-tables.test.ts +105 -9
- package/src/schema/ensure-collection-tables.ts +220 -32
- package/src/schema/generate-drizzle-schema-logic.ts +16 -3
- package/src/schema/generate-postgres-ddl-logic.ts +375 -16
- package/src/schema/introspect-db-constraints.ts +385 -0
- package/src/schema/introspect-db-inference.ts +18 -8
- package/src/schema/introspect-db-logic.ts +385 -71
- package/src/schema/introspect-db-queries.ts +326 -0
- package/src/schema/introspect-db-structure.ts +670 -0
- package/src/schema/introspect-db-types.ts +56 -0
- package/src/schema/introspect-db.ts +37 -80
- package/src/schema/introspect-runtime.test.ts +56 -8
- package/src/schema/introspect-runtime.ts +31 -9
- package/src/security/policy-drift.test.ts +11 -3
- package/src/services/FetchService.ts +76 -14
- package/src/services/PersistService.ts +20 -6
- package/src/services/RelationService.ts +249 -48
- package/src/services/channel-bus/index.ts +0 -9
- package/src/services/collection-helpers.ts +40 -1
- package/src/services/dataService.ts +3 -1
- package/src/services/realtimeService.ts +3 -3
- package/src/services/row-pipeline.ts +1 -1
- package/src/utils/connection-string.ts +58 -0
- package/src/utils/drizzle-conditions.ts +31 -6
- package/src/utils/pg-error-utils.ts +46 -0
- package/src/websocket.ts +18 -9
- package/dist/backup-service-DH9kPg-E.js.map +0 -1
- package/dist/connection-B5Wndbr1.js.map +0 -1
- package/dist/ensure-collection-tables-CIHSH962.js +0 -304
- package/dist/ensure-collection-tables-CIHSH962.js.map +0 -1
- package/dist/src-DihrDFuP.js.map +0 -1
- package/dist/websocket-BKcGvILX.js.map +0 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "module";
|
|
2
2
|
import "process";
|
|
3
3
|
__createRequire(import.meta.url);
|
|
4
|
-
import {
|
|
4
|
+
import { l as __require, s as __commonJSMin } from "./connection-BuZ97wsr.js";
|
|
5
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";
|
|
6
7
|
//#region ../types/src/types/entities.ts
|
|
7
8
|
/**
|
|
8
9
|
* Class used to create a reference to a entity in a different path
|
|
@@ -55,81 +56,6 @@ function isManyToMany(relation) {
|
|
|
55
56
|
return relation.kind === "manyToMany";
|
|
56
57
|
}
|
|
57
58
|
//#endregion
|
|
58
|
-
//#region ../types/src/types/policy.ts
|
|
59
|
-
/**
|
|
60
|
-
* The id a request without a logged-in user reports as `auth.uid()`.
|
|
61
|
-
*
|
|
62
|
-
* A user-context request always sets `app.uid`: blank would read back as
|
|
63
|
-
* `NULL`, and `NULL` is how the trusted server context is recognised, so an
|
|
64
|
-
* anonymous visitor would be promoted to server privileges. The driver
|
|
65
|
-
* therefore substitutes this sentinel at the single chokepoint where the GUC
|
|
66
|
-
* is set.
|
|
67
|
-
*
|
|
68
|
-
* The consequence for policy authors is that **`auth.uid() IS NOT NULL` is a
|
|
69
|
-
* tautology on the user path** — it is true for anonymous visitors too. Use
|
|
70
|
-
* {@link policy.authenticated} (or `auth.uid() <> 'anonymous'`) to mean "signed
|
|
71
|
-
* in", and {@link policy.serverContext} to mean "the trusted server context".
|
|
72
|
-
*
|
|
73
|
-
* @group Models
|
|
74
|
-
*/
|
|
75
|
-
var ANONYMOUS_USER_ID = "anonymous";
|
|
76
|
-
/** @group Models */
|
|
77
|
-
var policy = {
|
|
78
|
-
true: () => ({ kind: "true" }),
|
|
79
|
-
false: () => ({ kind: "false" }),
|
|
80
|
-
and: (...operands) => ({
|
|
81
|
-
kind: "and",
|
|
82
|
-
operands
|
|
83
|
-
}),
|
|
84
|
-
or: (...operands) => ({
|
|
85
|
-
kind: "or",
|
|
86
|
-
operands
|
|
87
|
-
}),
|
|
88
|
-
not: (operand) => ({
|
|
89
|
-
kind: "not",
|
|
90
|
-
operand
|
|
91
|
-
}),
|
|
92
|
-
compare: (left, op, right) => ({
|
|
93
|
-
kind: "compare",
|
|
94
|
-
op,
|
|
95
|
-
left,
|
|
96
|
-
right
|
|
97
|
-
}),
|
|
98
|
-
rolesOverlap: (roles) => ({
|
|
99
|
-
kind: "rolesOverlap",
|
|
100
|
-
roles
|
|
101
|
-
}),
|
|
102
|
-
rolesContain: (roles) => ({
|
|
103
|
-
kind: "rolesContain",
|
|
104
|
-
roles
|
|
105
|
-
}),
|
|
106
|
-
authenticated: () => ({ kind: "authenticated" }),
|
|
107
|
-
serverContext: () => ({ kind: "serverContext" }),
|
|
108
|
-
existsIn: (args) => ({
|
|
109
|
-
kind: "existsIn",
|
|
110
|
-
collection: args.collection,
|
|
111
|
-
where: args.where
|
|
112
|
-
}),
|
|
113
|
-
raw: (sql) => ({
|
|
114
|
-
kind: "raw",
|
|
115
|
-
sql
|
|
116
|
-
}),
|
|
117
|
-
field: (name) => ({
|
|
118
|
-
kind: "field",
|
|
119
|
-
name
|
|
120
|
-
}),
|
|
121
|
-
outerField: (name) => ({
|
|
122
|
-
kind: "outerField",
|
|
123
|
-
name
|
|
124
|
-
}),
|
|
125
|
-
literal: (value) => ({
|
|
126
|
-
kind: "literal",
|
|
127
|
-
value
|
|
128
|
-
}),
|
|
129
|
-
authUid: () => ({ kind: "authUid" }),
|
|
130
|
-
authRoles: () => ({ kind: "authRoles" })
|
|
131
|
-
};
|
|
132
|
-
//#endregion
|
|
133
59
|
//#region ../common/src/util/common.ts
|
|
134
60
|
var DEFAULT_ONE_OF_TYPE = "type";
|
|
135
61
|
var DEFAULT_ONE_OF_VALUE = "value";
|
|
@@ -1141,16 +1067,12 @@ function removeFunctions(o) {
|
|
|
1141
1067
|
if (o === void 0) return void 0;
|
|
1142
1068
|
if (o === null) return null;
|
|
1143
1069
|
if (typeof o === "object") {
|
|
1144
|
-
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));
|
|
1145
1071
|
if (!isPlainObject(o)) return o;
|
|
1146
|
-
return Object.entries(o).filter(([_, value]) => typeof value !== "function").
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
}).reduce((a, b) => ({
|
|
1151
|
-
...a,
|
|
1152
|
-
...b
|
|
1153
|
-
}), {});
|
|
1072
|
+
return Object.entries(o).filter(([_, value]) => typeof value !== "function").reduce((acc, [key, value]) => {
|
|
1073
|
+
acc[key] = removeFunctions(value);
|
|
1074
|
+
return acc;
|
|
1075
|
+
}, {});
|
|
1154
1076
|
}
|
|
1155
1077
|
return o;
|
|
1156
1078
|
}
|
|
@@ -1289,11 +1211,101 @@ function getPolicyNamesForRule(rule, tableName) {
|
|
|
1289
1211
|
return ops.map((op, opIdx) => rule.name ? ops.length > 1 ? `${rule.name}_${op}` : rule.name : `${tableName}_${op}_${ruleHash}${ops.length > 1 ? `_${opIdx}` : ""}`);
|
|
1290
1212
|
}
|
|
1291
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
|
|
1292
1302
|
//#region ../utils/src/names.ts
|
|
1293
1303
|
/**
|
|
1294
1304
|
* Generates a foreign key column name from a given string, typically a collection slug or name.
|
|
1295
|
-
* It
|
|
1296
|
-
*
|
|
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".
|
|
1297
1309
|
*
|
|
1298
1310
|
* @param name The base name to convert to a foreign key.
|
|
1299
1311
|
* @returns A foreign key name in the format 'singular_name_id'.
|
|
@@ -1303,8 +1315,8 @@ function getPolicyNamesForRule(rule, tableName) {
|
|
|
1303
1315
|
* generateForeignKeyName("users")
|
|
1304
1316
|
*
|
|
1305
1317
|
* @example
|
|
1306
|
-
* // returns "
|
|
1307
|
-
* generateForeignKeyName("
|
|
1318
|
+
* // returns "category_id"
|
|
1319
|
+
* generateForeignKeyName("categories")
|
|
1308
1320
|
*
|
|
1309
1321
|
* @example
|
|
1310
1322
|
* // returns "product_id"
|
|
@@ -1312,8 +1324,41 @@ function getPolicyNamesForRule(rule, tableName) {
|
|
|
1312
1324
|
*
|
|
1313
1325
|
*/
|
|
1314
1326
|
function generateForeignKeyName(name) {
|
|
1315
|
-
|
|
1316
|
-
|
|
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`;
|
|
1317
1362
|
}
|
|
1318
1363
|
//#endregion
|
|
1319
1364
|
//#region ../common/src/util/entities.ts
|
|
@@ -1553,8 +1598,7 @@ function enumToObjectEntries(enumValues) {
|
|
|
1553
1598
|
function resolveRelation(relation, sourceCollection, propertyKey) {
|
|
1554
1599
|
const target = relation.target;
|
|
1555
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\`.`);
|
|
1556
|
-
const targetCollection = target
|
|
1557
|
-
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);
|
|
1558
1602
|
const relationName = relation.relationName ?? propertyKey ?? toSnakeCase(targetCollection.slug);
|
|
1559
1603
|
const shared = {
|
|
1560
1604
|
relationName,
|
|
@@ -1581,7 +1625,8 @@ function resolveRelation(relation, sourceCollection, propertyKey) {
|
|
|
1581
1625
|
cardinality: "one",
|
|
1582
1626
|
writable: true,
|
|
1583
1627
|
shared: false,
|
|
1584
|
-
foreignKeyOnTarget: relation.foreignKeyOnTarget ?? generateForeignKeyName(sourceName)
|
|
1628
|
+
foreignKeyOnTarget: relation.foreignKeyOnTarget ?? generateForeignKeyName(sourceName),
|
|
1629
|
+
sourceKey: relation.sourceKey
|
|
1585
1630
|
};
|
|
1586
1631
|
case "hasMany": return {
|
|
1587
1632
|
...shared,
|
|
@@ -1589,7 +1634,8 @@ function resolveRelation(relation, sourceCollection, propertyKey) {
|
|
|
1589
1634
|
cardinality: "many",
|
|
1590
1635
|
writable: true,
|
|
1591
1636
|
shared: false,
|
|
1592
|
-
foreignKeyOnTarget: relation.foreignKeyOnTarget ?? generateForeignKeyName(sourceName)
|
|
1637
|
+
foreignKeyOnTarget: relation.foreignKeyOnTarget ?? generateForeignKeyName(sourceName),
|
|
1638
|
+
sourceKey: relation.sourceKey
|
|
1593
1639
|
};
|
|
1594
1640
|
case "manyToMany": {
|
|
1595
1641
|
const sourceTable = getTableName(sourceCollection);
|
|
@@ -1618,6 +1664,43 @@ function resolveRelation(relation, sourceCollection, propertyKey) {
|
|
|
1618
1664
|
default: throw new Error(`Unknown relation kind: ${JSON.stringify(relation)}`);
|
|
1619
1665
|
}
|
|
1620
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
|
+
}
|
|
1621
1704
|
//#endregion
|
|
1622
1705
|
//#region ../common/src/util/relations.ts
|
|
1623
1706
|
/**
|
|
@@ -1938,7 +2021,12 @@ var UID_NOT_NULL = /auth\.uid\(\)\s+IS\s+NOT\s+NULL/i;
|
|
|
1938
2021
|
* is how the trusted *server* context is recognised), so:
|
|
1939
2022
|
*
|
|
1940
2023
|
* - `auth.uid() IS NOT NULL` is a tautology on the user path, and
|
|
1941
|
-
* - `auth.uid() != 'anon'`
|
|
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}.
|
|
1942
2030
|
*
|
|
1943
2031
|
* Either one turns a lockdown into a full grant, and neither looks wrong. No
|
|
1944
2032
|
* real user id is ever one of these literals, and a user-context request is
|
|
@@ -1976,7 +2064,7 @@ function findAnonymousGrants(expr) {
|
|
|
1976
2064
|
found.push({
|
|
1977
2065
|
pattern: "foreign-uid-literal",
|
|
1978
2066
|
detail: literal.value,
|
|
1979
|
-
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.`
|
|
1980
2068
|
});
|
|
1981
2069
|
return;
|
|
1982
2070
|
}
|
|
@@ -2071,7 +2159,7 @@ function compile(expr, scope) {
|
|
|
2071
2159
|
}
|
|
2072
2160
|
case "rolesOverlap": return `string_to_array(auth.roles(), ',') && ${rolesArraySql(expr.roles)}`;
|
|
2073
2161
|
case "rolesContain": return `string_to_array(auth.roles(), ',') @> ${rolesArraySql(expr.roles)}`;
|
|
2074
|
-
case "authenticated": return `auth.uid() IS NOT NULL AND auth.uid()
|
|
2162
|
+
case "authenticated": return `auth.uid() IS NOT NULL AND auth.uid() NOT IN (${ANONYMOUS_USER_IDS.map(quoteLiteral).join(", ")})`;
|
|
2075
2163
|
case "serverContext": return "auth.uid() IS NULL";
|
|
2076
2164
|
case "existsIn": return compileExistsIn(expr, scope);
|
|
2077
2165
|
case "raw": return expr.sql.replace(/\{(\w+)\}/g, (_, col) => `${outerQualifier(scope)}${resolveColumnName(col, scope.outerCollection)}`);
|
|
@@ -3800,7 +3888,7 @@ function rowToEntity(row, slug, primaryKeys = []) {
|
|
|
3800
3888
|
};
|
|
3801
3889
|
}
|
|
3802
3890
|
/**
|
|
3803
|
-
* The relation envelope `
|
|
3891
|
+
* The relation envelope `toFlatRow` writes where a relation was:
|
|
3804
3892
|
* `{ id, path, __type: "relation", data: { id, path, values } }`. It is the
|
|
3805
3893
|
* admin's view-model, and the only pipeline that produces one is postgres'.
|
|
3806
3894
|
*/
|
|
@@ -4178,6 +4266,6 @@ function buildSdkData(driver) {
|
|
|
4178
4266
|
return wrapAsSdkData(buildRebaseData(driver));
|
|
4179
4267
|
}
|
|
4180
4268
|
//#endregion
|
|
4181
|
-
export {
|
|
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 };
|
|
4182
4270
|
|
|
4183
|
-
//# sourceMappingURL=src-
|
|
4271
|
+
//# sourceMappingURL=src-CzbghKwf.js.map
|