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,6 +1,6 @@
|
|
|
1
|
-
import { n as dbError } from "./errors-
|
|
1
|
+
import { n as dbError } from "./errors-L0xK41y_.js";
|
|
2
2
|
import { t as consoleLogger } from "./logger-glM28NVN.js";
|
|
3
|
-
import { n as decodeJwtPayload } from "./base64-
|
|
3
|
+
import { n as decodeJwtPayload } from "./base64-D2gsioCY.js";
|
|
4
4
|
import { DEFAULT_COOKIE_OPTIONS, createChunks, isChunkLike, parseCookieHeader, serializeCookieHeader, stringFromBase64URL, stringToBase64URL } from "@supabase/ssr";
|
|
5
5
|
import { extractCredentials, verifyCredentials } from "@supabase/server/core";
|
|
6
6
|
//#region src/auth/impersonation.ts
|
|
@@ -89,6 +89,7 @@ function delegationOf(claims) {
|
|
|
89
89
|
* refresh-token reuse interval of Supabase Auth.
|
|
90
90
|
*/
|
|
91
91
|
const REUSE_MS = 1e4;
|
|
92
|
+
const DEFAULT_TIMEOUT_MS = 5e3;
|
|
92
93
|
const inflight = /* @__PURE__ */ new Map();
|
|
93
94
|
const recent = /* @__PURE__ */ new Map();
|
|
94
95
|
function shared(outcome) {
|
|
@@ -98,10 +99,14 @@ function shared(outcome) {
|
|
|
98
99
|
} : outcome;
|
|
99
100
|
}
|
|
100
101
|
function prune(now) {
|
|
101
|
-
for (const [token, entry] of recent)
|
|
102
|
+
for (const [token, entry] of recent) {
|
|
103
|
+
if (entry.until > now) return;
|
|
104
|
+
recent.delete(token);
|
|
105
|
+
}
|
|
102
106
|
}
|
|
103
107
|
async function request(refreshToken, options, now) {
|
|
104
108
|
const doFetch = options.fetch ?? fetch;
|
|
109
|
+
const signal = AbortSignal.timeout(options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
105
110
|
let response;
|
|
106
111
|
try {
|
|
107
112
|
response = await doFetch(`${options.url}/auth/v1/token?grant_type=refresh_token`, {
|
|
@@ -111,7 +116,8 @@ async function request(refreshToken, options, now) {
|
|
|
111
116
|
"content-type": "application/json",
|
|
112
117
|
...options.forwardedFor ? { "sb-forwarded-for": options.forwardedFor.ip } : {}
|
|
113
118
|
},
|
|
114
|
-
body: JSON.stringify({ refresh_token: refreshToken })
|
|
119
|
+
body: JSON.stringify({ refresh_token: refreshToken }),
|
|
120
|
+
signal
|
|
115
121
|
});
|
|
116
122
|
} catch (cause) {
|
|
117
123
|
return {
|
|
@@ -121,6 +127,11 @@ async function request(refreshToken, options, now) {
|
|
|
121
127
|
};
|
|
122
128
|
}
|
|
123
129
|
const body = await response.json().catch(() => null);
|
|
130
|
+
if (signal.aborted) return {
|
|
131
|
+
ok: false,
|
|
132
|
+
reason: "network",
|
|
133
|
+
message: "refresh timed out"
|
|
134
|
+
};
|
|
124
135
|
if (!response.ok || !body || typeof body["access_token"] !== "string" || typeof body["refresh_token"] !== "string") {
|
|
125
136
|
const message = typeof body?.["msg"] === "string" ? body["msg"] : typeof body?.["error_description"] === "string" ? body["error_description"] : `Refresh failed with ${String(response.status)}`;
|
|
126
137
|
return {
|
|
@@ -154,12 +165,16 @@ function refreshSession(refreshToken, options) {
|
|
|
154
165
|
const pending = inflight.get(refreshToken);
|
|
155
166
|
if (pending) return pending.then(shared);
|
|
156
167
|
const promise = request(refreshToken, options, now).then((outcome) => {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
168
|
+
if (outcome.ok || outcome.reason === "rejected") {
|
|
169
|
+
recent.delete(refreshToken);
|
|
170
|
+
recent.set(refreshToken, {
|
|
171
|
+
outcome,
|
|
172
|
+
until: now + REUSE_MS
|
|
173
|
+
});
|
|
174
|
+
}
|
|
162
175
|
return outcome;
|
|
176
|
+
}).finally(() => {
|
|
177
|
+
inflight.delete(refreshToken);
|
|
163
178
|
});
|
|
164
179
|
inflight.set(refreshToken, promise);
|
|
165
180
|
return promise;
|
|
@@ -175,8 +190,15 @@ const AUTH_CACHE_HEADERS = {
|
|
|
175
190
|
};
|
|
176
191
|
/** `sb-<first label of the hostname>-auth-token`, the supabase-js default. */
|
|
177
192
|
function sessionCookieName(url) {
|
|
178
|
-
|
|
193
|
+
let name = cookieNames.get(url);
|
|
194
|
+
if (name === void 0) {
|
|
195
|
+
name = `sb-${new URL(url).hostname.split(".")[0] ?? ""}-auth-token`;
|
|
196
|
+
if (cookieNames.size < 16) cookieNames.set(url, name);
|
|
197
|
+
}
|
|
198
|
+
return name;
|
|
179
199
|
}
|
|
200
|
+
/** Project URLs come from configuration, so a handful of entries suffice. */
|
|
201
|
+
const cookieNames = /* @__PURE__ */ new Map();
|
|
180
202
|
function parseCookies(header) {
|
|
181
203
|
return header ? parseCookieHeader(header) : [];
|
|
182
204
|
}
|
|
@@ -297,8 +319,31 @@ function remembered(memo, token, now) {
|
|
|
297
319
|
memo.set(token, hit);
|
|
298
320
|
return hit;
|
|
299
321
|
}
|
|
300
|
-
|
|
301
|
-
|
|
322
|
+
const NO_SCHEMA = {};
|
|
323
|
+
const checkedByMemo = /* @__PURE__ */ new WeakMap();
|
|
324
|
+
/**
|
|
325
|
+
* Tokens that already passed (or failed) the claims and `userMetadata`
|
|
326
|
+
* schemas, per verification memo and schema pair, so a memo hit skips
|
|
327
|
+
* validation too.
|
|
328
|
+
*/
|
|
329
|
+
function checkedFor(memo, options) {
|
|
330
|
+
const claims = options.claims ?? NO_SCHEMA;
|
|
331
|
+
const metadata = options.userMetadata ?? NO_SCHEMA;
|
|
332
|
+
let byClaims = checkedByMemo.get(memo);
|
|
333
|
+
if (!byClaims) checkedByMemo.set(memo, byClaims = /* @__PURE__ */ new WeakMap());
|
|
334
|
+
let byMetadata = byClaims.get(claims);
|
|
335
|
+
if (!byMetadata) byClaims.set(claims, byMetadata = /* @__PURE__ */ new WeakMap());
|
|
336
|
+
let checked = byMetadata.get(metadata);
|
|
337
|
+
if (!checked) byMetadata.set(metadata, checked = /* @__PURE__ */ new Map());
|
|
338
|
+
return checked;
|
|
339
|
+
}
|
|
340
|
+
function withoutSource(state) {
|
|
341
|
+
if (state.kind !== "user") return state;
|
|
342
|
+
const { source: _source, ...rest } = state;
|
|
343
|
+
return rest;
|
|
344
|
+
}
|
|
345
|
+
function remember(memo, token, user, expiresAt) {
|
|
346
|
+
if (expiresAt === null) return;
|
|
302
347
|
memo.set(token, user);
|
|
303
348
|
if (memo.size > MEMO_SIZE) memo.delete(memo.keys().next().value);
|
|
304
349
|
}
|
|
@@ -307,10 +352,20 @@ async function verify(credentials, modes, options, source) {
|
|
|
307
352
|
const memo = token ? memoFor(options) : void 0;
|
|
308
353
|
if (token && memo) {
|
|
309
354
|
const hit = remembered(memo, token, Math.floor((options.now ?? Date.now)() / 1e3));
|
|
310
|
-
if (hit)
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
355
|
+
if (hit) {
|
|
356
|
+
const checked = checkedFor(memo, options);
|
|
357
|
+
const known = checked.get(token);
|
|
358
|
+
if (known) return known.kind === "user" ? {
|
|
359
|
+
...known,
|
|
360
|
+
source
|
|
361
|
+
} : known;
|
|
362
|
+
const state = await checkUser({
|
|
363
|
+
...hit,
|
|
364
|
+
source
|
|
365
|
+
}, options);
|
|
366
|
+
remember(checked, token, withoutSource(state), hit.expiresAt);
|
|
367
|
+
return state;
|
|
368
|
+
}
|
|
314
369
|
}
|
|
315
370
|
const state = await verifyOnce(credentials, modes, options, source);
|
|
316
371
|
if (token && memo && state.kind === "user") remember(memo, token, {
|
|
@@ -319,8 +374,10 @@ async function verify(credentials, modes, options, source) {
|
|
|
319
374
|
claims: state.claims,
|
|
320
375
|
user: state.user,
|
|
321
376
|
expiresAt: state.expiresAt
|
|
322
|
-
});
|
|
323
|
-
|
|
377
|
+
}, state.expiresAt);
|
|
378
|
+
const checked = await checkUser(state, options);
|
|
379
|
+
if (token && memo && state.kind === "user") remember(checkedFor(memo, options), token, withoutSource(checked), state.expiresAt);
|
|
380
|
+
return checked;
|
|
324
381
|
}
|
|
325
382
|
/** Validates a user's claims against `options.claims`, keeping every JWT claim. */
|
|
326
383
|
async function checkClaims(state, options) {
|
|
@@ -368,10 +425,34 @@ async function checkUser(state, options) {
|
|
|
368
425
|
};
|
|
369
426
|
if (!warnedMetadata.has(schema)) {
|
|
370
427
|
warnedMetadata.add(schema);
|
|
371
|
-
(options.logger ?? consoleLogger).warn("user_metadata does not match
|
|
428
|
+
(options.logger ?? consoleLogger).warn("user_metadata does not match betterSupabase.userMetadata(schema); session.profile is undefined", { paths: outcome.issues.map((issue) => issue.path?.map((segment) => typeof segment === "object" ? String(segment.key) : String(segment)).join(".") ?? "") });
|
|
372
429
|
}
|
|
373
430
|
return user;
|
|
374
431
|
}
|
|
432
|
+
/** A token whose `kid` matches no key: verifying it loads the JWKS and fails. */
|
|
433
|
+
const PREFETCH_TOKEN = `${base64url(JSON.stringify({
|
|
434
|
+
alg: "ES256",
|
|
435
|
+
kid: "better-supabase-prefetch",
|
|
436
|
+
typ: "JWT"
|
|
437
|
+
}))}.e30.AA`;
|
|
438
|
+
function base64url(text) {
|
|
439
|
+
return btoa(text).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Loads the remote JWKS into the verifier's cache so the first request
|
|
443
|
+
* doesn't wait for it. Never throws; a failure leaves the first request to
|
|
444
|
+
* fetch it as before.
|
|
445
|
+
*/
|
|
446
|
+
function prefetchJwks(options) {
|
|
447
|
+
if (options.jwks !== void 0) return Promise.resolve();
|
|
448
|
+
return verifyCredentials({
|
|
449
|
+
token: PREFETCH_TOKEN,
|
|
450
|
+
apikey: null
|
|
451
|
+
}, {
|
|
452
|
+
auth: ["user"],
|
|
453
|
+
env: serverEnv(options)
|
|
454
|
+
}).then(() => {}, () => {});
|
|
455
|
+
}
|
|
375
456
|
async function verifyOnce(credentials, modes, options, source) {
|
|
376
457
|
const { data, error } = await verifyCredentials(credentials, {
|
|
377
458
|
auth: modes,
|
|
@@ -406,11 +487,16 @@ async function verifyOnce(credentials, modes, options, source) {
|
|
|
406
487
|
}
|
|
407
488
|
function resolution(auth, cookies, writes = []) {
|
|
408
489
|
const headers = writes.length > 0 ? AUTH_CACHE_HEADERS : {};
|
|
490
|
+
let requestCookies;
|
|
409
491
|
return {
|
|
410
492
|
auth,
|
|
411
493
|
cookies: writes,
|
|
412
494
|
headers,
|
|
413
|
-
|
|
495
|
+
/** Parsed on first read: bearer requests rarely need their cookies. */
|
|
496
|
+
get requestCookies() {
|
|
497
|
+
requestCookies ??= writes.length > 0 ? applyCookieWrites(cookies(), writes) : cookies();
|
|
498
|
+
return requestCookies;
|
|
499
|
+
},
|
|
414
500
|
apply(response) {
|
|
415
501
|
if (writes.length === 0) return response;
|
|
416
502
|
let target = response;
|
|
@@ -440,7 +526,8 @@ function clientIp(request) {
|
|
|
440
526
|
* set, through a single-flight request, and only then are cookies written.
|
|
441
527
|
*/
|
|
442
528
|
async function resolveAuth(request, options) {
|
|
443
|
-
|
|
529
|
+
let parsed;
|
|
530
|
+
const cookies = () => parsed ??= parseCookies(request.headers.get("cookie"));
|
|
444
531
|
for (const resolver of options.resolvers ?? []) {
|
|
445
532
|
const state = await resolver.resolve(request);
|
|
446
533
|
if (!state) continue;
|
|
@@ -460,10 +547,10 @@ async function resolveAuth(request, options) {
|
|
|
460
547
|
apikey: credentials.apikey
|
|
461
548
|
}, options.secret === true ? ["secret"] : options.secret.map((name) => `secret:${name}`), options, "bearer"), cookies);
|
|
462
549
|
const name = options.cookie?.name ?? sessionCookieName(options.env.url);
|
|
463
|
-
const session = readSession(cookies, name);
|
|
550
|
+
const session = readSession(cookies(), name);
|
|
464
551
|
if (!session) {
|
|
465
|
-
const stale = cookies.some((cookie) => cookie.name === name || cookie.name.startsWith(`${name}.`));
|
|
466
|
-
const writes = stale && options.refresh ? writeSession(cookies, name, null, options.cookie?.options) : [];
|
|
552
|
+
const stale = cookies().some((cookie) => cookie.name === name || cookie.name.startsWith(`${name}.`));
|
|
553
|
+
const writes = stale && options.refresh ? writeSession(cookies(), name, null, options.cookie?.options) : [];
|
|
467
554
|
return resolution({
|
|
468
555
|
kind: "anon",
|
|
469
556
|
reason: stale ? "signed_out" : "none"
|
|
@@ -471,7 +558,8 @@ async function resolveAuth(request, options) {
|
|
|
471
558
|
}
|
|
472
559
|
const now = Math.floor((options.now ?? Date.now)() / 1e3);
|
|
473
560
|
const expiry = expiryOf(session);
|
|
474
|
-
|
|
561
|
+
const leeway = options.refresh ? options.leeway ?? 60 : 0;
|
|
562
|
+
if (expiry !== void 0 && expiry - leeway > now) {
|
|
475
563
|
const state = await verify({
|
|
476
564
|
token: session.access_token,
|
|
477
565
|
apikey: null
|
|
@@ -496,7 +584,8 @@ async function resolveAuth(request, options) {
|
|
|
496
584
|
secretKey
|
|
497
585
|
} } : {},
|
|
498
586
|
...options.fetch ? { fetch: options.fetch } : {},
|
|
499
|
-
...options.now ? { now: options.now } : {}
|
|
587
|
+
...options.now ? { now: options.now } : {},
|
|
588
|
+
...options.refreshTimeoutMs === void 0 ? {} : { timeoutMs: options.refreshTimeoutMs }
|
|
500
589
|
});
|
|
501
590
|
options.onRefresh?.({
|
|
502
591
|
ok: outcome.ok,
|
|
@@ -511,9 +600,9 @@ async function resolveAuth(request, options) {
|
|
|
511
600
|
return resolution({
|
|
512
601
|
kind: "anon",
|
|
513
602
|
reason: "signed_out"
|
|
514
|
-
}, cookies, writeSession(cookies, name, null, options.cookie?.options));
|
|
603
|
+
}, cookies, writeSession(cookies(), name, null, options.cookie?.options));
|
|
515
604
|
}
|
|
516
|
-
const writes = writeSession(cookies, name, outcome.session, options.cookie?.options);
|
|
605
|
+
const writes = writeSession(cookies(), name, outcome.session, options.cookie?.options);
|
|
517
606
|
return resolution(await verify({
|
|
518
607
|
token: outcome.session.access_token,
|
|
519
608
|
apikey: null
|
|
@@ -593,4 +682,4 @@ function checkAal(auth, required) {
|
|
|
593
682
|
});
|
|
594
683
|
}
|
|
595
684
|
//#endregion
|
|
596
|
-
export {
|
|
685
|
+
export { delegationOf as _, clientIp as a, AUTH_CACHE_HEADERS as c, readSession as d, serializeCookie as f, actorOf as g, refreshSession as h, authContext as i, applyCookieWrites as l, writeSession as m, amrOf as n, prefetchJwks as o, sessionCookieName as p, checkAal as r, resolveAuth as s, aalOf as t, parseCookies as u, actClaim as v, impersonatorOf as y };
|
package/dist/next/image/index.js
CHANGED
|
@@ -21,13 +21,16 @@ const clamp = (value, min, max) => Math.min(max, Math.max(min, Math.round(value)
|
|
|
21
21
|
*/
|
|
22
22
|
function createImageLoader(options) {
|
|
23
23
|
const storage = `${options.url.replace(/\/+$/, "")}/storage/v1`;
|
|
24
|
-
const publicPrefixes = [`${storage}/object/public/`, `${storage}/render/image/public/`]
|
|
24
|
+
const publicPrefixes = [`${storage}/object/public/`, `${storage}/render/image/public/`].map((prefix) => ({
|
|
25
|
+
prefix,
|
|
26
|
+
length: new URL(prefix).pathname.length
|
|
27
|
+
}));
|
|
25
28
|
const fallback = options.fallback ?? (({ src }) => src);
|
|
26
29
|
return (props) => {
|
|
27
|
-
const prefix = publicPrefixes.find((candidate) => props.src.startsWith(candidate));
|
|
30
|
+
const prefix = publicPrefixes.find((candidate) => props.src.startsWith(candidate.prefix));
|
|
28
31
|
if (prefix === void 0) return fallback(props);
|
|
29
32
|
const source = new URL(props.src);
|
|
30
|
-
const object = source.pathname.slice(
|
|
33
|
+
const object = source.pathname.slice(prefix.length);
|
|
31
34
|
const target = new URL(`${storage}/render/image/public/${object}`);
|
|
32
35
|
for (const [key, value] of source.searchParams) target.searchParams.set(key, value);
|
|
33
36
|
target.searchParams.set("width", String(clamp(props.width, 1, MAX_WIDTH)));
|
package/dist/next/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { n as AnyModels, t as AnyFunctions } from "../types-DONv9SHN.js";
|
|
2
|
-
import { p as DbError } from "../result-
|
|
3
|
-
import { B as ReadSet, P as DbStats, Z as QuerySpec, l as CacheAdapter, t as BetterSupabase } from "../define-
|
|
4
|
-
import { n as AmrEntry, s as Impersonator, t as Aal } from "../mfa-
|
|
5
|
-
import { r as AuthState } from "../resolve-
|
|
6
|
-
import { d as
|
|
7
|
-
import { n as toSession, t as AuthSession } from "../view-
|
|
8
|
-
import { r as LiveCountSeed, t as CountRunner } from "../live-
|
|
9
|
-
import { n as MembershipClaim, r as hasEntitlement, t as EntitlementKey } from "../entitlements-
|
|
2
|
+
import { p as DbError } from "../result-CqEsbgYs.js";
|
|
3
|
+
import { B as ReadSet, P as DbStats, Z as QuerySpec, l as CacheAdapter, t as BetterSupabase } from "../define-CRS2MRV3.js";
|
|
4
|
+
import { n as AmrEntry, s as Impersonator, t as Aal } from "../mfa-C7MNQ1Ob.js";
|
|
5
|
+
import { r as AuthState } from "../resolve-BAqQcwMW.js";
|
|
6
|
+
import { d as ContextOptions, f as ServerContext, n as GuardOptions, p as ServerOptions, t as AuthKind, u as BetterServer } from "../respond-DgIbdrt8.js";
|
|
7
|
+
import { n as toSession, t as AuthSession } from "../view-B64o81wp.js";
|
|
8
|
+
import { r as LiveCountSeed, t as CountRunner } from "../live-BHakSWWo.js";
|
|
9
|
+
import { n as MembershipClaim, r as hasEntitlement, t as EntitlementKey } from "../entitlements-Dm-FHpNH.js";
|
|
10
10
|
import { NextRequest } from "next/server.js";
|
|
11
11
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
12
12
|
//#region src/next/collector.d.ts
|
|
@@ -33,12 +33,12 @@ interface NextDebugOptions {
|
|
|
33
33
|
readonly header?: string;
|
|
34
34
|
/** Warns in development when one render goes over it. */
|
|
35
35
|
readonly budget?: DbBudget;
|
|
36
|
-
/** Where `
|
|
36
|
+
/** Where `bs.debugRoute()` is mounted. Defaults to `/api/bs-stats`. */
|
|
37
37
|
readonly route?: string;
|
|
38
38
|
}
|
|
39
|
-
/** Response header with the URL of the request's totals on `
|
|
39
|
+
/** Response header with the URL of the request's totals on `bs.debugRoute()`. */
|
|
40
40
|
export declare const STATS_URL_HEADER = "x-bs-stats";
|
|
41
|
-
interface ProxyOptions<C = unknown,
|
|
41
|
+
interface ProxyOptions<C = unknown, P = unknown> {
|
|
42
42
|
/**
|
|
43
43
|
* Another middleware to compose with, such as next-intl's. It runs on the
|
|
44
44
|
* original request, alongside auth; its rewrite, redirect or request
|
|
@@ -46,9 +46,9 @@ interface ProxyOptions<C = unknown, U = unknown> {
|
|
|
46
46
|
*/
|
|
47
47
|
readonly before?: (request: NextRequest) => Response | undefined | Promise<Response | undefined>;
|
|
48
48
|
/** Answer before rendering, e.g. redirect signed-out users. Refreshed cookies are kept. */
|
|
49
|
-
readonly protect?: (auth: AuthState<C,
|
|
49
|
+
readonly protect?: (auth: AuthState<C, P>, request: NextRequest) => Response | undefined | Promise<Response | undefined>;
|
|
50
50
|
/** Post-processes the final response; return a new one to replace it. */
|
|
51
|
-
readonly after?: (response: Response, auth: AuthState<C,
|
|
51
|
+
readonly after?: (response: Response, auth: AuthState<C, P>) => Response | undefined | void | Promise<Response | undefined | void>;
|
|
52
52
|
/**
|
|
53
53
|
* Adds `Server-Timing: bs-proxy;dur=..., bs-verify;dur=...` (ms): the whole
|
|
54
54
|
* proxy, and resolving the session (a local verify, or a refresh).
|
|
@@ -76,25 +76,28 @@ type Unwrapped<T> = T extends {
|
|
|
76
76
|
} | {
|
|
77
77
|
readonly ok: false;
|
|
78
78
|
} ? D : T;
|
|
79
|
-
interface BetterNext<M extends AnyModels, F extends AnyFunctions, E, C = unknown,
|
|
79
|
+
interface BetterNext<M extends AnyModels, F extends AnyFunctions, E, C = unknown, P = unknown> extends BetterServer<M, F, E, C, P> {
|
|
80
80
|
/** `proxy.ts`: refreshes sessions for page loads and server actions. */
|
|
81
|
-
proxy(request: NextRequest, options?: ProxyOptions<C,
|
|
82
|
-
/**
|
|
83
|
-
|
|
81
|
+
proxy(request: NextRequest, options?: ProxyOptions<C, P>): Promise<Response>;
|
|
82
|
+
/**
|
|
83
|
+
* The caller's context. Without a request (Server Components, actions) it
|
|
84
|
+
* reads the incoming headers and is memoized per request.
|
|
85
|
+
*/
|
|
86
|
+
context(request?: Request, options?: ContextOptions): Promise<ServerContext<M, F, E, C, P>>;
|
|
84
87
|
/**
|
|
85
88
|
* The verified caller as serializable data (no token, no clients), memoized
|
|
86
89
|
* per request. Wrap it in a `'use cache: private'` function with Cache
|
|
87
90
|
* Components and pass the promise to `<SessionProvider>`.
|
|
88
91
|
*/
|
|
89
|
-
session(): Promise<AuthSession<C,
|
|
92
|
+
session(): Promise<AuthSession<C, P>>;
|
|
90
93
|
/**
|
|
91
94
|
* The context for a session and its token, without reading the request.
|
|
92
95
|
* The token is verified again (memoized, no network call); a token for
|
|
93
96
|
* another user than `session` gives an `invalid` context.
|
|
94
97
|
*/
|
|
95
|
-
|
|
98
|
+
contextForSession(session: AuthSession<C, P>, options: {
|
|
96
99
|
readonly token: string | null;
|
|
97
|
-
}): Promise<ServerContext<M, F, E, C,
|
|
100
|
+
}): Promise<ServerContext<M, F, E, C, P>>;
|
|
98
101
|
/**
|
|
99
102
|
* First statement of an app-authored `'use cache: private'` function: sets
|
|
100
103
|
* `cacheLife` from the session's expiry (`sessionStale`, capped by
|
|
@@ -104,14 +107,14 @@ interface BetterNext<M extends AnyModels, F extends AnyFunctions, E, C = unknown
|
|
|
104
107
|
* ```ts
|
|
105
108
|
* async function getCustomers() {
|
|
106
109
|
* 'use cache: private';
|
|
107
|
-
* const { db } = await
|
|
110
|
+
* const { db } = await bs.cached();
|
|
108
111
|
* return db.customers.findMany().orThrow();
|
|
109
112
|
* }
|
|
110
113
|
* ```
|
|
111
114
|
*/
|
|
112
|
-
cached(options?: CachedOptions): Promise<CachedContext<M, F, E, C,
|
|
115
|
+
cached(options?: CachedOptions): Promise<CachedContext<M, F, E, C, P>>;
|
|
113
116
|
/**
|
|
114
|
-
* Drops every `
|
|
117
|
+
* Drops every `bs.cached()` entry of a user, e.g. after a role change,
|
|
115
118
|
* and the entries tagged with `tags` (such as PermDock's `snapshotTag(userId)`).
|
|
116
119
|
*/
|
|
117
120
|
invalidateSession(userId: string, options?: {
|
|
@@ -121,18 +124,18 @@ interface BetterNext<M extends AnyModels, F extends AnyFunctions, E, C = unknown
|
|
|
121
124
|
* Counts on the server and returns a serializable seed for
|
|
122
125
|
* `useLiveCount(seed)`, so the badge renders with a number and the client
|
|
123
126
|
* only refetches on changes. Pass `db` inside `'use cache: private'`
|
|
124
|
-
* (from `
|
|
127
|
+
* (from `bs.cached()`); otherwise it uses `bs.context()`. A failed
|
|
125
128
|
* count gives `count: null` instead of throwing.
|
|
126
129
|
*/
|
|
127
130
|
liveCount<T extends Extract<keyof M, string>>(spec: QuerySpec<T, "count", number>, db?: CountRunner): Promise<LiveCountSeed<T>>;
|
|
128
131
|
/** Route handler with auth, Result unwrapping and Problem Details errors. */
|
|
129
|
-
route<
|
|
130
|
-
readonly params:
|
|
132
|
+
route<Params = Record<string, string | string[]>>(handler: (request: NextRequest, ctx: ServerContext<M, F, E, C, P> & {
|
|
133
|
+
readonly params: Params;
|
|
131
134
|
}) => unknown, options?: GuardOptions): (request: NextRequest, segment: {
|
|
132
|
-
readonly params: Promise<
|
|
135
|
+
readonly params: Promise<Params>;
|
|
133
136
|
}) => Promise<Response>;
|
|
134
137
|
/** Server action returning a serializable `ActionResult`. */
|
|
135
|
-
action<S extends StandardSchemaV1 | undefined, T>(options: ActionOptions<S>, fn: (input: ActionParsed<S>, ctx: ServerContext<M, F, E, C,
|
|
138
|
+
action<S extends StandardSchemaV1 | undefined, T>(options: ActionOptions<S>, fn: (input: ActionParsed<S>, ctx: ServerContext<M, F, E, C, P>) => Promise<T> | T): (input: ActionInput<S>) => Promise<ActionResult<Unwrapped<Awaited<T>>>>;
|
|
136
139
|
/** Tags the current `"use cache"` scope with a table (and row) tag. */
|
|
137
140
|
cacheTag(table: Extract<keyof M, string>, id?: string | number): void;
|
|
138
141
|
/**
|
|
@@ -172,10 +175,10 @@ interface CachedOptions {
|
|
|
172
175
|
/** More `cacheTag`s for the entry, e.g. `snapshotTag(sub)` or `org:<id>`. */
|
|
173
176
|
readonly tags?: readonly string[];
|
|
174
177
|
}
|
|
175
|
-
type CachedContext<M extends AnyModels, F extends AnyFunctions, E, C = unknown,
|
|
176
|
-
readonly session: AuthSession<C,
|
|
178
|
+
type CachedContext<M extends AnyModels, F extends AnyFunctions, E, C = unknown, P = unknown> = ServerContext<M, F, E, C, P> & {
|
|
179
|
+
readonly session: AuthSession<C, P>;
|
|
177
180
|
};
|
|
178
|
-
/** The tag `
|
|
181
|
+
/** The tag `bs.cached()` puts on a user's entries. */
|
|
179
182
|
export declare function sessionTag(userId: string): string;
|
|
180
183
|
/** `bs:<table>` or `bs:<table>:<id>`. Mutations invalidate both. */
|
|
181
184
|
export declare function tagFor(table: string, id?: string | number): string;
|
|
@@ -202,7 +205,7 @@ interface RequireAalOptions {
|
|
|
202
205
|
* combine it with your sign-in redirect.
|
|
203
206
|
*
|
|
204
207
|
* ```ts
|
|
205
|
-
*
|
|
208
|
+
* bs.proxy(request, {
|
|
206
209
|
* protect: requireAal('aal2', { redirect: '/mfa', match: (path) => path.startsWith('/settings') }),
|
|
207
210
|
* });
|
|
208
211
|
* ```
|
|
@@ -215,9 +218,9 @@ export declare function shouldRefresh(request: Request): boolean;
|
|
|
215
218
|
* actions and cache tags, on top of `createServer`.
|
|
216
219
|
*
|
|
217
220
|
* ```ts
|
|
218
|
-
* export const
|
|
221
|
+
* export const bs = createNext(betterSupabase);
|
|
219
222
|
* ```
|
|
220
223
|
*/
|
|
221
|
-
export declare function createNext<M extends AnyModels, D, F extends AnyFunctions, E, C = unknown,
|
|
224
|
+
export declare function createNext<M extends AnyModels, D, F extends AnyFunctions, E, C = unknown, P = unknown>(betterSupabase: BetterSupabase<M, D, F, E, C, P>, options?: NextOptions): BetterNext<M, F, E, C, P>;
|
|
222
225
|
//#endregion
|
|
223
|
-
export { type Aal, type ActionOptions, type ActionResult, type AmrEntry, type AuthKind, type AuthSession, type BetterNext, type CachedContext, type CachedOptions, type DbBudget, type DbStats, type EntitlementKey, type GuardOptions, type Impersonator, type MembershipClaim, type NextDebugOptions, type NextOptions, type ProxyOptions, type RequireAalOptions, type SessionStaleOptions, hasEntitlement, toSession };
|
|
226
|
+
export { type Aal, type ActionOptions, type ActionResult, type AmrEntry, type AuthKind, type AuthSession, type BetterNext, type CachedContext, type CachedOptions, type DbBudget, type DbStats, type EntitlementKey, type GuardOptions, type Impersonator, type LiveCountSeed, type MembershipClaim, type NextDebugOptions, type NextOptions, type ProxyOptions, type RequireAalOptions, type SessionStaleOptions, hasEntitlement, toSession };
|
package/dist/next/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { n as dbError } from "../errors-
|
|
2
|
-
import { n as StatsRecorder, t as EMPTY_STATS } from "../stats-
|
|
3
|
-
import { o as isReadSet } from "../read-set-
|
|
4
|
-
import { t as validate } from "../standard-
|
|
5
|
-
import { a as problemResponse } from "../problem-
|
|
1
|
+
import { n as dbError } from "../errors-L0xK41y_.js";
|
|
2
|
+
import { n as StatsRecorder, t as EMPTY_STATS } from "../stats-C_YxA2r1.js";
|
|
3
|
+
import { o as isReadSet } from "../read-set-FWK8qQ58.js";
|
|
4
|
+
import { t as validate } from "../standard-BRyBGTtp.js";
|
|
5
|
+
import { a as problemResponse } from "../problem-BihjPR0t.js";
|
|
6
6
|
import { t as isList } from "../guards-BnzDvFrz.js";
|
|
7
7
|
import { t as hasEntitlement } from "../entitlements-CTEBm7IB.js";
|
|
8
|
-
import { a as
|
|
9
|
-
import { r as checkAal } from "../mfa-
|
|
10
|
-
import { t as toSession } from "../view-
|
|
8
|
+
import { a as guard, c as settle, d as primaryCookie, i as defaultExpose, n as extendServer, r as withExtra, s as respond, t as createServer, u as PRIMARY_COOKIE } from "../server-BA75B0mT.js";
|
|
9
|
+
import { r as checkAal } from "../mfa-byfjruR9.js";
|
|
10
|
+
import { t as toSession } from "../view-BrJI2LKp.js";
|
|
11
11
|
import { cache } from "react";
|
|
12
12
|
import { cacheLife, cacheTag, revalidateTag, updateTag } from "next/cache.js";
|
|
13
13
|
import { cookies, headers } from "next/headers.js";
|
|
@@ -143,7 +143,7 @@ function serverTimingValue(metrics) {
|
|
|
143
143
|
}
|
|
144
144
|
//#endregion
|
|
145
145
|
//#region src/next/create.ts
|
|
146
|
-
/** Response header with the URL of the request's totals on `
|
|
146
|
+
/** Response header with the URL of the request's totals on `bs.debugRoute()`. */
|
|
147
147
|
const STATS_URL_HEADER = "x-bs-stats";
|
|
148
148
|
/**
|
|
149
149
|
* `cacheLife` `stale` seconds for a view of `session`: `max`, but never past
|
|
@@ -156,7 +156,7 @@ function sessionStale(session, options = {}, now = Date.now()) {
|
|
|
156
156
|
const remaining = session.expiresAt - Math.floor(now / 1e3);
|
|
157
157
|
return Math.min(max, Math.max(min, remaining));
|
|
158
158
|
}
|
|
159
|
-
/** The tag `
|
|
159
|
+
/** The tag `bs.cached()` puts on a user's entries. */
|
|
160
160
|
function sessionTag(userId) {
|
|
161
161
|
return `bs:session:${userId}`;
|
|
162
162
|
}
|
|
@@ -202,7 +202,7 @@ function formDataObject(form) {
|
|
|
202
202
|
* combine it with your sign-in redirect.
|
|
203
203
|
*
|
|
204
204
|
* ```ts
|
|
205
|
-
*
|
|
205
|
+
* bs.proxy(request, {
|
|
206
206
|
* protect: requireAal('aal2', { redirect: '/mfa', match: (path) => path.startsWith('/settings') }),
|
|
207
207
|
* });
|
|
208
208
|
* ```
|
|
@@ -235,20 +235,20 @@ function shouldRefresh(request) {
|
|
|
235
235
|
* actions and cache tags, on top of `createServer`.
|
|
236
236
|
*
|
|
237
237
|
* ```ts
|
|
238
|
-
* export const
|
|
238
|
+
* export const bs = createNext(betterSupabase);
|
|
239
239
|
* ```
|
|
240
240
|
*/
|
|
241
|
-
function createNext(
|
|
242
|
-
const base = createServer(
|
|
241
|
+
function createNext(betterSupabase, options = {}) {
|
|
242
|
+
const base = createServer(betterSupabase, options);
|
|
243
243
|
const pinMs = options.replicas?.pinMs ?? 5e3;
|
|
244
244
|
const expose = options.exposeErrors ?? defaultExpose();
|
|
245
|
-
if (options.cacheTags !== false)
|
|
245
|
+
if (options.cacheTags !== false) betterSupabase.cache(nextCache());
|
|
246
246
|
const debug = options.debug;
|
|
247
247
|
const statsHeader = debug?.header ?? "x-bs-db-calls";
|
|
248
248
|
const statsRoute = debug?.route ?? "/api/bs-stats";
|
|
249
249
|
const development = process.env["NODE_ENV"] === "development";
|
|
250
250
|
const collector = debug?.enabled ? sharedCollector({
|
|
251
|
-
logger:
|
|
251
|
+
logger: betterSupabase.events.logger,
|
|
252
252
|
warn: development,
|
|
253
253
|
...debug.budget ? { budget: debug.budget } : {}
|
|
254
254
|
}) : void 0;
|
|
@@ -257,34 +257,42 @@ function createNext(sb, options = {}) {
|
|
|
257
257
|
return id ? { stats: collector.recorderFor(id) } : {};
|
|
258
258
|
};
|
|
259
259
|
const incomingRequest = async () => new Request("http://next.local/", { headers: new Headers(await headers()) });
|
|
260
|
-
|
|
260
|
+
/** One token verification per render scope backs `context()`, `session()` and `cached()`. */
|
|
261
|
+
const incoming = cache(async () => {
|
|
261
262
|
const request = await incomingRequest();
|
|
262
|
-
return
|
|
263
|
+
return {
|
|
264
|
+
request,
|
|
265
|
+
resolution: await base.resolve(request, { refresh: false })
|
|
266
|
+
};
|
|
263
267
|
});
|
|
264
|
-
const
|
|
265
|
-
const resolution = await
|
|
266
|
-
return
|
|
268
|
+
const current = cache(async () => {
|
|
269
|
+
const { request, resolution } = await incoming();
|
|
270
|
+
return base.contextFromResolution(resolution, request, statsFor(request));
|
|
267
271
|
});
|
|
268
|
-
const
|
|
272
|
+
const context = (request, contextOptions) => request ? base.context(request, contextOptions) : current();
|
|
273
|
+
const session = cache(async () => toSession((await incoming()).resolution.auth));
|
|
274
|
+
const contextForSession = async (view, { token }) => {
|
|
269
275
|
const request = new Request("http://next.local/", { headers: token ? { authorization: `Bearer ${token}` } : {} });
|
|
270
276
|
const ctx = await base.context(request);
|
|
271
277
|
if (ctx.auth.kind === "user" ? view.kind === "user" && view.user.id === ctx.auth.user.id : view.kind !== "user") return ctx;
|
|
272
278
|
return base.contextFor({
|
|
273
279
|
kind: "invalid",
|
|
274
280
|
reason: "token",
|
|
275
|
-
error: dbError("unauthorized", "The token does not belong to the session passed to
|
|
281
|
+
error: dbError("unauthorized", "The token does not belong to the session passed to contextForSession()")
|
|
276
282
|
});
|
|
277
283
|
};
|
|
278
|
-
const withAccounts = withExtra(base, {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
284
|
+
const withAccounts = withExtra(base, {
|
|
285
|
+
context,
|
|
286
|
+
deleteAccount: ((userId, deleteOptions) => base.deleteAccount(userId, deleteOptions).map((result) => {
|
|
287
|
+
invalidate(sessionTag(userId));
|
|
288
|
+
return result;
|
|
289
|
+
}))
|
|
290
|
+
});
|
|
282
291
|
return extendServer(withAccounts, {
|
|
283
|
-
server,
|
|
284
292
|
session,
|
|
285
|
-
|
|
293
|
+
contextForSession,
|
|
286
294
|
async cached(cachedOptions = {}) {
|
|
287
|
-
const [view, ctx] = await Promise.all([session(),
|
|
295
|
+
const [view, ctx] = await Promise.all([session(), current()]);
|
|
288
296
|
const life = cachedOptions.life;
|
|
289
297
|
const stale = sessionStale(view, life);
|
|
290
298
|
cacheLife({
|
|
@@ -301,7 +309,7 @@ function createNext(sb, options = {}) {
|
|
|
301
309
|
for (const tag of invalidateOptions.tags ?? []) invalidate(tag);
|
|
302
310
|
},
|
|
303
311
|
async liveCount(spec, db) {
|
|
304
|
-
const result = await (db ?? (await
|
|
312
|
+
const result = await (db ?? (await current()).db).$run(spec);
|
|
305
313
|
return {
|
|
306
314
|
spec,
|
|
307
315
|
count: result.ok && typeof result.data === "number" ? result.data : null
|
|
@@ -378,7 +386,7 @@ function createNext(sb, options = {}) {
|
|
|
378
386
|
},
|
|
379
387
|
action(actionOptions, fn) {
|
|
380
388
|
return async (input) => {
|
|
381
|
-
const ctx = await
|
|
389
|
+
const ctx = await current();
|
|
382
390
|
const denied = guard(ctx.auth, actionOptions.allow, actionOptions.aal, actionOptions.scopes);
|
|
383
391
|
if (denied) return {
|
|
384
392
|
ok: false,
|
|
@@ -420,7 +428,7 @@ function createNext(sb, options = {}) {
|
|
|
420
428
|
const specs = isReadSet(target) ? Object.values(target.specs) : isList(target) ? target : [target];
|
|
421
429
|
const tags = /* @__PURE__ */ new Set();
|
|
422
430
|
for (const spec of specs) {
|
|
423
|
-
for (const table of
|
|
431
|
+
for (const table of betterSupabase.tablesOf(spec)) tags.add(tagFor(table));
|
|
424
432
|
const [id] = spec.args;
|
|
425
433
|
if (spec.method === "findById" && (typeof id === "string" || typeof id === "number")) tags.add(tagFor(spec.table, id));
|
|
426
434
|
}
|
package/dist/openapi/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as ResourceOptions, i as ResourceOperation, n as OpenApiOptions, o as createOpenApi, r as PROBLEM_SCHEMA, t as OpenApiDocument } from "../index-
|
|
1
|
+
import { a as ResourceOptions, i as ResourceOperation, n as OpenApiOptions, o as createOpenApi, r as PROBLEM_SCHEMA, t as OpenApiDocument } from "../index-BhHEC04r.js";
|
|
2
2
|
export { OpenApiDocument, OpenApiOptions, PROBLEM_SCHEMA, ResourceOperation, ResourceOptions, createOpenApi };
|