@rebasepro/common 0.22.0 → 0.23.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.
@@ -17,8 +17,8 @@ export declare const defaultUsersCollection: import("@rebasepro/types").Postgres
17
17
  } & {
18
18
  id?: string | undefined;
19
19
  metadata?: import("@rebasepro/types").InferEntityType<{}> | undefined;
20
- photoURL?: string | undefined;
21
20
  roles?: string[] | undefined;
21
+ photoURL?: string | undefined;
22
22
  passwordHash?: string | undefined;
23
23
  emailVerified?: boolean | undefined;
24
24
  emailVerificationToken?: string | undefined;
@@ -60,6 +60,11 @@ export declare function canWriteField(property: Property | undefined, viewer: Fi
60
60
  * who knows the table can send `password_hash` as readily as `passwordHash`, and
61
61
  * a rule that only knew the wire name would be one rename away from useless.
62
62
  *
63
+ * A restricted to-one relation takes its foreign key with it. `bandId: 7` names
64
+ * the band exactly as `band: { id: 7 }` does, and the row carries the column
65
+ * beside the relation — so a rule on the relation that left the key alone
66
+ * withheld the value from the row and still let `?bandId=7` ask for it.
67
+ *
63
68
  * `kind` picks which half of the rule is read; nothing else differs.
64
69
  */
65
70
  export declare function restrictedFieldNames(collection: CollectionConfig, viewer: FieldViewer | undefined, kind: "read" | "write"): {
@@ -3,3 +3,4 @@ export * from "./CollectionRegistry.js";
3
3
  export * from "./default-collections.js";
4
4
  export * from "./engine-support.js";
5
5
  export * from "./field-access.js";
6
+ export * from "./soft-delete.js";
@@ -0,0 +1,23 @@
1
+ import type { CollectionConfig } from "@rebasepro/types";
2
+ /** The field `softDelete: true` means, when the object form names none. */
3
+ export declare const DEFAULT_SOFT_DELETE_FIELD = "deletedAt";
4
+ /**
5
+ * The property a `softDelete` collection records a deletion in — its wire
6
+ * name, what a delete stamps and what a restore (an update to `null`) clears —
7
+ * or `undefined` for a collection without soft delete.
8
+ *
9
+ * One reading of the declaration for every layer that needs it: the driver
10
+ * that stamps and filters on it, and the REST route that has to recognise a
11
+ * restore before it looks the row up.
12
+ */
13
+ export declare function softDeleteFieldOf(collection: CollectionConfig | undefined): string | undefined;
14
+ /**
15
+ * Whether an update's values restore a soft-deleted row: they set the
16
+ * soft-delete field back to `null`, the documented restore.
17
+ *
18
+ * A restore is an ordinary update of a row every default read hides, so a door
19
+ * that looks the row up before updating it has to include the trashed rows for
20
+ * this update — and only for this one: any other edit of a trashed row is a
21
+ * 404.
22
+ */
23
+ export declare function restoresSoftDeletedRow(collection: CollectionConfig | undefined, values: Record<string, unknown> | undefined): boolean;
@@ -64,6 +64,19 @@ export declare class UnknownFilterOperatorError extends Error {
64
64
  };
65
65
  constructor(field: string, operator: string);
66
66
  }
67
+ /**
68
+ * The query-parameter names a REST listing reads as something other than a
69
+ * field filter: pagination, sorting, includes, projection, search, the logical
70
+ * groups, the JSON `where` dialect, an aggregate's `select`/`groupBy`, and the
71
+ * soft-delete switches.
72
+ *
73
+ * One list for both ends. The server skips these names when it collects
74
+ * `?<field>=<op>.<value>` filters, and the SDK sends a filter on a column with
75
+ * one of these names inside `?where=` instead — a collection is free to have a
76
+ * `page`, `select` or `hard` column, and a filter on it sent as its own
77
+ * parameter was read as the parameter and never applied.
78
+ */
79
+ export declare const RESERVED_QUERY_KEYS: ReadonlySet<string>;
67
80
  /**
68
81
  * Convert `FilterValues` (or `WireFilterValues`) to a PostgREST-style
69
82
  * querystring record.
package/dist/index.es.js CHANGED
@@ -2130,6 +2130,81 @@ function evaluateCompare(op, left, right, ctx) {
2130
2130
  return "unknown";
2131
2131
  }
2132
2132
  //#endregion
2133
+ //#region src/util/policy/policyToSecurityRule.ts
2134
+ /**
2135
+ * The rule a Postgres policy compiles back from — a `pg_policies` row, or what
2136
+ * a policy editor produced in that shape.
2137
+ *
2138
+ * One definition for every place that turns a policy into a rule: Studio's RLS
2139
+ * editor ("Save" and "Import to codebase"), the collection editor's RLS tab
2140
+ * ("Import to codebase") and "Import from table"
2141
+ * (`buildCollectionFromTableMetadata`). The rule is what `db push` compiles back
2142
+ * into the database, so anything this gets wrong is a policy that changes on
2143
+ * the way back:
2144
+ *
2145
+ * - The `TO` list names *database* roles, which is `pgRoles`. `roles` holds
2146
+ * *application* roles and compiles to a `rebase.roles()` check: filed there,
2147
+ * `TO public` is a check no user passes, and on a restrictive policy — which
2148
+ * compiles to `NOT (roles) OR condition` — a gate every user passes.
2149
+ * `pgRoles` is omitted at the `public` default, so a rule that targets every
2150
+ * connection, nearly all of them, carries no advanced field it does not need.
2151
+ * - The WITH CHECK is kept whether or not there is a USING beside it. Every
2152
+ * INSERT policy has only a check, and a rule with neither clause compiles to
2153
+ * `WITH CHECK (false)`, which stops every insert.
2154
+ * - `mode` is written when the policy states one: a restrictive policy read
2155
+ * back as permissive is OR'd with every grant beside it.
2156
+ * - Retired RLS helpers (`auth.uid()`) are respelled, as `sqlToPolicy` does
2157
+ * for what it reads, because this rule is written into the project's config.
2158
+ */
2159
+ function policyToSecurityRule(policy) {
2160
+ const operation = toSecurityOperation(policy.cmd);
2161
+ const mode = toSecurityMode(policy.permissive);
2162
+ const pgRoles = toPgRoles(policy.roles);
2163
+ const base = {
2164
+ ...policy.policyname ? { name: policy.policyname } : {},
2165
+ ...operation ? { operation } : {},
2166
+ ...mode ? { mode } : {},
2167
+ ...pgRoles ? { pgRoles } : {}
2168
+ };
2169
+ const using = policy.qual ? rewriteLegacyRlsFunctions(policy.qual) : void 0;
2170
+ const withCheck = policy.with_check ? rewriteLegacyRlsFunctions(policy.with_check) : void 0;
2171
+ if (using) return withCheck ? {
2172
+ ...base,
2173
+ using,
2174
+ withCheck
2175
+ } : {
2176
+ ...base,
2177
+ using
2178
+ };
2179
+ if (withCheck) return {
2180
+ ...base,
2181
+ withCheck
2182
+ };
2183
+ return base;
2184
+ }
2185
+ function toPgRoles(roles) {
2186
+ if (!roles || roles.length === 0) return void 0;
2187
+ if (roles.length === 1 && roles[0] === "public") return void 0;
2188
+ return [...roles];
2189
+ }
2190
+ function toSecurityOperation(cmd) {
2191
+ switch (cmd) {
2192
+ case "SELECT": return "select";
2193
+ case "INSERT": return "insert";
2194
+ case "UPDATE": return "update";
2195
+ case "DELETE": return "delete";
2196
+ case "ALL": return "all";
2197
+ default: return;
2198
+ }
2199
+ }
2200
+ function toSecurityMode(permissive) {
2201
+ switch (permissive) {
2202
+ case "PERMISSIVE": return "permissive";
2203
+ case "RESTRICTIVE": return "restrictive";
2204
+ default: return;
2205
+ }
2206
+ }
2207
+ //#endregion
2133
2208
  //#region src/util/permissions.ts
2134
2209
  /** Combine clause results with AND under three-valued (Kleene) logic. */
2135
2210
  function kleeneAnd(values) {
@@ -3293,6 +3368,26 @@ function buildConditionContext(params) {
3293
3368
  */
3294
3369
  //#endregion
3295
3370
  //#region src/util/pg-column-to-property.ts
3371
+ var POLICY_COMMANDS = [
3372
+ "SELECT",
3373
+ "INSERT",
3374
+ "UPDATE",
3375
+ "DELETE",
3376
+ "ALL"
3377
+ ];
3378
+ /**
3379
+ * A policy's command, as `pg_policies.cmd` names it.
3380
+ *
3381
+ * Anything else is refused rather than guessed at. A rule with no operation
3382
+ * compiles to FOR ALL, where the USING doubles as the WITH CHECK — so a
3383
+ * `SELECT ... USING (true)` whose command went unrecognised (`pg_policy.polcmd`
3384
+ * spells it `r`) would come back a write grant.
3385
+ */
3386
+ function policyCommand(policy, tableName) {
3387
+ const cmd = POLICY_COMMANDS.find((c) => c === policy.cmd);
3388
+ if (!cmd) throw new Error(`Policy "${policy.policy_name}" on "${tableName}" has the command "${policy.cmd}", not one of ${POLICY_COMMANDS.join(", ")}, so it cannot be imported as a security rule.`);
3389
+ return cmd;
3390
+ }
3296
3391
  /**
3297
3392
  * Maps a PostgreSQL column data type to a Rebase property type.
3298
3393
  */
@@ -3490,40 +3585,14 @@ function buildCollectionFromTableMetadata(tableName, metadata) {
3490
3585
  }
3491
3586
  });
3492
3587
  }
3493
- if (metadata.policies) for (const policy of metadata.policies) {
3494
- let operations = [];
3495
- switch (policy.cmd) {
3496
- case "ALL":
3497
- operations = ["all"];
3498
- break;
3499
- case "SELECT":
3500
- operations = ["select"];
3501
- break;
3502
- case "INSERT":
3503
- operations = ["insert"];
3504
- break;
3505
- case "UPDATE":
3506
- operations = ["update"];
3507
- break;
3508
- case "DELETE":
3509
- operations = ["delete"];
3510
- break;
3511
- }
3512
- const qual = policy.qual ? rewriteLegacyRlsFunctions(policy.qual) : void 0;
3513
- const withCheck = policy.with_check ? rewriteLegacyRlsFunctions(policy.with_check) : void 0;
3514
- if (qual) securityRules.push({
3515
- name: policy.policy_name,
3516
- operations,
3517
- roles: policy.roles ?? [],
3518
- using: qual,
3519
- ...withCheck ? { withCheck } : {}
3520
- });
3521
- else securityRules.push({
3522
- name: policy.policy_name,
3523
- operations,
3524
- roles: policy.roles ?? []
3525
- });
3526
- }
3588
+ if (metadata.policies) for (const policy of metadata.policies) securityRules.push(policyToSecurityRule({
3589
+ policyname: policy.policy_name,
3590
+ cmd: policyCommand(policy, tableName),
3591
+ permissive: policy.permissive,
3592
+ roles: policy.roles,
3593
+ qual: policy.qual ?? null,
3594
+ with_check: policy.with_check ?? null
3595
+ }));
3527
3596
  return {
3528
3597
  name: prettifyIdentifier(tableName),
3529
3598
  slug: tableName,
@@ -3662,6 +3731,7 @@ var REBASE_INTERNAL_TABLES = [
3662
3731
  "api_keys",
3663
3732
  "cron_logs",
3664
3733
  "cron_claims",
3734
+ "cron_job_state",
3665
3735
  "jobs",
3666
3736
  "rate_limit_hits",
3667
3737
  "idempotency_keys",
@@ -4368,18 +4438,36 @@ function canWriteField(property, viewer) {
4368
4438
  * who knows the table can send `password_hash` as readily as `passwordHash`, and
4369
4439
  * a rule that only knew the wire name would be one rename away from useless.
4370
4440
  *
4441
+ * A restricted to-one relation takes its foreign key with it. `bandId: 7` names
4442
+ * the band exactly as `band: { id: 7 }` does, and the row carries the column
4443
+ * beside the relation — so a rule on the relation that left the key alone
4444
+ * withheld the value from the row and still let `?bandId=7` ask for it.
4445
+ *
4371
4446
  * `kind` picks which half of the rule is read; nothing else differs.
4372
4447
  */
4373
4448
  function restrictedFieldNames(collection, viewer, kind) {
4374
4449
  const declared = [];
4375
4450
  const refused = /* @__PURE__ */ new Set();
4376
4451
  const allowed = kind === "read" ? canReadField : canWriteField;
4377
- for (const [name, property] of Object.entries(collection.properties ?? {})) {
4378
- if (allowed(property, viewer)) continue;
4379
- declared.push(name);
4452
+ const properties = collection.properties ?? {};
4453
+ let relations;
4454
+ const restrict = (name) => {
4455
+ if (name in properties && !declared.includes(name)) declared.push(name);
4380
4456
  refused.add(name);
4457
+ };
4458
+ for (const [name, property] of Object.entries(properties)) {
4459
+ if (allowed(property, viewer)) continue;
4460
+ restrict(name);
4381
4461
  const columnName = property.columnName;
4382
4462
  if (columnName) refused.add(columnName);
4463
+ if (property.type === "relation") {
4464
+ relations ??= resolveCollectionRelations(collection);
4465
+ const relation = findRelation(relations, name);
4466
+ if (relation?.kind === "belongsTo") {
4467
+ restrict(fieldKeyForColumn(collection, relation.localKey));
4468
+ refused.add(relation.localKey);
4469
+ }
4470
+ }
4383
4471
  }
4384
4472
  return {
4385
4473
  declared,
@@ -4398,6 +4486,37 @@ function hasFieldAccessRules(collection) {
4398
4486
  return false;
4399
4487
  }
4400
4488
  //#endregion
4489
+ //#region src/collections/soft-delete.ts
4490
+ /** The field `softDelete: true` means, when the object form names none. */
4491
+ var DEFAULT_SOFT_DELETE_FIELD = "deletedAt";
4492
+ /**
4493
+ * The property a `softDelete` collection records a deletion in — its wire
4494
+ * name, what a delete stamps and what a restore (an update to `null`) clears —
4495
+ * or `undefined` for a collection without soft delete.
4496
+ *
4497
+ * One reading of the declaration for every layer that needs it: the driver
4498
+ * that stamps and filters on it, and the REST route that has to recognise a
4499
+ * restore before it looks the row up.
4500
+ */
4501
+ function softDeleteFieldOf(collection) {
4502
+ const declared = collection && "softDelete" in collection ? collection.softDelete : void 0;
4503
+ if (!declared) return void 0;
4504
+ return typeof declared === "object" && declared.field || "deletedAt";
4505
+ }
4506
+ /**
4507
+ * Whether an update's values restore a soft-deleted row: they set the
4508
+ * soft-delete field back to `null`, the documented restore.
4509
+ *
4510
+ * A restore is an ordinary update of a row every default read hides, so a door
4511
+ * that looks the row up before updating it has to include the trashed rows for
4512
+ * this update — and only for this one: any other edit of a trashed row is a
4513
+ * 404.
4514
+ */
4515
+ function restoresSoftDeletedRow(collection, values) {
4516
+ const field = softDeleteFieldOf(collection);
4517
+ return field !== void 0 && values?.[field] === null;
4518
+ }
4519
+ //#endregion
4401
4520
  //#region src/data/cursor.ts
4402
4521
  /** A cursor that cannot be read at all — truncated, re-encoded, or invented. */
4403
4522
  var CursorError = class CursorError extends Error {
@@ -5295,19 +5414,23 @@ function normalizeMaxRows(raw) {
5295
5414
  * @param label the collection name, so an error says which walk failed
5296
5415
  */
5297
5416
  async function* paginateFind(find, params, label = "collection") {
5298
- const { pageSize, cursor, maxPages, ...rest } = params ?? {};
5417
+ const { pageSize, cursor, maxPages, after: startAfter, offset: startOffset, page: startPage, ...rest } = params ?? {};
5299
5418
  const findParams = { ...rest };
5300
5419
  const size = normalizePageSize(pageSize);
5301
5420
  const pageCap = normalizeMaxPages(maxPages);
5302
- const seekRequested = cursor !== void 0 && cursor !== null;
5303
- if (seekRequested) {
5421
+ const seekRequested = cursor !== void 0 && cursor !== null || !!startAfter;
5422
+ if (cursor !== void 0 && cursor !== null) {
5304
5423
  const field = typeof cursor === "string" ? cursor : cursor.field;
5305
5424
  const requested = typeof cursor === "object" && cursor !== null ? cursor.direction : void 0;
5306
5425
  if (!normalizeOrderBy(findParams.orderBy)) findParams.orderBy = [field, requested ?? "asc"];
5307
5426
  }
5308
- let offset = 0;
5427
+ let offset = resolveFindWindow({
5428
+ limit: size,
5429
+ offset: startOffset,
5430
+ page: startPage
5431
+ }).offset;
5309
5432
  let pages = 0;
5310
- let after;
5433
+ let after = startAfter || void 0;
5311
5434
  for (;;) {
5312
5435
  if (pages >= pageCap) throw new RebasePaginationError("max-pages", `Iterating "${label}" made ${pages} requests without the server reporting the end of the collection. Stopping rather than looping forever — raise \`maxPages\` if the walk is genuinely this long, or check that the backend sets \`meta.hasMore\`.`);
5313
5436
  const pageParams = {
@@ -5384,9 +5507,16 @@ function createPaginationHelpers(find, label) {
5384
5507
  * Relation values (`EntityRelation` instances or `{ __type: "relation", id, path }`
5385
5508
  * objects) are serialized as their raw id — the wire format only carries the
5386
5509
  * value to compare against the FK column.
5510
+ *
5511
+ * A `Date` is its ISO 8601 instant — what JSON makes of it on the socket and
5512
+ * in-process, so one filter names one instant through every door. `String()`
5513
+ * gave the viewer's local zone, no milliseconds and a parenthesised zone name
5514
+ * Postgres cannot parse. An invalid date keeps its "Invalid Date" spelling for
5515
+ * the server to refuse, rather than throwing a `RangeError` from here.
5387
5516
  */
5388
5517
  function stringifyValue(value) {
5389
5518
  if (value === null) return "null";
5519
+ if (value instanceof Date && !Number.isNaN(value.getTime())) return value.toISOString();
5390
5520
  const relation = normalizeToEntityRelation(value);
5391
5521
  if (relation) return String(relation.id);
5392
5522
  return String(value);
@@ -5444,6 +5574,41 @@ function unescapeWireValue(value) {
5444
5574
  return result;
5445
5575
  }
5446
5576
  /**
5577
+ * Whether a scalar, sent raw as a query parameter's operand, would be read
5578
+ * back as something other than itself.
5579
+ *
5580
+ * A query parameter owns its whole value, so its scalar goes out unescaped —
5581
+ * `eq.a,b`, `eq.C:\x` — and the decoder returns it verbatim. Two shapes break
5582
+ * that. A parenthesised operand is a list for every operator (so that
5583
+ * `["==", ["a","b"]]` on an array column stays a list), so raw, the scalar
5584
+ * `"(deleted)"` would arrive as `["deleted"]`: an `==` matching nothing, a
5585
+ * `!=` returning the very rows it excludes. Such a scalar is sent escaped,
5586
+ * `eq.\(deleted\)`. And that spelling has to be told apart from a raw value
5587
+ * that looks the same, so a scalar of *that* shape is escaped in turn.
5588
+ *
5589
+ * Everything else stays raw, so a value an older client sends decodes as it
5590
+ * always has — unless it is exactly the escaped spelling of such a scalar,
5591
+ * which decodes to the scalar it spells.
5592
+ */
5593
+ function scalarNeedsEscape(value) {
5594
+ if (value.startsWith("(") && value.endsWith(")")) return true;
5595
+ return decodeEscapedScalar(value) !== void 0;
5596
+ }
5597
+ /**
5598
+ * The scalar an operand is the escaped spelling of, when it is one.
5599
+ *
5600
+ * Exact on purpose: only an operand that {@link escapeWireValue} produces from
5601
+ * a scalar that {@link scalarNeedsEscape} is decoded. Any other operand —
5602
+ * including a raw backslash an older client sent, like `\\server\share` — is
5603
+ * left verbatim. Terminates because an operand that matches contains an
5604
+ * escape pair, so the value is strictly shorter than it.
5605
+ */
5606
+ function decodeEscapedScalar(operand) {
5607
+ if (!operand.startsWith("\\")) return void 0;
5608
+ const value = unescapeWireValue(operand);
5609
+ return escapeWireValue(value) === operand && scalarNeedsEscape(value) ? value : void 0;
5610
+ }
5611
+ /**
5447
5612
  * Split a parenthesized list string on unescaped commas.
5448
5613
  * Input is the content between `(` and `)`.
5449
5614
  *
@@ -5688,6 +5853,42 @@ function readTuple(field, raw) {
5688
5853
  if (isOperatorShaped(op)) throw new UnknownFilterOperatorError(field, op);
5689
5854
  }
5690
5855
  /**
5856
+ * The query-parameter names a REST listing reads as something other than a
5857
+ * field filter: pagination, sorting, includes, projection, search, the logical
5858
+ * groups, the JSON `where` dialect, an aggregate's `select`/`groupBy`, and the
5859
+ * soft-delete switches.
5860
+ *
5861
+ * One list for both ends. The server skips these names when it collects
5862
+ * `?<field>=<op>.<value>` filters, and the SDK sends a filter on a column with
5863
+ * one of these names inside `?where=` instead — a collection is free to have a
5864
+ * `page`, `select` or `hard` column, and a filter on it sent as its own
5865
+ * parameter was read as the parameter and never applied.
5866
+ */
5867
+ var RESERVED_QUERY_KEYS = /* @__PURE__ */ new Set([
5868
+ "limit",
5869
+ "offset",
5870
+ "page",
5871
+ "after",
5872
+ "orderBy",
5873
+ "include",
5874
+ "fields",
5875
+ "distinct",
5876
+ "searchString",
5877
+ "searchExplain",
5878
+ "vector_search",
5879
+ "vector",
5880
+ "vector_distance",
5881
+ "vector_threshold",
5882
+ "or",
5883
+ "and",
5884
+ "not",
5885
+ "where",
5886
+ "select",
5887
+ "groupBy",
5888
+ "deleted",
5889
+ "hard"
5890
+ ]);
5891
+ /**
5691
5892
  * Encode the `<op>.<value>` half of a wire condition.
5692
5893
  *
5693
5894
  * This is the single leaf encoder. Both wire positions that carry a condition
@@ -5715,7 +5916,7 @@ function serializeOperatorAndValue(op, value, { escapeScalar, where }) {
5715
5916
  return `${restOp}.(${value.map((v) => escapeWireValue(stringifyValue(v))).join(",")})`;
5716
5917
  }
5717
5918
  const scalar = stringifyValue(value);
5718
- return `${restOp}.${escapeScalar ? escapeWireValue(scalar) : scalar}`;
5919
+ return `${restOp}.${escapeScalar || !LIST_OPS.has(op) && scalarNeedsEscape(scalar) ? escapeWireValue(scalar) : scalar}`;
5719
5920
  }
5720
5921
  /**
5721
5922
  * Serialize a single canonical condition tuple to a PostgREST dot-string.
@@ -5811,7 +6012,10 @@ var NULL_OPERANDS = /* @__PURE__ */ new Set([
5811
6012
  * operand: only {@link NULL_OPERANDS}. `notnull.reason` is the value
5812
6013
  * `"notnull.reason"`, not "reason is not null".
5813
6014
  * - **Everything else** takes one scalar, and any remainder is one — including
5814
- * the empty string, so `eq.` really is "equals the empty string".
6015
+ * the empty string, so `eq.` really is "equals the empty string". A
6016
+ * parenthesised remainder is a list for these too (`eq.(a,b)` is array
6017
+ * equality); a scalar that is itself parenthesised arrives escaped,
6018
+ * `eq.\(none\)`, and is decoded here — see {@link scalarNeedsEscape}.
5815
6019
  *
5816
6020
  * ### The one ambiguity that remains, and how to write past it
5817
6021
  *
@@ -5846,7 +6050,7 @@ function deserializeSingle(raw) {
5846
6050
  return [canonicalOp, inner === EMPTY_LIST_TOKEN ? [] : splitListItems(inner)];
5847
6051
  }
5848
6052
  if (LIST_OPS.has(canonicalOp)) return ["==", raw];
5849
- return [canonicalOp, rest];
6053
+ return [canonicalOp, decodeEscapedScalar(rest) ?? rest];
5850
6054
  }
5851
6055
  /**
5852
6056
  * Convert a PostgREST-style querystring record to `FilterValues`.
@@ -7026,6 +7230,6 @@ async function detectJunctionTables(executeSql) {
7026
7230
  return junctionTables;
7027
7231
  }
7028
7232
  //#endregion
7029
- export { ADMIN_ROLE, CALLBACK_REJECTED, COLLECTION_PATH_SEPARATOR, COMPOSITE_ID_SEPARATOR, CollectionRegistry, CursorError, CursorMismatchError, DEFAULT_FIND_ALL_MAX_ROWS, DEFAULT_MAX_PAGES, DEFAULT_ONE_OF_TYPE, DEFAULT_ONE_OF_VALUE, DEFAULT_PAGE_SIZE, DEFAULT_STRING_COLUMN_LENGTH, IncludeSpecError, JUNCTION_TABLES_SQL, MAX_LOGICAL_NESTING_DEPTH, OrderBySpecError, QueryBuilder, REBASE_INTERNAL_PREFIXES, REBASE_INTERNAL_SCHEMAS, REBASE_INTERNAL_TABLES, REBASE_USER_ROLE, RebasePaginationError, TENANT_INDEX_REASON, UnknownFilterOperatorError, aggregateAlias, and, applyDefaultValuesOnCreate, assertBeforeQueryIsPostgresOnly, authSecretsMissingExclusion, buildCollectionFromTableMetadata, buildCompositeId, buildConditionContext, buildPropertyCallbacks, buildRebaseData, buildRoutedRebaseData, buildSdkData, buildTenantSecurityRule, callbackRefusal, canCreateEntity, canDeleteEntity, canEditEntity, canReadCollection, canReadField, canWriteField, checkOperation, classifyTable, collectAllPages, cond, createDataSourceRegistry, createPaginationHelpers, createRelationRef, createRelationRefWithData, cursorToStartAfter, decodeCursor, defaultUsersCollection, defineCollection, denormalizeInclude, deserializeFilter, deserializeInclude, deserializeLogicalCondition, deserializeOrderBy, deserializeOrderByList, detectJunctionTables, effectiveAccess, embedParentExpression, encodeCursor, enumToObjectEntries, evaluateCondition, evaluatePolicy, fieldKeyForColumn, findAnonymousGrants, findRelation, firstSqlRow, fullPathToCollectionSegments, getArrayResolvedProperties, getChildViewDeclaringProperties, getChildViewRelationPropertyKeys, getColumnName, getDeclaredPrimaryKeys, getDefaultValueFor, getDefaultValueFortype, getDefaultValuesFor, getEffectiveSecurityRules, getEntityChildViews, getEnumVarName, getGeneratedPolicyNames, getInjectedSecurityRules, getJunctionCollectionConfig, getJunctionConfigForRelation, getJunctionSecurityRules, getLabelOrConfigFrom, getPrimaryKeys, getReferenceFrom, getRelationFrom, getRelationTargetPath, getSubcollections, getTableName, getTableVarName, getTenantConfig, hasFieldAccessRules, includePaths, isAddressableId, isJunctionBackedRelation, isPropertyBuilder, isRebaseInternalTable, isRelationRequired, isRelationalCollection, mergeIncludeSpecs, normalizeDriverOrderBy, normalizeEmail, normalizeInclude, normalizeOrderBy, normalizeToEntityRelation, not, or, paginateFind, parseIdValues, parseOrderBySpecStrict, policyToPostgres, primaryOrderBy, reconcileCursorOrder, registerConditionOperations, relationDeclaringProperty, relationalCollections, requireCallbackClient, requireCallbackCollection, resolveArrayProperties, resolveCollectionRelations, resolveDataSource, resolveEnumValues, resolveFindWindow, resolveJunctionSpecs, resolvePrimaryKeys, resolveProperties, resolveProperty, resolvePropertyEnum, resolveRelation, resolveRelationProperty, resolveStorageFilenameString, resolveStoragePathString, resolveStorageSource, resolveStringColumnLength, resolveTenantWrite, restrictedFieldNames, revokeInternalTableAccess, revokeInternalTableSql, sanitizeData, securityRuleToConditions, segmentsToStrippedPath, serializeFilter, serializeInclude, serializeLogicalCondition, serializeOrderBy, sortCollectionsBySlug, sortProperties, sqlRows, sqlToPolicy, stripCollectionPath, tenantBypassRoles, tenantPolicyName, tenantScopeExpression, toCallbackError, toFilterTuples, topLevelIncludeNames, traverseValueProperty, traverseValuesProperties, updateDateAutoValues, updateUserAutoValues, wrapAsEntityData, wrapAsSdkData };
7233
+ export { ADMIN_ROLE, CALLBACK_REJECTED, COLLECTION_PATH_SEPARATOR, COMPOSITE_ID_SEPARATOR, CollectionRegistry, CursorError, CursorMismatchError, DEFAULT_FIND_ALL_MAX_ROWS, DEFAULT_MAX_PAGES, DEFAULT_ONE_OF_TYPE, DEFAULT_ONE_OF_VALUE, DEFAULT_PAGE_SIZE, DEFAULT_SOFT_DELETE_FIELD, DEFAULT_STRING_COLUMN_LENGTH, IncludeSpecError, JUNCTION_TABLES_SQL, MAX_LOGICAL_NESTING_DEPTH, OrderBySpecError, QueryBuilder, REBASE_INTERNAL_PREFIXES, REBASE_INTERNAL_SCHEMAS, REBASE_INTERNAL_TABLES, REBASE_USER_ROLE, RESERVED_QUERY_KEYS, RebasePaginationError, TENANT_INDEX_REASON, UnknownFilterOperatorError, aggregateAlias, and, applyDefaultValuesOnCreate, assertBeforeQueryIsPostgresOnly, authSecretsMissingExclusion, buildCollectionFromTableMetadata, buildCompositeId, buildConditionContext, buildPropertyCallbacks, buildRebaseData, buildRoutedRebaseData, buildSdkData, buildTenantSecurityRule, callbackRefusal, canCreateEntity, canDeleteEntity, canEditEntity, canReadCollection, canReadField, canWriteField, checkOperation, classifyTable, collectAllPages, cond, createDataSourceRegistry, createPaginationHelpers, createRelationRef, createRelationRefWithData, cursorToStartAfter, decodeCursor, defaultUsersCollection, defineCollection, denormalizeInclude, deserializeFilter, deserializeInclude, deserializeLogicalCondition, deserializeOrderBy, deserializeOrderByList, detectJunctionTables, effectiveAccess, embedParentExpression, encodeCursor, enumToObjectEntries, evaluateCondition, evaluatePolicy, fieldKeyForColumn, findAnonymousGrants, findRelation, firstSqlRow, fullPathToCollectionSegments, getArrayResolvedProperties, getChildViewDeclaringProperties, getChildViewRelationPropertyKeys, getColumnName, getDeclaredPrimaryKeys, getDefaultValueFor, getDefaultValueFortype, getDefaultValuesFor, getEffectiveSecurityRules, getEntityChildViews, getEnumVarName, getGeneratedPolicyNames, getInjectedSecurityRules, getJunctionCollectionConfig, getJunctionConfigForRelation, getJunctionSecurityRules, getLabelOrConfigFrom, getPrimaryKeys, getReferenceFrom, getRelationFrom, getRelationTargetPath, getSubcollections, getTableName, getTableVarName, getTenantConfig, hasFieldAccessRules, includePaths, isAddressableId, isJunctionBackedRelation, isPropertyBuilder, isRebaseInternalTable, isRelationRequired, isRelationalCollection, mergeIncludeSpecs, normalizeDriverOrderBy, normalizeEmail, normalizeInclude, normalizeOrderBy, normalizeToEntityRelation, not, or, paginateFind, parseIdValues, parseOrderBySpecStrict, policyToPostgres, policyToSecurityRule, primaryOrderBy, reconcileCursorOrder, registerConditionOperations, relationDeclaringProperty, relationalCollections, requireCallbackClient, requireCallbackCollection, resolveArrayProperties, resolveCollectionRelations, resolveDataSource, resolveEnumValues, resolveFindWindow, resolveJunctionSpecs, resolvePrimaryKeys, resolveProperties, resolveProperty, resolvePropertyEnum, resolveRelation, resolveRelationProperty, resolveStorageFilenameString, resolveStoragePathString, resolveStorageSource, resolveStringColumnLength, resolveTenantWrite, restoresSoftDeletedRow, restrictedFieldNames, revokeInternalTableAccess, revokeInternalTableSql, sanitizeData, securityRuleToConditions, segmentsToStrippedPath, serializeFilter, serializeInclude, serializeLogicalCondition, serializeOrderBy, softDeleteFieldOf, sortCollectionsBySlug, sortProperties, sqlRows, sqlToPolicy, stripCollectionPath, tenantBypassRoles, tenantPolicyName, tenantScopeExpression, toCallbackError, toFilterTuples, topLevelIncludeNames, traverseValueProperty, traverseValuesProperties, updateDateAutoValues, updateUserAutoValues, wrapAsEntityData, wrapAsSdkData };
7030
7234
 
7031
7235
  //# sourceMappingURL=index.es.js.map