@supacloud/lite 0.6.0 → 0.7.1
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/CHANGELOG.md +16 -0
- package/README.md +6 -2
- package/dist/cli.js +151 -48
- package/dist/index.js +118 -44
- package/dist/project-runtime.d.ts.map +1 -1
- package/dist/runtime/auth/handler.d.ts +6 -0
- package/dist/runtime/auth/handler.d.ts.map +1 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/jwt.d.ts +6 -0
- package/dist/runtime/jwt.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.1](https://github.com/zuohuadong/supacloud/compare/supacloud-lite-v0.7.0...supacloud-lite-v0.7.1) (2026-08-11)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **lite:** bound standalone subprocess collection ([#827](https://github.com/zuohuadong/supacloud/issues/827)) ([4c37c33](https://github.com/zuohuadong/supacloud/commit/4c37c3325391de11ff6224b0297eb211a3627f5a))
|
|
9
|
+
* **lite:** guard db reset on uninitialized state ([#826](https://github.com/zuohuadong/supacloud/issues/826)) ([1e45f5f](https://github.com/zuohuadong/supacloud/commit/1e45f5fdd0cda0dbe238043526eb8d5ab8ebf1e1))
|
|
10
|
+
* **lite:** keep project API keys stable ([#817](https://github.com/zuohuadong/supacloud/issues/817)) ([80c5818](https://github.com/zuohuadong/supacloud/commit/80c581846a91654268af2b745f9a7d3d01ab8d5e))
|
|
11
|
+
|
|
12
|
+
## [0.7.0](https://github.com/zuohuadong/supacloud/compare/supacloud-lite-v0.6.0...supacloud-lite-v0.7.0) (2026-08-11)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* **lite:** support admin magic link verification ([#788](https://github.com/zuohuadong/supacloud/issues/788)) ([97defa0](https://github.com/zuohuadong/supacloud/commit/97defa0e3ba875d1bd0363f9f64df02a089238ff))
|
|
18
|
+
|
|
3
19
|
## [0.6.0](https://github.com/zuohuadong/supacloud/compare/supacloud-lite-v0.5.10...supacloud-lite-v0.6.0) (2026-08-11)
|
|
4
20
|
|
|
5
21
|
|
package/README.md
CHANGED
|
@@ -109,6 +109,8 @@ supacloud-lite inspect
|
|
|
109
109
|
supacloud-lite version
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
+
首次初始化或 state 目录不存在/为空时,先运行 `supacloud-lite migrate`。`db reset` 只接受已经初始化且保留有效 `secrets.json` 标记的 state;它不会为 reset 创建或覆盖项目 secrets。
|
|
113
|
+
|
|
112
114
|
通用参数:
|
|
113
115
|
|
|
114
116
|
- `--project-dir`:包含 `supabase/` 的项目目录
|
|
@@ -257,7 +259,7 @@ RLS 表的 Realtime DELETE 无法在行删除后安全重放 SELECT policy,因
|
|
|
257
259
|
应用代码、SQL migrations、RLS policy、Storage 调用和 Realtime 订阅可以保持原来的 Supabase 形状。迁移时仍需验证以下边界:
|
|
258
260
|
|
|
259
261
|
1. 把现有 `supabase/migrations`、`config.toml`、Functions 和 seed 文件带到 Lite 项目。
|
|
260
|
-
2.
|
|
262
|
+
2. 先用 `supacloud-lite migrate` 初始化空 state 并重放 schema;只有在已初始化的可丢弃 state 上需要再次重放时才使用 `supacloud-lite db reset`,然后导入业务数据。
|
|
261
263
|
3. 对使用 PGlite 未提供扩展或 PostgREST 高级语法的 SQL/API 做替代处理。
|
|
262
264
|
4. 通过真实 `@supabase/supabase-js` 集成测试验证关键查询、RLS、Storage 和 Realtime。
|
|
263
265
|
|
|
@@ -441,6 +443,8 @@ supacloud-lite inspect
|
|
|
441
443
|
supacloud-lite version
|
|
442
444
|
```
|
|
443
445
|
|
|
446
|
+
Run `supacloud-lite migrate` first when initializing a project or when the state directory is missing or empty. `db reset` only accepts initialized state with a valid `secrets.json` marker; it never creates or replaces project secrets for a reset.
|
|
447
|
+
|
|
444
448
|
Common flags:
|
|
445
449
|
|
|
446
450
|
- `--project-dir`: the project directory containing `supabase/`
|
|
@@ -589,7 +593,7 @@ Realtime DELETE on RLS tables cannot safely replay SELECT policies after a row i
|
|
|
589
593
|
Application code, SQL migrations, RLS policies, Storage calls, and Realtime subscriptions can keep their original Supabase shape. When migrating, you still need to validate the following boundaries:
|
|
590
594
|
|
|
591
595
|
1. Bring the existing `supabase/migrations`, `config.toml`, Functions, and seed files into the Lite project.
|
|
592
|
-
2. Use `supacloud-lite
|
|
596
|
+
2. Use `supacloud-lite migrate` to initialize empty state and replay the schema. Use `supacloud-lite db reset` only when replaying an already initialized disposable state, then import business data.
|
|
593
597
|
3. Provide alternatives for SQL/API that use extensions not offered by PGlite or advanced PostgREST syntax.
|
|
594
598
|
4. Verify key queries, RLS, Storage, and Realtime through real `@supabase/supabase-js` integration tests.
|
|
595
599
|
|
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import { dirname as dirname5, join as join9, resolve as resolve4 } from "path";
|
|
|
8
8
|
// package.json
|
|
9
9
|
var package_default = {
|
|
10
10
|
name: "@supacloud/lite",
|
|
11
|
-
version: "0.
|
|
11
|
+
version: "0.7.1",
|
|
12
12
|
description: "Bun-native, single-project Supabase-compatible backend powered by PGlite",
|
|
13
13
|
type: "module",
|
|
14
14
|
license: "Apache-2.0",
|
|
@@ -83,6 +83,8 @@ var package_default = {
|
|
|
83
83
|
// src/runtime/jwt.ts
|
|
84
84
|
var encoder = new TextEncoder;
|
|
85
85
|
var decoder = new TextDecoder;
|
|
86
|
+
var PROJECT_API_KEY_ISSUED_AT = 1641769200;
|
|
87
|
+
var PROJECT_API_KEY_EXPIRES_AT = 4102444800;
|
|
86
88
|
function bytesToBase64Url(bytes) {
|
|
87
89
|
let binary = "";
|
|
88
90
|
const chunk = 32768;
|
|
@@ -111,6 +113,18 @@ async function signJwt(claims, secret) {
|
|
|
111
113
|
const sig = await crypto.subtle.sign("HMAC", key, encoder.encode(data));
|
|
112
114
|
return `${data}.${bytesToBase64Url(new Uint8Array(sig))}`;
|
|
113
115
|
}
|
|
116
|
+
async function mintProjectApiKeys(jwtSecret) {
|
|
117
|
+
const commonClaims = {
|
|
118
|
+
iss: "supabase",
|
|
119
|
+
ref: "local",
|
|
120
|
+
iat: PROJECT_API_KEY_ISSUED_AT,
|
|
121
|
+
exp: PROJECT_API_KEY_EXPIRES_AT
|
|
122
|
+
};
|
|
123
|
+
return {
|
|
124
|
+
anonKey: await signJwt({ ...commonClaims, role: "anon" }, jwtSecret),
|
|
125
|
+
serviceRoleKey: await signJwt({ ...commonClaims, role: "service_role" }, jwtSecret)
|
|
126
|
+
};
|
|
127
|
+
}
|
|
114
128
|
async function verifyJwt(token, secret) {
|
|
115
129
|
const parts = token.split(".");
|
|
116
130
|
if (parts.length !== 3)
|
|
@@ -1112,6 +1126,10 @@ function randomOtp(length) {
|
|
|
1112
1126
|
}
|
|
1113
1127
|
return code;
|
|
1114
1128
|
}
|
|
1129
|
+
async function sha256Hex(value) {
|
|
1130
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
|
|
1131
|
+
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
1132
|
+
}
|
|
1115
1133
|
function normalizePhone(value) {
|
|
1116
1134
|
if (typeof value !== "string")
|
|
1117
1135
|
return null;
|
|
@@ -1650,33 +1668,58 @@ Or sign in with this link: ${link}`
|
|
|
1650
1668
|
}
|
|
1651
1669
|
static MAX_OTP_ATTEMPTS = 5;
|
|
1652
1670
|
async redeem(token, types, email) {
|
|
1653
|
-
const
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
await this.db.query(`delete from auth.one_time_tokens where email = $1 and attempts >= $2`, [normalizedEmail, AuthHandler.MAX_OTP_ATTEMPTS]);
|
|
1665
|
-
}
|
|
1671
|
+
const redemption = {
|
|
1672
|
+
token,
|
|
1673
|
+
tokenTypes: `{${types.join(",")}}`,
|
|
1674
|
+
email: email?.toLowerCase().trim() ?? null
|
|
1675
|
+
};
|
|
1676
|
+
return this.db.transaction((query) => this.claimEmailToken(query, redemption));
|
|
1677
|
+
}
|
|
1678
|
+
async claimEmailToken(query, redemption) {
|
|
1679
|
+
const candidate = await this.findEmailTokenCandidate(query, redemption);
|
|
1680
|
+
if (!candidate) {
|
|
1681
|
+
await this.recordFailedEmailTokenAttempt(query, redemption);
|
|
1666
1682
|
return null;
|
|
1667
1683
|
}
|
|
1668
|
-
await this.
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1684
|
+
const claimedToken = await this.lockAndDeleteEmailToken(query, candidate, redemption);
|
|
1685
|
+
return claimedToken ? this.confirmEmailTokenUser(query, claimedToken) : null;
|
|
1686
|
+
}
|
|
1687
|
+
async lockAndDeleteEmailToken(query, candidate, redemption) {
|
|
1688
|
+
await query(`select id from auth.users where id = $1 for update`, [candidate.user_id]);
|
|
1689
|
+
const claimedTokens = await query(`delete from auth.one_time_tokens
|
|
1690
|
+
where id = $1 and token = $2 and token_type = any($3::text[])
|
|
1691
|
+
and expires_at > now() and attempts < $4
|
|
1692
|
+
returning id, user_id, email`, [candidate.id, redemption.token, redemption.tokenTypes, AuthHandler.MAX_OTP_ATTEMPTS]);
|
|
1693
|
+
return claimedTokens.rows[0] ?? null;
|
|
1694
|
+
}
|
|
1695
|
+
async confirmEmailTokenUser(query, claimedToken) {
|
|
1696
|
+
await query(`delete from auth.one_time_tokens where email = $1`, [claimedToken.email]);
|
|
1697
|
+
const users = await query(`update auth.users set email_confirmed_at = coalesce(email_confirmed_at, now()), last_sign_in_at = now()
|
|
1698
|
+
where id = $1 returning *`, [claimedToken.user_id]);
|
|
1699
|
+
return users.rows[0] ?? null;
|
|
1700
|
+
}
|
|
1701
|
+
async findEmailTokenCandidate(query, redemption) {
|
|
1702
|
+
const candidates = await query(`select id, user_id, email from auth.one_time_tokens
|
|
1703
|
+
where token = $1 and token_type = any($2::text[])
|
|
1704
|
+
and ($3::text is null or email = $3) and expires_at > now()
|
|
1705
|
+
and attempts < $4`, [redemption.token, redemption.tokenTypes, redemption.email, AuthHandler.MAX_OTP_ATTEMPTS]);
|
|
1706
|
+
return candidates.rows[0] ?? null;
|
|
1707
|
+
}
|
|
1708
|
+
async recordFailedEmailTokenAttempt(query, redemption) {
|
|
1709
|
+
if (!redemption.email)
|
|
1710
|
+
return;
|
|
1711
|
+
await query(`update auth.one_time_tokens set attempts = attempts + 1
|
|
1712
|
+
where email = $1 and token_type = any($2::text[]) and expires_at > now()`, [redemption.email, redemption.tokenTypes]);
|
|
1713
|
+
await query(`delete from auth.one_time_tokens where email = $1 and attempts >= $2`, [redemption.email, AuthHandler.MAX_OTP_ATTEMPTS]);
|
|
1672
1714
|
}
|
|
1673
1715
|
async verifyToken(req) {
|
|
1674
1716
|
const body = await req.json().catch(() => ({}));
|
|
1675
|
-
|
|
1676
|
-
|
|
1717
|
+
const token = body.token ?? body.token_hash;
|
|
1718
|
+
if (!token)
|
|
1719
|
+
return authError(400, "validation_failed", "token or token_hash is required");
|
|
1677
1720
|
if (body.type === "sms" || body.phone !== undefined) {
|
|
1678
1721
|
const phone = normalizePhone(body.phone);
|
|
1679
|
-
if (body.type !== "sms" || !phone || !/^\d{6,10}$/.test(body.token)) {
|
|
1722
|
+
if (body.type !== "sms" || !phone || !body.token || !/^\d{6,10}$/.test(body.token)) {
|
|
1680
1723
|
return authError(400, "validation_failed", "phone, token, and type=sms are required");
|
|
1681
1724
|
}
|
|
1682
1725
|
const fingerprint = await keyedDigest(this.config.jwtSecret, "supacloud-lite:phone-fingerprint:v1", phone);
|
|
@@ -1695,7 +1738,7 @@ Or sign in with this link: ${link}`
|
|
|
1695
1738
|
return json(200, session);
|
|
1696
1739
|
}
|
|
1697
1740
|
const types = body.type === "recovery" ? ["recovery"] : body.type === "magiclink" ? ["magiclink"] : ["otp", "magiclink"];
|
|
1698
|
-
const user = await this.redeem(
|
|
1741
|
+
const user = await this.redeem(token, types, body.email);
|
|
1699
1742
|
if (!user)
|
|
1700
1743
|
return authError(403, "otp_expired", "Token has expired or is invalid");
|
|
1701
1744
|
return json(200, await this.sessionFor(user));
|
|
@@ -1753,6 +1796,9 @@ Or sign in with this link: ${link}`
|
|
|
1753
1796
|
}
|
|
1754
1797
|
const idMatch = path.match(/^admin\/users\/([0-9a-f-]{36})$/);
|
|
1755
1798
|
const exportMatch = path.match(/^admin\/users\/([0-9a-f-]{36})\/export$/);
|
|
1799
|
+
if (path === "admin/generate_link" && method === "POST") {
|
|
1800
|
+
return await this.generateAdminMagicLink(req);
|
|
1801
|
+
}
|
|
1756
1802
|
if (path === "admin/audit" && method === "GET") {
|
|
1757
1803
|
const res = await this.db.query(`select id, payload, created_at, ip_address from auth.audit_log_entries
|
|
1758
1804
|
order by created_at desc limit 200`);
|
|
@@ -1823,6 +1869,50 @@ Or sign in with this link: ${link}`
|
|
|
1823
1869
|
}
|
|
1824
1870
|
return authError(404, "not_found", `unknown admin endpoint`);
|
|
1825
1871
|
}
|
|
1872
|
+
async generateAdminMagicLink(req) {
|
|
1873
|
+
const body = await req.json().catch(() => ({}));
|
|
1874
|
+
if (body.type !== "magiclink") {
|
|
1875
|
+
return authError(422, "unsupported_link_type", "Only magiclink generation is supported");
|
|
1876
|
+
}
|
|
1877
|
+
if (!body.email)
|
|
1878
|
+
return authError(400, "validation_failed", "email is required");
|
|
1879
|
+
const email = body.email.toLowerCase().trim();
|
|
1880
|
+
const emailOtp = randomOtp(this.settings.otpLength);
|
|
1881
|
+
const hashedToken = await sha256Hex(randomToken(32));
|
|
1882
|
+
const expiry = `${this.settings.otpExpirySeconds} seconds`;
|
|
1883
|
+
const requestUrl = new URL(req.url);
|
|
1884
|
+
const redirectTo = resolveRedirect(requestUrl.searchParams.get("redirect_to") ?? body.redirect_to, this.config.siteUrl, this.config.uriAllowList, this.config.enforceRedirectAllowList);
|
|
1885
|
+
const user = await this.db.transaction(async (query) => {
|
|
1886
|
+
const result = await query(`insert into auth.users
|
|
1887
|
+
(aud, role, email, raw_app_meta_data, raw_user_meta_data)
|
|
1888
|
+
values ('authenticated', 'authenticated', $1, '{"provider":"email","providers":["email"]}', $2::jsonb)
|
|
1889
|
+
on conflict (email) do update set email = excluded.email
|
|
1890
|
+
returning *`, [email, JSON.stringify(body.data ?? {})]);
|
|
1891
|
+
const linkedUser = result.rows[0];
|
|
1892
|
+
await query(`insert into auth.identities (user_id, provider, provider_id, identity_data)
|
|
1893
|
+
values ($1::uuid, 'email', $1::text, $2::jsonb)
|
|
1894
|
+
on conflict (provider, provider_id) do nothing`, [linkedUser.id, JSON.stringify({ sub: linkedUser.id, email })]);
|
|
1895
|
+
await query(`delete from auth.one_time_tokens
|
|
1896
|
+
where email = $1 and token_type = any($2::text[])`, [email, "{otp,magiclink}"]);
|
|
1897
|
+
await query(`insert into auth.one_time_tokens (user_id, email, token_type, token, expires_at)
|
|
1898
|
+
values ($1, $2, 'otp', $3, now() + $5::interval),
|
|
1899
|
+
($1, $2, 'magiclink', $4, now() + $5::interval)`, [linkedUser.id, email, emailOtp, hashedToken, expiry]);
|
|
1900
|
+
return linkedUser;
|
|
1901
|
+
});
|
|
1902
|
+
const actionUrl = new URL(`${this.config.apiUrl}/auth/v1/verify`);
|
|
1903
|
+
actionUrl.searchParams.set("token", hashedToken);
|
|
1904
|
+
actionUrl.searchParams.set("type", "magiclink");
|
|
1905
|
+
actionUrl.searchParams.set("redirect_to", redirectTo);
|
|
1906
|
+
await this.audit("user_magiclink_requested", { actorId: user.id, actorEmail: email, type: "admin" });
|
|
1907
|
+
return json(200, {
|
|
1908
|
+
...this.userJson(user, [], await this.getUserIdentities(user.id)),
|
|
1909
|
+
action_link: actionUrl.toString(),
|
|
1910
|
+
email_otp: emailOtp,
|
|
1911
|
+
hashed_token: hashedToken,
|
|
1912
|
+
redirect_to: redirectTo,
|
|
1913
|
+
verification_type: "magiclink"
|
|
1914
|
+
});
|
|
1915
|
+
}
|
|
1826
1916
|
async audit(action, opts = {}) {
|
|
1827
1917
|
try {
|
|
1828
1918
|
const payload = {
|
|
@@ -4148,7 +4238,7 @@ class Database {
|
|
|
4148
4238
|
}
|
|
4149
4239
|
}
|
|
4150
4240
|
if (seedSql) {
|
|
4151
|
-
const hash = await
|
|
4241
|
+
const hash = await sha256Hex2(seedSql);
|
|
4152
4242
|
const seen = await this.engine.query(`select 1 from supabase_migrations.seed_files where path = 'supabase/seed.sql' and hash = $1`, [hash]);
|
|
4153
4243
|
if (seen.rows.length === 0) {
|
|
4154
4244
|
await this.engine.transaction(async (tx) => {
|
|
@@ -4441,7 +4531,7 @@ function quoteIdent(name) {
|
|
|
4441
4531
|
function quoteLiteral(value) {
|
|
4442
4532
|
return `'${value.replaceAll("'", "''")}'`;
|
|
4443
4533
|
}
|
|
4444
|
-
async function
|
|
4534
|
+
async function sha256Hex2(text) {
|
|
4445
4535
|
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));
|
|
4446
4536
|
return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
4447
4537
|
}
|
|
@@ -8514,10 +8604,7 @@ async function createBackend(config = {}) {
|
|
|
8514
8604
|
await failStartup(e);
|
|
8515
8605
|
}
|
|
8516
8606
|
const pgredis = await PgredisCache.create(db).catch(failStartup);
|
|
8517
|
-
const
|
|
8518
|
-
const tenYears = 10 * 365 * 24 * 3600;
|
|
8519
|
-
const anonKey = await signJwt({ iss: "supabase", ref: "local", role: "anon", iat: now, exp: now + tenYears }, jwtSecret);
|
|
8520
|
-
const serviceRoleKey = await signJwt({ iss: "supabase", ref: "local", role: "service_role", iat: now, exp: now + tenYears }, jwtSecret);
|
|
8607
|
+
const { anonKey, serviceRoleKey } = await mintProjectApiKeys(jwtSecret);
|
|
8521
8608
|
const exposedSchemas = [...new Set(config.dbSchemas ?? ["public", "pgmq_public"])];
|
|
8522
8609
|
const rest = new RestHandler(db, { exposedSchemas, maxRows: config.maxRows });
|
|
8523
8610
|
const exposed = isNetworkExposed(config.host);
|
|
@@ -9625,6 +9712,8 @@ class S3StorageDriver {
|
|
|
9625
9712
|
}
|
|
9626
9713
|
|
|
9627
9714
|
// src/project-runtime.ts
|
|
9715
|
+
var RESET_INITIALIZATION_ERROR = 'db reset requires initialized state; run "supacloud-lite migrate" first';
|
|
9716
|
+
var RESET_INVALID_SECRETS_ERROR = "db reset requires a valid project secrets marker; restore the state before retrying";
|
|
9628
9717
|
function resolveProjectPaths(options = {}) {
|
|
9629
9718
|
const projectDir = resolve2(options.projectDir ?? process.cwd());
|
|
9630
9719
|
const stateDir = resolvePath(projectDir, options.stateDir ?? process.env.SUPACLOUD_LITE_STATE_DIR ?? ".supacloud-lite");
|
|
@@ -9642,7 +9731,7 @@ async function assertResetPathsSafe(paths) {
|
|
|
9642
9731
|
const stateDir = resolve2(paths.stateDir);
|
|
9643
9732
|
if (stateDir === parse(stateDir).root)
|
|
9644
9733
|
throw new Error("refusing to use the filesystem root as the state directory");
|
|
9645
|
-
const stateInfo = await
|
|
9734
|
+
const stateInfo = await requiredResetEntry(stateDir);
|
|
9646
9735
|
if (!stateInfo.isDirectory() || stateInfo.isSymbolicLink()) {
|
|
9647
9736
|
throw new Error(`refusing to reset through an invalid state directory: ${stateDir}`);
|
|
9648
9737
|
}
|
|
@@ -9651,10 +9740,11 @@ async function assertResetPathsSafe(paths) {
|
|
|
9651
9740
|
if (secretsFile !== join7(stateDir, "secrets.json")) {
|
|
9652
9741
|
throw new Error(`refusing to reset a state directory with an invalid secrets marker path: ${secretsFile}`);
|
|
9653
9742
|
}
|
|
9654
|
-
const markerInfo = await
|
|
9743
|
+
const markerInfo = await requiredResetEntry(secretsFile);
|
|
9655
9744
|
if (!markerInfo.isFile() || markerInfo.isSymbolicLink()) {
|
|
9656
|
-
throw new Error(
|
|
9745
|
+
throw new Error(RESET_INVALID_SECRETS_ERROR);
|
|
9657
9746
|
}
|
|
9747
|
+
await assertResetSecretsValid(secretsFile);
|
|
9658
9748
|
const targets = [
|
|
9659
9749
|
...paths.dataDir ? [["database", paths.dataDir]] : [],
|
|
9660
9750
|
["storage", paths.storageDir]
|
|
@@ -9668,6 +9758,30 @@ async function assertResetPathsSafe(paths) {
|
|
|
9668
9758
|
await assertResetTargetCanonical(stateDir, canonicalStateDir, target, label);
|
|
9669
9759
|
}
|
|
9670
9760
|
}
|
|
9761
|
+
async function requiredResetEntry(path) {
|
|
9762
|
+
try {
|
|
9763
|
+
return await lstat(path);
|
|
9764
|
+
} catch (error) {
|
|
9765
|
+
if (error.code === "ENOENT")
|
|
9766
|
+
throw new Error(RESET_INITIALIZATION_ERROR);
|
|
9767
|
+
throw error;
|
|
9768
|
+
}
|
|
9769
|
+
}
|
|
9770
|
+
async function assertResetSecretsValid(path) {
|
|
9771
|
+
let serializedSecrets;
|
|
9772
|
+
try {
|
|
9773
|
+
serializedSecrets = await readFile6(path, "utf8");
|
|
9774
|
+
} catch (error) {
|
|
9775
|
+
if (error.code === "ENOENT")
|
|
9776
|
+
throw new Error(RESET_INITIALIZATION_ERROR);
|
|
9777
|
+
throw error;
|
|
9778
|
+
}
|
|
9779
|
+
try {
|
|
9780
|
+
validateSecrets(JSON.parse(serializedSecrets));
|
|
9781
|
+
} catch {
|
|
9782
|
+
throw new Error(RESET_INVALID_SECRETS_ERROR);
|
|
9783
|
+
}
|
|
9784
|
+
}
|
|
9671
9785
|
async function assertResetTargetCanonical(stateDir, canonicalStateDir, target, label) {
|
|
9672
9786
|
let current = target;
|
|
9673
9787
|
while (current !== stateDir) {
|
|
@@ -9750,13 +9864,7 @@ async function ensureProjectSecrets(paths) {
|
|
|
9750
9864
|
});
|
|
9751
9865
|
}
|
|
9752
9866
|
async function mintProjectKeys(jwtSecret) {
|
|
9753
|
-
|
|
9754
|
-
const exp = now + 10 * 365 * 24 * 3600;
|
|
9755
|
-
const common = { iss: "supabase", ref: "local", iat: now, exp };
|
|
9756
|
-
return {
|
|
9757
|
-
anonKey: await signJwt({ ...common, role: "anon" }, jwtSecret),
|
|
9758
|
-
serviceRoleKey: await signJwt({ ...common, role: "service_role" }, jwtSecret)
|
|
9759
|
-
};
|
|
9867
|
+
return await mintProjectApiKeys(jwtSecret);
|
|
9760
9868
|
}
|
|
9761
9869
|
async function createProjectBackend(options = {}) {
|
|
9762
9870
|
const paths = resolveProjectPaths(options);
|
|
@@ -9928,7 +10036,7 @@ async function findEphemeralPort(host = "127.0.0.1") {
|
|
|
9928
10036
|
}
|
|
9929
10037
|
|
|
9930
10038
|
// src/snapshot.ts
|
|
9931
|
-
import { chmod as chmod2, copyFile,
|
|
10039
|
+
import { chmod as chmod2, copyFile, lstat as lstat2, mkdir as mkdir6, mkdtemp, readdir as readdir3, readFile as readFile7, rename as rename2, rm as rm3, writeFile as writeFile5 } from "fs/promises";
|
|
9932
10040
|
import { dirname as dirname4, join as join8, parse as parse2, relative as relative2, resolve as resolve3, sep as sep2 } from "path";
|
|
9933
10041
|
import { create as createTar, extract as extractTar } from "tar";
|
|
9934
10042
|
var SNAPSHOT_FORMAT = "supacloud-lite-snapshot";
|
|
@@ -10153,14 +10261,7 @@ async function stageDirectory(root, destination) {
|
|
|
10153
10261
|
}
|
|
10154
10262
|
async function stageFile(source, target) {
|
|
10155
10263
|
await mkdir6(dirname4(target), { recursive: true });
|
|
10156
|
-
|
|
10157
|
-
await link2(source, target);
|
|
10158
|
-
} catch (error) {
|
|
10159
|
-
const code = error.code;
|
|
10160
|
-
if (code !== "EXDEV" && code !== "EPERM" && code !== "EACCES")
|
|
10161
|
-
throw error;
|
|
10162
|
-
await copyFile(source, target);
|
|
10163
|
-
}
|
|
10264
|
+
await copyFile(source, target);
|
|
10164
10265
|
}
|
|
10165
10266
|
async function readManifest(payloadRoot) {
|
|
10166
10267
|
let parsed;
|
|
@@ -10677,7 +10778,7 @@ Commands:
|
|
|
10677
10778
|
keys print the anon key
|
|
10678
10779
|
keys --service-role also print the privileged service_role key
|
|
10679
10780
|
gen types emit Supabase-shaped TypeScript database types
|
|
10680
|
-
db reset
|
|
10781
|
+
db reset reset initialized database/storage and re-run migrations
|
|
10681
10782
|
db diff print schema changes outside migrations
|
|
10682
10783
|
db pull [name] write live schema changes as an applied migration
|
|
10683
10784
|
snapshot create create a compressed database/storage/secrets snapshot
|
|
@@ -10686,6 +10787,8 @@ Commands:
|
|
|
10686
10787
|
inspect show table rows and sizes
|
|
10687
10788
|
version print the package version
|
|
10688
10789
|
|
|
10790
|
+
Fresh projects must run "supacloud-lite migrate" before "db reset".
|
|
10791
|
+
|
|
10689
10792
|
Options:
|
|
10690
10793
|
-p, --port <n> port (default 54321)
|
|
10691
10794
|
--host <host> bind host (default 127.0.0.1)
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,8 @@ var __require = import.meta.require;
|
|
|
4
4
|
// src/runtime/jwt.ts
|
|
5
5
|
var encoder = new TextEncoder;
|
|
6
6
|
var decoder = new TextDecoder;
|
|
7
|
+
var PROJECT_API_KEY_ISSUED_AT = 1641769200;
|
|
8
|
+
var PROJECT_API_KEY_EXPIRES_AT = 4102444800;
|
|
7
9
|
function bytesToBase64Url(bytes) {
|
|
8
10
|
let binary = "";
|
|
9
11
|
const chunk = 32768;
|
|
@@ -32,6 +34,18 @@ async function signJwt(claims, secret) {
|
|
|
32
34
|
const sig = await crypto.subtle.sign("HMAC", key, encoder.encode(data));
|
|
33
35
|
return `${data}.${bytesToBase64Url(new Uint8Array(sig))}`;
|
|
34
36
|
}
|
|
37
|
+
async function mintProjectApiKeys(jwtSecret) {
|
|
38
|
+
const commonClaims = {
|
|
39
|
+
iss: "supabase",
|
|
40
|
+
ref: "local",
|
|
41
|
+
iat: PROJECT_API_KEY_ISSUED_AT,
|
|
42
|
+
exp: PROJECT_API_KEY_EXPIRES_AT
|
|
43
|
+
};
|
|
44
|
+
return {
|
|
45
|
+
anonKey: await signJwt({ ...commonClaims, role: "anon" }, jwtSecret),
|
|
46
|
+
serviceRoleKey: await signJwt({ ...commonClaims, role: "service_role" }, jwtSecret)
|
|
47
|
+
};
|
|
48
|
+
}
|
|
35
49
|
async function verifyJwt(token, secret) {
|
|
36
50
|
const parts = token.split(".");
|
|
37
51
|
if (parts.length !== 3)
|
|
@@ -71,7 +85,7 @@ function randomToken(bytes = 32) {
|
|
|
71
85
|
// package.json
|
|
72
86
|
var package_default = {
|
|
73
87
|
name: "@supacloud/lite",
|
|
74
|
-
version: "0.
|
|
88
|
+
version: "0.7.1",
|
|
75
89
|
description: "Bun-native, single-project Supabase-compatible backend powered by PGlite",
|
|
76
90
|
type: "module",
|
|
77
91
|
license: "Apache-2.0",
|
|
@@ -1117,6 +1131,10 @@ function randomOtp(length) {
|
|
|
1117
1131
|
}
|
|
1118
1132
|
return code;
|
|
1119
1133
|
}
|
|
1134
|
+
async function sha256Hex(value) {
|
|
1135
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
|
|
1136
|
+
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
1137
|
+
}
|
|
1120
1138
|
function normalizePhone(value) {
|
|
1121
1139
|
if (typeof value !== "string")
|
|
1122
1140
|
return null;
|
|
@@ -1655,33 +1673,58 @@ Or sign in with this link: ${link}`
|
|
|
1655
1673
|
}
|
|
1656
1674
|
static MAX_OTP_ATTEMPTS = 5;
|
|
1657
1675
|
async redeem(token, types, email) {
|
|
1658
|
-
const
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
await this.db.query(`delete from auth.one_time_tokens where email = $1 and attempts >= $2`, [normalizedEmail, AuthHandler.MAX_OTP_ATTEMPTS]);
|
|
1670
|
-
}
|
|
1676
|
+
const redemption = {
|
|
1677
|
+
token,
|
|
1678
|
+
tokenTypes: `{${types.join(",")}}`,
|
|
1679
|
+
email: email?.toLowerCase().trim() ?? null
|
|
1680
|
+
};
|
|
1681
|
+
return this.db.transaction((query) => this.claimEmailToken(query, redemption));
|
|
1682
|
+
}
|
|
1683
|
+
async claimEmailToken(query, redemption) {
|
|
1684
|
+
const candidate = await this.findEmailTokenCandidate(query, redemption);
|
|
1685
|
+
if (!candidate) {
|
|
1686
|
+
await this.recordFailedEmailTokenAttempt(query, redemption);
|
|
1671
1687
|
return null;
|
|
1672
1688
|
}
|
|
1673
|
-
await this.
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1689
|
+
const claimedToken = await this.lockAndDeleteEmailToken(query, candidate, redemption);
|
|
1690
|
+
return claimedToken ? this.confirmEmailTokenUser(query, claimedToken) : null;
|
|
1691
|
+
}
|
|
1692
|
+
async lockAndDeleteEmailToken(query, candidate, redemption) {
|
|
1693
|
+
await query(`select id from auth.users where id = $1 for update`, [candidate.user_id]);
|
|
1694
|
+
const claimedTokens = await query(`delete from auth.one_time_tokens
|
|
1695
|
+
where id = $1 and token = $2 and token_type = any($3::text[])
|
|
1696
|
+
and expires_at > now() and attempts < $4
|
|
1697
|
+
returning id, user_id, email`, [candidate.id, redemption.token, redemption.tokenTypes, AuthHandler.MAX_OTP_ATTEMPTS]);
|
|
1698
|
+
return claimedTokens.rows[0] ?? null;
|
|
1699
|
+
}
|
|
1700
|
+
async confirmEmailTokenUser(query, claimedToken) {
|
|
1701
|
+
await query(`delete from auth.one_time_tokens where email = $1`, [claimedToken.email]);
|
|
1702
|
+
const users = await query(`update auth.users set email_confirmed_at = coalesce(email_confirmed_at, now()), last_sign_in_at = now()
|
|
1703
|
+
where id = $1 returning *`, [claimedToken.user_id]);
|
|
1704
|
+
return users.rows[0] ?? null;
|
|
1705
|
+
}
|
|
1706
|
+
async findEmailTokenCandidate(query, redemption) {
|
|
1707
|
+
const candidates = await query(`select id, user_id, email from auth.one_time_tokens
|
|
1708
|
+
where token = $1 and token_type = any($2::text[])
|
|
1709
|
+
and ($3::text is null or email = $3) and expires_at > now()
|
|
1710
|
+
and attempts < $4`, [redemption.token, redemption.tokenTypes, redemption.email, AuthHandler.MAX_OTP_ATTEMPTS]);
|
|
1711
|
+
return candidates.rows[0] ?? null;
|
|
1712
|
+
}
|
|
1713
|
+
async recordFailedEmailTokenAttempt(query, redemption) {
|
|
1714
|
+
if (!redemption.email)
|
|
1715
|
+
return;
|
|
1716
|
+
await query(`update auth.one_time_tokens set attempts = attempts + 1
|
|
1717
|
+
where email = $1 and token_type = any($2::text[]) and expires_at > now()`, [redemption.email, redemption.tokenTypes]);
|
|
1718
|
+
await query(`delete from auth.one_time_tokens where email = $1 and attempts >= $2`, [redemption.email, AuthHandler.MAX_OTP_ATTEMPTS]);
|
|
1677
1719
|
}
|
|
1678
1720
|
async verifyToken(req) {
|
|
1679
1721
|
const body = await req.json().catch(() => ({}));
|
|
1680
|
-
|
|
1681
|
-
|
|
1722
|
+
const token = body.token ?? body.token_hash;
|
|
1723
|
+
if (!token)
|
|
1724
|
+
return authError(400, "validation_failed", "token or token_hash is required");
|
|
1682
1725
|
if (body.type === "sms" || body.phone !== undefined) {
|
|
1683
1726
|
const phone = normalizePhone(body.phone);
|
|
1684
|
-
if (body.type !== "sms" || !phone || !/^\d{6,10}$/.test(body.token)) {
|
|
1727
|
+
if (body.type !== "sms" || !phone || !body.token || !/^\d{6,10}$/.test(body.token)) {
|
|
1685
1728
|
return authError(400, "validation_failed", "phone, token, and type=sms are required");
|
|
1686
1729
|
}
|
|
1687
1730
|
const fingerprint = await keyedDigest(this.config.jwtSecret, "supacloud-lite:phone-fingerprint:v1", phone);
|
|
@@ -1700,7 +1743,7 @@ Or sign in with this link: ${link}`
|
|
|
1700
1743
|
return json(200, session);
|
|
1701
1744
|
}
|
|
1702
1745
|
const types = body.type === "recovery" ? ["recovery"] : body.type === "magiclink" ? ["magiclink"] : ["otp", "magiclink"];
|
|
1703
|
-
const user = await this.redeem(
|
|
1746
|
+
const user = await this.redeem(token, types, body.email);
|
|
1704
1747
|
if (!user)
|
|
1705
1748
|
return authError(403, "otp_expired", "Token has expired or is invalid");
|
|
1706
1749
|
return json(200, await this.sessionFor(user));
|
|
@@ -1758,6 +1801,9 @@ Or sign in with this link: ${link}`
|
|
|
1758
1801
|
}
|
|
1759
1802
|
const idMatch = path.match(/^admin\/users\/([0-9a-f-]{36})$/);
|
|
1760
1803
|
const exportMatch = path.match(/^admin\/users\/([0-9a-f-]{36})\/export$/);
|
|
1804
|
+
if (path === "admin/generate_link" && method === "POST") {
|
|
1805
|
+
return await this.generateAdminMagicLink(req);
|
|
1806
|
+
}
|
|
1761
1807
|
if (path === "admin/audit" && method === "GET") {
|
|
1762
1808
|
const res = await this.db.query(`select id, payload, created_at, ip_address from auth.audit_log_entries
|
|
1763
1809
|
order by created_at desc limit 200`);
|
|
@@ -1828,6 +1874,50 @@ Or sign in with this link: ${link}`
|
|
|
1828
1874
|
}
|
|
1829
1875
|
return authError(404, "not_found", `unknown admin endpoint`);
|
|
1830
1876
|
}
|
|
1877
|
+
async generateAdminMagicLink(req) {
|
|
1878
|
+
const body = await req.json().catch(() => ({}));
|
|
1879
|
+
if (body.type !== "magiclink") {
|
|
1880
|
+
return authError(422, "unsupported_link_type", "Only magiclink generation is supported");
|
|
1881
|
+
}
|
|
1882
|
+
if (!body.email)
|
|
1883
|
+
return authError(400, "validation_failed", "email is required");
|
|
1884
|
+
const email = body.email.toLowerCase().trim();
|
|
1885
|
+
const emailOtp = randomOtp(this.settings.otpLength);
|
|
1886
|
+
const hashedToken = await sha256Hex(randomToken(32));
|
|
1887
|
+
const expiry = `${this.settings.otpExpirySeconds} seconds`;
|
|
1888
|
+
const requestUrl = new URL(req.url);
|
|
1889
|
+
const redirectTo = resolveRedirect(requestUrl.searchParams.get("redirect_to") ?? body.redirect_to, this.config.siteUrl, this.config.uriAllowList, this.config.enforceRedirectAllowList);
|
|
1890
|
+
const user = await this.db.transaction(async (query) => {
|
|
1891
|
+
const result = await query(`insert into auth.users
|
|
1892
|
+
(aud, role, email, raw_app_meta_data, raw_user_meta_data)
|
|
1893
|
+
values ('authenticated', 'authenticated', $1, '{"provider":"email","providers":["email"]}', $2::jsonb)
|
|
1894
|
+
on conflict (email) do update set email = excluded.email
|
|
1895
|
+
returning *`, [email, JSON.stringify(body.data ?? {})]);
|
|
1896
|
+
const linkedUser = result.rows[0];
|
|
1897
|
+
await query(`insert into auth.identities (user_id, provider, provider_id, identity_data)
|
|
1898
|
+
values ($1::uuid, 'email', $1::text, $2::jsonb)
|
|
1899
|
+
on conflict (provider, provider_id) do nothing`, [linkedUser.id, JSON.stringify({ sub: linkedUser.id, email })]);
|
|
1900
|
+
await query(`delete from auth.one_time_tokens
|
|
1901
|
+
where email = $1 and token_type = any($2::text[])`, [email, "{otp,magiclink}"]);
|
|
1902
|
+
await query(`insert into auth.one_time_tokens (user_id, email, token_type, token, expires_at)
|
|
1903
|
+
values ($1, $2, 'otp', $3, now() + $5::interval),
|
|
1904
|
+
($1, $2, 'magiclink', $4, now() + $5::interval)`, [linkedUser.id, email, emailOtp, hashedToken, expiry]);
|
|
1905
|
+
return linkedUser;
|
|
1906
|
+
});
|
|
1907
|
+
const actionUrl = new URL(`${this.config.apiUrl}/auth/v1/verify`);
|
|
1908
|
+
actionUrl.searchParams.set("token", hashedToken);
|
|
1909
|
+
actionUrl.searchParams.set("type", "magiclink");
|
|
1910
|
+
actionUrl.searchParams.set("redirect_to", redirectTo);
|
|
1911
|
+
await this.audit("user_magiclink_requested", { actorId: user.id, actorEmail: email, type: "admin" });
|
|
1912
|
+
return json(200, {
|
|
1913
|
+
...this.userJson(user, [], await this.getUserIdentities(user.id)),
|
|
1914
|
+
action_link: actionUrl.toString(),
|
|
1915
|
+
email_otp: emailOtp,
|
|
1916
|
+
hashed_token: hashedToken,
|
|
1917
|
+
redirect_to: redirectTo,
|
|
1918
|
+
verification_type: "magiclink"
|
|
1919
|
+
});
|
|
1920
|
+
}
|
|
1831
1921
|
async audit(action, opts = {}) {
|
|
1832
1922
|
try {
|
|
1833
1923
|
const payload = {
|
|
@@ -4153,7 +4243,7 @@ class Database {
|
|
|
4153
4243
|
}
|
|
4154
4244
|
}
|
|
4155
4245
|
if (seedSql) {
|
|
4156
|
-
const hash = await
|
|
4246
|
+
const hash = await sha256Hex2(seedSql);
|
|
4157
4247
|
const seen = await this.engine.query(`select 1 from supabase_migrations.seed_files where path = 'supabase/seed.sql' and hash = $1`, [hash]);
|
|
4158
4248
|
if (seen.rows.length === 0) {
|
|
4159
4249
|
await this.engine.transaction(async (tx) => {
|
|
@@ -4446,7 +4536,7 @@ function quoteIdent(name) {
|
|
|
4446
4536
|
function quoteLiteral(value) {
|
|
4447
4537
|
return `'${value.replaceAll("'", "''")}'`;
|
|
4448
4538
|
}
|
|
4449
|
-
async function
|
|
4539
|
+
async function sha256Hex2(text) {
|
|
4450
4540
|
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));
|
|
4451
4541
|
return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
4452
4542
|
}
|
|
@@ -8358,10 +8448,7 @@ async function createBackend(config = {}) {
|
|
|
8358
8448
|
await failStartup(e);
|
|
8359
8449
|
}
|
|
8360
8450
|
const pgredis = await PgredisCache.create(db).catch(failStartup);
|
|
8361
|
-
const
|
|
8362
|
-
const tenYears = 10 * 365 * 24 * 3600;
|
|
8363
|
-
const anonKey = await signJwt({ iss: "supabase", ref: "local", role: "anon", iat: now, exp: now + tenYears }, jwtSecret);
|
|
8364
|
-
const serviceRoleKey = await signJwt({ iss: "supabase", ref: "local", role: "service_role", iat: now, exp: now + tenYears }, jwtSecret);
|
|
8451
|
+
const { anonKey, serviceRoleKey } = await mintProjectApiKeys(jwtSecret);
|
|
8365
8452
|
const exposedSchemas = [...new Set(config.dbSchemas ?? ["public", "pgmq_public"])];
|
|
8366
8453
|
const rest = new RestHandler(db, { exposedSchemas, maxRows: config.maxRows });
|
|
8367
8454
|
const exposed = isNetworkExposed(config.host);
|
|
@@ -9434,13 +9521,7 @@ async function ensureProjectSecrets(paths) {
|
|
|
9434
9521
|
});
|
|
9435
9522
|
}
|
|
9436
9523
|
async function mintProjectKeys(jwtSecret) {
|
|
9437
|
-
|
|
9438
|
-
const exp = now + 10 * 365 * 24 * 3600;
|
|
9439
|
-
const common = { iss: "supabase", ref: "local", iat: now, exp };
|
|
9440
|
-
return {
|
|
9441
|
-
anonKey: await signJwt({ ...common, role: "anon" }, jwtSecret),
|
|
9442
|
-
serviceRoleKey: await signJwt({ ...common, role: "service_role" }, jwtSecret)
|
|
9443
|
-
};
|
|
9524
|
+
return await mintProjectApiKeys(jwtSecret);
|
|
9444
9525
|
}
|
|
9445
9526
|
async function createProjectBackend(options = {}) {
|
|
9446
9527
|
const paths = resolveProjectPaths(options);
|
|
@@ -9611,7 +9692,7 @@ async function findEphemeralPort(host = "127.0.0.1") {
|
|
|
9611
9692
|
return port;
|
|
9612
9693
|
}
|
|
9613
9694
|
// src/snapshot.ts
|
|
9614
|
-
import { chmod as chmod2, copyFile,
|
|
9695
|
+
import { chmod as chmod2, copyFile, lstat as lstat2, mkdir as mkdir5, mkdtemp, readdir as readdir3, readFile as readFile7, rename as rename2, rm as rm3, writeFile as writeFile4 } from "fs/promises";
|
|
9615
9696
|
import { dirname as dirname4, join as join7, parse as parse2, relative as relative2, resolve as resolve3, sep as sep2 } from "path";
|
|
9616
9697
|
import { create as createTar, extract as extractTar } from "tar";
|
|
9617
9698
|
var SNAPSHOT_FORMAT = "supacloud-lite-snapshot";
|
|
@@ -9836,14 +9917,7 @@ async function stageDirectory(root, destination) {
|
|
|
9836
9917
|
}
|
|
9837
9918
|
async function stageFile(source, target) {
|
|
9838
9919
|
await mkdir5(dirname4(target), { recursive: true });
|
|
9839
|
-
|
|
9840
|
-
await link2(source, target);
|
|
9841
|
-
} catch (error) {
|
|
9842
|
-
const code = error.code;
|
|
9843
|
-
if (code !== "EXDEV" && code !== "EPERM" && code !== "EACCES")
|
|
9844
|
-
throw error;
|
|
9845
|
-
await copyFile(source, target);
|
|
9846
|
-
}
|
|
9920
|
+
await copyFile(source, target);
|
|
9847
9921
|
}
|
|
9848
9922
|
async function readManifest(payloadRoot) {
|
|
9849
9923
|
let parsed;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-runtime.d.ts","sourceRoot":"","sources":["../src/project-runtime.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"project-runtime.d.ts","sourceRoot":"","sources":["../src/project-runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -119,10 +119,16 @@ export declare class AuthHandler {
|
|
|
119
119
|
/** Max wrong guesses for a one-time code before its tokens are invalidated. */
|
|
120
120
|
private static readonly MAX_OTP_ATTEMPTS;
|
|
121
121
|
private redeem;
|
|
122
|
+
private claimEmailToken;
|
|
123
|
+
private lockAndDeleteEmailToken;
|
|
124
|
+
private confirmEmailTokenUser;
|
|
125
|
+
private findEmailTokenCandidate;
|
|
126
|
+
private recordFailedEmailTokenAttempt;
|
|
122
127
|
private verifyToken;
|
|
123
128
|
private redeemPhoneOtp;
|
|
124
129
|
private verifyLink;
|
|
125
130
|
private admin;
|
|
131
|
+
private generateAdminMagicLink;
|
|
126
132
|
/**
|
|
127
133
|
* Append a security event to auth.audit_log_entries (GoTrue-compatible
|
|
128
134
|
* payload). Best-effort: a logging failure never breaks the request.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/runtime/auth/handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAW,MAAM,mBAAmB,CAAA;AAE1D,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAc,SAAS,EAAE,MAAM,aAAa,CAAA;AAEhF,OAAO,EAAgB,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAGnE,OAAO,EAAyB,KAAK,YAAY,EAAE,MAAM,eAAe,CAAA;AAExE,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAG7C,wDAAwD;AACxD,MAAM,WAAW,UAAU;IACzB,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAA;IACjB,2FAA2F;IAC3F,MAAM,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAA;IACf,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAA;IACjB,yGAAyG;IACzG,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,uEAAuE;IACvE,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAA;IACd,+DAA+D;IAC/D,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI,CAAA;IAC5B,oFAAoF;IACpF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;IACpD,gFAAgF;IAChF,UAAU,CAAC,EAAE,OAAO,KAAK,CAAA;IACzB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB;;;;OAIG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAA;IAClC;;;OAGG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,CAAA;CACjC;AAED,UAAU,OAAO;IACf,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,kBAAkB,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAAA;IACxC,eAAe,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAAA;IACrC,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IACjD,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IAClD,UAAU,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAAA;IAChC,UAAU,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAAA;IAChC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,kBAAkB,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAAA;IACxC,YAAY,EAAE,OAAO,GAAG,IAAI,CAAA;IAC5B,YAAY,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAAA;IAClC,UAAU,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAAA;CACjC;
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/runtime/auth/handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime/jwt.d.ts
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* Minimal HS256 JWT implementation on WebCrypto.
|
|
3
3
|
* Works in Node (>=18) and browsers - no dependencies.
|
|
4
4
|
*/
|
|
5
|
+
export interface ProjectApiKeys {
|
|
6
|
+
anonKey: string;
|
|
7
|
+
serviceRoleKey: string;
|
|
8
|
+
}
|
|
5
9
|
/** Standard + Supabase/GoTrue claims carried in an access token. Open-ended: any extra claims are preserved. */
|
|
6
10
|
export interface JwtClaims {
|
|
7
11
|
[key: string]: unknown;
|
|
@@ -22,6 +26,8 @@ export interface JwtClaims {
|
|
|
22
26
|
}
|
|
23
27
|
/** Sign claims as an HS256 JWT. */
|
|
24
28
|
export declare function signJwt(claims: JwtClaims, secret: string): Promise<string>;
|
|
29
|
+
/** Keep project API keys canonical so CLI output and restarted runtimes remain byte-identical. */
|
|
30
|
+
export declare function mintProjectApiKeys(jwtSecret: string): Promise<ProjectApiKeys>;
|
|
25
31
|
/** Verifies signature and expiry. Returns claims, or null when invalid. */
|
|
26
32
|
export declare function verifyJwt(token: string, secret: string): Promise<JwtClaims | null>;
|
|
27
33
|
/** Decode without verification (for introspection/debugging only). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/runtime/jwt.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/runtime/jwt.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,cAAc,EAAE,MAAM,CAAA;CACvB;AA8BD,gHAAgH;AAChH,MAAM,WAAW,SAAS;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;IACtB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,qFAAqF;IACrF,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,2FAA2F;IAC3F,GAAG,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAC9C;AAED,mCAAmC;AACnC,wBAAsB,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOhF;AAED,kGAAkG;AAClG,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAWnF;AAED,2EAA2E;AAC3E,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAuBxF;AAED,sEAAsE;AACtE,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAQzD;AAED,0GAA0G;AAC1G,wBAAgB,WAAW,CAAC,KAAK,SAAK,GAAG,MAAM,CAI9C"}
|