@rebasepro/server-postgres 0.12.1-canary.gf5f1d39 → 0.13.1-canary.g18cfeb7

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 (112) hide show
  1. package/dist/PostgresBackendDriver.d.ts +49 -2
  2. package/dist/PostgresBootstrapper.d.ts +25 -1
  3. package/dist/auth/services.d.ts +21 -0
  4. package/dist/{src-BbFOPJ1S.js → auth-users-columns-Do9mw5Y5.js} +602 -200
  5. package/dist/auth-users-columns-Do9mw5Y5.js.map +1 -0
  6. package/dist/backup/backup-service.d.ts +10 -1
  7. package/dist/backup/pg-tools.d.ts +47 -0
  8. package/dist/backup-service-Bww-Lg0s.js +8999 -0
  9. package/dist/backup-service-Bww-Lg0s.js.map +1 -0
  10. package/dist/cli-helpers.d.ts +40 -1
  11. package/dist/connection-BuZ97wsr.js +250 -0
  12. package/dist/connection-BuZ97wsr.js.map +1 -0
  13. package/dist/connection.d.ts +42 -0
  14. package/dist/ensure-collection-policies-DMUdRQdM.js +57 -0
  15. package/dist/ensure-collection-policies-DMUdRQdM.js.map +1 -0
  16. package/dist/ensure-collection-tables-DSIxvLLD.js +694 -0
  17. package/dist/ensure-collection-tables-DSIxvLLD.js.map +1 -0
  18. package/dist/index.es.js +1701 -10167
  19. package/dist/index.es.js.map +1 -1
  20. package/dist/policy-CPkCqVTz.js +105 -0
  21. package/dist/policy-CPkCqVTz.js.map +1 -0
  22. package/dist/rls-bootstrap-sql-Bpv3nUZo.js +244 -0
  23. package/dist/rls-bootstrap-sql-Bpv3nUZo.js.map +1 -0
  24. package/dist/schema/auth-schema.d.ts +83 -144
  25. package/dist/schema/auth-users-columns.d.ts +97 -0
  26. package/dist/schema/ensure-collection-policies.d.ts +60 -0
  27. package/dist/schema/ensure-collection-tables.d.ts +45 -3
  28. package/dist/schema/generate-drizzle-schema-logic.d.ts +1 -1
  29. package/dist/schema/generate-postgres-ddl-logic.d.ts +137 -3
  30. package/dist/schema/generated-schema-staleness.d.ts +39 -0
  31. package/dist/schema/introspect-db-constraints.d.ts +57 -0
  32. package/dist/schema/introspect-db-logic.d.ts +94 -5
  33. package/dist/schema/introspect-db-queries.d.ts +119 -0
  34. package/dist/schema/introspect-db-structure.d.ts +263 -0
  35. package/dist/schema/introspect-db-types.d.ts +11 -0
  36. package/dist/schema/rls-bootstrap-sql.d.ts +135 -0
  37. package/dist/security/rls-enforcement.d.ts +53 -2
  38. package/dist/services/FetchService.d.ts +14 -8
  39. package/dist/services/RelationService.d.ts +24 -1
  40. package/dist/services/channel-bus/index.d.ts +1 -7
  41. package/dist/services/collection-helpers.d.ts +36 -2
  42. package/dist/services/dataService.d.ts +5 -1
  43. package/dist/services/realtimeService.d.ts +25 -21
  44. package/dist/services/row-pipeline.d.ts +1 -1
  45. package/dist/{src-Zqwaw3P5.js → src-C_wvdMnl.js} +78 -145
  46. package/dist/src-C_wvdMnl.js.map +1 -0
  47. package/dist/utils/connection-string.d.ts +29 -0
  48. package/dist/utils/drizzle-conditions.d.ts +5 -4
  49. package/dist/utils/pg-error-utils.d.ts +35 -0
  50. package/dist/websocket-D0TBU3ia.js +530 -0
  51. package/dist/websocket-D0TBU3ia.js.map +1 -0
  52. package/package.json +17 -16
  53. package/src/PostgresAdapter.ts +21 -2
  54. package/src/PostgresBackendDriver.ts +169 -3
  55. package/src/PostgresBootstrapper.ts +233 -35
  56. package/src/auth/ensure-tables.ts +335 -81
  57. package/src/auth/services.ts +24 -2
  58. package/src/backup/backup-cli.ts +41 -2
  59. package/src/backup/backup-service.ts +38 -5
  60. package/src/backup/pg-tools.ts +96 -3
  61. package/src/cli-helpers.ts +92 -9
  62. package/src/cli.ts +219 -56
  63. package/src/collections/validate-relations.ts +136 -14
  64. package/src/connection.ts +73 -0
  65. package/src/data-transformer.ts +22 -6
  66. package/src/databasePoolManager.ts +5 -2
  67. package/src/history/ensure-history-table.ts +7 -0
  68. package/src/schema/auth-schema.ts +30 -19
  69. package/src/schema/auth-users-columns.ts +131 -0
  70. package/src/schema/doctor.ts +7 -5
  71. package/src/schema/ensure-collection-policies.ts +105 -0
  72. package/src/schema/ensure-collection-tables.test.ts +105 -9
  73. package/src/schema/ensure-collection-tables.ts +301 -44
  74. package/src/schema/generate-drizzle-schema-logic.ts +49 -7
  75. package/src/schema/generate-postgres-ddl-logic.ts +474 -27
  76. package/src/schema/generated-schema-staleness.ts +169 -0
  77. package/src/schema/introspect-db-constraints.ts +385 -0
  78. package/src/schema/introspect-db-inference.ts +18 -8
  79. package/src/schema/introspect-db-logic.ts +385 -71
  80. package/src/schema/introspect-db-queries.ts +326 -0
  81. package/src/schema/introspect-db-structure.ts +670 -0
  82. package/src/schema/introspect-db-types.ts +56 -0
  83. package/src/schema/introspect-db.ts +37 -80
  84. package/src/schema/introspect-runtime.test.ts +56 -8
  85. package/src/schema/introspect-runtime.ts +31 -9
  86. package/src/schema/non-sql-collections.test.ts +131 -0
  87. package/src/schema/rls-bootstrap-sql.ts +288 -0
  88. package/src/security/anonymous-grants.test.ts +4 -2
  89. package/src/security/policy-drift.test.ts +11 -3
  90. package/src/security/rls-enforcement.ts +141 -3
  91. package/src/services/BranchService.ts +71 -28
  92. package/src/services/FetchService.ts +100 -107
  93. package/src/services/PersistService.ts +34 -7
  94. package/src/services/RelationService.ts +249 -48
  95. package/src/services/channel-bus/index.ts +0 -9
  96. package/src/services/channel-history.ts +8 -0
  97. package/src/services/channel-presence.ts +6 -0
  98. package/src/services/collection-helpers.ts +69 -3
  99. package/src/services/dataService.ts +5 -1
  100. package/src/services/realtimeService.ts +38 -35
  101. package/src/services/row-pipeline.ts +1 -1
  102. package/src/utils/connection-string.ts +58 -0
  103. package/src/utils/drizzle-conditions.ts +31 -6
  104. package/src/utils/pg-error-utils.ts +65 -0
  105. package/src/websocket.ts +18 -9
  106. package/dist/chunk-DSJWtz9O.js +0 -40
  107. package/dist/ensure-collection-tables-CNTcZGvn.js +0 -304
  108. package/dist/ensure-collection-tables-CNTcZGvn.js.map +0 -1
  109. package/dist/schema/auth-bootstrap-sql.d.ts +0 -24
  110. package/dist/src-BbFOPJ1S.js.map +0 -1
  111. package/dist/src-Zqwaw3P5.js.map +0 -1
  112. package/src/schema/auth-bootstrap-sql.ts +0 -47
@@ -141,7 +141,7 @@ export declare class FetchService {
141
141
  /**
142
142
  * Fallback path used when db.query is unavailable.
143
143
  *
144
- * The primary path runs the results through `toCmsRow`, which maps
144
+ * The primary path runs the results through `toFlatRow`, which maps
145
145
  * relations from what drizzle already nested — no query per row. This one
146
146
  * has no nesting to read, so it resolves relations itself, in batches.
147
147
  *
@@ -153,6 +153,16 @@ export declare class FetchService {
153
153
  */
154
154
  fetchCollection<M extends Record<string, unknown>>(collectionPath: string, options?: {
155
155
  filter?: FilterValues<Extract<keyof M, string>>;
156
+ /**
157
+ * An `or(...)`/`and(...)` group, applied alongside `filter`.
158
+ *
159
+ * `fetchRowsWithConditions` below has always applied this; it was
160
+ * simply absent from this signature, so the only callers that could
161
+ * pass one were the ones that went around this method. Realtime
162
+ * came through here, which is why a subscription filtered by a
163
+ * logical group was pushed every row in the table.
164
+ */
165
+ logical?: LogicalCondition;
156
166
  orderBy?: string;
157
167
  order?: "desc" | "asc";
158
168
  limit?: number;
@@ -177,6 +187,7 @@ export declare class FetchService {
177
187
  */
178
188
  count<M extends Record<string, unknown>>(collectionPath: string, options?: {
179
189
  filter?: FilterValues<Extract<keyof M, string>>;
190
+ logical?: LogicalCondition;
180
191
  searchString?: string;
181
192
  databaseId?: string;
182
193
  }): Promise<number>;
@@ -198,6 +209,8 @@ export declare class FetchService {
198
209
  */
199
210
  fetchCollectionForRest<M extends Record<string, unknown>>(collectionPath: string, options?: {
200
211
  filter?: FilterValues<Extract<keyof M, string>>;
212
+ /** An `or(...)`/`and(...)` group, applied alongside `filter`. */
213
+ logical?: LogicalCondition;
201
214
  orderBy?: string;
202
215
  order?: "desc" | "asc";
203
216
  limit?: number;
@@ -223,13 +236,6 @@ export declare class FetchService {
223
236
  * Note: Primary path now uses inline `getQueryBuilder()` checks.
224
237
  */
225
238
  private hasDrizzleQueryAPI;
226
- /**
227
- * Attempt to use Drizzle's relational query API (db.query.<table>.findMany)
228
- * for efficient JOIN-based relation loading.
229
- * Returns null if the API is not available or the query fails.
230
- * Note: Primary path now uses `buildWithConfig` + `buildDrizzleQueryOptions`.
231
- */
232
- private fetchWithDrizzleQuery;
233
239
  /**
234
240
  * Fallback path used when db.query is unavailable.
235
241
  * The primary path uses db.query.findMany with `with` config, which
@@ -1,5 +1,5 @@
1
1
  import { DrizzleClient } from "../interfaces";
2
- import { CollectionConfig, FilterValues, ResolvedRelation, ResolvedManyToMany } from "@rebasepro/types";
2
+ import { CollectionConfig, FilterValues, ResolvedRelation, ResolvedManyToMany, ResolvedHasMany, ResolvedHasOne } from "@rebasepro/types";
3
3
  import { type ResolvedVia } from "@rebasepro/types";
4
4
  import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
5
5
  import type { NestedPathHop } from "./nested-path";
@@ -56,6 +56,29 @@ export declare class RelationService {
56
56
  * hand a tenant's rows to its neighbour — say so instead.
57
57
  */
58
58
  private assertSingleKeyAddressable;
59
+ /**
60
+ * What the target's foreign key holds, for each of these parent rows.
61
+ *
62
+ * Ordinarily the parent's id, and then this is free. When the relation
63
+ * declares a `sourceKey` the two are different values, and the mapping
64
+ * between them lives in the source table — so it costs one SELECT, issued
65
+ * once for the whole batch rather than per parent.
66
+ *
67
+ * Both directions come back because both are needed and deriving one from
68
+ * the other by hand is how a batch loader ends up attributing a child to the
69
+ * wrong parent: reads translate id → key to build the WHERE, and then
70
+ * translate key → id to attribute each row that comes back.
71
+ */
72
+ /**
73
+ * The value a related row's foreign key must hold to belong to this parent.
74
+ *
75
+ * `undefined` when the parent's source key is null — which is not an error
76
+ * here, only in the callers that were about to write it. Exposed for
77
+ * {@link PersistService}, which stamps this onto a child created under a
78
+ * nested path and would otherwise write the id and lose the row.
79
+ */
80
+ parentKeyValue(parentCollection: CollectionConfig, relation: ResolvedHasOne | ResolvedHasMany, parentId: string | number, db?: DrizzleClient): Promise<string | number | undefined>;
81
+ private resolveSourceKeys;
59
82
  /**
60
83
  * Fetch rows related to a parent row through a specific relation
61
84
  */
@@ -15,7 +15,7 @@
15
15
  * `types/channel_bus.ts` for the contract such a package implements.
16
16
  */
17
17
  import { NodePgDatabase } from "drizzle-orm/node-postgres";
18
- import { type ChannelBus, type ChannelBusConfig, type ChannelBusSetting } from "@rebasepro/types";
18
+ import { type ChannelBus, type ChannelBusSetting } from "@rebasepro/types";
19
19
  export * from "./ChannelBus";
20
20
  export { PostgresChannelBus, CHANNEL_BUS_NOTIFY_CHANNEL, PG_NOTIFY_MAX_PAYLOAD_BYTES, DEFAULT_BATCH_WINDOW_MS, parseChannelBusFrame, parseChannelBusPayload } from "./PostgresChannelBus";
21
21
  export interface ChannelBusDeps {
@@ -37,12 +37,6 @@ export interface ChannelBusDeps {
37
37
  * mean silently discarding the object the application handed us.
38
38
  */
39
39
  export declare function resolveChannelBusSetting(configured?: ChannelBusSetting): ChannelBusSetting;
40
- /**
41
- * @deprecated Use {@link resolveChannelBusSetting}, which also accepts a
42
- * supplied {@link ChannelBus} instance. Kept as a narrow alias so existing
43
- * config-only callers keep their exact types.
44
- */
45
- export declare function resolveChannelBusConfig(configured?: ChannelBusConfig): ChannelBusConfig;
46
40
  /**
47
41
  * Produce the bus a setting asks for.
48
42
  *
@@ -1,7 +1,7 @@
1
1
  import { PgTable, AnyPgColumn } from "drizzle-orm/pg-core";
2
- import { CollectionConfig } from "@rebasepro/types";
2
+ import { CollectionConfig, ResolvedHasMany, ResolvedHasOne } from "@rebasepro/types";
3
3
  import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
4
- export { buildCompositeId, parseIdValues, COMPOSITE_ID_SEPARATOR } from "@rebasepro/common";
4
+ export { buildCompositeId, parseIdValues, isAddressableId, COMPOSITE_ID_SEPARATOR } from "@rebasepro/common";
5
5
  export type { PrimaryKeyInfo } from "@rebasepro/common";
6
6
  import type { PrimaryKeyInfo } from "@rebasepro/common";
7
7
  /**
@@ -22,6 +22,17 @@ export interface DrizzleColumnMeta {
22
22
  }
23
23
  /** Safely extract Drizzle column metadata from a column object. */
24
24
  export declare function getColumnMeta(col: AnyPgColumn): DrizzleColumnMeta;
25
+ /**
26
+ * Whether an address could name a row in this table, judged by the columns.
27
+ *
28
+ * {@link getPrimaryKeys} lets a config's `isId: "uuid"` win over the schema, so
29
+ * its `isUUID` is a claim rather than a fact — right for deriving addresses,
30
+ * wrong for refusing a query. Here the Drizzle column type decides, because it
31
+ * is what Postgres will enforce: a `uuid` column meets `/c/products/new` with
32
+ * `22P02`, which aborts the surrounding transaction and turns every later
33
+ * statement into an unrelated-looking `25P02`.
34
+ */
35
+ export declare function idCanAddressTable(id: string | number, table: PgTable, idInfoArray: PrimaryKeyInfo[]): boolean;
25
36
  export declare function getCollectionByPath(collectionPath: string, registry: PostgresCollectionRegistry): CollectionConfig;
26
37
  export declare function getTableForCollection(collection: CollectionConfig, registry: PostgresCollectionRegistry): PgTable<any>;
27
38
  /**
@@ -55,6 +66,29 @@ export declare function getPrimaryKeys(collection: CollectionConfig, registry: P
55
66
  * wrong and which collection it is wrong about.
56
67
  */
57
68
  export declare function requirePrimaryKeys(collection: CollectionConfig, registry: PostgresCollectionRegistry): PrimaryKeyInfo[];
69
+ /**
70
+ * The column on the *source* table that a `hasOne`/`hasMany` link points at.
71
+ *
72
+ * `sourceKey` is authored when the two sides join on a natural key — an
73
+ * external identity id, a SKU — and left off when they join on the row id,
74
+ * which is the overwhelming majority. That makes `undefined` the only optional
75
+ * field on a resolved relation, so it gets exactly one reader: this function.
76
+ * Every consumer that needs the column asks here, and none of them re-derives
77
+ * "or else the primary key" for itself. That is the whole point — the fallback
78
+ * chains this codebase removed from relation resolution were dangerous because
79
+ * they were *duplicated* and could disagree, not because they existed.
80
+ */
81
+ export declare function sourceKeyField(relation: ResolvedHasOne | ResolvedHasMany, sourceCollection: CollectionConfig, registry: PostgresCollectionRegistry): string;
82
+ /**
83
+ * Whether this link joins on something other than the source's primary key.
84
+ *
85
+ * Callers that hold a parent *id* — which is most of them, since an id is what
86
+ * a URL carries — must translate it to the source key's value before it can be
87
+ * compared with the target's foreign key. Those that hold the parent *row*, or
88
+ * that build a correlated subquery over the source table, can read the column
89
+ * directly and skip the lookup.
90
+ */
91
+ export declare function joinsOnNaturalKey(relation: ResolvedHasOne | ResolvedHasMany, sourceCollection: CollectionConfig, registry: PostgresCollectionRegistry): boolean;
58
92
  /**
59
93
  * Collections whose key the *browser* cannot resolve, and what it will do
60
94
  * instead.
@@ -1,4 +1,4 @@
1
- import { FilterValues } from "@rebasepro/types";
1
+ import { FilterValues, LogicalCondition } from "@rebasepro/types";
2
2
  import type { VectorSearchParams } from "@rebasepro/types";
3
3
  import { FetchService } from "./FetchService";
4
4
  import { PersistService } from "./PersistService";
@@ -36,6 +36,8 @@ export declare class DataService implements DataRepository {
36
36
  */
37
37
  fetchCollection<M extends Record<string, unknown>>(collectionPath: string, options?: {
38
38
  filter?: FilterValues<Extract<keyof M, string>>;
39
+ /** An `or(...)`/`and(...)` group, applied alongside `filter`. */
40
+ logical?: LogicalCondition;
39
41
  orderBy?: string;
40
42
  order?: "desc" | "asc";
41
43
  limit?: number;
@@ -60,6 +62,8 @@ export declare class DataService implements DataRepository {
60
62
  */
61
63
  count<M extends Record<string, unknown>>(collectionPath: string, options?: {
62
64
  filter?: FilterValues<Extract<keyof M, string>>;
65
+ /** An `or(...)`/`and(...)` group, applied alongside `filter`. */
66
+ logical?: LogicalCondition;
63
67
  searchString?: string;
64
68
  databaseId?: string;
65
69
  }): Promise<number>;
@@ -1,6 +1,6 @@
1
1
  import { WebSocket } from "ws";
2
2
  import { EventEmitter } from "events";
3
- import { DataDriver, WebSocketMessage } from "@rebasepro/types";
3
+ import { DataDriver, WebSocketMessage, LogicalCondition } from "@rebasepro/types";
4
4
  import { NodePgDatabase } from "drizzle-orm/node-postgres";
5
5
  import { RealtimeProvider, CollectionSubscriptionConfig, SingleSubscriptionConfig } from "../interfaces";
6
6
  import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
@@ -14,6 +14,27 @@ export interface SubscriptionAuthContext {
14
14
  uid: string;
15
15
  roles: string[];
16
16
  }
17
+ /**
18
+ * The narrowing a collection subscription was created with, kept so that every
19
+ * refetch answers the same query the initial fetch did.
20
+ *
21
+ * Named once because it used to be written out inline in five places, and a
22
+ * field missing from one of them is accepted over the wire and then silently
23
+ * ignored: `offset` was declared on the incoming props and never stored, so a
24
+ * live list on page three served page one, and `logical` was never stored
25
+ * either, so an `or(...)` subscription was pushed every row in the table.
26
+ */
27
+ type StoredCollectionRequest = {
28
+ filter?: Record<string, unknown>;
29
+ logical?: LogicalCondition;
30
+ orderBy?: string;
31
+ order?: "desc" | "asc";
32
+ limit?: number;
33
+ offset?: number;
34
+ startAfter?: Record<string, unknown>;
35
+ databaseId?: string;
36
+ searchString?: string;
37
+ };
17
38
  /**
18
39
  * PostgreSQL-specific realtime service.
19
40
  * Handles WebSocket connections and subscriptions for real-time row updates.
@@ -128,16 +149,7 @@ export declare class RealtimeService extends EventEmitter implements RealtimePro
128
149
  type: "collection" | "single";
129
150
  path: string;
130
151
  id?: string | number;
131
- collectionRequest?: {
132
- filter?: Record<string, unknown>;
133
- orderBy?: string;
134
- order?: "desc" | "asc";
135
- limit?: number;
136
- offset?: number;
137
- startAfter?: Record<string, unknown>;
138
- databaseId?: string;
139
- searchString?: string;
140
- };
152
+ collectionRequest?: StoredCollectionRequest;
141
153
  authContext?: SubscriptionAuthContext;
142
154
  }>;
143
155
  registerDataDriverSubscription(subscriptionId: string, subscription: {
@@ -145,16 +157,7 @@ export declare class RealtimeService extends EventEmitter implements RealtimePro
145
157
  type: "collection" | "single";
146
158
  path: string;
147
159
  id?: string | number;
148
- collectionRequest?: {
149
- filter?: Record<string, unknown>;
150
- orderBy?: string;
151
- order?: "desc" | "asc";
152
- limit?: number;
153
- offset?: number;
154
- startAfter?: Record<string, unknown>;
155
- databaseId?: string;
156
- searchString?: string;
157
- };
160
+ collectionRequest?: StoredCollectionRequest;
158
161
  authContext?: SubscriptionAuthContext;
159
162
  }): void;
160
163
  addSubscriptionCallback(subscriptionId: string, callback: (data: Record<string, unknown>[] | Record<string, unknown> | null) => void): void;
@@ -497,3 +500,4 @@ export declare class RealtimeService extends EventEmitter implements RealtimePro
497
500
  * This allows code to use PostgresRealtimeProvider alongside future MongoRealtimeProvider, etc.
498
501
  */
499
502
  export declare const PostgresRealtimeProvider: typeof RealtimeService;
503
+ export {};
@@ -47,7 +47,7 @@ export declare function relationTargetAddress(targetRow: Record<string, unknown>
47
47
  * expects real types. The row's own address is *not* among the columns — it is
48
48
  * derived by the consumer from the collection's primary keys.
49
49
  */
50
- export declare function toCmsRow(row: Record<string, unknown>, collection: CollectionConfig, registry: PostgresCollectionRegistry): Record<string, unknown>;
50
+ export declare function toFlatRow(row: Record<string, unknown>, collection: CollectionConfig, registry: PostgresCollectionRegistry): Record<string, unknown>;
51
51
  /**
52
52
  * The row REST serves: every column under its own name, with the value Postgres
53
53
  * returned, and relations inlined as the target's columns.
@@ -1,48 +1,6 @@
1
1
  import { createRequire as __createRequire } from "module";
2
2
  import "process";
3
3
  __createRequire(import.meta.url);
4
- //#region ../types/src/types/entities.ts
5
- /**
6
- * Class used to create a reference to a entity in a different path
7
- */
8
- var EntityRelation = class {
9
- __type = "relation";
10
- /**
11
- * ID of the entity
12
- */
13
- id;
14
- /**
15
- * A string representing the path of the referenced document (relative
16
- * to the root of the database).
17
- */
18
- path;
19
- /**
20
- * Pre-fetched data payload to eliminate N+1 queries.
21
- * When present, clients can use this directly instead of fetching.
22
- */
23
- data;
24
- constructor(id, path, data) {
25
- this.id = id;
26
- this.path = path;
27
- this.data = data;
28
- }
29
- get pathWithId() {
30
- return `${this.path}/${this.id}`;
31
- }
32
- isEntityReference() {
33
- return false;
34
- }
35
- isEntityRelation() {
36
- return true;
37
- }
38
- };
39
- var Vector = class {
40
- value;
41
- constructor(value) {
42
- this.value = value;
43
- }
44
- };
45
- //#endregion
46
4
  //#region ../types/src/types/filter-operators.ts
47
5
  /** Maps REST short-code operators to their canonical equivalents. */
48
6
  var REST_TO_CANONICAL = {
@@ -67,7 +25,7 @@ var REST_TO_CANONICAL = {
67
25
  * Operators that test for null/not-null and therefore ignore their value.
68
26
  * Codecs normalize the value of these conditions to `null`.
69
27
  */
70
- var NULL_OPS = new Set(["is-null", "is-not-null"]);
28
+ var NULL_OPS = /* @__PURE__ */ new Set(["is-null", "is-not-null"]);
71
29
  /**
72
30
  * Every canonical operator, in a stable order. Useful for engine capability
73
31
  * declarations ({@link DataSourceCapabilities.filterOperators}) and for
@@ -273,120 +231,95 @@ function getDeclaredSubcollections(collection) {
273
231
  return collection.subcollections;
274
232
  }
275
233
  //#endregion
276
- //#region ../types/src/types/relations.ts
277
- /** @group Models */
278
- function hasForeignKeyOnTarget(relation) {
279
- return relation.kind === "hasOne" || relation.kind === "hasMany";
280
- }
281
- /** @group Models */
282
- function isManyToMany(relation) {
283
- return relation.kind === "manyToMany";
284
- }
285
- //#endregion
286
- //#region ../types/src/types/policy.ts
234
+ //#region ../types/src/types/rls-functions.ts
287
235
  /**
288
- * The id a request without a logged-in user reports as `auth.uid()`.
236
+ * The SQL helper functions RLS policies call, and the schema they live in.
289
237
  *
290
- * A user-context request always sets `app.uid`: blank would read back as
291
- * `NULL`, and `NULL` is how the trusted server context is recognised, so an
292
- * anonymous visitor would be promoted to server privileges. The driver
293
- * therefore substitutes this sentinel at the single chokepoint where the GUC
294
- * is set.
238
+ * ## One schema, and it is ours
295
239
  *
296
- * The consequence for policy authors is that **`auth.uid() IS NOT NULL` is a
297
- * tautology on the user path** — it is true for anonymous visitors too. Use
298
- * {@link policy.authenticated} (or `auth.uid() <> 'anonymous'`) to mean "signed
299
- * in", and {@link policy.serverContext} to mean "the trusted server context".
240
+ * Rebase creates exactly one schema in a project's database: `rebase`. These
241
+ * three functions live in it alongside the framework's own tables, and that is
242
+ * the whole contract — a reader can look at a database and know precisely which
243
+ * namespace belongs to the framework and that nothing else was touched.
300
244
  *
301
- * @group Models
245
+ * It used to be two. `uid()`, `jwt()` and `roles()` sat in a schema called
246
+ * `auth`, which is Supabase's name, chosen so that a developer who had written
247
+ * Supabase RLS would recognise `auth.uid()`. The familiarity was real but the
248
+ * name was not Rebase's to take, and taking it had a concrete cost: pointing
249
+ * Rebase at a database that already had a Supabase `auth` schema meant
250
+ * `CREATE OR REPLACE FUNCTION auth.uid() RETURNS text` against Supabase's
251
+ * `RETURNS uuid`, which Postgres rejects outright —
252
+ *
253
+ * ERROR: cannot change return type of existing function
254
+ * HINT: Use DROP FUNCTION auth.uid() first.
255
+ *
256
+ * — and the failure landed inside a catch-all that logged a warning and carried
257
+ * on, leaving a database with auth tables, no helper functions, and policies
258
+ * calling functions that did not exist. Under `rebase db migrate` the same
259
+ * statements aborted the migration instead.
260
+ *
261
+ * `rebase.uid()` collides with nobody. A Supabase database keeps its `auth`
262
+ * schema untouched and gains a `rebase` one, which is what a gradual migration
263
+ * needs.
264
+ *
265
+ * ## Why functions at all, rather than inlining `current_setting`
266
+ *
267
+ * Because the indirection has already been spent once. `uid()` resolves
268
+ * `app.uid` and falls back to the pre-rename `app.user_id`, so that during a
269
+ * rolling deploy — old and new pods serving one database — both eras resolve
270
+ * the principal. That was a single `CREATE OR REPLACE`. Inlined into policy
271
+ * bodies it would have been a rewrite of every policy on every table.
272
+ *
273
+ * ## Why the name is not configurable
274
+ *
275
+ * A policy body is stored SQL: Postgres parses `USING (…)` once and keeps it, so
276
+ * these strings are written into every policy in every database Rebase has
277
+ * provisioned. Everything that reads policies back — the SQL-to-policy parser
278
+ * behind the admin UI, the drift checker, `rls-check` — would have to know the
279
+ * configured value to recognise its own output. One frozen name is the feature.
302
280
  */
303
- var ANONYMOUS_USER_ID = "anonymous";
304
- /** @group Models */
305
- var policy = {
306
- true: () => ({ kind: "true" }),
307
- false: () => ({ kind: "false" }),
308
- and: (...operands) => ({
309
- kind: "and",
310
- operands
311
- }),
312
- or: (...operands) => ({
313
- kind: "or",
314
- operands
315
- }),
316
- not: (operand) => ({
317
- kind: "not",
318
- operand
319
- }),
320
- compare: (left, op, right) => ({
321
- kind: "compare",
322
- op,
323
- left,
324
- right
325
- }),
326
- rolesOverlap: (roles) => ({
327
- kind: "rolesOverlap",
328
- roles
329
- }),
330
- rolesContain: (roles) => ({
331
- kind: "rolesContain",
332
- roles
333
- }),
334
- authenticated: () => ({ kind: "authenticated" }),
335
- serverContext: () => ({ kind: "serverContext" }),
336
- existsIn: (args) => ({
337
- kind: "existsIn",
338
- collection: args.collection,
339
- where: args.where
340
- }),
341
- raw: (sql) => ({
342
- kind: "raw",
343
- sql
344
- }),
345
- field: (name) => ({
346
- kind: "field",
347
- name
348
- }),
349
- outerField: (name) => ({
350
- kind: "outerField",
351
- name
352
- }),
353
- literal: (value) => ({
354
- kind: "literal",
355
- value
356
- }),
357
- authUid: () => ({ kind: "authUid" }),
358
- authRoles: () => ({ kind: "authRoles" })
359
- };
360
- //#endregion
361
- //#region ../types/src/types/backend.ts
281
+ /** The schema Rebase owns. The only schema Rebase creates. */
282
+ var REBASE_SCHEMA = "rebase";
362
283
  /**
363
- * Type guard: does this admin support SQL operations?
364
- * @group Admin
284
+ * The principal of the current request, as text, or NULL in the server context.
285
+ *
286
+ * Never NULL for a user request — an anonymous one carries
287
+ * {@link ANONYMOUS_USER_ID} — which is what makes `IS NULL` a reliable test for
288
+ * the trusted server plane and `IS NOT NULL` a tautology.
365
289
  */
366
- function isSQLAdmin(admin) {
367
- return !!admin && typeof admin.executeSql === "function";
368
- }
290
+ var RLS_UID_SQL = `${REBASE_SCHEMA}.uid()`;
291
+ /** The request's roles as a comma-separated string, for `string_to_array`. */
292
+ var RLS_ROLES_SQL = `${REBASE_SCHEMA}.roles()`;
293
+ `${REBASE_SCHEMA}`;
369
294
  /**
370
- * Type guard: does this admin support schema management?
371
- * @group Admin
295
+ * The pre-1.0 spellings, for recognising policies and hand-written SQL that
296
+ * predate the move.
297
+ *
298
+ * Kept because policies outlive the server that wrote them: a database migrated
299
+ * by an older release still holds `auth.uid()` in its policy bodies until the
300
+ * next push or boot recompiles them, and anything that reads policies back has
301
+ * to recognise both eras or report the framework's own output as foreign drift.
302
+ * Also used to give a project whose `securityRules` contain raw `auth.uid()` a
303
+ * message naming the replacement, instead of a parse failure.
372
304
  */
373
- function isSchemaAdmin(admin) {
374
- return !!admin && (typeof admin.fetchUnmappedTables === "function" || typeof admin.fetchTableMetadata === "function");
375
- }
376
- //#endregion
377
- //#region ../types/src/types/channel_bus.ts
305
+ var LEGACY_RLS_SCHEMA = "auth";
306
+ `${LEGACY_RLS_SCHEMA}`;
307
+ `${LEGACY_RLS_SCHEMA}`;
308
+ `${LEGACY_RLS_SCHEMA}`;
378
309
  /**
379
- * Whether `setting` is an already-constructed transport rather than a request
380
- * for a built-in one.
310
+ * Rewrites the pre-1.0 function calls in a fragment of policy SQL.
381
311
  *
382
- * Structural rather than nominal so that an instance from a *different copy* of
383
- * `@rebasepro/types` — an entirely normal outcome of a separately versioned
384
- * transport package — is still recognised.
312
+ * Deliberately anchored on a word boundary and the schema qualifier, so a column
313
+ * called `auth_uid` or a table named `auth` is left alone.
385
314
  */
386
- function isChannelBusInstance(setting) {
387
- return typeof setting?.publish === "function";
315
+ function rewriteLegacyRlsFunctions(sql) {
316
+ return sql.replace(/\bauth\.(uid|jwt|roles)\s*\(\s*\)/gi, (_match, fn) => `${REBASE_SCHEMA}.${fn.toLowerCase()}()`);
317
+ }
318
+ /** Whether a fragment of SQL still calls the pre-1.0 functions. */
319
+ function usesLegacyRlsFunctions(sql) {
320
+ return /\bauth\.(uid|jwt|roles)\s*\(\s*\)/i.test(sql);
388
321
  }
389
322
  //#endregion
390
- export { Vector as _, policy as a, getDeclaredSubcollections as c, DEFAULT_DATA_SOURCE_KEY as d, getDataSourceCapabilities as f, EntityRelation as g, toCanonicalOp as h, ANONYMOUS_USER_ID as i, isPostgresCollectionConfig as l, REST_TO_CANONICAL as m, isSQLAdmin as n, hasForeignKeyOnTarget as o, NULL_OPS as p, isSchemaAdmin as r, isManyToMany as s, isChannelBusInstance as t, isRelationalCollectionConfig as u };
323
+ export { rewriteLegacyRlsFunctions as a, isPostgresCollectionConfig as c, getDataSourceCapabilities as d, NULL_OPS as f, RLS_UID_SQL as i, isRelationalCollectionConfig as l, toCanonicalOp as m, REBASE_SCHEMA as n, usesLegacyRlsFunctions as o, REST_TO_CANONICAL as p, RLS_ROLES_SQL as r, getDeclaredSubcollections as s, LEGACY_RLS_SCHEMA as t, DEFAULT_DATA_SOURCE_KEY as u };
391
324
 
392
- //# sourceMappingURL=src-Zqwaw3P5.js.map
325
+ //# sourceMappingURL=src-C_wvdMnl.js.map