@rebasepro/types 0.15.0 → 0.16.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.
@@ -345,7 +345,7 @@ export interface SQLAdmin {
345
345
  * Fetch the *application-level* roles in use in this project.
346
346
  *
347
347
  * These are the strings stored on the users table's `roles` column and
348
- * exposed to policies as `auth.roles()` — what `SecurityRule.roles`
348
+ * exposed to policies as `rebase.roles()` — what `SecurityRule.roles`
349
349
  * matches against. Distinct from {@link fetchAvailableRoles}; the two are
350
350
  * not interchangeable.
351
351
  */
@@ -667,6 +667,33 @@ export interface BackendBootstrapper {
667
667
  ensureCollectionPolicies?(collections: unknown[], driverResult?: InitializedDriver, log?: (message: string) => void): Promise<{
668
668
  applied: number;
669
669
  }>;
670
+ /**
671
+ * Read the collections schema version this database was last provisioned
672
+ * from, or `null` when nothing has ever stamped it.
673
+ *
674
+ * The companion to {@link stampCollectionsSchemaVersion}: one process writes
675
+ * what it applied, every other process compares itself to it. This is what
676
+ * lets a split deployment — several processes over one database, only one of
677
+ * which provisions — notice that a unit is serving against a schema it was
678
+ * not built for. That failure is otherwise silent in both directions: a
679
+ * column that does not exist is a SQL error on one route, and a policy that
680
+ * was never applied is a 200 with no rows.
681
+ *
682
+ * `null` is not an error and MUST NOT be treated as one — every database
683
+ * provisioned before the stamp existed reads this way, and so does every
684
+ * fresh one until its first provisioning boot finishes.
685
+ */
686
+ readCollectionsSchemaVersion?(driverResult?: InitializedDriver): Promise<string | null>;
687
+ /**
688
+ * Record the collections schema version this process just applied.
689
+ *
690
+ * Called only by the process that provisions, and only after both
691
+ * {@link ensureCollectionSchema} and {@link ensureCollectionPolicies} have
692
+ * run — a stamp written before the policies would claim a schema that is
693
+ * only half in place, and the half that is missing is the one that fails
694
+ * without an error.
695
+ */
696
+ stampCollectionsSchemaVersion?(version: string, driverResult?: InitializedDriver): Promise<void>;
670
697
  /**
671
698
  * Initialize WebSocket server for realtime operations.
672
699
  */
@@ -210,9 +210,9 @@ export interface PostgresCollectionConfig<M extends Record<string, unknown> = Re
210
210
  * 3. **Combined** — mix shortcuts with `roles` for common patterns
211
211
  *
212
212
  * The authenticated user context is available in raw SQL via:
213
- * - `auth.uid()` — the current user's ID
214
- * - `auth.roles()` — comma-separated app role IDs
215
- * - `auth.jwt()` — full JWT claims as JSONB
213
+ * - `rebase.uid()` — the current user's ID
214
+ * - `rebase.roles()` — comma-separated app role IDs
215
+ * - `rebase.jwt()` — full JWT claims as JSONB
216
216
  */
217
217
  securityRules?: readonly SecurityRule[];
218
218
  /**
@@ -222,7 +222,7 @@ export interface PostgresCollectionConfig<M extends Record<string, unknown> = Re
222
222
  * baseline SELECT policy granting the trusted server context and the
223
223
  * `admin` role read access (reads run under a restricted role, so RLS
224
224
  * default-denies without it). For auth collections it additionally injects
225
- * a self-read policy (`id = auth.uid()`) and an admin-only write gate
225
+ * a self-read policy (`id = rebase.uid()`) and an admin-only write gate
226
226
  * (INSERT/UPDATE/DELETE require the `admin` role or the trusted server
227
227
  * context), making privileged columns such as `roles` safe by default.
228
228
  *
@@ -81,10 +81,14 @@ export interface CronJobContext {
81
81
  * hands its callback. Spelled the same way here so that one thing has one
82
82
  * name across every server-side authoring surface.
83
83
  *
84
- * Its data plane is {@link RebaseServerClient.dataAsAdmin}, which runs with
85
- * **admin privileges and bypasses RLS** (`{ uid: "service", roles:
86
- * ["admin"] }`). A cron has no per-request user, so there is no user-scoped
87
- * alternative here and no policy to fall back on: scope every query's
84
+ * Its data plane is {@link RebaseServerClient.dataAsAdmin}, scoped as
85
+ * `{ uid: "service", roles: ["admin"] }` — **admin-scoped, not
86
+ * RLS-bypassing**. Statements still run as `rebase_user` with the policies
87
+ * evaluated against that identity; the admin role merely clears the default
88
+ * policies through their `rolesOverlap(['admin'])` arm, and
89
+ * `policy.serverContext()` (`rebase.uid() IS NULL`) is *false* for it.
90
+ * `rebase.sql()` is the unconditional bypass. A cron has no per-request
91
+ * user, so there is no user-scoped alternative here: scope every query's
88
92
  * filters yourself.
89
93
  *
90
94
  * @example
@@ -109,6 +109,27 @@ export interface DatabaseAdapter {
109
109
  ensureCollectionPolicies?(collections: unknown[], driverResult?: InitializedDriver, log?: (message: string) => void): Promise<{
110
110
  applied: number;
111
111
  }>;
112
+ /**
113
+ * Read the collections schema version this database was last provisioned
114
+ * from, or `null` when nothing has ever stamped it.
115
+ *
116
+ * `null` is not an error and MUST NOT be treated as one — every database
117
+ * provisioned before the stamp existed reads this way, and so does every
118
+ * fresh one until its first provisioning boot finishes.
119
+ *
120
+ * Same forwarding requirement as the two hooks above: a wrapper that omits
121
+ * it turns the check off, and a check that is off looks exactly like a check
122
+ * that passed.
123
+ */
124
+ readCollectionsSchemaVersion?(driverResult?: InitializedDriver): Promise<string | null>;
125
+ /**
126
+ * Record the collections schema version this process just applied.
127
+ *
128
+ * Called only by the process that provisions, and only after the tables AND
129
+ * the policies are in place — a stamp written earlier would claim a schema
130
+ * that a half-finished boot never finished creating.
131
+ */
132
+ stampCollectionsSchemaVersion?(version: string, driverResult?: InitializedDriver): Promise<void>;
112
133
  /**
113
134
  * Return admin capabilities for this database (SQL editor, schema browser, branching).
114
135
  */
@@ -176,4 +197,33 @@ export interface DatabaseAdapterInitConfig {
176
197
  /** Why it did not, when it did not — safe to print verbatim. */
177
198
  reason?: string;
178
199
  };
200
+ /**
201
+ * What this process wants from the realtime subsystem.
202
+ *
203
+ * Both halves used to be assumed true, and both were wrong for a split
204
+ * deployment. A `functions` or `worker` process has no websocket clients, so
205
+ * consuming change events buys it a dedicated `LISTEN` connection to deliver
206
+ * to nobody; and it is explicitly not the process that owns schema DDL, so
207
+ * installing capture triggers from it contradicts the one-owner rule the
208
+ * runtime otherwise refuses to boot without.
209
+ *
210
+ * Absent means both — every caller that predates this field is a
211
+ * single-process deployment, where both are true.
212
+ */
213
+ realtime?: {
214
+ /**
215
+ * Consume change events: open the `LISTEN` connection, start CDC or the
216
+ * app-level fallback. False for a process that serves no websockets.
217
+ *
218
+ * Writes made by a non-consuming process are still published: capture is
219
+ * database triggers, so the publisher is the database.
220
+ */
221
+ subscribe: boolean;
222
+ /**
223
+ * Install what capture needs — the trigger function, the per-table
224
+ * triggers, any channel-history tables. This is DDL, and it follows the
225
+ * same single-owner rule as every other boot-time schema change.
226
+ */
227
+ provision: boolean;
228
+ };
179
229
  }
@@ -395,6 +395,45 @@ export interface RebaseBundleManifest {
395
395
  deps: {
396
396
  /** Runtime dependencies of user code, as declared. */
397
397
  declared: Record<string, string>;
398
+ /**
399
+ * The dependency tree ships *inside* the bundle, already installed.
400
+ *
401
+ * Absent or false means the tree is declared but not present, and
402
+ * whoever boots the bundle has to install it. On the managed runtime that
403
+ * install runs in an init container on **every** pod start — the bundle
404
+ * lives on a volume that is wiped each time — and it is the single
405
+ * largest cost in a managed pod's life: 35–55 seconds of a 40–60 second
406
+ * cold start. Since a pod restarts on every eviction, node failure, OOM
407
+ * and runtime rollout, that number is not a startup detail. It is what an
408
+ * outage costs.
409
+ *
410
+ * Vendoring moves the install to build time, where it happens once. It is
411
+ * skipped when the closure contains native code, because a prebuilt
412
+ * binary is only valid for the platform it was built for — see
413
+ * {@link vendorTarget} for what "the platform" means here.
414
+ */
415
+ vendored?: boolean;
416
+ /**
417
+ * What {@link vendored} was resolved for, recorded so a mismatch can be
418
+ * refused rather than discovered at import time.
419
+ *
420
+ * Cross-platform vendoring is safe for pure JavaScript and unsafe for
421
+ * anything compiled, and the boundary between them is not always visible
422
+ * in a dependency list: `esbuild` is pure-JS with a *platform-specific
423
+ * optional dependency* holding the actual binary, so an install run on a
424
+ * developer's Mac silently produces a tree that cannot run on the Linux
425
+ * image. The install therefore resolves optional dependencies for the
426
+ * target explicitly rather than for the machine it runs on, and records
427
+ * the answer here.
428
+ */
429
+ vendorTarget?: {
430
+ /** npm `--os`, e.g. `linux`. */
431
+ os: string;
432
+ /** npm `--cpu`, e.g. `x64`. */
433
+ cpu: string;
434
+ /** Node major the tree was resolved for. */
435
+ node: string;
436
+ };
398
437
  };
399
438
  build: {
400
439
  /** `@rebasepro/cli` version that produced this bundle. */
@@ -29,9 +29,9 @@ export type SecurityOperation = "select" | "insert" | "update" | "delete" | "all
29
29
  * full power of PostgreSQL Row Level Security.
30
30
  *
31
31
  * The authenticated user's identity is available in raw SQL via:
32
- * - `auth.uid()` — the user's ID
33
- * - `auth.roles()` — comma-separated app role IDs
34
- * - `auth.jwt()` — full JWT claims as JSONB
32
+ * - `rebase.uid()` — the user's ID
33
+ * - `rebase.roles()` — comma-separated app role IDs
34
+ * - `rebase.jwt()` — full JWT claims as JSONB
35
35
  *
36
36
  * These are set automatically per-transaction by the backend.
37
37
  *
@@ -119,13 +119,13 @@ export interface SecurityRuleBase {
119
119
  * produce a condition no user can satisfy if used here. These are
120
120
  * application roles managed by Rebase, stored as an inline `roles TEXT[]`
121
121
  * column on the users table, and injected into each transaction as
122
- * `app.user_roles` — which `auth.roles()` reads.
122
+ * `app.user_roles` — which `rebase.roles()` reads.
123
123
  *
124
124
  * There is no roles registry: a role exists once it is assigned to a user.
125
125
  *
126
126
  * Generates a safe array-overlap condition — the user passes if they hold
127
127
  * *any* of the listed roles:
128
- * `string_to_array(auth.roles(), ',') && ARRAY['<role1>', '<role2>']`
128
+ * `string_to_array(rebase.roles(), ',') && ARRAY['<role1>', '<role2>']`
129
129
  *
130
130
  * (Note: this is a true set intersection, NOT a regex/substring match, so
131
131
  * a role named `admin` never matches `nonadmin` or `superadmin`.)
@@ -152,7 +152,7 @@ export interface SecurityRuleBase {
152
152
  *
153
153
  * **Important:** These are NOT the same as the application-level
154
154
  * {@link roles} (admin, editor, viewer, etc.) — those are enforced in the
155
- * USING/WITH CHECK clauses via `auth.roles()`. This field controls the
155
+ * USING/WITH CHECK clauses via `rebase.roles()`. This field controls the
156
156
  * PostgreSQL `TO` clause in `CREATE POLICY ... TO role_name`.
157
157
  *
158
158
  * Use this if you have dedicated PostgreSQL roles (e.g. `app_read`,
@@ -168,7 +168,7 @@ export interface SecurityRuleBase {
168
168
  }
169
169
  /**
170
170
  * Security rule that grants access based on row ownership.
171
- * Generates a USING/WITH CHECK clause like: `<column> = auth.uid()`
171
+ * Generates a USING/WITH CHECK clause like: `<column> = rebase.uid()`
172
172
  *
173
173
  * Cannot be combined with `using`, `withCheck`, or `access`.
174
174
  *
@@ -271,7 +271,7 @@ export interface StructuredSecurityRule extends SecurityRuleBase {
271
271
  * // Only the owner, or users with 'moderator' role
272
272
  * {
273
273
  * operation: "select",
274
- * using: "{user_id} = auth.uid() OR auth.roles() ~ 'moderator'"
274
+ * using: "{user_id} = rebase.uid() OR rebase.roles() ~ 'moderator'"
275
275
  * }
276
276
  *
277
277
  * @group Models
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rebasepro/types",
3
3
  "type": "module",
4
- "version": "0.15.0",
4
+ "version": "0.16.0",
5
5
  "description": "Rebase type definitions — shared interfaces and controller types",
6
6
  "funding": {
7
7
  "url": "https://github.com/sponsors/rebaseco"
@@ -67,7 +67,7 @@ export type RebaseCallContext<USER extends User = User> = {
67
67
  * because RLS filters rather than raises. Write callbacks that tolerate
68
68
  * that, or reach for {@link client}`.dataAsAdmin` deliberately when the
69
69
  * callback genuinely has to see what an admin may see. Note what that does
70
- * *not* buy you: `policy.serverContext()` (`auth.uid() IS NULL`) is false
70
+ * *not* buy you: `policy.serverContext()` (`rebase.uid() IS NULL`) is false
71
71
  * for the service identity, so a collection whose only rule is
72
72
  * `serverContext()` stays closed to it.
73
73
  *
@@ -279,7 +279,7 @@ export interface RebaseClient<DB = unknown> {
279
279
  *
280
280
  * Two consequences the name does not suggest:
281
281
  *
282
- * - `policy.serverContext()` compiles to `auth.uid() IS NULL` and is
282
+ * - `policy.serverContext()` compiles to `rebase.uid() IS NULL` and is
283
283
  * therefore **false** here. A collection with `disableDefaultPolicies:
284
284
  * true` whose only rule is `serverContext()` refuses these writes
285
285
  * (`42501`) and returns zero rows — HTTP 200, empty — for these reads.
@@ -470,7 +470,7 @@ export interface SQLAdmin {
470
470
  * Fetch the *application-level* roles in use in this project.
471
471
  *
472
472
  * These are the strings stored on the users table's `roles` column and
473
- * exposed to policies as `auth.roles()` — what `SecurityRule.roles`
473
+ * exposed to policies as `rebase.roles()` — what `SecurityRule.roles`
474
474
  * matches against. Distinct from {@link fetchAvailableRoles}; the two are
475
475
  * not interchangeable.
476
476
  */
@@ -857,6 +857,40 @@ export interface BackendBootstrapper {
857
857
  log?: (message: string) => void
858
858
  ): Promise<{ applied: number }>;
859
859
 
860
+ /**
861
+ * Read the collections schema version this database was last provisioned
862
+ * from, or `null` when nothing has ever stamped it.
863
+ *
864
+ * The companion to {@link stampCollectionsSchemaVersion}: one process writes
865
+ * what it applied, every other process compares itself to it. This is what
866
+ * lets a split deployment — several processes over one database, only one of
867
+ * which provisions — notice that a unit is serving against a schema it was
868
+ * not built for. That failure is otherwise silent in both directions: a
869
+ * column that does not exist is a SQL error on one route, and a policy that
870
+ * was never applied is a 200 with no rows.
871
+ *
872
+ * `null` is not an error and MUST NOT be treated as one — every database
873
+ * provisioned before the stamp existed reads this way, and so does every
874
+ * fresh one until its first provisioning boot finishes.
875
+ */
876
+ readCollectionsSchemaVersion?(
877
+ driverResult?: InitializedDriver
878
+ ): Promise<string | null>;
879
+
880
+ /**
881
+ * Record the collections schema version this process just applied.
882
+ *
883
+ * Called only by the process that provisions, and only after both
884
+ * {@link ensureCollectionSchema} and {@link ensureCollectionPolicies} have
885
+ * run — a stamp written before the policies would claim a schema that is
886
+ * only half in place, and the half that is missing is the one that fails
887
+ * without an error.
888
+ */
889
+ stampCollectionsSchemaVersion?(
890
+ version: string,
891
+ driverResult?: InitializedDriver
892
+ ): Promise<void>;
893
+
860
894
  /**
861
895
  * Initialize WebSocket server for realtime operations.
862
896
  */
@@ -283,9 +283,9 @@ export interface PostgresCollectionConfig<M extends Record<string, unknown> = Re
283
283
  * 3. **Combined** — mix shortcuts with `roles` for common patterns
284
284
  *
285
285
  * The authenticated user context is available in raw SQL via:
286
- * - `auth.uid()` — the current user's ID
287
- * - `auth.roles()` — comma-separated app role IDs
288
- * - `auth.jwt()` — full JWT claims as JSONB
286
+ * - `rebase.uid()` — the current user's ID
287
+ * - `rebase.roles()` — comma-separated app role IDs
288
+ * - `rebase.jwt()` — full JWT claims as JSONB
289
289
  */
290
290
  securityRules?: readonly SecurityRule[];
291
291
 
@@ -296,7 +296,7 @@ export interface PostgresCollectionConfig<M extends Record<string, unknown> = Re
296
296
  * baseline SELECT policy granting the trusted server context and the
297
297
  * `admin` role read access (reads run under a restricted role, so RLS
298
298
  * default-denies without it). For auth collections it additionally injects
299
- * a self-read policy (`id = auth.uid()`) and an admin-only write gate
299
+ * a self-read policy (`id = rebase.uid()`) and an admin-only write gate
300
300
  * (INSERT/UPDATE/DELETE require the `admin` role or the trusted server
301
301
  * context), making privileged columns such as `roles` safe by default.
302
302
  *
package/src/types/cron.ts CHANGED
@@ -99,10 +99,14 @@ export interface CronJobContext {
99
99
  * hands its callback. Spelled the same way here so that one thing has one
100
100
  * name across every server-side authoring surface.
101
101
  *
102
- * Its data plane is {@link RebaseServerClient.dataAsAdmin}, which runs with
103
- * **admin privileges and bypasses RLS** (`{ uid: "service", roles:
104
- * ["admin"] }`). A cron has no per-request user, so there is no user-scoped
105
- * alternative here and no policy to fall back on: scope every query's
102
+ * Its data plane is {@link RebaseServerClient.dataAsAdmin}, scoped as
103
+ * `{ uid: "service", roles: ["admin"] }` — **admin-scoped, not
104
+ * RLS-bypassing**. Statements still run as `rebase_user` with the policies
105
+ * evaluated against that identity; the admin role merely clears the default
106
+ * policies through their `rolesOverlap(['admin'])` arm, and
107
+ * `policy.serverContext()` (`rebase.uid() IS NULL`) is *false* for it.
108
+ * `rebase.sql()` is the unconditional bypass. A cron has no per-request
109
+ * user, so there is no user-scoped alternative here: scope every query's
106
110
  * filters yourself.
107
111
  *
108
112
  * @example
@@ -139,6 +139,34 @@ export interface DatabaseAdapter {
139
139
  log?: (message: string) => void,
140
140
  ): Promise<{ applied: number }>;
141
141
 
142
+ /**
143
+ * Read the collections schema version this database was last provisioned
144
+ * from, or `null` when nothing has ever stamped it.
145
+ *
146
+ * `null` is not an error and MUST NOT be treated as one — every database
147
+ * provisioned before the stamp existed reads this way, and so does every
148
+ * fresh one until its first provisioning boot finishes.
149
+ *
150
+ * Same forwarding requirement as the two hooks above: a wrapper that omits
151
+ * it turns the check off, and a check that is off looks exactly like a check
152
+ * that passed.
153
+ */
154
+ readCollectionsSchemaVersion?(
155
+ driverResult?: InitializedDriver,
156
+ ): Promise<string | null>;
157
+
158
+ /**
159
+ * Record the collections schema version this process just applied.
160
+ *
161
+ * Called only by the process that provisions, and only after the tables AND
162
+ * the policies are in place — a stamp written earlier would claim a schema
163
+ * that a half-finished boot never finished creating.
164
+ */
165
+ stampCollectionsSchemaVersion?(
166
+ version: string,
167
+ driverResult?: InitializedDriver,
168
+ ): Promise<void>;
169
+
142
170
  /**
143
171
  * Return admin capabilities for this database (SQL editor, schema browser, branching).
144
172
  */
@@ -207,4 +235,33 @@ export interface DatabaseAdapterInitConfig {
207
235
  /** Why it did not, when it did not — safe to print verbatim. */
208
236
  reason?: string;
209
237
  };
238
+ /**
239
+ * What this process wants from the realtime subsystem.
240
+ *
241
+ * Both halves used to be assumed true, and both were wrong for a split
242
+ * deployment. A `functions` or `worker` process has no websocket clients, so
243
+ * consuming change events buys it a dedicated `LISTEN` connection to deliver
244
+ * to nobody; and it is explicitly not the process that owns schema DDL, so
245
+ * installing capture triggers from it contradicts the one-owner rule the
246
+ * runtime otherwise refuses to boot without.
247
+ *
248
+ * Absent means both — every caller that predates this field is a
249
+ * single-process deployment, where both are true.
250
+ */
251
+ realtime?: {
252
+ /**
253
+ * Consume change events: open the `LISTEN` connection, start CDC or the
254
+ * app-level fallback. False for a process that serves no websockets.
255
+ *
256
+ * Writes made by a non-consuming process are still published: capture is
257
+ * database triggers, so the publisher is the database.
258
+ */
259
+ subscribe: boolean;
260
+ /**
261
+ * Install what capture needs — the trigger function, the per-table
262
+ * triggers, any channel-history tables. This is DDL, and it follows the
263
+ * same single-owner rule as every other boot-time schema change.
264
+ */
265
+ provision: boolean;
266
+ };
210
267
  }
@@ -415,6 +415,45 @@ export interface RebaseBundleManifest {
415
415
  deps: {
416
416
  /** Runtime dependencies of user code, as declared. */
417
417
  declared: Record<string, string>;
418
+ /**
419
+ * The dependency tree ships *inside* the bundle, already installed.
420
+ *
421
+ * Absent or false means the tree is declared but not present, and
422
+ * whoever boots the bundle has to install it. On the managed runtime that
423
+ * install runs in an init container on **every** pod start — the bundle
424
+ * lives on a volume that is wiped each time — and it is the single
425
+ * largest cost in a managed pod's life: 35–55 seconds of a 40–60 second
426
+ * cold start. Since a pod restarts on every eviction, node failure, OOM
427
+ * and runtime rollout, that number is not a startup detail. It is what an
428
+ * outage costs.
429
+ *
430
+ * Vendoring moves the install to build time, where it happens once. It is
431
+ * skipped when the closure contains native code, because a prebuilt
432
+ * binary is only valid for the platform it was built for — see
433
+ * {@link vendorTarget} for what "the platform" means here.
434
+ */
435
+ vendored?: boolean;
436
+ /**
437
+ * What {@link vendored} was resolved for, recorded so a mismatch can be
438
+ * refused rather than discovered at import time.
439
+ *
440
+ * Cross-platform vendoring is safe for pure JavaScript and unsafe for
441
+ * anything compiled, and the boundary between them is not always visible
442
+ * in a dependency list: `esbuild` is pure-JS with a *platform-specific
443
+ * optional dependency* holding the actual binary, so an install run on a
444
+ * developer's Mac silently produces a tree that cannot run on the Linux
445
+ * image. The install therefore resolves optional dependencies for the
446
+ * target explicitly rather than for the machine it runs on, and records
447
+ * the answer here.
448
+ */
449
+ vendorTarget?: {
450
+ /** npm `--os`, e.g. `linux`. */
451
+ os: string;
452
+ /** npm `--cpu`, e.g. `x64`. */
453
+ cpu: string;
454
+ /** Node major the tree was resolved for. */
455
+ node: string;
456
+ };
418
457
  };
419
458
  build: {
420
459
  /** `@rebasepro/cli` version that produced this bundle. */
@@ -31,9 +31,9 @@ export type SecurityOperation = "select" | "insert" | "update" | "delete" | "all
31
31
  * full power of PostgreSQL Row Level Security.
32
32
  *
33
33
  * The authenticated user's identity is available in raw SQL via:
34
- * - `auth.uid()` — the user's ID
35
- * - `auth.roles()` — comma-separated app role IDs
36
- * - `auth.jwt()` — full JWT claims as JSONB
34
+ * - `rebase.uid()` — the user's ID
35
+ * - `rebase.roles()` — comma-separated app role IDs
36
+ * - `rebase.jwt()` — full JWT claims as JSONB
37
37
  *
38
38
  * These are set automatically per-transaction by the backend.
39
39
  *
@@ -131,13 +131,13 @@ export interface SecurityRuleBase {
131
131
  * produce a condition no user can satisfy if used here. These are
132
132
  * application roles managed by Rebase, stored as an inline `roles TEXT[]`
133
133
  * column on the users table, and injected into each transaction as
134
- * `app.user_roles` — which `auth.roles()` reads.
134
+ * `app.user_roles` — which `rebase.roles()` reads.
135
135
  *
136
136
  * There is no roles registry: a role exists once it is assigned to a user.
137
137
  *
138
138
  * Generates a safe array-overlap condition — the user passes if they hold
139
139
  * *any* of the listed roles:
140
- * `string_to_array(auth.roles(), ',') && ARRAY['<role1>', '<role2>']`
140
+ * `string_to_array(rebase.roles(), ',') && ARRAY['<role1>', '<role2>']`
141
141
  *
142
142
  * (Note: this is a true set intersection, NOT a regex/substring match, so
143
143
  * a role named `admin` never matches `nonadmin` or `superadmin`.)
@@ -167,7 +167,7 @@ export interface SecurityRuleBase {
167
167
  *
168
168
  * **Important:** These are NOT the same as the application-level
169
169
  * {@link roles} (admin, editor, viewer, etc.) — those are enforced in the
170
- * USING/WITH CHECK clauses via `auth.roles()`. This field controls the
170
+ * USING/WITH CHECK clauses via `rebase.roles()`. This field controls the
171
171
  * PostgreSQL `TO` clause in `CREATE POLICY ... TO role_name`.
172
172
  *
173
173
  * Use this if you have dedicated PostgreSQL roles (e.g. `app_read`,
@@ -184,7 +184,7 @@ export interface SecurityRuleBase {
184
184
 
185
185
  /**
186
186
  * Security rule that grants access based on row ownership.
187
- * Generates a USING/WITH CHECK clause like: `<column> = auth.uid()`
187
+ * Generates a USING/WITH CHECK clause like: `<column> = rebase.uid()`
188
188
  *
189
189
  * Cannot be combined with `using`, `withCheck`, or `access`.
190
190
  *
@@ -292,7 +292,7 @@ export interface StructuredSecurityRule extends SecurityRuleBase {
292
292
  * // Only the owner, or users with 'moderator' role
293
293
  * {
294
294
  * operation: "select",
295
- * using: "{user_id} = auth.uid() OR auth.roles() ~ 'moderator'"
295
+ * using: "{user_id} = rebase.uid() OR rebase.roles() ~ 'moderator'"
296
296
  * }
297
297
  *
298
298
  * @group Models