better-supabase 0.0.0 → 0.2.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.
Files changed (157) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +88 -1
  3. package/bin/better-supabase.js +4 -0
  4. package/dist/casing-da0uRTqt.js +14 -0
  5. package/dist/claims-CoTobNC-.js +25 -0
  6. package/dist/cli/bin.d.ts +1 -0
  7. package/dist/cli/bin.js +15 -0
  8. package/dist/cli/index.d.ts +226 -0
  9. package/dist/cli/index.js +3 -0
  10. package/dist/cli-DrSgDOQC.js +6646 -0
  11. package/dist/client/index.d.ts +2 -0
  12. package/dist/client/index.js +112 -0
  13. package/dist/compiler-CZ9nIuqy.d.ts +14 -0
  14. package/dist/config/index.d.ts +3 -0
  15. package/dist/config/index.js +3 -0
  16. package/dist/config-ClDXmVtY.js +277 -0
  17. package/dist/define-BXMYD9AY.js +1071 -0
  18. package/dist/define-e3zI4_4g.d.ts +679 -0
  19. package/dist/edge/index.d.ts +43 -0
  20. package/dist/edge/index.js +103 -0
  21. package/dist/entitlements-CTEBm7IB.js +20 -0
  22. package/dist/entitlements-Dng-ctuT.d.ts +42 -0
  23. package/dist/env/index.d.ts +2 -0
  24. package/dist/env/index.js +2 -0
  25. package/dist/env-BEToab0I.js +204 -0
  26. package/dist/errors-Bl3rkOzo.js +196 -0
  27. package/dist/events/index.d.ts +2 -0
  28. package/dist/events/index.js +2 -0
  29. package/dist/events-BuzTgn2D.js +135 -0
  30. package/dist/events-DOt3nSO-.d.ts +84 -0
  31. package/dist/executor-BYXQ9AGn.d.ts +25 -0
  32. package/dist/executor-CGdNQ27g.d.ts +195 -0
  33. package/dist/executor-DeppvirK.js +89 -0
  34. package/dist/guards-BnzDvFrz.js +10 -0
  35. package/dist/hono/index.d.ts +45 -0
  36. package/dist/hono/index.js +70 -0
  37. package/dist/index-Bw1bwtC0.d.ts +144 -0
  38. package/dist/index-CBDufH1M.d.ts +120 -0
  39. package/dist/index-CG69s15v.d.ts +38 -0
  40. package/dist/index-Ciu5Xlml.d.ts +74 -0
  41. package/dist/index-D4v7sncu.d.ts +62 -0
  42. package/dist/index-DOsjFvMf.d.ts +618 -0
  43. package/dist/index-DbxFr7XG.d.ts +76 -0
  44. package/dist/index-DuP14VHo.d.ts +216 -0
  45. package/dist/index-Dy6kuF0P.d.ts +71 -0
  46. package/dist/index-K-3WM2Hp.d.ts +117 -0
  47. package/dist/index.d.ts +110 -0
  48. package/dist/index.js +43 -0
  49. package/dist/invalidate-DbxuL2jL.js +18 -0
  50. package/dist/jobs/index.d.ts +173 -0
  51. package/dist/jobs/index.js +478 -0
  52. package/dist/json-schema-BpYqkCKf.js +182 -0
  53. package/dist/lint/index.d.ts +75 -0
  54. package/dist/lint/index.js +167 -0
  55. package/dist/list/index.d.ts +2 -0
  56. package/dist/list/index.js +410 -0
  57. package/dist/live-D8rV1Ldw.js +168 -0
  58. package/dist/live-DJyZMD6w.d.ts +191 -0
  59. package/dist/logger-glM28NVN.js +21 -0
  60. package/dist/mcp/index.d.ts +142 -0
  61. package/dist/mcp/index.js +463 -0
  62. package/dist/mfa-CpLfJSde.js +541 -0
  63. package/dist/mfa-TVia554c.d.ts +44 -0
  64. package/dist/next/image/index.d.ts +34 -0
  65. package/dist/next/image/index.js +40 -0
  66. package/dist/next/index.d.ts +210 -0
  67. package/dist/next/index.js +427 -0
  68. package/dist/openapi/index.d.ts +2 -0
  69. package/dist/openapi/index.js +332 -0
  70. package/dist/orpc/index.d.ts +46 -0
  71. package/dist/orpc/index.js +50 -0
  72. package/dist/otel/index.d.ts +40 -0
  73. package/dist/otel/index.js +168 -0
  74. package/dist/path-Cv__-OTj.d.ts +17 -0
  75. package/dist/permdock-sql-CghlHPuH.js +117 -0
  76. package/dist/plugin-BqR6wKMB.js +23 -0
  77. package/dist/plugin-C4TR9J0Z.d.ts +118 -0
  78. package/dist/plugins/actor/index.d.ts +13 -0
  79. package/dist/plugins/actor/index.js +43 -0
  80. package/dist/plugins/rules/index.d.ts +89 -0
  81. package/dist/plugins/rules/index.js +167 -0
  82. package/dist/plugins/soft-delete/index.d.ts +38 -0
  83. package/dist/plugins/soft-delete/index.js +69 -0
  84. package/dist/plugins/tenant/index.d.ts +49 -0
  85. package/dist/plugins/tenant/index.js +75 -0
  86. package/dist/plugins/timestamps/index.d.ts +9 -0
  87. package/dist/plugins/timestamps/index.js +37 -0
  88. package/dist/plugins/validation/index.d.ts +24 -0
  89. package/dist/plugins/validation/index.js +59 -0
  90. package/dist/pool-R2m_DkXi.d.ts +37 -0
  91. package/dist/postgres/index.d.ts +28 -0
  92. package/dist/postgres/index.js +79 -0
  93. package/dist/postgrest-cAEQ_IQN.d.ts +43 -0
  94. package/dist/problem-BTkTtRV9.js +97 -0
  95. package/dist/problem-DlgB0lYl.d.ts +47 -0
  96. package/dist/query/index.d.ts +2 -0
  97. package/dist/query/index.js +3 -0
  98. package/dist/query-ChvDbsDE.js +186 -0
  99. package/dist/react/index.d.ts +7 -0
  100. package/dist/react/index.js +5 -0
  101. package/dist/react/server.d.ts +13 -0
  102. package/dist/react/server.js +25 -0
  103. package/dist/react/session.d.ts +2 -0
  104. package/dist/react/session.js +3 -0
  105. package/dist/react-C83BdBGt.js +242 -0
  106. package/dist/read-set-4lI3W_gZ.js +216 -0
  107. package/dist/realtime/index.d.ts +4 -0
  108. package/dist/realtime/index.js +268 -0
  109. package/dist/resolve-CjHILk2w.d.ts +170 -0
  110. package/dist/resource-BHEWmQJK.js +175 -0
  111. package/dist/resource-CgZa3YG_.d.ts +65 -0
  112. package/dist/respond-DMcbQwfN.js +383 -0
  113. package/dist/respond-Dne1ARSa.d.ts +169 -0
  114. package/dist/result-CTkCZ6JA.d.ts +198 -0
  115. package/dist/result-DWXatkd6.js +103 -0
  116. package/dist/scope-CDHcS7dE.js +90 -0
  117. package/dist/seed-CzecODcJ.js +101 -0
  118. package/dist/server/index.d.ts +42 -0
  119. package/dist/server/index.js +68 -0
  120. package/dist/session-C3LxnQ0e.d.ts +22 -0
  121. package/dist/session-CqEwzVup.js +20 -0
  122. package/dist/shared-_6-uPL7E.js +57 -0
  123. package/dist/simplify-bwJpLnaS.js +665 -0
  124. package/dist/spec-pins-C3oc-Tdp.js +20 -0
  125. package/dist/spec-pins-CqorWDnO.d.ts +20 -0
  126. package/dist/sql-DTjA1LPj.js +260 -0
  127. package/dist/ssr/index.d.ts +5 -0
  128. package/dist/ssr/index.js +4 -0
  129. package/dist/standard-CyhRzctb.d.ts +7 -0
  130. package/dist/standard-FUi3Z3-7.js +21 -0
  131. package/dist/stats-C5W-rBfR.js +566 -0
  132. package/dist/storage/index.d.ts +5 -0
  133. package/dist/storage/index.js +2 -0
  134. package/dist/storage-DuGn38fr.js +527 -0
  135. package/dist/tables-rZxRxNPW.js +59 -0
  136. package/dist/template-mbvlysOo.d.ts +6 -0
  137. package/dist/testing/index.d.ts +325 -0
  138. package/dist/testing/index.js +819 -0
  139. package/dist/types-6cYK9pbJ.js +29 -0
  140. package/dist/types-C83v5SQz.d.ts +248 -0
  141. package/dist/version-Cqq1m3UY.js +4 -0
  142. package/dist/view-D1s0wa0T.d.ts +49 -0
  143. package/dist/view-aOYizTeE.js +36 -0
  144. package/dist/webhooks/index.d.ts +152 -0
  145. package/dist/webhooks/index.js +2 -0
  146. package/dist/webhooks-DMipjhSP.js +139 -0
  147. package/package.json +250 -17
  148. package/schemas/config-v1.json +373 -0
  149. package/schemas/doctor-report-v1.json +106 -0
  150. package/schemas/snapshot-v2.json +1006 -0
  151. package/skills/better-supabase/SKILL.md +84 -0
  152. package/skills/better-supabase/references/plugins.md +65 -0
  153. package/skills/better-supabase/references/troubleshooting.md +39 -0
  154. package/skills/better-supabase-api/SKILL.md +67 -0
  155. package/skills/better-supabase-api/references/adapters.md +108 -0
  156. package/skills/better-supabase-testing/SKILL.md +66 -0
  157. package/index.js +0 -1
@@ -0,0 +1,325 @@
1
+ import { d as Generator, f as GeneratorInput, y as ResolvedConfig } from "../index-DOsjFvMf.js";
2
+ import { A as SchemaMeta, N as TableKey, R as Update, _ as Insert, n as AnyModels, t as AnyFunctions } from "../types-C83v5SQz.js";
3
+ import { r as Executor } from "../executor-CGdNQ27g.js";
4
+ import { P as DbStats, l as CacheAdapter, t as BetterSupabase, y as Db } from "../define-e3zI4_4g.js";
5
+ import { h as RequestContext, n as AnyPlugin } from "../plugin-C4TR9J0Z.js";
6
+ import { t as SqlClient } from "../executor-BYXQ9AGn.js";
7
+ import { t as Postgres } from "../pool-R2m_DkXi.js";
8
+ import { n as AuthResolver } from "../resolve-CjHILk2w.js";
9
+ import { r as EventSink, t as CloudEvent } from "../index-Ciu5Xlml.js";
10
+ import { SupabaseClient } from "@supabase/supabase-js";
11
+ //#region src/testing/jwt.d.ts
12
+ interface TestJwtClaims {
13
+ readonly sub: string;
14
+ readonly role?: string;
15
+ readonly email?: string;
16
+ readonly aal?: "aal1" | "aal2";
17
+ readonly expiresIn?: number;
18
+ readonly [claim: string]: unknown;
19
+ }
20
+ /**
21
+ * Signs an HS256 access token the local Supabase stack accepts. Test-only:
22
+ * production tokens come from Supabase Auth.
23
+ */
24
+ export declare function signTestJwt(secret: string, claims: TestJwtClaims): Promise<string>;
25
+ /**
26
+ * Accepts `signTestJwt` tokens as users, for API servers tested against the
27
+ * local stack: `createServer(sb, { auth: { resolvers: [localAuth(secret)] } })`.
28
+ * Tokens that are not HS256-signed with `secret` fall through. Test-only.
29
+ */
30
+ export declare function localAuth(secret: string): AuthResolver;
31
+ interface TestSigner {
32
+ /** Public JWKS; pass as `jwks` to `resolveAuth` / `createServer({ auth: { jwks } })`. */
33
+ readonly jwks: {
34
+ readonly keys: readonly JsonWebKey[];
35
+ };
36
+ sign(claims: TestJwtClaims): Promise<string>;
37
+ }
38
+ /** A private ES256 JWK, as `better-supabase keys` writes to `supabase/signing_keys.json`. */
39
+ interface SigningJwk extends JsonWebKey {
40
+ readonly kid: string;
41
+ }
42
+ /**
43
+ * Signs an ES256 access token with a private JWK, the way the local stack
44
+ * signs them once `signing_keys_path` is set. Test-only.
45
+ */
46
+ export declare function signTestJwtWithKey(key: SigningJwk, claims: TestJwtClaims): Promise<string>;
47
+ /** An in-memory ES256 key pair that signs tokens like Supabase Auth's asymmetric keys. */
48
+ export declare function createTestSigner(): Promise<TestSigner>;
49
+ //#endregion
50
+ //#region src/testing/local-key.d.ts
51
+ /**
52
+ * The key the local stack signs with: the first entry of the file
53
+ * `better-supabase keys` wrote. `path` defaults to `$SUPABASE_SIGNING_KEYS_PATH`,
54
+ * then `signing_keys_path` from the nearest `supabase/config.toml`.
55
+ */
56
+ export declare function localSigningKey(path?: string): Promise<SigningJwk>;
57
+ /** Signs a token with the local stack's ES256 key (see `localSigningKey`). Test-only. */
58
+ export declare function signLocalJwt(claims: TestJwtClaims, path?: string): Promise<string>;
59
+ //#endregion
60
+ //#region src/testing/as-user.d.ts
61
+ /** The local CLI stack's default JWT secret. */
62
+ export declare const LOCAL_JWT_SECRET = "super-secret-jwt-token-with-at-least-32-characters-long";
63
+ interface LocalStack {
64
+ /** Defaults to `$SUPABASE_URL`, then `http://127.0.0.1:54321`. */
65
+ readonly url?: string;
66
+ /** Defaults to `$SUPABASE_PUBLISHABLE_KEY`, then `$SUPABASE_ANON_KEY`. */
67
+ readonly publishableKey?: string;
68
+ /**
69
+ * `ES256` (default) signs with the key `better-supabase keys` wrote, as
70
+ * the hosted project's asymmetric keys do. `HS256` signs with the shared
71
+ * JWT secret and only works against a local stack.
72
+ */
73
+ readonly alg?: "ES256" | "HS256";
74
+ /** The private ES256 key. Defaults to the first key in `signingKeysPath`. */
75
+ readonly signingKey?: SigningJwk;
76
+ /** Defaults to `$SUPABASE_SIGNING_KEYS_PATH`, then `signing_keys_path` in `supabase/config.toml`. */
77
+ readonly signingKeysPath?: string;
78
+ /** For `alg: 'HS256'`. Defaults to `$SUPABASE_JWT_SECRET`, then the CLI default. */
79
+ readonly jwtSecret?: string;
80
+ /** Service-role key for `expectTenantIsolation`; defaults to `$SUPABASE_SECRET_KEY`. */
81
+ readonly secretKey?: string;
82
+ /** Enables `sql`: the same user over direct Postgres. */
83
+ readonly postgres?: Postgres;
84
+ }
85
+ interface TestUser<M extends AnyModels, F extends AnyFunctions, E> {
86
+ readonly token: string;
87
+ readonly claims: TestJwtClaims;
88
+ /** supabase-js signed in as the user (storage, realtime, functions). */
89
+ readonly supabase: SupabaseClient;
90
+ /** Repositories over PostgREST as the user; RLS applies. */
91
+ readonly db: Db<M, F, E, SupabaseClient>;
92
+ /** Repositories over direct Postgres as the user, when `postgres` is given. */
93
+ readonly sql: Db<M, F, E, unknown> | undefined;
94
+ }
95
+ /**
96
+ * A test user against the local stack: a signed token and repositories that
97
+ * run as that user, for live RLS tests. The token is ES256-signed with the
98
+ * key from `better-supabase keys`; pass `{ alg: 'HS256' }` for a stack that
99
+ * still uses the shared JWT secret.
100
+ *
101
+ * ```ts
102
+ * const alice = await asUser(sb, { sub: aliceId, tenant_id: acme });
103
+ * expect(await alice.db.customers.count().orThrow()).toBe(3);
104
+ * ```
105
+ */
106
+ export declare function asUser<M extends AnyModels, D, F extends AnyFunctions, E>(sb: BetterSupabase<M, D, F, E>, claims: TestJwtClaims, stack?: LocalStack): Promise<TestUser<M, F, E>>;
107
+ //#endregion
108
+ //#region src/testing/budget.d.ts
109
+ /** The part of a Playwright `Response` the budget check reads. */
110
+ interface BudgetResponse {
111
+ url(): string;
112
+ headers(): Record<string, string>;
113
+ finished(): Promise<unknown>;
114
+ request(): {
115
+ headers(): Record<string, string>;
116
+ };
117
+ }
118
+ /** The part of a Playwright `Page` the budget check uses. */
119
+ interface BudgetPage {
120
+ on(event: "response", listener: (response: BudgetResponse) => void): unknown;
121
+ off(event: "response", listener: (response: BudgetResponse) => void): unknown;
122
+ reload(): Promise<unknown>;
123
+ readonly request: {
124
+ get(url: string): Promise<{
125
+ ok(): boolean;
126
+ status(): number;
127
+ json(): Promise<unknown>;
128
+ }>;
129
+ };
130
+ }
131
+ interface DbBudgetExpectation {
132
+ readonly maxCalls?: number;
133
+ readonly maxWaves?: number;
134
+ /** The navigation to measure. Defaults to reloading the page. */
135
+ readonly during?: () => Promise<unknown>;
136
+ /** Also measure router prefetches. Defaults to false. */
137
+ readonly prefetches?: boolean;
138
+ /** How long to wait for a streamed response to finish. Defaults to 10 seconds. */
139
+ readonly timeoutMs?: number;
140
+ }
141
+ interface MeasuredRender {
142
+ readonly url: string;
143
+ readonly requestId: string;
144
+ readonly stats: DbStats;
145
+ }
146
+ /**
147
+ * Measures every document and RSC navigation response during `during` and
148
+ * fails when one render makes more database calls or waves than allowed.
149
+ * Needs `createNext(sb, { debug })` and `next.debugRoute()` in the app.
150
+ */
151
+ export declare function expectDbBudget(page: BudgetPage, expectation: DbBudgetExpectation): Promise<readonly MeasuredRender[]>;
152
+ //#endregion
153
+ //#region src/testing/conformance.d.ts
154
+ interface ConformanceCheck {
155
+ readonly name: string;
156
+ readonly ok: boolean;
157
+ readonly message?: string;
158
+ }
159
+ interface ConformanceReport {
160
+ /** `Executor "postgrest"`, `CacheAdapter "next"`, ... */
161
+ readonly subject: string;
162
+ readonly checks: readonly ConformanceCheck[];
163
+ }
164
+ /** Thrown by a conformance kit when any check fails. Lists every failure, not just the first. */
165
+ export declare class ConformanceError extends Error {
166
+ readonly report: ConformanceReport;
167
+ constructor(report: ConformanceReport);
168
+ }
169
+ type AnySupabase = BetterSupabase<any, any, any, any>;
170
+ interface TestExecutorOptions {
171
+ /** A definition whose schema matches the executor's database. Install no plugins. */
172
+ readonly sb: AnySupabase;
173
+ /** App key of a table with rows the executor can read. Defaults to the first table. */
174
+ readonly table?: string;
175
+ /** A row to insert and delete again, to check writes. Skips write checks when omitted. */
176
+ readonly create?: Readonly<Record<string, unknown>>;
177
+ }
178
+ /**
179
+ * Proves an `Executor` meets the contract: rows keyed by the selection's
180
+ * aliases, counts, `aborted` errors, failures returned as `Result`s rather
181
+ * than thrown, and (with `create`) a write round trip.
182
+ *
183
+ * ```ts
184
+ * it('conforms', () => testExecutor(myExecutor, { sb, table: 'tags', create: { name: 'x' } }));
185
+ * ```
186
+ */
187
+ export declare function testExecutor(executor: Executor, options: TestExecutorOptions): Promise<ConformanceReport>;
188
+ /**
189
+ * Proves a `CacheAdapter` accepts table and row targets, repeated and
190
+ * concurrent calls, and never mutates its input.
191
+ */
192
+ export declare function testCacheAdapter(adapter: CacheAdapter, options?: {
193
+ readonly table?: string;
194
+ }): Promise<ConformanceReport>;
195
+ interface TestEventSinkOptions {
196
+ /** Events the sink delivered, for sinks that can be read back (an outbox, a test queue). */
197
+ readonly received?: () => readonly CloudEvent[] | Promise<readonly CloudEvent[]>;
198
+ }
199
+ /** Proves an `EventSink` accepts empty and full batches without mutating them, and delivers them when readable. */
200
+ export declare function testEventSink(sink: EventSink, options?: TestEventSinkOptions): Promise<ConformanceReport>;
201
+ interface TestAuthResolverOptions {
202
+ /** Requests with credentials this resolver owns but that must not verify. */
203
+ readonly invalid: readonly Request[];
204
+ /** Requests that must resolve to a user or service, optionally with the expected user id. */
205
+ readonly valid?: readonly {
206
+ readonly request: Request;
207
+ readonly userId?: string;
208
+ }[];
209
+ /** A request without this resolver's credentials. Defaults to a bare GET. */
210
+ readonly unrelated?: Request;
211
+ }
212
+ /**
213
+ * Proves an `AuthResolver` passes on requests it doesn't understand, fails
214
+ * closed (`invalid`, never anon) on bad credentials, and never throws.
215
+ */
216
+ export declare function testAuthResolver(resolver: AuthResolver, options: TestAuthResolverOptions): Promise<ConformanceReport>;
217
+ interface TestGeneratorOptions {
218
+ /** Schema metadata to generate from: `schema.meta` from your generated module. */
219
+ readonly meta: SchemaMeta;
220
+ /** Typegen metadata; defaults to an empty database. */
221
+ readonly introspection?: GeneratorInput["introspection"];
222
+ readonly extras?: GeneratorInput["extras"];
223
+ readonly config?: ResolvedConfig;
224
+ }
225
+ /** Proves a `Generator` writes relative, unique paths, is deterministic and doesn't mutate its input. */
226
+ export declare function testGenerator(generator: Generator, options: TestGeneratorOptions): Promise<ConformanceReport>;
227
+ interface TestPluginOptions {
228
+ /** The definition without this plugin. */
229
+ readonly sb: AnySupabase;
230
+ /** Table to exercise. Defaults to the first table. */
231
+ readonly table?: string;
232
+ /** Context the plugin needs, such as `{ tenant }` for `tenant()`. */
233
+ readonly context?: RequestContext;
234
+ /** Row for `create`, to exercise `beforeMutation`. */
235
+ readonly create?: Readonly<Record<string, unknown>>;
236
+ }
237
+ /**
238
+ * Proves a `Plugin` targets API v1, installs cleanly, keeps `transformQuery`
239
+ * and `beforeMutation` pure and deterministic, and keeps executors'
240
+ * results intact when it wraps them.
241
+ */
242
+ export declare function testPlugin(plugin: AnyPlugin, options: TestPluginOptions): Promise<ConformanceReport>;
243
+ //#endregion
244
+ //#region src/testing/isolation.d.ts
245
+ interface IsolationTenant {
246
+ /** Handed to each table's `row`, usually the tenant's id. */
247
+ readonly id: string;
248
+ /** The claims of a user in this tenant, as for `asUser`. */
249
+ readonly claims: TestJwtClaims;
250
+ /** Used in failure messages; defaults to `id`. */
251
+ readonly name?: string;
252
+ }
253
+ interface IsolationTable<M extends AnyModels, K extends keyof M> {
254
+ /**
255
+ * A row owned by `tenant`. `n` is 0 for the row seeded through the service
256
+ * role and 1 for the other tenant's insert attempt: put it in unique columns.
257
+ */
258
+ readonly row: (tenant: IsolationTenant, n: 0 | 1) => Insert<M, K>;
259
+ /** A change the other tenant tries to make. It must differ from `row`. */
260
+ readonly update: Update<M, K>;
261
+ }
262
+ type IsolationTables<M extends AnyModels> = { readonly [K in TableKey<M>]?: IsolationTable<M, K>; };
263
+ interface TenantIsolationOptions<M extends AnyModels> {
264
+ readonly tenants: readonly [IsolationTenant, IsolationTenant];
265
+ readonly tables: IsolationTables<M>;
266
+ /** Defaults to `$SUPABASE_URL`, `$SUPABASE_PUBLISHABLE_KEY` and `$SUPABASE_SECRET_KEY`. */
267
+ readonly stack?: LocalStack;
268
+ /** Runs before any row is created, e.g. `() => seed.insert(sql)` for the tenants and their memberships. */
269
+ readonly seed?: () => Promise<void>;
270
+ }
271
+ /**
272
+ * Checks row-level security between two tenants against a running stack: for
273
+ * each table, a user of one tenant must not select, insert, update or delete
274
+ * the other tenant's rows. Runs without `sb`'s plugins, so the `tenant()`
275
+ * plugin can't hide a missing policy. Throws a `ConformanceError` naming each
276
+ * table and command that leaks; removes every row it created.
277
+ *
278
+ * ```ts
279
+ * await expectTenantIsolation(sb, {
280
+ * tenants: [
281
+ * { id: ACME, claims: { sub: alice, tenant_id: ACME } },
282
+ * { id: GLOBEX, claims: { sub: bob, tenant_id: GLOBEX } },
283
+ * ],
284
+ * tables: {
285
+ * tags: {
286
+ * row: (tenant, n) => ({ organizationId: tenant.id, name: `iso-${n}` }),
287
+ * update: { name: 'changed' },
288
+ * },
289
+ * },
290
+ * });
291
+ * ```
292
+ */
293
+ export declare function expectTenantIsolation<M extends AnyModels, D, F extends AnyFunctions, E>(sb: BetterSupabase<M, D, F, E>, options: TenantIsolationOptions<M>): Promise<ConformanceReport>;
294
+ //#endregion
295
+ //#region src/testing/seed.d.ts
296
+ /** Named rows per table, in app casing: `{ customers: { acme: { ... } } }`. */
297
+ type SeedFixtures<M extends AnyModels> = { readonly [K in keyof M]?: Readonly<Record<string, M[K]["Insert"]>>; };
298
+ /** Rejects columns that are not in the table's Insert type. */
299
+ type ExactSeed<M extends AnyModels, S> = { readonly [K in keyof S]: K extends keyof M ? { readonly [N in keyof S[K]]: { readonly [C in keyof S[K][N]]: C extends keyof M[K]["Insert"] ? S[K][N][C] : never; }; } : never; };
300
+ declare const SEED: unique symbol;
301
+ interface Seed<S> {
302
+ readonly [SEED]: true;
303
+ /** The fixtures as given, so tests can reference `seed.rows.customers.acme.id`. */
304
+ readonly rows: S;
305
+ /** One `insert ... on conflict do nothing` per table, parents before children. */
306
+ statements(): string[];
307
+ sql(): string;
308
+ /** Inserts the fixtures, e.g. in a test's `beforeAll`. Needs a service-role client. */
309
+ insert(sql: SqlClient): Promise<void>;
310
+ }
311
+ export declare function isSeed(value: unknown): value is Seed<unknown>;
312
+ /**
313
+ * Typed fixtures shared by `supabase/seeds` and your tests. Rows use app
314
+ * casing and Insert types; `better-supabase seed` renders them to SQL.
315
+ *
316
+ * ```ts
317
+ * export const seed = defineSeed(sb, {
318
+ * organizations: { acme: { id: ACME, name: 'Acme' } },
319
+ * customers: { first: { organizationId: ACME, name: 'First customer' } },
320
+ * });
321
+ * ```
322
+ */
323
+ export declare function defineSeed<M extends AnyModels, D, F extends AnyFunctions, E, const S extends SeedFixtures<M>>(sb: BetterSupabase<M, D, F, E>, fixtures: S & ExactSeed<M, S>): Seed<S>;
324
+ //#endregion
325
+ export type { BudgetPage, BudgetResponse, ConformanceCheck, ConformanceReport, DbBudgetExpectation, ExactSeed, IsolationTable, IsolationTables, IsolationTenant, LocalStack, MeasuredRender, Seed, SeedFixtures, SigningJwk, TenantIsolationOptions, TestAuthResolverOptions, TestEventSinkOptions, TestExecutorOptions, TestGeneratorOptions, TestJwtClaims, TestPluginOptions, TestSigner, TestUser };