better-supabase 0.3.0 → 0.4.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.
- package/README.md +7 -6
- package/bin/better-supabase.js +4 -0
- package/dist/{base64-CQeB1eSf.js → base64-D2gsioCY.js} +2 -2
- package/dist/claims-BAf6c7is.js +48 -0
- package/dist/cli/_format-Cax5EsM9.js +101 -0
- package/dist/cli/bin.d.ts +1 -0
- package/dist/cli/bin.js +48 -0
- package/dist/cli/command-CK14fP91.js +502 -0
- package/dist/cli/compare-BmIWVEui.js +9 -0
- package/dist/cli/config-D9R0o1LH.js +1895 -0
- package/dist/cli/config-SSKSTUl2.js +2 -0
- package/dist/cli/db-DOBPt660.js +52 -0
- package/dist/cli/dist-B1MvLv-M.js +129 -0
- package/dist/cli/dist-CFgGknmZ.js +1112 -0
- package/dist/cli/dist-Du7VnEUG.js +621 -0
- package/dist/cli/doctor-BOym3mbL.js +2382 -0
- package/dist/cli/env-BZ0uy8XK.js +108 -0
- package/dist/cli/env-jIFUADLY.js +511 -0
- package/dist/cli/errors-4v4DTtda.js +56 -0
- package/dist/cli/fastest-levenshtein-CFN-lNDv.js +120 -0
- package/dist/cli/gen-Ccn_p90L.js +2008 -0
- package/dist/cli/gen-D5cLCULx.js +2 -0
- package/dist/cli/index.d.ts +493 -0
- package/dist/cli/index.js +184 -0
- package/dist/cli/init-ClnxRYBF.js +550 -0
- package/dist/cli/introspect-DxqfkVIv.js +81 -0
- package/dist/cli/io-k41_z-jT.js +24 -0
- package/dist/cli/json5-ChRycquj.js +787 -0
- package/dist/cli/jsonc-BUniUpOk.js +2 -0
- package/dist/cli/jsonc-D5Fu67jw.js +45 -0
- package/dist/cli/keys-ByKHnvP9.js +83 -0
- package/dist/cli/ohash-D7bG_EOb.js +277 -0
- package/dist/cli/openapi-8WHjxiTJ.js +66 -0
- package/dist/cli/project-B_GeXyHh.js +70 -0
- package/dist/cli/prompts-BNcNfAve.js +1142 -0
- package/dist/cli/prompts-BTYQGunc.js +2 -0
- package/dist/cli/read-sets-CMa29t9a.js +971 -0
- package/dist/cli/rolldown-runtime-BPOCksWG.js +24 -0
- package/dist/cli/run-CP20LKk_.js +347 -0
- package/dist/cli/seed-5J6eu_Xg.js +98 -0
- package/dist/cli/skills-LJJIhLFR.js +137 -0
- package/dist/cli/sql-D4VbqmXi.js +199 -0
- package/dist/cli/style-C0NFdJRL.js +29 -0
- package/dist/cli/toml-DB-MNnFs.js +424 -0
- package/dist/cli/version-5mW_8sY1.js +4 -0
- package/dist/cli/yaml-CYCbJ6et.js +2252 -0
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +13 -13
- package/dist/{compiler-2zqGzxVZ.d.ts → compiler-DB3aSFOA.d.ts} +2 -2
- package/dist/config/index.js +4 -4
- package/dist/{config-Be4GwsqI.js → config-BpxDfnbg.js} +1 -1
- package/dist/{config-DOsGYSiT.js → config-CbvFmGD8.js} +1 -1
- package/dist/{define-DF341GDj.js → define-Bh0AqTik.js} +160 -79
- package/dist/{define-DUbydmJa.d.ts → define-CRS2MRV3.d.ts} +32 -28
- package/dist/edge/index.d.ts +8 -12
- package/dist/edge/index.js +50 -24
- package/dist/{entitlements-DvJXoI02.d.ts → entitlements-Dm-FHpNH.d.ts} +2 -2
- package/dist/{errors-Bl3rkOzo.js → errors-L0xK41y_.js} +1 -1
- package/dist/events/index.d.ts +1 -1
- package/dist/events/index.js +4 -4
- package/dist/{events-Do8jXh4D.d.ts → events-B21UOhvP.d.ts} +4 -4
- package/dist/{executor-DynmIWhq.d.ts → executor-B5IoUxLE.d.ts} +1 -1
- package/dist/{executor-C57jx2pn.js → executor-CVt6dD0B.js} +3 -3
- package/dist/{executor-B26lgbHD.d.ts → executor-CZ7ImRiD.d.ts} +2 -2
- package/dist/hono/index.d.ts +16 -23
- package/dist/hono/index.js +10 -10
- package/dist/{index-CTTMS6_1.d.ts → index-528Ugmyp.d.ts} +12 -3
- package/dist/{index-CADlNHK-.d.ts → index-BAy4tsAP.d.ts} +5 -5
- package/dist/{index-BNsABq7P.d.ts → index-BBdvo-5d.d.ts} +23 -25
- package/dist/{index-qriRM9cZ.d.ts → index-BhHEC04r.d.ts} +3 -3
- package/dist/{index-GV77NpRP.d.ts → index-D5IfUIDh.d.ts} +3 -3
- package/dist/{index-CriFFJ_p.d.ts → index-DFmOpBGC.d.ts} +11 -11
- package/dist/{index-UJ-LUxtI.d.ts → index-RlLXd8dL.d.ts} +12 -12
- package/dist/index.d.ts +15 -15
- package/dist/index.js +13 -13
- package/dist/{invalidate-DbxuL2jL.js → invalidate-CgxmRamI.js} +7 -1
- package/dist/jobs/index.d.ts +10 -4
- package/dist/jobs/index.js +32 -16
- package/dist/{json-schema--aOXAGfU.js → json-schema-DP6V7cbr.js} +1 -1
- package/dist/list/index.d.ts +1 -1
- package/dist/list/index.js +3 -3
- package/dist/{live-QE3UPbGm.d.ts → live-BHakSWWo.d.ts} +12 -12
- package/dist/{live-D8rV1Ldw.js → live-CdJBOc4f.js} +13 -9
- package/dist/lookup-BaP5bI27.js +18 -0
- package/dist/mcp/index.d.ts +18 -18
- package/dist/mcp/index.js +23 -18
- package/dist/{mfa-x3V3vGh-.d.ts → mfa-C7MNQ1Ob.d.ts} +1 -1
- package/dist/{mfa-BxoR1RkN.js → mfa-byfjruR9.js} +118 -29
- package/dist/next/image/index.js +6 -3
- package/dist/next/index.d.ts +38 -35
- package/dist/next/index.js +41 -33
- package/dist/openapi/index.d.ts +1 -1
- package/dist/openapi/index.js +6 -6
- package/dist/orpc/index.d.ts +17 -20
- package/dist/orpc/index.js +11 -11
- package/dist/otel/index.d.ts +5 -5
- package/dist/otel/index.js +81 -62
- package/dist/{permdock-sql-Bta_G0v-.js → permdock-sql-C4KFzLc9.js} +1 -1
- package/dist/{plugin-DVRB8qNE.d.ts → plugin-bNhvJwRh.d.ts} +2 -2
- package/dist/plugins/actor/index.d.ts +1 -1
- package/dist/plugins/actor/index.js +1 -1
- package/dist/plugins/rules/index.d.ts +2 -2
- package/dist/plugins/rules/index.js +42 -12
- package/dist/plugins/soft-delete/index.d.ts +2 -2
- package/dist/plugins/soft-delete/index.js +2 -2
- package/dist/plugins/tenant/index.d.ts +2 -2
- package/dist/plugins/tenant/index.js +10 -4
- package/dist/plugins/timestamps/index.d.ts +1 -1
- package/dist/plugins/timestamps/index.js +1 -1
- package/dist/plugins/validation/index.d.ts +2 -2
- package/dist/plugins/validation/index.js +3 -3
- package/dist/{pool-B9qsLyFR.d.ts → pool-DFwEQwmN.d.ts} +11 -4
- package/dist/postgres/index.d.ts +5 -5
- package/dist/postgres/index.js +3 -2
- package/dist/{postgrest-DmBlevh-.d.ts → postgrest-Bc-0Xw62.d.ts} +1 -1
- package/dist/{problem-CGt1ADix.js → problem-BihjPR0t.js} +1 -1
- package/dist/{problem-Z2RTQjZD.d.ts → problem-U8UEKccv.d.ts} +1 -1
- package/dist/query/index.d.ts +2 -2
- package/dist/query/index.js +2 -2
- package/dist/{query-BdKLTPlj.js → query-BMMSWbI7.js} +18 -18
- package/dist/react/index.d.ts +6 -6
- package/dist/react/index.js +1 -1
- package/dist/react/server.d.ts +5 -5
- package/dist/react/server.js +3 -3
- package/dist/react/session.d.ts +4 -4
- package/dist/react/session.js +2 -2
- package/dist/{react-DNBYNazu.js → react-CQHMaESR.js} +39 -39
- package/dist/{read-set-D0qBcboM.js → read-set-FWK8qQ58.js} +50 -15
- package/dist/realtime/index.d.ts +1 -1
- package/dist/realtime/index.js +13 -12
- package/dist/{index-kpgopLNv.d.ts → refresh-BwYkyNOQ.d.ts} +6 -3
- package/dist/{resolve-BRciX2jK.d.ts → resolve-BAqQcwMW.d.ts} +15 -10
- package/dist/{resource-CwVgiI5q.d.ts → resource-BJcaIfxi.d.ts} +5 -5
- package/dist/{resource-D30rp0GN.js → resource-My_y-Syh.js} +6 -6
- package/dist/{respond-DAkPIdTH.d.ts → respond-DgIbdrt8.d.ts} +31 -12
- package/dist/{result-DWXatkd6.js → result-Bj6yt33D.js} +2 -2
- package/dist/{result-c2OYgCV2.d.ts → result-CqEsbgYs.d.ts} +3 -3
- package/dist/server/index.d.ts +14 -14
- package/dist/server/index.js +12 -12
- package/dist/{respond-C44EZAJo.js → server-BA75B0mT.js} +139 -100
- package/dist/{shared-_6-uPL7E.js → shared-DnoCdMDr.js} +4 -3
- package/dist/{simplify-LakqK1vH.js → simplify-Cqvfr9dj.js} +67 -24
- package/dist/sql/index.d.ts +1 -1
- package/dist/sql/index.js +7 -7
- package/dist/{sql-BIgk12ew.js → sql-B34HU2DI.js} +3 -2
- package/dist/ssr/index.d.ts +4 -4
- package/dist/ssr/index.js +2 -2
- package/dist/{standard-FUi3Z3-7.js → standard-BRyBGTtp.js} +2 -2
- package/dist/{standard-eudBiRk1.d.ts → standard-BsaCYQJc.d.ts} +1 -1
- package/dist/{stats-D78UQ8Yu.js → stats-C_YxA2r1.js} +33 -8
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.js +26 -8
- package/dist/{tables-Dhha3BXM.js → tables-Cb-3_VWc.js} +14 -0
- package/dist/{temporal-required-CMxeSVPo.js → temporal-required-CBNHT6ni.js} +1 -1
- package/dist/testing/index.d.ts +20 -21
- package/dist/testing/index.js +45 -45
- package/dist/{version-BfpG2gks.js → version-Bmf7_FzM.js} +1 -1
- package/dist/{view-3Po_PVlr.d.ts → view-B64o81wp.d.ts} +5 -5
- package/dist/{view-wZ-9qIUz.js → view-BrJI2LKp.js} +1 -1
- package/dist/webhooks/index.d.ts +3 -3
- package/dist/webhooks/index.js +1 -1
- package/dist/{webhooks-CAIFQSTM.js → webhooks-Bh_Jf_-l.js} +37 -18
- package/package.json +36 -4
- package/skills/better-supabase/SKILL.md +57 -10
- package/skills/better-supabase/references/plugins.md +7 -11
- package/skills/better-supabase/references/troubleshooting.md +24 -4
- package/skills/better-supabase-api/SKILL.md +66 -18
- package/skills/better-supabase-api/references/adapters.md +44 -26
- package/skills/better-supabase-auth/SKILL.md +146 -0
- package/skills/better-supabase-auth/references/permdock.md +55 -0
- package/skills/better-supabase-testing/SKILL.md +58 -4
- package/dist/claims-CoTobNC-.js +0 -25
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { c as mapDbError, n as dbError } from "./errors-
|
|
2
|
-
import { a as invalidRequest, n as simplifyOrFalse } from "./simplify-
|
|
1
|
+
import { c as mapDbError, n as dbError } from "./errors-L0xK41y_.js";
|
|
2
|
+
import { a as invalidRequest, n as simplifyOrFalse } from "./simplify-Cqvfr9dj.js";
|
|
3
3
|
import { i as temporalText } from "./temporal-BwshQk0W.js";
|
|
4
|
-
import { i as ok, n as err, o as toDbError } from "./result-
|
|
4
|
+
import { i as ok, n as err, o as toDbError } from "./result-Bj6yt33D.js";
|
|
5
5
|
//#region src/compile/postgrest.ts
|
|
6
6
|
function scalar(value) {
|
|
7
7
|
if (typeof value === "string") return value;
|
|
8
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
8
9
|
const temporalValue = temporalText(value);
|
|
9
10
|
if (temporalValue !== void 0) return temporalValue;
|
|
10
11
|
if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") return String(value);
|
|
@@ -275,11 +276,21 @@ function filterEmbed(alias, condition, inner) {
|
|
|
275
276
|
children: []
|
|
276
277
|
};
|
|
277
278
|
}
|
|
279
|
+
const columnTexts = /* @__PURE__ */ new WeakMap();
|
|
280
|
+
/** The rendered column list, cached per (shared, immutable) column array. */
|
|
281
|
+
function columnText(columns) {
|
|
282
|
+
let text = columnTexts.get(columns);
|
|
283
|
+
if (text === void 0) {
|
|
284
|
+
text = columns.map(({ alias, column, cast }) => {
|
|
285
|
+
const source = cast ? `${column}::${cast}` : column;
|
|
286
|
+
return alias === column ? source : `${alias}:${source}`;
|
|
287
|
+
}).join(",");
|
|
288
|
+
columnTexts.set(columns, text);
|
|
289
|
+
}
|
|
290
|
+
return text;
|
|
291
|
+
}
|
|
278
292
|
function columnList(columns) {
|
|
279
|
-
return columns.
|
|
280
|
-
const source = cast ? `${column}::${cast}` : column;
|
|
281
|
-
return alias === column ? source : `${alias}:${source}`;
|
|
282
|
-
});
|
|
293
|
+
return columns.length > 0 ? [columnText(columns)] : [];
|
|
283
294
|
}
|
|
284
295
|
/** `key:column.sum()::text`, PostgREST's aggregate syntax (PostgREST 12+). */
|
|
285
296
|
function measureList(measures) {
|
|
@@ -298,6 +309,7 @@ function renderEmbeds(embeds) {
|
|
|
298
309
|
});
|
|
299
310
|
}
|
|
300
311
|
function renderSelect(selection, embeds) {
|
|
312
|
+
if (!selection.aggregate && embeds.length === 0) return selection.columns.length > 0 ? columnText(selection.columns) : "*";
|
|
301
313
|
const parts = [
|
|
302
314
|
...columnList(selection.columns),
|
|
303
315
|
...selection.aggregate ? aggregateList(selection.aggregate) : [],
|
|
@@ -350,8 +362,21 @@ function compilePostgrest(op) {
|
|
|
350
362
|
//#region src/core/postgrest-executor.ts
|
|
351
363
|
function scope(client, schema) {
|
|
352
364
|
const loose = client;
|
|
353
|
-
|
|
365
|
+
if (schema === "public" || !loose.schema) return loose;
|
|
366
|
+
let schemas = scopedClients.get(client);
|
|
367
|
+
if (!schemas) {
|
|
368
|
+
schemas = /* @__PURE__ */ new Map();
|
|
369
|
+
scopedClients.set(client, schemas);
|
|
370
|
+
}
|
|
371
|
+
let scoped = schemas.get(schema);
|
|
372
|
+
if (!scoped) {
|
|
373
|
+
scoped = loose.schema(schema);
|
|
374
|
+
schemas.set(schema, scoped);
|
|
375
|
+
}
|
|
376
|
+
return scoped;
|
|
354
377
|
}
|
|
378
|
+
/** `schema()` builds a new client on every call; one per client and schema is enough. */
|
|
379
|
+
const scopedClients = /* @__PURE__ */ new WeakMap();
|
|
355
380
|
function fromTable(client, schema, table) {
|
|
356
381
|
return scope(client, schema).from(table);
|
|
357
382
|
}
|
package/dist/storage/index.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ import { b as PermdockBucketPolicy } from "../types-DONv9SHN.js";
|
|
|
2
2
|
import { n as StoragePath, t as PathIn } from "../path-Cv__-OTj.js";
|
|
3
3
|
import { t as PermdockCatalog } from "../permdock-sql-DImJULY-.js";
|
|
4
4
|
import { n as TemplateValues, t as TemplateParams } from "../template-mbvlysOo.js";
|
|
5
|
-
import { C as
|
|
6
|
-
export { type ActualBucket, type Bucket, type BucketClient, type BucketConfig, type BucketDrift, type BucketPolicy, type ObjectTarget, type PathIn, type PermdockBucketPolicy, type PermdockCatalog, type ReplaceOptions, type ReplaceResult, type Reservation, type StorageClient, type StoragePath, type StoredObject, type SweepOptions, type SweepResult, TTL, type TemplateParams, type TemplateValues, type TransformOptions, type TtlPreset, type UploadBody, type UploadOptions, type UrlOptions, defineBucket, fromStorageError, parseSize };
|
|
5
|
+
import { C as fromStorageError, S as defineBucket, _ as TransformOptions, a as BucketConnectOptions, b as UploadOptions, c as ObjectTarget, d as Reservation, f as StorageClient, g as TTL, h as SweepResult, i as BucketConfig, l as ReplaceOptions, m as SweepOptions, n as Bucket, o as BucketDrift, p as StoredObject, r as BucketClient, s as BucketPolicy, t as ActualBucket, u as ReplaceResult, v as TtlPreset, w as parseSize, x as UrlOptions, y as UploadBody } from "../index-528Ugmyp.js";
|
|
6
|
+
export { type ActualBucket, type Bucket, type BucketClient, type BucketConfig, type BucketConnectOptions, type BucketDrift, type BucketPolicy, type ObjectTarget, type PathIn, type PermdockBucketPolicy, type PermdockCatalog, type ReplaceOptions, type ReplaceResult, type Reservation, type StorageClient, type StoragePath, type StoredObject, type SweepOptions, type SweepResult, TTL, type TemplateParams, type TemplateValues, type TransformOptions, type TtlPreset, type UploadBody, type UploadOptions, type UrlOptions, defineBucket, fromStorageError, parseSize };
|
package/dist/storage/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { n as dbError, o as isDbError, t as DbException } from "../errors-
|
|
1
|
+
import { n as dbError, o as isDbError, t as DbException } from "../errors-L0xK41y_.js";
|
|
2
2
|
import { r as optionalTemporal } from "../temporal-BwshQk0W.js";
|
|
3
|
-
import { n as temporalMissing } from "../temporal-required-
|
|
4
|
-
import { i as ok, n as err, o as toDbError, t as AsyncResult } from "../result-
|
|
5
|
-
import { i as tenantClaimPaths } from "../claims-
|
|
6
|
-
import { a as sqlIdent, i as slug, o as sqlString, r as parseTemplate, t as permdockCheck } from "../permdock-sql-
|
|
3
|
+
import { n as temporalMissing } from "../temporal-required-CBNHT6ni.js";
|
|
4
|
+
import { i as ok, n as err, o as toDbError, t as AsyncResult } from "../result-Bj6yt33D.js";
|
|
5
|
+
import { i as tenantClaimPaths } from "../claims-BAf6c7is.js";
|
|
6
|
+
import { a as sqlIdent, i as slug, o as sqlString, r as parseTemplate, t as permdockCheck } from "../permdock-sql-C4KFzLc9.js";
|
|
7
7
|
//#region src/storage/bucket.ts
|
|
8
8
|
/** Storage operations that list objects; every other `select` is a read. */
|
|
9
9
|
const LIST_OPERATIONS = [
|
|
@@ -309,7 +309,7 @@ function defineBucket(config) {
|
|
|
309
309
|
});
|
|
310
310
|
return issues;
|
|
311
311
|
},
|
|
312
|
-
connect: (client) => connectBucket(bucket, client, resolve)
|
|
312
|
+
connect: (client, options) => connectBucket(bucket, client, resolve, options)
|
|
313
313
|
};
|
|
314
314
|
return bucket;
|
|
315
315
|
}
|
|
@@ -328,8 +328,9 @@ function ttlSeconds(ttl) {
|
|
|
328
328
|
function isErrorResult(value) {
|
|
329
329
|
return typeof value === "object" && value !== null && value.ok === false && "error" in value;
|
|
330
330
|
}
|
|
331
|
-
function connectBucket(bucket, client, resolve) {
|
|
331
|
+
function connectBucket(bucket, client, resolve, connectOptions = {}) {
|
|
332
332
|
const api = () => client.storage.from(bucket.id);
|
|
333
|
+
const signed = connectOptions.cacheSignedUrls ? /* @__PURE__ */ new Map() : void 0;
|
|
333
334
|
const run = (fn) => AsyncResult.from(async () => {
|
|
334
335
|
try {
|
|
335
336
|
const { data, error } = await fn();
|
|
@@ -398,10 +399,27 @@ function connectBucket(bucket, client, resolve) {
|
|
|
398
399
|
}));
|
|
399
400
|
const signedUrl = (target, options) => AsyncResult.from(async () => {
|
|
400
401
|
const path = resolve(target);
|
|
401
|
-
|
|
402
|
+
const ttl = ttlSeconds(options?.ttl);
|
|
403
|
+
const key = signed ? JSON.stringify([
|
|
404
|
+
path,
|
|
405
|
+
ttl,
|
|
406
|
+
options?.transform,
|
|
407
|
+
options?.download
|
|
408
|
+
]) : "";
|
|
409
|
+
const cached = signed?.get(key);
|
|
410
|
+
if (cached && cached.until > Date.now()) return ok(cached.url);
|
|
411
|
+
const result = await run(() => api().createSignedUrl(path, ttl, {
|
|
402
412
|
...download(options?.download),
|
|
403
413
|
...options?.transform ? { transform: { ...options.transform } } : {}
|
|
404
414
|
})).map((data) => data.signedUrl);
|
|
415
|
+
if (signed && result.ok) {
|
|
416
|
+
const margin = Math.min(60, ttl / 10);
|
|
417
|
+
signed.set(key, {
|
|
418
|
+
url: result.data,
|
|
419
|
+
until: Date.now() + (ttl - margin) * 1e3
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
return result;
|
|
405
423
|
});
|
|
406
424
|
return {
|
|
407
425
|
bucket,
|
|
@@ -42,6 +42,20 @@ function visitCondition(condition, tables) {
|
|
|
42
42
|
* followed through chains of cascades.
|
|
43
43
|
*/
|
|
44
44
|
function invalidationTargets(meta, table) {
|
|
45
|
+
let byTable = targetsByMeta.get(meta);
|
|
46
|
+
if (!byTable) {
|
|
47
|
+
byTable = /* @__PURE__ */ new Map();
|
|
48
|
+
targetsByMeta.set(meta, byTable);
|
|
49
|
+
}
|
|
50
|
+
let targets = byTable.get(table);
|
|
51
|
+
if (!targets) {
|
|
52
|
+
targets = Object.freeze(computeTargets(meta, table));
|
|
53
|
+
byTable.set(table, targets);
|
|
54
|
+
}
|
|
55
|
+
return targets;
|
|
56
|
+
}
|
|
57
|
+
const targetsByMeta = /* @__PURE__ */ new WeakMap();
|
|
58
|
+
function computeTargets(meta, table) {
|
|
45
59
|
const targets = /* @__PURE__ */ new Set([table]);
|
|
46
60
|
const queue = [table];
|
|
47
61
|
for (let key = queue.shift(); key !== void 0; key = queue.shift()) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as dbError, t as DbException } from "./errors-
|
|
1
|
+
import { n as dbError, t as DbException } from "./errors-L0xK41y_.js";
|
|
2
2
|
import { r as optionalTemporal, t as TEMPORAL_MISSING } from "./temporal-BwshQk0W.js";
|
|
3
3
|
//#region src/core/temporal-required.ts
|
|
4
4
|
/** The error for a runtime without Temporal, naming the polyfill to load. */
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { A as SchemaMeta, N as TableKey, R as Update, g as Insert, n as AnyModels, t as AnyFunctions } from "../types-DONv9SHN.js";
|
|
2
|
-
import { r as Executor } from "../executor-
|
|
3
|
-
import { P as DbStats, l as CacheAdapter, t as BetterSupabase, y as Db } from "../define-
|
|
4
|
-
import { h as RequestContext, n as AnyPlugin } from "../plugin-
|
|
2
|
+
import { r as Executor } from "../executor-B5IoUxLE.js";
|
|
3
|
+
import { P as DbStats, l as CacheAdapter, t as BetterSupabase, y as Db } from "../define-CRS2MRV3.js";
|
|
4
|
+
import { h as RequestContext, n as AnyPlugin } from "../plugin-bNhvJwRh.js";
|
|
5
5
|
import { b as ResolvedConfig, d as Generator, f as GeneratorInput } from "../config-C1CYcm6o.js";
|
|
6
|
-
import "../
|
|
7
|
-
import { t as
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { r as EventSink, t as CloudEvent } from "../index-GV77NpRP.js";
|
|
6
|
+
import { t as SqlClient } from "../executor-CZ7ImRiD.js";
|
|
7
|
+
import { t as BetterPostgres } from "../pool-DFwEQwmN.js";
|
|
8
|
+
import { n as AuthResolver } from "../resolve-BAqQcwMW.js";
|
|
9
|
+
import { r as EventSink, t as CloudEvent } from "../index-D5IfUIDh.js";
|
|
11
10
|
import { SupabaseClient } from "@supabase/supabase-js";
|
|
12
11
|
import { webcrypto } from "node:crypto";
|
|
13
12
|
//#region src/testing/jwt.d.ts
|
|
@@ -26,7 +25,7 @@ interface TestJwtClaims {
|
|
|
26
25
|
export declare function signTestJwt(secret: string, claims: TestJwtClaims): Promise<string>;
|
|
27
26
|
/**
|
|
28
27
|
* Accepts `signTestJwt` tokens as users, for API servers tested against the
|
|
29
|
-
* local stack: `createServer(
|
|
28
|
+
* local stack: `createServer(betterSupabase, { auth: { resolvers: [localAuth(secret)] } })`.
|
|
30
29
|
* Tokens that are not HS256-signed with `secret` fall through. Test-only.
|
|
31
30
|
*/
|
|
32
31
|
export declare function localAuth(secret: string): AuthResolver;
|
|
@@ -82,7 +81,7 @@ interface LocalStack {
|
|
|
82
81
|
/** Service-role key for `expectTenantIsolation`; defaults to `$SUPABASE_SECRET_KEY`. */
|
|
83
82
|
readonly secretKey?: string;
|
|
84
83
|
/** Enables `sql`: the same user over direct Postgres. */
|
|
85
|
-
readonly postgres?:
|
|
84
|
+
readonly postgres?: BetterPostgres;
|
|
86
85
|
}
|
|
87
86
|
interface TestUser<M extends AnyModels, F extends AnyFunctions, E> {
|
|
88
87
|
readonly token: string;
|
|
@@ -101,11 +100,11 @@ interface TestUser<M extends AnyModels, F extends AnyFunctions, E> {
|
|
|
101
100
|
* still uses the shared JWT secret.
|
|
102
101
|
*
|
|
103
102
|
* ```ts
|
|
104
|
-
* const alice = await asUser(
|
|
103
|
+
* const alice = await asUser(betterSupabase, { sub: aliceId, tenant_id: acme });
|
|
105
104
|
* expect(await alice.db.customers.count().orThrow()).toBe(3);
|
|
106
105
|
* ```
|
|
107
106
|
*/
|
|
108
|
-
export declare function asUser<M extends AnyModels, D, F extends AnyFunctions, E>(
|
|
107
|
+
export declare function asUser<M extends AnyModels, D, F extends AnyFunctions, E>(betterSupabase: BetterSupabase<M, D, F, E>, claims: TestJwtClaims, stack?: LocalStack): Promise<TestUser<M, F, E>>;
|
|
109
108
|
//#endregion
|
|
110
109
|
//#region src/testing/budget.d.ts
|
|
111
110
|
/** The part of a Playwright `Response` the budget check reads. */
|
|
@@ -148,7 +147,7 @@ interface MeasuredRender {
|
|
|
148
147
|
/**
|
|
149
148
|
* Measures every document and RSC navigation response during `during` and
|
|
150
149
|
* fails when one render makes more database calls or waves than allowed.
|
|
151
|
-
* Needs `createNext(
|
|
150
|
+
* Needs `createNext(betterSupabase, { debug })` and `bs.debugRoute()` in the app.
|
|
152
151
|
*/
|
|
153
152
|
export declare function expectDbBudget(page: BudgetPage, expectation: DbBudgetExpectation): Promise<readonly MeasuredRender[]>;
|
|
154
153
|
//#endregion
|
|
@@ -171,7 +170,7 @@ export declare class ConformanceError extends Error {
|
|
|
171
170
|
type AnySupabase = BetterSupabase<any, any, any, any>;
|
|
172
171
|
interface TestExecutorOptions {
|
|
173
172
|
/** A definition whose schema matches the executor's database. Install no plugins. */
|
|
174
|
-
readonly
|
|
173
|
+
readonly betterSupabase: AnySupabase;
|
|
175
174
|
/** App key of a table with rows the executor can read. Defaults to the first table. */
|
|
176
175
|
readonly table?: string;
|
|
177
176
|
/** A row to insert and delete again, to check writes. Skips write checks when omitted. */
|
|
@@ -183,7 +182,7 @@ interface TestExecutorOptions {
|
|
|
183
182
|
* than thrown, and (with `create`) a write round trip.
|
|
184
183
|
*
|
|
185
184
|
* ```ts
|
|
186
|
-
* it('conforms', () => testExecutor(myExecutor, {
|
|
185
|
+
* it('conforms', () => testExecutor(myExecutor, { betterSupabase, table: 'tags', create: { name: 'x' } }));
|
|
187
186
|
* ```
|
|
188
187
|
*/
|
|
189
188
|
export declare function testExecutor(executor: Executor, options: TestExecutorOptions): Promise<ConformanceReport>;
|
|
@@ -228,7 +227,7 @@ interface TestGeneratorOptions {
|
|
|
228
227
|
export declare function testGenerator(generator: Generator, options: TestGeneratorOptions): Promise<ConformanceReport>;
|
|
229
228
|
interface TestPluginOptions {
|
|
230
229
|
/** The definition without this plugin. */
|
|
231
|
-
readonly
|
|
230
|
+
readonly betterSupabase: AnySupabase;
|
|
232
231
|
/** Table to exercise. Defaults to the first table. */
|
|
233
232
|
readonly table?: string;
|
|
234
233
|
/** Context the plugin needs, such as `{ tenant }` for `tenant()`. */
|
|
@@ -273,12 +272,12 @@ interface TenantIsolationOptions<M extends AnyModels> {
|
|
|
273
272
|
/**
|
|
274
273
|
* Checks row-level security between two tenants against a running stack: for
|
|
275
274
|
* each table, a user of one tenant must not select, insert, update or delete
|
|
276
|
-
* the other tenant's rows. Runs without `
|
|
275
|
+
* the other tenant's rows. Runs without `betterSupabase`'s plugins, so the `tenant()`
|
|
277
276
|
* plugin can't hide a missing policy. Throws a `ConformanceError` naming each
|
|
278
277
|
* table and command that leaks; removes every row it created.
|
|
279
278
|
*
|
|
280
279
|
* ```ts
|
|
281
|
-
* await expectTenantIsolation(
|
|
280
|
+
* await expectTenantIsolation(betterSupabase, {
|
|
282
281
|
* tenants: [
|
|
283
282
|
* { id: ACME, claims: { sub: alice, tenant_id: ACME } },
|
|
284
283
|
* { id: GLOBEX, claims: { sub: bob, tenant_id: GLOBEX } },
|
|
@@ -292,7 +291,7 @@ interface TenantIsolationOptions<M extends AnyModels> {
|
|
|
292
291
|
* });
|
|
293
292
|
* ```
|
|
294
293
|
*/
|
|
295
|
-
export declare function expectTenantIsolation<M extends AnyModels, D, F extends AnyFunctions, E>(
|
|
294
|
+
export declare function expectTenantIsolation<M extends AnyModels, D, F extends AnyFunctions, E>(betterSupabase: BetterSupabase<M, D, F, E>, options: TenantIsolationOptions<M>): Promise<ConformanceReport>;
|
|
296
295
|
//#endregion
|
|
297
296
|
//#region src/testing/seed.d.ts
|
|
298
297
|
/** Named rows per table, in app casing: `{ customers: { acme: { ... } } }`. */
|
|
@@ -316,12 +315,12 @@ export declare function isSeed(value: unknown): value is Seed<unknown>;
|
|
|
316
315
|
* casing and Insert types; `better-supabase seed` renders them to SQL.
|
|
317
316
|
*
|
|
318
317
|
* ```ts
|
|
319
|
-
* export const seed = defineSeed(
|
|
318
|
+
* export const seed = defineSeed(betterSupabase, {
|
|
320
319
|
* organizations: { acme: { id: ACME, name: 'Acme' } },
|
|
321
320
|
* customers: { first: { organizationId: ACME, name: 'First customer' } },
|
|
322
321
|
* });
|
|
323
322
|
* ```
|
|
324
323
|
*/
|
|
325
|
-
export declare function defineSeed<M extends AnyModels, D, F extends AnyFunctions, E, const S extends SeedFixtures<M>>(
|
|
324
|
+
export declare function defineSeed<M extends AnyModels, D, F extends AnyFunctions, E, const S extends SeedFixtures<M>>(betterSupabase: BetterSupabase<M, D, F, E>, fixtures: S & ExactSeed<M, S>): Seed<S>;
|
|
326
325
|
//#endregion
|
|
327
326
|
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 };
|
package/dist/testing/index.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { n as dbError } from "../errors-
|
|
1
|
+
import { n as dbError } from "../errors-L0xK41y_.js";
|
|
2
2
|
import { i as temporalText } from "../temporal-BwshQk0W.js";
|
|
3
|
-
import { t as temporal } from "../temporal-required-
|
|
4
|
-
import { i as ok } from "../result-
|
|
5
|
-
import { t as BetterSupabase } from "../define-
|
|
6
|
-
import { a as toBase64Url, r as fromBase64, t as base64ToText } from "../base64-
|
|
7
|
-
import { r as resolveConfig } from "../config-
|
|
3
|
+
import { t as temporal } from "../temporal-required-CBNHT6ni.js";
|
|
4
|
+
import { i as ok } from "../result-Bj6yt33D.js";
|
|
5
|
+
import { t as BetterSupabase } from "../define-Bh0AqTik.js";
|
|
6
|
+
import { a as toBase64Url, r as fromBase64, t as base64ToText } from "../base64-D2gsioCY.js";
|
|
7
|
+
import { r as resolveConfig } from "../config-BpxDfnbg.js";
|
|
8
8
|
import { t as isList } from "../guards-BnzDvFrz.js";
|
|
9
9
|
import { ENV_VARIABLES } from "../env/index.js";
|
|
10
|
-
import { n as postgresExecutor } from "../executor-
|
|
10
|
+
import { n as postgresExecutor } from "../executor-CVt6dD0B.js";
|
|
11
11
|
import { toCloudEvents } from "../events/index.js";
|
|
12
12
|
import { createClient } from "@supabase/supabase-js";
|
|
13
13
|
import { existsSync } from "node:fs";
|
|
14
14
|
import { readFile } from "node:fs/promises";
|
|
15
15
|
import { dirname, join, resolve } from "node:path";
|
|
16
16
|
//#region src/testing/jwt.ts
|
|
17
|
-
const encoder = new TextEncoder();
|
|
17
|
+
const encoder = /* @__PURE__ */ new TextEncoder();
|
|
18
18
|
/**
|
|
19
19
|
* Signs an HS256 access token the local Supabase stack accepts. Test-only:
|
|
20
20
|
* production tokens come from Supabase Auth.
|
|
@@ -44,7 +44,7 @@ async function signTestJwt(secret, claims) {
|
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
46
|
* Accepts `signTestJwt` tokens as users, for API servers tested against the
|
|
47
|
-
* local stack: `createServer(
|
|
47
|
+
* local stack: `createServer(betterSupabase, { auth: { resolvers: [localAuth(secret)] } })`.
|
|
48
48
|
* Tokens that are not HS256-signed with `secret` fall through. Test-only.
|
|
49
49
|
*/
|
|
50
50
|
function localAuth(secret) {
|
|
@@ -198,11 +198,11 @@ async function signFor(stack, url, claims) {
|
|
|
198
198
|
* still uses the shared JWT secret.
|
|
199
199
|
*
|
|
200
200
|
* ```ts
|
|
201
|
-
* const alice = await asUser(
|
|
201
|
+
* const alice = await asUser(betterSupabase, { sub: aliceId, tenant_id: acme });
|
|
202
202
|
* expect(await alice.db.customers.count().orThrow()).toBe(3);
|
|
203
203
|
* ```
|
|
204
204
|
*/
|
|
205
|
-
async function asUser(
|
|
205
|
+
async function asUser(betterSupabase, claims, stack = {}) {
|
|
206
206
|
const url = stack.url ?? env$1(...ENV_VARIABLES.url) ?? "http://127.0.0.1:54321";
|
|
207
207
|
const publishableKey = stack.publishableKey ?? env$1(...ENV_VARIABLES.publishableKey, "SUPABASE_ANON_KEY");
|
|
208
208
|
if (!publishableKey) throw new TypeError("asUser needs publishableKey or $SUPABASE_PUBLISHABLE_KEY. Run `better-supabase env` to write it to .env.local.");
|
|
@@ -225,8 +225,8 @@ async function asUser(sb, claims, stack = {}) {
|
|
|
225
225
|
token,
|
|
226
226
|
claims: full,
|
|
227
227
|
supabase,
|
|
228
|
-
db:
|
|
229
|
-
sql: stack.postgres ?
|
|
228
|
+
db: betterSupabase.connect(supabase, context),
|
|
229
|
+
sql: stack.postgres ? betterSupabase.connect(postgresExecutor(stack.postgres.asUser(full)), context) : void 0
|
|
230
230
|
};
|
|
231
231
|
}
|
|
232
232
|
//#endregion
|
|
@@ -246,7 +246,7 @@ function settle(promise, ms) {
|
|
|
246
246
|
/**
|
|
247
247
|
* Measures every document and RSC navigation response during `during` and
|
|
248
248
|
* fails when one render makes more database calls or waves than allowed.
|
|
249
|
-
* Needs `createNext(
|
|
249
|
+
* Needs `createNext(betterSupabase, { debug })` and `bs.debugRoute()` in the app.
|
|
250
250
|
*/
|
|
251
251
|
async function expectDbBudget(page, expectation) {
|
|
252
252
|
const seen = [];
|
|
@@ -267,12 +267,12 @@ async function expectDbBudget(page, expectation) {
|
|
|
267
267
|
} finally {
|
|
268
268
|
page.off("response", listener);
|
|
269
269
|
}
|
|
270
|
-
if (seen.length === 0) throw new Error("expectDbBudget: no response carried x-bs-request-id. Enable createNext(
|
|
270
|
+
if (seen.length === 0) throw new Error("expectDbBudget: no response carried x-bs-request-id. Enable createNext(betterSupabase, { debug: { enabled: true } }) and run the proxy.");
|
|
271
271
|
await Promise.all(seen.map(({ response }) => settle(response.finished(), expectation.timeoutMs ?? 1e4)));
|
|
272
272
|
const renders = [];
|
|
273
273
|
for (const { response, id, url } of seen) {
|
|
274
274
|
const reply = await page.request.get(url);
|
|
275
|
-
if (!reply.ok()) throw new Error(`expectDbBudget: ${url} answered ${reply.status()}. Mount
|
|
275
|
+
if (!reply.ok()) throw new Error(`expectDbBudget: ${url} answered ${reply.status()}. Mount bs.debugRoute() at that path.`);
|
|
276
276
|
renders.push({
|
|
277
277
|
url: response.url(),
|
|
278
278
|
requestId: id,
|
|
@@ -348,17 +348,17 @@ const recorder = (ops) => ({
|
|
|
348
348
|
}));
|
|
349
349
|
}
|
|
350
350
|
});
|
|
351
|
-
/** The operation `run` sends to the executor, built by `
|
|
352
|
-
async function captureOp(
|
|
351
|
+
/** The operation `run` sends to the executor, built by `betterSupabase` without touching a database. */
|
|
352
|
+
async function captureOp(betterSupabase, run) {
|
|
353
353
|
const ops = [];
|
|
354
|
-
await run(
|
|
354
|
+
await run(betterSupabase.connect(recorder(ops)));
|
|
355
355
|
const [op] = ops;
|
|
356
356
|
if (!op) throw new Error("the repository call did not reach the executor");
|
|
357
357
|
return op;
|
|
358
358
|
}
|
|
359
|
-
function tableKey(
|
|
360
|
-
const key = table ?? Object.keys(
|
|
361
|
-
if (!key || !(key in
|
|
359
|
+
function tableKey(betterSupabase, table) {
|
|
360
|
+
const key = table ?? Object.keys(betterSupabase.meta.tables)[0];
|
|
361
|
+
if (!key || !(key in betterSupabase.meta.tables)) throw new TypeError(`better-supabase: unknown table "${String(key)}"`);
|
|
362
362
|
return key;
|
|
363
363
|
}
|
|
364
364
|
const hasName = (subject) => ["has a name", () => {
|
|
@@ -370,14 +370,14 @@ const hasName = (subject) => ["has a name", () => {
|
|
|
370
370
|
* than thrown, and (with `create`) a write round trip.
|
|
371
371
|
*
|
|
372
372
|
* ```ts
|
|
373
|
-
* it('conforms', () => testExecutor(myExecutor, {
|
|
373
|
+
* it('conforms', () => testExecutor(myExecutor, { betterSupabase, table: 'tags', create: { name: 'x' } }));
|
|
374
374
|
* ```
|
|
375
375
|
*/
|
|
376
376
|
function testExecutor(executor, options) {
|
|
377
|
-
const {
|
|
378
|
-
const table = tableKey(
|
|
377
|
+
const { betterSupabase } = options;
|
|
378
|
+
const table = tableKey(betterSupabase, options.table);
|
|
379
379
|
const context = { errorMappers: [] };
|
|
380
|
-
const read = () => captureOp(
|
|
380
|
+
const read = () => captureOp(betterSupabase, (db) => db[table]["findMany"]({ limit: 2 }));
|
|
381
381
|
const create = options.create;
|
|
382
382
|
return conform(`Executor "${executor.name}"`, [
|
|
383
383
|
hasName(executor),
|
|
@@ -396,7 +396,7 @@ function testExecutor(executor, options) {
|
|
|
396
396
|
}
|
|
397
397
|
}],
|
|
398
398
|
["counts rows", async () => {
|
|
399
|
-
const op = await captureOp(
|
|
399
|
+
const op = await captureOp(betterSupabase, (db) => db[table]["count"]());
|
|
400
400
|
const result = await executor.execute(op, context);
|
|
401
401
|
expect(result.ok, `count failed: ${result.ok ? "" : result.error.message}`);
|
|
402
402
|
expect(typeof result.data.count === "number" && result.data.count >= 0, "count must be a number");
|
|
@@ -444,7 +444,7 @@ function testExecutor(executor, options) {
|
|
|
444
444
|
}],
|
|
445
445
|
executor.batch && ["batch returns one result per operation, in order", async () => {
|
|
446
446
|
const rows = await read();
|
|
447
|
-
const count = await captureOp(
|
|
447
|
+
const count = await captureOp(betterSupabase, (db) => db[table]["count"]());
|
|
448
448
|
const missing = {
|
|
449
449
|
...rows,
|
|
450
450
|
table: {
|
|
@@ -464,12 +464,12 @@ function testExecutor(executor, options) {
|
|
|
464
464
|
expect(third?.ok === false, "a failing operation must fail on its own, as a result");
|
|
465
465
|
}],
|
|
466
466
|
create && ["round-trips a write", async () => {
|
|
467
|
-
const repository =
|
|
467
|
+
const repository = betterSupabase.connect(executor)[table];
|
|
468
468
|
const created = await repository["create"](create);
|
|
469
469
|
expect(created.ok, `create failed: ${JSON.stringify(created.error)}`);
|
|
470
470
|
const row = created.data;
|
|
471
471
|
for (const [key, value] of Object.entries(create)) expect(same(row[key], value), `created row has ${key} = ${JSON.stringify(row[key])}`);
|
|
472
|
-
const [primary] =
|
|
472
|
+
const [primary] = betterSupabase.meta.tables[table].primaryKey;
|
|
473
473
|
expect(primary, "write checks need a table with a primary key");
|
|
474
474
|
const removed = await repository["delete"](row[primary]);
|
|
475
475
|
expect(removed.ok, `delete failed: ${JSON.stringify(removed.error)}`);
|
|
@@ -643,12 +643,12 @@ function testGenerator(generator, options) {
|
|
|
643
643
|
* results intact when it wraps them.
|
|
644
644
|
*/
|
|
645
645
|
function testPlugin(plugin, options) {
|
|
646
|
-
const {
|
|
647
|
-
const table = tableKey(
|
|
646
|
+
const { betterSupabase } = options;
|
|
647
|
+
const table = tableKey(betterSupabase, options.table);
|
|
648
648
|
const context = options.context ?? {};
|
|
649
649
|
const hook = (op) => ({
|
|
650
650
|
table: op.table,
|
|
651
|
-
schema:
|
|
651
|
+
schema: betterSupabase.meta,
|
|
652
652
|
context,
|
|
653
653
|
options: {},
|
|
654
654
|
now: () => temporal().Instant.fromEpochMilliseconds(0)
|
|
@@ -660,18 +660,18 @@ function testPlugin(plugin, options) {
|
|
|
660
660
|
expect(plugin.apiVersion === 1, `apiVersion is ${String(plugin.apiVersion)}`);
|
|
661
661
|
}],
|
|
662
662
|
["installs and builds repositories", () => {
|
|
663
|
-
const db =
|
|
664
|
-
for (const key of Object.keys(
|
|
663
|
+
const db = betterSupabase.use(plugin).connect(recorder([]), context);
|
|
664
|
+
for (const key of Object.keys(betterSupabase.meta.tables)) expect(db[key], `db.${key} is missing`);
|
|
665
665
|
}],
|
|
666
666
|
plugin.transformQuery && ["transformQuery is pure and deterministic", async () => {
|
|
667
|
-
const op = await captureOp(
|
|
667
|
+
const op = await captureOp(betterSupabase, (db) => db[table]["findMany"]({ limit: 1 }));
|
|
668
668
|
const first = plugin.transformQuery(frozenCopy(op), hook(op));
|
|
669
669
|
const second = plugin.transformQuery(frozenCopy(op), hook(op));
|
|
670
670
|
expect(typeof first === "object" && first !== null && first.kind === op.kind, "must return an operation of the same kind");
|
|
671
671
|
expect(same(first, second), "two calls with the same input differ");
|
|
672
672
|
}],
|
|
673
673
|
plugin.beforeMutation && create && ["beforeMutation is pure and deterministic", async () => {
|
|
674
|
-
const op = await captureOp(
|
|
674
|
+
const op = await captureOp(betterSupabase, (db) => db[table]["create"](create));
|
|
675
675
|
if (op.kind === "select") throw new Violation("create did not produce a mutation");
|
|
676
676
|
const first = await plugin.beforeMutation(frozenCopy(op), hook(op));
|
|
677
677
|
const second = await plugin.beforeMutation(frozenCopy(op), hook(op));
|
|
@@ -679,7 +679,7 @@ function testPlugin(plugin, options) {
|
|
|
679
679
|
expect(same(first, second), "two calls with the same input differ");
|
|
680
680
|
}],
|
|
681
681
|
plugin.wrapExecutor && ["wrapExecutor keeps results intact", async () => {
|
|
682
|
-
const op = await captureOp(
|
|
682
|
+
const op = await captureOp(betterSupabase, (db) => db[table]["findMany"]({ limit: 1 }));
|
|
683
683
|
const data = {
|
|
684
684
|
rows: [{ marker: "conformance" }],
|
|
685
685
|
count: 1
|
|
@@ -723,12 +723,12 @@ function env(names) {
|
|
|
723
723
|
/**
|
|
724
724
|
* Checks row-level security between two tenants against a running stack: for
|
|
725
725
|
* each table, a user of one tenant must not select, insert, update or delete
|
|
726
|
-
* the other tenant's rows. Runs without `
|
|
726
|
+
* the other tenant's rows. Runs without `betterSupabase`'s plugins, so the `tenant()`
|
|
727
727
|
* plugin can't hide a missing policy. Throws a `ConformanceError` naming each
|
|
728
728
|
* table and command that leaks; removes every row it created.
|
|
729
729
|
*
|
|
730
730
|
* ```ts
|
|
731
|
-
* await expectTenantIsolation(
|
|
731
|
+
* await expectTenantIsolation(betterSupabase, {
|
|
732
732
|
* tenants: [
|
|
733
733
|
* { id: ACME, claims: { sub: alice, tenant_id: ACME } },
|
|
734
734
|
* { id: GLOBEX, claims: { sub: bob, tenant_id: GLOBEX } },
|
|
@@ -742,9 +742,9 @@ function env(names) {
|
|
|
742
742
|
* });
|
|
743
743
|
* ```
|
|
744
744
|
*/
|
|
745
|
-
async function expectTenantIsolation(
|
|
745
|
+
async function expectTenantIsolation(betterSupabase, options) {
|
|
746
746
|
const stack = options.stack ?? {};
|
|
747
|
-
const bare = new BetterSupabase(
|
|
747
|
+
const bare = new BetterSupabase(betterSupabase.schema);
|
|
748
748
|
const url = stack.url ?? env(ENV_VARIABLES.url) ?? "http://127.0.0.1:54321";
|
|
749
749
|
const secretKey = stack.secretKey ?? env(ENV_VARIABLES.secretKey);
|
|
750
750
|
if (!secretKey) throw new TypeError("expectTenantIsolation needs stack.secretKey or $SUPABASE_SECRET_KEY to seed rows.");
|
|
@@ -884,14 +884,14 @@ function statement(table, rows) {
|
|
|
884
884
|
* casing and Insert types; `better-supabase seed` renders them to SQL.
|
|
885
885
|
*
|
|
886
886
|
* ```ts
|
|
887
|
-
* export const seed = defineSeed(
|
|
887
|
+
* export const seed = defineSeed(betterSupabase, {
|
|
888
888
|
* organizations: { acme: { id: ACME, name: 'Acme' } },
|
|
889
889
|
* customers: { first: { organizationId: ACME, name: 'First customer' } },
|
|
890
890
|
* });
|
|
891
891
|
* ```
|
|
892
892
|
*/
|
|
893
|
-
function defineSeed(
|
|
894
|
-
const meta =
|
|
893
|
+
function defineSeed(betterSupabase, fixtures) {
|
|
894
|
+
const meta = betterSupabase.meta;
|
|
895
895
|
const statements = () => {
|
|
896
896
|
const keys = Object.keys(fixtures).filter((key) => fixtures[key] !== void 0);
|
|
897
897
|
for (const key of keys) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { p as DbError } from "./result-
|
|
2
|
-
import { n as AmrEntry, s as Impersonator, t as Aal } from "./mfa-
|
|
3
|
-
import { i as InvalidReason, r as AuthState } from "./resolve-
|
|
1
|
+
import { p as DbError } from "./result-CqEsbgYs.js";
|
|
2
|
+
import { n as AmrEntry, s as Impersonator, t as Aal } from "./mfa-C7MNQ1Ob.js";
|
|
3
|
+
import { i as InvalidReason, r as AuthState } from "./resolve-BAqQcwMW.js";
|
|
4
4
|
import { JWTClaims, UserClaims } from "@supabase/server";
|
|
5
5
|
//#region src/auth/actor.d.ts
|
|
6
6
|
/** One level of an RFC 8693 `act` chain: who acts, and who acted before it. */
|
|
@@ -35,13 +35,13 @@ type AuthSession<C = unknown, P = unknown> = {
|
|
|
35
35
|
readonly user: UserClaims;
|
|
36
36
|
/**
|
|
37
37
|
* The verified JWT payload, including custom access token hook claims,
|
|
38
|
-
* typed and validated by `
|
|
38
|
+
* typed and validated by `betterSupabase.claims(schema)`.
|
|
39
39
|
*/
|
|
40
40
|
readonly claims: JWTClaims & C;
|
|
41
41
|
/** Seconds since epoch, from the token's `exp`. */
|
|
42
42
|
readonly expiresAt: number | null;
|
|
43
43
|
/**
|
|
44
|
-
* `user_metadata` parsed by `
|
|
44
|
+
* `user_metadata` parsed by `betterSupabase.userMetadata(schema)`, for display.
|
|
45
45
|
* Absent without a schema or when the metadata fails it. Users
|
|
46
46
|
* write this data with `auth.updateUser()`: never base access on it.
|
|
47
47
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as delegationOf, g as actorOf, n as amrOf, t as aalOf, y as impersonatorOf } from "./mfa-byfjruR9.js";
|
|
2
2
|
//#region src/auth/view.ts
|
|
3
3
|
/** Drops the token from an `AuthState`, leaving only serializable fields. */
|
|
4
4
|
function toSession(auth) {
|
package/dist/webhooks/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
2
|
import { N as TableKey, O as Row, n as AnyModels, t as AnyFunctions } from "../types-DONv9SHN.js";
|
|
3
|
-
import { o as Result } from "../result-
|
|
4
|
-
import { t as BetterSupabase } from "../define-
|
|
3
|
+
import { o as Result } from "../result-CqEsbgYs.js";
|
|
4
|
+
import { t as BetterSupabase } from "../define-CRS2MRV3.js";
|
|
5
5
|
//#region src/webhooks/verify.d.ts
|
|
6
6
|
interface VerifiedWebhook<T = unknown> {
|
|
7
7
|
readonly id: string;
|
|
@@ -149,6 +149,6 @@ export declare function isDatabaseWebhook(value: unknown): value is DatabaseWebh
|
|
|
149
149
|
* Reads a database webhook payload for `table` as an app-cased change.
|
|
150
150
|
* Returns `null` for other tables or payloads that aren't database webhooks.
|
|
151
151
|
*/
|
|
152
|
-
export declare function databaseChange<M extends AnyModels, D, F extends AnyFunctions, E, T extends TableKey<M>>(
|
|
152
|
+
export declare function databaseChange<M extends AnyModels, D, F extends AnyFunctions, E, T extends TableKey<M>>(betterSupabase: BetterSupabase<M, D, F, E>, table: T, payload: unknown): DatabaseChange<Row<M, T>> | null;
|
|
153
153
|
//#endregion
|
|
154
154
|
export type { AuthHookError, AuthHookKind, AuthHooks, DatabaseChange, DatabaseWebhookPayload, VerifiedWebhook, VerifyOptions, WebhookInput };
|
package/dist/webhooks/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as signWebhook, c as verifyWebhook, i as isDatabaseWebhook, n as databaseChange, o as timingSafeEqual, r as hookError, s as verifySharedSecret, t as authHook } from "../webhooks-
|
|
1
|
+
import { a as signWebhook, c as verifyWebhook, i as isDatabaseWebhook, n as databaseChange, o as timingSafeEqual, r as hookError, s as verifySharedSecret, t as authHook } from "../webhooks-Bh_Jf_-l.js";
|
|
2
2
|
export { authHook, databaseChange, hookError, isDatabaseWebhook, signWebhook, timingSafeEqual, verifySharedSecret, verifyWebhook };
|