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

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 (35) hide show
  1. package/dist/auth/services.d.ts +16 -0
  2. package/dist/backup-service-DH9kPg-E.js +8866 -0
  3. package/dist/backup-service-DH9kPg-E.js.map +1 -0
  4. package/dist/connection-B5Wndbr1.js +196 -0
  5. package/dist/connection-B5Wndbr1.js.map +1 -0
  6. package/dist/ensure-collection-policies-CT-zIUWA.js +57 -0
  7. package/dist/ensure-collection-policies-CT-zIUWA.js.map +1 -0
  8. package/dist/{ensure-collection-tables-CNTcZGvn.js → ensure-collection-tables-Vu-GRELM.js} +83 -6
  9. package/dist/ensure-collection-tables-Vu-GRELM.js.map +1 -0
  10. package/dist/index.es.js +420 -9598
  11. package/dist/index.es.js.map +1 -1
  12. package/dist/schema/auth-schema.d.ts +83 -144
  13. package/dist/schema/ensure-collection-policies.d.ts +60 -0
  14. package/dist/schema/generate-postgres-ddl-logic.d.ts +43 -1
  15. package/dist/{src-BbFOPJ1S.js → src-DihrDFuP.js} +160 -150
  16. package/dist/src-DihrDFuP.js.map +1 -0
  17. package/dist/{src-Zqwaw3P5.js → src-DoU9yPqq.js} +3 -159
  18. package/dist/src-DoU9yPqq.js.map +1 -0
  19. package/dist/utils/pg-error-utils.d.ts +19 -0
  20. package/dist/websocket-BKcGvILX.js +528 -0
  21. package/dist/websocket-BKcGvILX.js.map +1 -0
  22. package/package.json +14 -14
  23. package/src/PostgresAdapter.ts +14 -0
  24. package/src/PostgresBootstrapper.ts +104 -12
  25. package/src/auth/ensure-tables.ts +164 -9
  26. package/src/auth/services.ts +21 -2
  27. package/src/schema/auth-schema.ts +30 -19
  28. package/src/schema/ensure-collection-policies.ts +105 -0
  29. package/src/schema/generate-drizzle-schema-logic.ts +7 -3
  30. package/src/schema/generate-postgres-ddl-logic.ts +100 -13
  31. package/src/utils/pg-error-utils.ts +46 -0
  32. package/dist/chunk-DSJWtz9O.js +0 -40
  33. package/dist/ensure-collection-tables-CNTcZGvn.js.map +0 -1
  34. package/dist/src-BbFOPJ1S.js.map +0 -1
  35. package/dist/src-Zqwaw3P5.js.map +0 -1
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Applying a bundle's RLS policies to a database at boot, idempotently.
3
+ *
4
+ * ## Why this exists
5
+ *
6
+ * {@link ensureCollectionTables} creates the collection *tables* a managed
7
+ * runtime boots against, but a table with row-level security disabled and no
8
+ * policies is not servable: authenticated requests run as the restricted
9
+ * `rebase_user` role, so a read with no `SELECT` policy returns nothing (a
10
+ * public collection answered 401) and a write with no `INSERT`/`UPDATE` policy
11
+ * is denied. The policies live in the collections' `securityRules`; nothing at
12
+ * boot applied them. `rebase db push` does — but it drives Atlas against a
13
+ * local `DATABASE_URL`, and a managed tenant's database is reachable only from
14
+ * inside the cluster, by the runtime that is already connected to it. So the
15
+ * runtime is the only thing that *can* apply them, and this is where it does.
16
+ *
17
+ * ## Why this is safe to run on every boot
18
+ *
19
+ * Every statement is idempotent: `ENABLE ROW LEVEL SECURITY` is a no-op once
20
+ * enabled, and each policy is a `DROP POLICY IF EXISTS` immediately followed by
21
+ * a `CREATE POLICY`, so re-applying asserts exactly the declared state. It adds
22
+ * and replaces; it never drops data. (It does not *reconcile* — a policy a
23
+ * previous push left behind under an old name is not removed here; that stays a
24
+ * `db push` / `db migrate` concern, alongside destructive schema changes.)
25
+ *
26
+ * Unlike table creation, a failure here is not fatal: RLS stays enabled, so a
27
+ * table whose policies could not be applied fails **closed** (denies) rather
28
+ * than leaking rows. One collection's policy failing (e.g. a rule that
29
+ * references a table a real migration has not created yet) must not crash-loop
30
+ * the whole deployment and take the other collections' working routes down with
31
+ * it. Failures are reported loudly and per-table so the operator can see
32
+ * exactly which collection is not yet servable and why.
33
+ */
34
+ import { type CollectionConfig } from "@rebasepro/types";
35
+ import { type Queryable } from "./ensure-collection-tables";
36
+ export interface PolicyEnsureResult {
37
+ /** `CREATE POLICY` statements that ran successfully. */
38
+ policiesApplied: number;
39
+ /** Tables that had RLS enabled. */
40
+ tablesSecured: number;
41
+ /** Declared tables absent from the database — left to a real migration. */
42
+ skipped: {
43
+ table: string;
44
+ reason: string;
45
+ }[];
46
+ /** Tables whose RLS could not be fully applied (fail closed). */
47
+ failures: {
48
+ table: string;
49
+ error: string;
50
+ }[];
51
+ }
52
+ /**
53
+ * Bring the declared collections' RLS policies up to date. Returns what it did.
54
+ *
55
+ * Only tables that already exist are touched: the boot-time table creator runs
56
+ * first, so anything still missing is a table this additive path is not allowed
57
+ * to create (a junction, or a relation left to a migration). Enabling RLS on a
58
+ * non-existent table would error, so those are recorded as skipped, not failed.
59
+ */
60
+ export declare function ensureCollectionPolicies(client: Queryable, collections: CollectionConfig[], log?: (message: string) => void): Promise<PolicyEnsureResult>;
@@ -1,8 +1,50 @@
1
- import { CollectionConfig, Property } from "@rebasepro/types";
1
+ import { CollectionConfig, Property, SecurityRule } from "@rebasepro/types";
2
2
  export declare const resolveColumnName: (propName: string, prop?: Property | null) => string;
3
3
  export declare const isIdProperty: (propName: string, prop: Property, collection: CollectionConfig) => boolean;
4
+ type ResolveCollection = (slug: string) => CollectionConfig | undefined;
5
+ /**
6
+ * The individual SQL statements a single security rule compiles to: a
7
+ * `DROP POLICY IF EXISTS` / `CREATE POLICY` pair per operation, each a complete
8
+ * statement (terminated by `;`, no trailing newline).
9
+ *
10
+ * This is the primitive the boot-time RLS applier runs one statement at a time
11
+ * (the runtime's DB handle speaks the extended query protocol, which forbids
12
+ * multiple commands in one execute), while `db push` writes the joined string.
13
+ */
14
+ export declare const generatePolicyStatements: (collection: CollectionConfig, rule: SecurityRule, resolveCollection: ResolveCollection) => string[];
4
15
  export declare const getSqlColumnType: (propName: string, prop: Property, collection: CollectionConfig, collections: CollectionConfig[]) => string;
5
16
  export declare const generatePostgresDdl: (collections: CollectionConfig[], options?: {
6
17
  includePolicies?: boolean;
7
18
  }) => Promise<string>;
19
+ /** The RLS statements one declared collection's table needs, ready to run. */
20
+ export interface CollectionPolicyPlan {
21
+ /** The table's schema (e.g. `public`, `rebase`). */
22
+ schema: string;
23
+ /** The bare table name, no schema prefix. */
24
+ table: string;
25
+ /** `schema.table` — matches the keys `readExistingSchema` returns. */
26
+ qualified: string;
27
+ /** `ALTER TABLE … ENABLE ROW LEVEL SECURITY;` — locked by default. */
28
+ enableRls: string;
29
+ /** `DROP POLICY IF EXISTS` / `CREATE POLICY` statements, in order. */
30
+ policyStatements: string[];
31
+ }
32
+ /**
33
+ * The per-table RLS plan for the *declared* collections, as executable
34
+ * statements — what the managed runtime applies at boot so a freshly
35
+ * provisioned tenant database serves data instead of 401ing every read.
36
+ *
37
+ * Mirrors the non-junction half of {@link generatePostgresPoliciesDdl} exactly
38
+ * (same `generatePolicyStatements`, same enable-RLS, same effective rules), so
39
+ * boot and `db push` produce identical policies from identical collections.
40
+ *
41
+ * Junction tables are deliberately excluded: they are derived from `through`
42
+ * relations, not declared collections, and the boot-time *table* creator
43
+ * (`ensureCollectionTables`) does not create them either — enabling RLS on a
44
+ * table that boot never created would fail. Their RLS stays a `db push` /
45
+ * `db migrate` concern, which is where those tables get created in the first
46
+ * place. `db push` still applies junction policies via the string generator.
47
+ */
48
+ export declare const planCollectionPolicies: (collections: CollectionConfig[]) => CollectionPolicyPlan[];
8
49
  export declare const generatePostgresPoliciesDdl: (collections: CollectionConfig[]) => string;
50
+ export {};
@@ -1,8 +1,135 @@
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 { c as __require, o as __commonJSMin } from "./connection-B5Wndbr1.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
+ //#region ../types/src/types/entities.ts
7
+ /**
8
+ * Class used to create a reference to a entity in a different path
9
+ */
10
+ var EntityRelation = class {
11
+ __type = "relation";
12
+ /**
13
+ * ID of the entity
14
+ */
15
+ id;
16
+ /**
17
+ * A string representing the path of the referenced document (relative
18
+ * to the root of the database).
19
+ */
20
+ path;
21
+ /**
22
+ * Pre-fetched data payload to eliminate N+1 queries.
23
+ * When present, clients can use this directly instead of fetching.
24
+ */
25
+ data;
26
+ constructor(id, path, data) {
27
+ this.id = id;
28
+ this.path = path;
29
+ this.data = data;
30
+ }
31
+ get pathWithId() {
32
+ return `${this.path}/${this.id}`;
33
+ }
34
+ isEntityReference() {
35
+ return false;
36
+ }
37
+ isEntityRelation() {
38
+ return true;
39
+ }
40
+ };
41
+ var Vector = class {
42
+ value;
43
+ constructor(value) {
44
+ this.value = value;
45
+ }
46
+ };
47
+ //#endregion
48
+ //#region ../types/src/types/relations.ts
49
+ /** @group Models */
50
+ function hasForeignKeyOnTarget(relation) {
51
+ return relation.kind === "hasOne" || relation.kind === "hasMany";
52
+ }
53
+ /** @group Models */
54
+ function isManyToMany(relation) {
55
+ return relation.kind === "manyToMany";
56
+ }
57
+ //#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
6
133
  //#region ../common/src/util/common.ts
7
134
  var DEFAULT_ONE_OF_TYPE = "type";
8
135
  var DEFAULT_ONE_OF_VALUE = "value";
@@ -2016,75 +2143,6 @@ function rolesArraySql(roles) {
2016
2143
  return `ARRAY[${[...roles].sort().map((r) => `'${r}'`).join(",")}]`;
2017
2144
  }
2018
2145
  //#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
2146
  //#region ../common/src/util/auth-default-policies.ts
2089
2147
  /**
2090
2148
  * Default RLS policies injected by the schema generator.
@@ -2659,10 +2717,27 @@ function getJunctionSecurityRules(spec) {
2659
2717
  });
2660
2718
  })))();
2661
2719
  /**
2662
- * Apply PropertyConditions to a resolved property, evaluating all JSON Logic rules.
2720
+ * How wide a `varchar`/`char` column should be for a given property.
2721
+ *
2722
+ * One definition, three call sites, because they used to disagree. For the same
2723
+ * `columnType: "varchar"` property the DDL generator emitted `VARCHAR(255)`
2724
+ * while the Drizzle generator emitted a bare `varchar("col")` — which Postgres
2725
+ * reads as *unbounded* — so which of the two you ran decided whether the column
2726
+ * had a limit at all. Introspection then dropped the length entirely, so reading
2727
+ * an existing `character varying(500)` column back and regenerating it produced
2728
+ * a `VARCHAR(255)`: a silent narrowing of a column with data already in it.
2729
+ *
2730
+ * `validation.max` is the property's own statement about how long the value may
2731
+ * be, so it is the only sensible source for the column's width — and it keeps
2732
+ * the constraint the database enforces in step with the one the app enforces,
2733
+ * rather than inventing a second, different limit underneath it.
2663
2734
  */
2735
+ function resolveStringColumnLength(prop) {
2736
+ const max = prop.validation?.max;
2737
+ return typeof max === "number" && Number.isInteger(max) && max > 0 ? max : 255;
2738
+ }
2664
2739
  //#endregion
2665
- //#region ../../node_modules/.pnpm/fast-equals@6.0.0/node_modules/fast-equals/dist/es/index.mjs
2740
+ //#region ../../node_modules/.pnpm/fast-equals@6.0.2/node_modules/fast-equals/dist/es/index.mjs
2666
2741
  var { getOwnPropertyNames, getOwnPropertySymbols } = Object;
2667
2742
  var { hasOwnProperty } = Object.prototype;
2668
2743
  /**
@@ -2698,7 +2773,8 @@ function createIsCircular(areItemsEqual) {
2698
2773
  * not enumerable and symbol properties.
2699
2774
  */
2700
2775
  function getStrictProperties(object) {
2701
- return getOwnPropertyNames(object).concat(getOwnPropertySymbols(object));
2776
+ const symbols = getOwnPropertySymbols(object);
2777
+ return symbols.length ? getOwnPropertyNames(object).concat(symbols) : getOwnPropertyNames(object);
2702
2778
  }
2703
2779
  /**
2704
2780
  * Whether the object contains the property passed as an own property.
@@ -2771,7 +2847,7 @@ function areMapsEqual(a, b, state) {
2771
2847
  const size = a.size;
2772
2848
  if (size !== b.size) return false;
2773
2849
  if (!size) return true;
2774
- const matchedIndices = new Array(size);
2850
+ const matchedIndices = new Uint8Array(size);
2775
2851
  const aIterable = a.entries();
2776
2852
  let aResult;
2777
2853
  let bResult;
@@ -2779,7 +2855,7 @@ function areMapsEqual(a, b, state) {
2779
2855
  while (aResult = aIterable.next()) {
2780
2856
  if (aResult.done) break;
2781
2857
  const bIterable = b.entries();
2782
- let hasMatch = false;
2858
+ let hasMatch = 0;
2783
2859
  let matchIndex = 0;
2784
2860
  while (bResult = bIterable.next()) {
2785
2861
  if (bResult.done) break;
@@ -2790,7 +2866,7 @@ function areMapsEqual(a, b, state) {
2790
2866
  const aEntry = aResult.value;
2791
2867
  const bEntry = bResult.value;
2792
2868
  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;
2869
+ hasMatch = matchedIndices[matchIndex] = 1;
2794
2870
  break;
2795
2871
  }
2796
2872
  matchIndex++;
@@ -2848,19 +2924,19 @@ function areSetsEqual(a, b, state) {
2848
2924
  const size = a.size;
2849
2925
  if (size !== b.size) return false;
2850
2926
  if (!size) return true;
2851
- const matchedIndices = new Array(size);
2927
+ const matchedIndices = new Uint8Array(size);
2852
2928
  const aIterable = a.values();
2853
2929
  let aResult;
2854
2930
  let bResult;
2855
2931
  while (aResult = aIterable.next()) {
2856
2932
  if (aResult.done) break;
2857
2933
  const bIterable = b.values();
2858
- let hasMatch = false;
2934
+ let hasMatch = 0;
2859
2935
  let matchIndex = 0;
2860
2936
  while (bResult = bIterable.next()) {
2861
2937
  if (bResult.done) break;
2862
2938
  if (!matchedIndices[matchIndex] && state.equals(aResult.value, bResult.value, aResult.value, bResult.value, a, b, state)) {
2863
- hasMatch = matchedIndices[matchIndex] = true;
2939
+ hasMatch = matchedIndices[matchIndex] = 1;
2864
2940
  break;
2865
2941
  }
2866
2942
  matchIndex++;
@@ -2873,8 +2949,8 @@ function areSetsEqual(a, b, state) {
2873
2949
  * Whether the TypedArray instances are equal in value.
2874
2950
  */
2875
2951
  function areTypedArraysEqual(a, b) {
2876
- let index = a.byteLength;
2877
- if (b.byteLength !== index || a.byteOffset !== b.byteOffset) return false;
2952
+ let index = a.length;
2953
+ if (b.length !== index || a.byteOffset !== b.byteOffset) return false;
2878
2954
  while (index-- > 0) if (a[index] !== b[index]) return false;
2879
2955
  return true;
2880
2956
  }
@@ -4102,72 +4178,6 @@ function buildSdkData(driver) {
4102
4178
  return wrapAsSdkData(buildRebaseData(driver));
4103
4179
  }
4104
4180
  //#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 };
4181
+ export { DEFAULT_ONE_OF_VALUE as A, updateDateAutoValues as C, camelCase as D, mergeDeep as E, hasForeignKeyOnTarget as M, isManyToMany as N, toSnakeCase as O, Vector as P, normalizeToEntityRelation as S, getPolicyNamesForRule 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, ANONYMOUS_USER_ID as j, DEFAULT_ONE_OF_TYPE 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
4182
 
4173
- //# sourceMappingURL=src-BbFOPJ1S.js.map
4183
+ //# sourceMappingURL=src-DihrDFuP.js.map