@supacloud/lite 0.31.1 → 0.31.3

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 CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.31.3](https://github.com/vibeunion/supacloud/compare/supacloud-lite-v0.31.2...supacloud-lite-v0.31.3) (2026-10-17)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **cli:** align verification target resolution ([#2052](https://github.com/vibeunion/supacloud/issues/2052)) ([3cfcc36](https://github.com/vibeunion/supacloud/commit/3cfcc362f87ecdaf82a4df303f5af436875fb36e))
9
+ * **lite:** align default storage size limit ([#2053](https://github.com/vibeunion/supacloud/issues/2053)) ([8414234](https://github.com/vibeunion/supacloud/commit/8414234d72fc42440ea1133646d6b11422097a4a))
10
+ * **lite:** validate image size metadata ([#2046](https://github.com/vibeunion/supacloud/issues/2046)) ([9ea248e](https://github.com/vibeunion/supacloud/commit/9ea248ecca9cebf5b1bba8b70ea50195613d1f3d))
11
+ * **supacloud-lite:** bind email tokens to current account address ([#2047](https://github.com/vibeunion/supacloud/issues/2047)) ([355d08c](https://github.com/vibeunion/supacloud/commit/355d08cdbc7d0d90085a2208557f1decc1d15e82))
12
+
13
+ ## [0.31.2](https://github.com/vibeunion/supacloud/compare/supacloud-lite-v0.31.1...supacloud-lite-v0.31.2) (2026-10-17)
14
+
15
+
16
+ ### Bug Fixes
17
+
18
+ * **cli:** sync published compiler dependency ([#2041](https://github.com/vibeunion/supacloud/issues/2041)) ([be44641](https://github.com/vibeunion/supacloud/commit/be446416b87bf009eec892bc20368e3595d7326a))
19
+ * **lite:** preflight image transformation size ([#2037](https://github.com/vibeunion/supacloud/issues/2037)) ([fd0e790](https://github.com/vibeunion/supacloud/commit/fd0e790a18513dfd7fa1682b7e72c0a147f392cc))
20
+ * recheck password issuance and align published tool dependencies ([#2039](https://github.com/vibeunion/supacloud/issues/2039)) ([250b1af](https://github.com/vibeunion/supacloud/commit/250b1afef3f78d6dd4ab34e94147f65beb8a8677))
21
+
3
22
  ## [0.31.1](https://github.com/vibeunion/supacloud/compare/supacloud-lite-v0.31.0...supacloud-lite-v0.31.1) (2026-10-17)
4
23
 
5
24
 
package/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ import { dirname as dirname8, join as join10, resolve as resolve6 } from "path";
8
8
  // package.json
9
9
  var package_default = {
10
10
  name: "@supacloud/lite",
11
- version: "0.31.1",
11
+ version: "0.31.3",
12
12
  description: "Bun-native, single-project Supabase-compatible backend powered by PGlite or native PostgreSQL",
13
13
  type: "module",
14
14
  license: "Apache-2.0",
@@ -67,16 +67,16 @@ var package_default = {
67
67
  "@electric-sql/pglite-pgmq": "0.0.8",
68
68
  "@electric-sql/pglite-pgvector": "0.0.11",
69
69
  "@electric-sql/pglite-postgis": "0.2.10",
70
- "@supacloud/db": "0.18.2",
70
+ "@supacloud/db": "0.18.4",
71
71
  "exact-mirror": "1.2.6",
72
72
  tar: "^7.5.22",
73
73
  typebox: "1.3.37"
74
74
  },
75
75
  devDependencies: {
76
- "@supacloud/app": "0.28.1",
77
- "@supacloud/contracts": "0.11.3",
78
- "@supacloud/compiler": "0.47.1",
79
- "@supacloud/elysia": "0.33.3",
76
+ "@supacloud/app": "0.28.3",
77
+ "@supacloud/contracts": "0.11.5",
78
+ "@supacloud/compiler": "0.47.3",
79
+ "@supacloud/elysia": "0.33.5",
80
80
  "@supabase/supabase-js": "^2.117.3",
81
81
  "@types/bun": "^1.4.3",
82
82
  effect: "4.0.5",
@@ -85,13 +85,13 @@ var package_default = {
85
85
  typescript: "^7.0.2"
86
86
  },
87
87
  overrides: {
88
- "@supacloud/db": "0.18.2",
89
- "@supacloud/app": "0.28.1",
90
- "@supacloud/compiler": "0.47.1",
91
- "@supacloud/elysia": "0.33.3",
92
- "@supacloud/contracts": "0.11.3",
93
- "@supacloud/commands": "0.9.5",
94
- "@supacloud/delivery": "0.19.2",
88
+ "@supacloud/db": "0.18.4",
89
+ "@supacloud/app": "0.28.3",
90
+ "@supacloud/compiler": "0.47.3",
91
+ "@supacloud/elysia": "0.33.5",
92
+ "@supacloud/contracts": "0.11.5",
93
+ "@supacloud/commands": "0.9.7",
94
+ "@supacloud/delivery": "0.19.4",
95
95
  "@graphql-tools/utils": "^12.0.4"
96
96
  },
97
97
  engines: {
@@ -1464,12 +1464,33 @@ class AuthHandler {
1464
1464
  await this.audit("login_failed", { actorEmail: email, traits: { grant_type: "password" } });
1465
1465
  return authError(400, "invalid_credentials", "Invalid login credentials");
1466
1466
  }
1467
- if (!this.settings.autoconfirm && !user.email_confirmed_at) {
1468
- return authError(400, "email_not_confirmed", "Email not confirmed");
1467
+ const response = await this.db.transaction(async (query) => {
1468
+ const currentResult = await query(`select *, coalesce(banned_until > now(), false) as is_banned
1469
+ from auth.users where id = $1 for update`, [user.id]);
1470
+ const current = currentResult.rows[0];
1471
+ if (!current || current.deleted_at !== null || !current.encrypted_password || current.email !== email) {
1472
+ return authError(400, "invalid_credentials", "Invalid login credentials");
1473
+ }
1474
+ if (current.is_banned) {
1475
+ return authError(400, "user_banned", "User is banned");
1476
+ }
1477
+ if (current.encrypted_password !== user.encrypted_password) {
1478
+ return authError(400, "invalid_credentials", "Invalid login credentials");
1479
+ }
1480
+ if (!this.settings.autoconfirm && !current.email_confirmed_at) {
1481
+ return authError(400, "email_not_confirmed", "Email not confirmed");
1482
+ }
1483
+ const signedIn = await query(`update auth.users set last_sign_in_at = now() where id = $1 returning *`, [current.id]);
1484
+ const updated = signedIn.rows[0];
1485
+ if (!updated) {
1486
+ return authError(400, "invalid_credentials", "Invalid login credentials");
1487
+ }
1488
+ return json(200, await this.sessionFor(updated, undefined, undefined, query));
1489
+ });
1490
+ if (response.ok) {
1491
+ await this.audit("login", { actorId: user.id, actorEmail: email, traits: { grant_type: "password" } });
1469
1492
  }
1470
- await this.db.query(`update auth.users set last_sign_in_at = now() where id = $1`, [user.id]);
1471
- await this.audit("login", { actorId: user.id, actorEmail: user.email, traits: { grant_type: "password" } });
1472
- return json(200, await this.sessionFor(user));
1493
+ return response;
1473
1494
  }
1474
1495
  if (grantType === "refresh_token") {
1475
1496
  const token = body.refresh_token;
@@ -1505,16 +1526,6 @@ class AuthHandler {
1505
1526
  if (body.email && !this.settings.autoconfirm) {
1506
1527
  return authError(501, "email_change_confirmation_not_supported", "Email changes that require confirmation are not supported by SupaCloud Lite V1");
1507
1528
  }
1508
- const upgradingAnon = (user.is_anonymous ?? false) && !!body.email;
1509
- if (body.email) {
1510
- const email = body.email.toLowerCase().trim();
1511
- const clash = await this.db.query(`select id from auth.users where email = $1 and id <> $2`, [email, user.id]);
1512
- if (clash.rows.length > 0) {
1513
- return authError(422, "email_exists", "A user with this email address has already been registered");
1514
- }
1515
- params.push(email);
1516
- sets.push(`email = $${params.length}, email_confirmed_at = now()`);
1517
- }
1518
1529
  if (body.password) {
1519
1530
  if (body.password.length < this.settings.minPasswordLength) {
1520
1531
  return authError(422, "weak_password", `Password should be at least ${this.settings.minPasswordLength} characters.`);
@@ -1526,22 +1537,41 @@ class AuthHandler {
1526
1537
  params.push(JSON.stringify(body.data));
1527
1538
  sets.push(`raw_user_meta_data = coalesce(raw_user_meta_data, '{}'::jsonb) || $${params.length}::jsonb`);
1528
1539
  }
1529
- if (upgradingAnon) {
1530
- sets.push(`is_anonymous = false`);
1531
- sets.push(`raw_app_meta_data = coalesce(raw_app_meta_data, '{}'::jsonb) || '{"provider":"email","providers":["email"]}'::jsonb`);
1532
- }
1533
- if (sets.length === 0) {
1534
- return json(200, this.userJson(user, await this.getUserFactors(user.id), await this.getUserIdentities(user.id)));
1535
- }
1536
- params.push(user.id);
1537
- const payload = await this.db.transaction(async (query) => {
1538
- const res = await query(`update auth.users set ${sets.join(", ")}, updated_at = now() where id = $${params.length} returning *`, params);
1539
- const updated = res.rows[0];
1540
+ const response = await this.db.transaction(async (query) => {
1541
+ const currentResult = await query(`select * from auth.users where id = $1 and deleted_at is null
1542
+ and (banned_until is null or banned_until <= now()) for update`, [user.id]);
1543
+ const current = currentResult.rows[0];
1544
+ if (!current)
1545
+ return authError(401, "no_authorization", "Invalid or expired token");
1546
+ const transactionSets = [...sets];
1547
+ const transactionParams = [...params];
1548
+ const upgradingAnon = (current.is_anonymous ?? false) && !!body.email;
1549
+ if (body.email) {
1550
+ const email = body.email.toLowerCase().trim();
1551
+ const clash = await query(`select id from auth.users where email = $1 and id <> $2`, [email, current.id]);
1552
+ if (clash.rows.length > 0) {
1553
+ return authError(422, "email_exists", "A user with this email address has already been registered");
1554
+ }
1555
+ transactionParams.push(email);
1556
+ transactionSets.push(`email = $${transactionParams.length}, email_confirmed_at = now()`);
1557
+ }
1558
+ if (upgradingAnon) {
1559
+ transactionSets.push(`is_anonymous = false`);
1560
+ transactionSets.push(`raw_app_meta_data = coalesce(raw_app_meta_data, '{}'::jsonb) || '{"provider":"email","providers":["email"]}'::jsonb`);
1561
+ }
1562
+ if (transactionSets.length === 0) {
1563
+ return json(200, await this.userJsonWithRelations(current, query));
1564
+ }
1565
+ transactionParams.push(current.id);
1566
+ const updatedResult = await query(`update auth.users set ${transactionSets.join(", ")}, updated_at = now() where id = $${transactionParams.length} returning *`, transactionParams);
1567
+ const updated = updatedResult.rows[0];
1568
+ if (!updated)
1569
+ return authError(401, "no_authorization", "Invalid or expired token");
1540
1570
  if (body.email)
1541
1571
  await this.ensureEmailIdentity(updated, query);
1542
- return this.userJsonWithRelations(updated, query);
1572
+ return json(200, await this.userJsonWithRelations(updated, query));
1543
1573
  });
1544
- return json(200, payload);
1574
+ return response;
1545
1575
  }
1546
1576
  async logout(req, url) {
1547
1577
  const claims = await this.claimsFromBearer(req);
@@ -1795,8 +1825,8 @@ Or sign in with this link: ${link}`
1795
1825
  return claimedToken ? this.confirmEmailTokenUser(query, claimedToken) : null;
1796
1826
  }
1797
1827
  async lockAndDeleteEmailToken(query, candidate, redemption) {
1798
- const eligible = await query(`select id from auth.users where id = $1 and deleted_at is null
1799
- and (banned_until is null or banned_until <= now()) for update`, [candidate.user_id]);
1828
+ const eligible = await query(`select id from auth.users where id = $1 and lower(email) = lower($2)
1829
+ and deleted_at is null and (banned_until is null or banned_until <= now()) for update`, [candidate.user_id, candidate.email]);
1800
1830
  if (eligible.rows.length === 0)
1801
1831
  return null;
1802
1832
  const claimedTokens = await query(`delete from auth.one_time_tokens
@@ -1859,11 +1889,10 @@ Or sign in with this link: ${link}`
1859
1889
  async redeemPhoneOtp(phone, code) {
1860
1890
  const tokenDigest = `hmac-sha256:v1:${await keyedDigest(this.config.jwtSecret, "supacloud-lite:phone-otp:v1", `${phone}\x00${code}`)}`;
1861
1891
  return this.db.transaction(async (query) => {
1862
- const claimed = await query(`delete from auth.one_time_tokens
1892
+ const candidate = await query(`select user_id from auth.one_time_tokens
1863
1893
  where phone = $1 and token_type = 'sms' and token = $2
1864
- and expires_at > now() and attempts < $3
1865
- returning user_id`, [phone, tokenDigest, AuthHandler.MAX_OTP_ATTEMPTS]);
1866
- const userId = claimed.rows[0]?.user_id;
1894
+ and expires_at > now() and attempts < $3`, [phone, tokenDigest, AuthHandler.MAX_OTP_ATTEMPTS]);
1895
+ const userId = candidate.rows[0]?.user_id;
1867
1896
  if (!userId) {
1868
1897
  const attempt = await query(`update auth.one_time_tokens set attempts = attempts + 1
1869
1898
  where phone = $1 and token_type = 'sms' and expires_at > now()
@@ -1875,6 +1904,22 @@ Or sign in with this link: ${link}`
1875
1904
  await query(`delete from auth.one_time_tokens where phone = $1 and expires_at <= now()`, [phone]);
1876
1905
  return null;
1877
1906
  }
1907
+ const currentUser = await query(`select phone,
1908
+ deleted_at is null and (banned_until is null or banned_until <= now()) as auth_eligible
1909
+ from auth.users where id = $1 for update`, [userId]);
1910
+ const current = currentUser.rows[0];
1911
+ if (!current || current.phone !== phone)
1912
+ return null;
1913
+ if (!current.auth_eligible) {
1914
+ await query(`delete from auth.one_time_tokens where phone = $1`, [phone]);
1915
+ return null;
1916
+ }
1917
+ const claimed = await query(`delete from auth.one_time_tokens
1918
+ where phone = $1 and token_type = 'sms' and token = $2
1919
+ and expires_at > now() and attempts < $3 and user_id = $4
1920
+ returning user_id`, [phone, tokenDigest, AuthHandler.MAX_OTP_ATTEMPTS, userId]);
1921
+ if (claimed.rows.length === 0)
1922
+ return null;
1878
1923
  await query(`delete from auth.one_time_tokens where phone = $1`, [phone]);
1879
1924
  const users = await query(`update auth.users
1880
1925
  set phone_confirmed_at = coalesce(phone_confirmed_at, now()), last_sign_in_at = now(), updated_at = now()
@@ -2180,6 +2225,9 @@ Or sign in with this link: ${link}`
2180
2225
  const user = await this.userFromBearer(req);
2181
2226
  if (!user)
2182
2227
  return authError(401, "no_authorization", "This endpoint requires a Bearer token");
2228
+ if (!this.settings.totpVerifyEnabled) {
2229
+ return authError(422, "mfa_totp_verify_disabled", "TOTP verification is disabled");
2230
+ }
2183
2231
  const body = await req.json().catch(() => ({}));
2184
2232
  const fr = await this.db.query(`select id, secret, status from auth.mfa_factors where id = $1 and user_id = $2`, [factorId, user.id]);
2185
2233
  const factor = fr.rows[0];
@@ -9066,6 +9114,14 @@ function resolveImageTransformLimits(options = {}) {
9066
9114
  }
9067
9115
  return { maxInputBytes, maxOutputBytes };
9068
9116
  }
9117
+ function imageTransformInputTooLarge(maxInputBytes) {
9118
+ return {
9119
+ ok: false,
9120
+ status: 413,
9121
+ error: "ImageTooLarge",
9122
+ message: `The source image exceeds the transformation limit (${maxInputBytes} bytes)`
9123
+ };
9124
+ }
9069
9125
  function invalid(message) {
9070
9126
  return { ok: false, status: 400, error: "InvalidTransformation", message };
9071
9127
  }
@@ -9209,14 +9265,10 @@ function applyResize(image, metadata, options) {
9209
9265
  async function transformImage(source, options, knownSourceSize, configuredLimits = {}) {
9210
9266
  const limits = resolveImageTransformLimits(configuredLimits);
9211
9267
  const actualSourceSize = source instanceof Uint8Array ? source.byteLength : await Promise.resolve(source.size);
9212
- const sourceSize = Math.max(knownSourceSize ?? 0, actualSourceSize);
9268
+ const declaredSourceSize = typeof knownSourceSize === "number" && Number.isFinite(knownSourceSize) && knownSourceSize >= 0 ? knownSourceSize : 0;
9269
+ const sourceSize = Math.max(declaredSourceSize, actualSourceSize);
9213
9270
  if (sourceSize > limits.maxInputBytes) {
9214
- return {
9215
- ok: false,
9216
- status: 413,
9217
- error: "ImageTooLarge",
9218
- message: `The source image exceeds the transformation limit (${limits.maxInputBytes} bytes)`
9219
- };
9271
+ return imageTransformInputTooLarge(limits.maxInputBytes);
9220
9272
  }
9221
9273
  const image = new Bun.Image(source, { maxPixels: MAX_TRANSFORM_PIXELS });
9222
9274
  let metadata;
@@ -9440,7 +9492,7 @@ function isRenderableActiveType(contentType) {
9440
9492
  return t === "text/html" || t === "application/xhtml+xml" || t === "image/svg+xml" || t === "application/xml" || t === "text/xml";
9441
9493
  }
9442
9494
  var TUS_VERSION = "1.0.0";
9443
- var DEFAULT_FILE_SIZE_LIMIT = 50 * 1024 * 1024;
9495
+ var DEFAULT_FILE_SIZE_LIMIT = 500 * 1024 * 1024;
9444
9496
  var MULTIPART_OVERHEAD_LIMIT = 1024 * 1024;
9445
9497
  var MAX_CONCURRENT_TUS_UPLOADS = 4;
9446
9498
  var MAX_COMPLETED_TUS_UPLOADS = 64;
@@ -9731,6 +9783,11 @@ class StorageHandler {
9731
9783
  const parsed = parseImageTransform(url.searchParams);
9732
9784
  if (!parsed.ok)
9733
9785
  return storageError(parsed.status, parsed.error, parsed.message);
9786
+ const declaredSize = objectSize(row);
9787
+ if (declaredSize !== undefined && declaredSize > this.transformLimits.maxInputBytes) {
9788
+ const rejected = imageTransformInputTooLarge(this.transformLimits.maxInputBytes);
9789
+ return storageError(rejected.status, rejected.error, rejected.message);
9790
+ }
9734
9791
  let result;
9735
9792
  try {
9736
9793
  result = await this.imageTransforms.getOrTransform(imageTransformCacheKey(row.version, parsed.value), async () => {
package/dist/index.js CHANGED
@@ -88,7 +88,7 @@ function randomToken(bytes = 32) {
88
88
  // package.json
89
89
  var package_default = {
90
90
  name: "@supacloud/lite",
91
- version: "0.31.1",
91
+ version: "0.31.3",
92
92
  description: "Bun-native, single-project Supabase-compatible backend powered by PGlite or native PostgreSQL",
93
93
  type: "module",
94
94
  license: "Apache-2.0",
@@ -147,16 +147,16 @@ var package_default = {
147
147
  "@electric-sql/pglite-pgmq": "0.0.8",
148
148
  "@electric-sql/pglite-pgvector": "0.0.11",
149
149
  "@electric-sql/pglite-postgis": "0.2.10",
150
- "@supacloud/db": "0.18.2",
150
+ "@supacloud/db": "0.18.4",
151
151
  "exact-mirror": "1.2.6",
152
152
  tar: "^7.5.22",
153
153
  typebox: "1.3.37"
154
154
  },
155
155
  devDependencies: {
156
- "@supacloud/app": "0.28.1",
157
- "@supacloud/contracts": "0.11.3",
158
- "@supacloud/compiler": "0.47.1",
159
- "@supacloud/elysia": "0.33.3",
156
+ "@supacloud/app": "0.28.3",
157
+ "@supacloud/contracts": "0.11.5",
158
+ "@supacloud/compiler": "0.47.3",
159
+ "@supacloud/elysia": "0.33.5",
160
160
  "@supabase/supabase-js": "^2.117.3",
161
161
  "@types/bun": "^1.4.3",
162
162
  effect: "4.0.5",
@@ -165,13 +165,13 @@ var package_default = {
165
165
  typescript: "^7.0.2"
166
166
  },
167
167
  overrides: {
168
- "@supacloud/db": "0.18.2",
169
- "@supacloud/app": "0.28.1",
170
- "@supacloud/compiler": "0.47.1",
171
- "@supacloud/elysia": "0.33.3",
172
- "@supacloud/contracts": "0.11.3",
173
- "@supacloud/commands": "0.9.5",
174
- "@supacloud/delivery": "0.19.2",
168
+ "@supacloud/db": "0.18.4",
169
+ "@supacloud/app": "0.28.3",
170
+ "@supacloud/compiler": "0.47.3",
171
+ "@supacloud/elysia": "0.33.5",
172
+ "@supacloud/contracts": "0.11.5",
173
+ "@supacloud/commands": "0.9.7",
174
+ "@supacloud/delivery": "0.19.4",
175
175
  "@graphql-tools/utils": "^12.0.4"
176
176
  },
177
177
  engines: {
@@ -1470,12 +1470,33 @@ class AuthHandler {
1470
1470
  await this.audit("login_failed", { actorEmail: email, traits: { grant_type: "password" } });
1471
1471
  return authError(400, "invalid_credentials", "Invalid login credentials");
1472
1472
  }
1473
- if (!this.settings.autoconfirm && !user.email_confirmed_at) {
1474
- return authError(400, "email_not_confirmed", "Email not confirmed");
1473
+ const response = await this.db.transaction(async (query) => {
1474
+ const currentResult = await query(`select *, coalesce(banned_until > now(), false) as is_banned
1475
+ from auth.users where id = $1 for update`, [user.id]);
1476
+ const current = currentResult.rows[0];
1477
+ if (!current || current.deleted_at !== null || !current.encrypted_password || current.email !== email) {
1478
+ return authError(400, "invalid_credentials", "Invalid login credentials");
1479
+ }
1480
+ if (current.is_banned) {
1481
+ return authError(400, "user_banned", "User is banned");
1482
+ }
1483
+ if (current.encrypted_password !== user.encrypted_password) {
1484
+ return authError(400, "invalid_credentials", "Invalid login credentials");
1485
+ }
1486
+ if (!this.settings.autoconfirm && !current.email_confirmed_at) {
1487
+ return authError(400, "email_not_confirmed", "Email not confirmed");
1488
+ }
1489
+ const signedIn = await query(`update auth.users set last_sign_in_at = now() where id = $1 returning *`, [current.id]);
1490
+ const updated = signedIn.rows[0];
1491
+ if (!updated) {
1492
+ return authError(400, "invalid_credentials", "Invalid login credentials");
1493
+ }
1494
+ return json(200, await this.sessionFor(updated, undefined, undefined, query));
1495
+ });
1496
+ if (response.ok) {
1497
+ await this.audit("login", { actorId: user.id, actorEmail: email, traits: { grant_type: "password" } });
1475
1498
  }
1476
- await this.db.query(`update auth.users set last_sign_in_at = now() where id = $1`, [user.id]);
1477
- await this.audit("login", { actorId: user.id, actorEmail: user.email, traits: { grant_type: "password" } });
1478
- return json(200, await this.sessionFor(user));
1499
+ return response;
1479
1500
  }
1480
1501
  if (grantType === "refresh_token") {
1481
1502
  const token = body.refresh_token;
@@ -1511,16 +1532,6 @@ class AuthHandler {
1511
1532
  if (body.email && !this.settings.autoconfirm) {
1512
1533
  return authError(501, "email_change_confirmation_not_supported", "Email changes that require confirmation are not supported by SupaCloud Lite V1");
1513
1534
  }
1514
- const upgradingAnon = (user.is_anonymous ?? false) && !!body.email;
1515
- if (body.email) {
1516
- const email = body.email.toLowerCase().trim();
1517
- const clash = await this.db.query(`select id from auth.users where email = $1 and id <> $2`, [email, user.id]);
1518
- if (clash.rows.length > 0) {
1519
- return authError(422, "email_exists", "A user with this email address has already been registered");
1520
- }
1521
- params.push(email);
1522
- sets.push(`email = $${params.length}, email_confirmed_at = now()`);
1523
- }
1524
1535
  if (body.password) {
1525
1536
  if (body.password.length < this.settings.minPasswordLength) {
1526
1537
  return authError(422, "weak_password", `Password should be at least ${this.settings.minPasswordLength} characters.`);
@@ -1532,22 +1543,41 @@ class AuthHandler {
1532
1543
  params.push(JSON.stringify(body.data));
1533
1544
  sets.push(`raw_user_meta_data = coalesce(raw_user_meta_data, '{}'::jsonb) || $${params.length}::jsonb`);
1534
1545
  }
1535
- if (upgradingAnon) {
1536
- sets.push(`is_anonymous = false`);
1537
- sets.push(`raw_app_meta_data = coalesce(raw_app_meta_data, '{}'::jsonb) || '{"provider":"email","providers":["email"]}'::jsonb`);
1538
- }
1539
- if (sets.length === 0) {
1540
- return json(200, this.userJson(user, await this.getUserFactors(user.id), await this.getUserIdentities(user.id)));
1541
- }
1542
- params.push(user.id);
1543
- const payload = await this.db.transaction(async (query) => {
1544
- const res = await query(`update auth.users set ${sets.join(", ")}, updated_at = now() where id = $${params.length} returning *`, params);
1545
- const updated = res.rows[0];
1546
+ const response = await this.db.transaction(async (query) => {
1547
+ const currentResult = await query(`select * from auth.users where id = $1 and deleted_at is null
1548
+ and (banned_until is null or banned_until <= now()) for update`, [user.id]);
1549
+ const current = currentResult.rows[0];
1550
+ if (!current)
1551
+ return authError(401, "no_authorization", "Invalid or expired token");
1552
+ const transactionSets = [...sets];
1553
+ const transactionParams = [...params];
1554
+ const upgradingAnon = (current.is_anonymous ?? false) && !!body.email;
1555
+ if (body.email) {
1556
+ const email = body.email.toLowerCase().trim();
1557
+ const clash = await query(`select id from auth.users where email = $1 and id <> $2`, [email, current.id]);
1558
+ if (clash.rows.length > 0) {
1559
+ return authError(422, "email_exists", "A user with this email address has already been registered");
1560
+ }
1561
+ transactionParams.push(email);
1562
+ transactionSets.push(`email = $${transactionParams.length}, email_confirmed_at = now()`);
1563
+ }
1564
+ if (upgradingAnon) {
1565
+ transactionSets.push(`is_anonymous = false`);
1566
+ transactionSets.push(`raw_app_meta_data = coalesce(raw_app_meta_data, '{}'::jsonb) || '{"provider":"email","providers":["email"]}'::jsonb`);
1567
+ }
1568
+ if (transactionSets.length === 0) {
1569
+ return json(200, await this.userJsonWithRelations(current, query));
1570
+ }
1571
+ transactionParams.push(current.id);
1572
+ const updatedResult = await query(`update auth.users set ${transactionSets.join(", ")}, updated_at = now() where id = $${transactionParams.length} returning *`, transactionParams);
1573
+ const updated = updatedResult.rows[0];
1574
+ if (!updated)
1575
+ return authError(401, "no_authorization", "Invalid or expired token");
1546
1576
  if (body.email)
1547
1577
  await this.ensureEmailIdentity(updated, query);
1548
- return this.userJsonWithRelations(updated, query);
1578
+ return json(200, await this.userJsonWithRelations(updated, query));
1549
1579
  });
1550
- return json(200, payload);
1580
+ return response;
1551
1581
  }
1552
1582
  async logout(req, url) {
1553
1583
  const claims = await this.claimsFromBearer(req);
@@ -1801,8 +1831,8 @@ Or sign in with this link: ${link}`
1801
1831
  return claimedToken ? this.confirmEmailTokenUser(query, claimedToken) : null;
1802
1832
  }
1803
1833
  async lockAndDeleteEmailToken(query, candidate, redemption) {
1804
- const eligible = await query(`select id from auth.users where id = $1 and deleted_at is null
1805
- and (banned_until is null or banned_until <= now()) for update`, [candidate.user_id]);
1834
+ const eligible = await query(`select id from auth.users where id = $1 and lower(email) = lower($2)
1835
+ and deleted_at is null and (banned_until is null or banned_until <= now()) for update`, [candidate.user_id, candidate.email]);
1806
1836
  if (eligible.rows.length === 0)
1807
1837
  return null;
1808
1838
  const claimedTokens = await query(`delete from auth.one_time_tokens
@@ -1865,11 +1895,10 @@ Or sign in with this link: ${link}`
1865
1895
  async redeemPhoneOtp(phone, code) {
1866
1896
  const tokenDigest = `hmac-sha256:v1:${await keyedDigest(this.config.jwtSecret, "supacloud-lite:phone-otp:v1", `${phone}\x00${code}`)}`;
1867
1897
  return this.db.transaction(async (query) => {
1868
- const claimed = await query(`delete from auth.one_time_tokens
1898
+ const candidate = await query(`select user_id from auth.one_time_tokens
1869
1899
  where phone = $1 and token_type = 'sms' and token = $2
1870
- and expires_at > now() and attempts < $3
1871
- returning user_id`, [phone, tokenDigest, AuthHandler.MAX_OTP_ATTEMPTS]);
1872
- const userId = claimed.rows[0]?.user_id;
1900
+ and expires_at > now() and attempts < $3`, [phone, tokenDigest, AuthHandler.MAX_OTP_ATTEMPTS]);
1901
+ const userId = candidate.rows[0]?.user_id;
1873
1902
  if (!userId) {
1874
1903
  const attempt = await query(`update auth.one_time_tokens set attempts = attempts + 1
1875
1904
  where phone = $1 and token_type = 'sms' and expires_at > now()
@@ -1881,6 +1910,22 @@ Or sign in with this link: ${link}`
1881
1910
  await query(`delete from auth.one_time_tokens where phone = $1 and expires_at <= now()`, [phone]);
1882
1911
  return null;
1883
1912
  }
1913
+ const currentUser = await query(`select phone,
1914
+ deleted_at is null and (banned_until is null or banned_until <= now()) as auth_eligible
1915
+ from auth.users where id = $1 for update`, [userId]);
1916
+ const current = currentUser.rows[0];
1917
+ if (!current || current.phone !== phone)
1918
+ return null;
1919
+ if (!current.auth_eligible) {
1920
+ await query(`delete from auth.one_time_tokens where phone = $1`, [phone]);
1921
+ return null;
1922
+ }
1923
+ const claimed = await query(`delete from auth.one_time_tokens
1924
+ where phone = $1 and token_type = 'sms' and token = $2
1925
+ and expires_at > now() and attempts < $3 and user_id = $4
1926
+ returning user_id`, [phone, tokenDigest, AuthHandler.MAX_OTP_ATTEMPTS, userId]);
1927
+ if (claimed.rows.length === 0)
1928
+ return null;
1884
1929
  await query(`delete from auth.one_time_tokens where phone = $1`, [phone]);
1885
1930
  const users = await query(`update auth.users
1886
1931
  set phone_confirmed_at = coalesce(phone_confirmed_at, now()), last_sign_in_at = now(), updated_at = now()
@@ -2186,6 +2231,9 @@ Or sign in with this link: ${link}`
2186
2231
  const user = await this.userFromBearer(req);
2187
2232
  if (!user)
2188
2233
  return authError(401, "no_authorization", "This endpoint requires a Bearer token");
2234
+ if (!this.settings.totpVerifyEnabled) {
2235
+ return authError(422, "mfa_totp_verify_disabled", "TOTP verification is disabled");
2236
+ }
2189
2237
  const body = await req.json().catch(() => ({}));
2190
2238
  const fr = await this.db.query(`select id, secret, status from auth.mfa_factors where id = $1 and user_id = $2`, [factorId, user.id]);
2191
2239
  const factor = fr.rows[0];
@@ -9060,6 +9108,14 @@ function resolveImageTransformLimits(options = {}) {
9060
9108
  }
9061
9109
  return { maxInputBytes, maxOutputBytes };
9062
9110
  }
9111
+ function imageTransformInputTooLarge(maxInputBytes) {
9112
+ return {
9113
+ ok: false,
9114
+ status: 413,
9115
+ error: "ImageTooLarge",
9116
+ message: `The source image exceeds the transformation limit (${maxInputBytes} bytes)`
9117
+ };
9118
+ }
9063
9119
  function invalid(message) {
9064
9120
  return { ok: false, status: 400, error: "InvalidTransformation", message };
9065
9121
  }
@@ -9203,14 +9259,10 @@ function applyResize(image, metadata, options) {
9203
9259
  async function transformImage(source, options, knownSourceSize, configuredLimits = {}) {
9204
9260
  const limits = resolveImageTransformLimits(configuredLimits);
9205
9261
  const actualSourceSize = source instanceof Uint8Array ? source.byteLength : await Promise.resolve(source.size);
9206
- const sourceSize = Math.max(knownSourceSize ?? 0, actualSourceSize);
9262
+ const declaredSourceSize = typeof knownSourceSize === "number" && Number.isFinite(knownSourceSize) && knownSourceSize >= 0 ? knownSourceSize : 0;
9263
+ const sourceSize = Math.max(declaredSourceSize, actualSourceSize);
9207
9264
  if (sourceSize > limits.maxInputBytes) {
9208
- return {
9209
- ok: false,
9210
- status: 413,
9211
- error: "ImageTooLarge",
9212
- message: `The source image exceeds the transformation limit (${limits.maxInputBytes} bytes)`
9213
- };
9265
+ return imageTransformInputTooLarge(limits.maxInputBytes);
9214
9266
  }
9215
9267
  const image = new Bun.Image(source, { maxPixels: MAX_TRANSFORM_PIXELS });
9216
9268
  let metadata;
@@ -9434,7 +9486,7 @@ function isRenderableActiveType(contentType) {
9434
9486
  return t === "text/html" || t === "application/xhtml+xml" || t === "image/svg+xml" || t === "application/xml" || t === "text/xml";
9435
9487
  }
9436
9488
  var TUS_VERSION = "1.0.0";
9437
- var DEFAULT_FILE_SIZE_LIMIT = 50 * 1024 * 1024;
9489
+ var DEFAULT_FILE_SIZE_LIMIT = 500 * 1024 * 1024;
9438
9490
  var MULTIPART_OVERHEAD_LIMIT = 1024 * 1024;
9439
9491
  var MAX_CONCURRENT_TUS_UPLOADS = 4;
9440
9492
  var MAX_COMPLETED_TUS_UPLOADS = 64;
@@ -9725,6 +9777,11 @@ class StorageHandler {
9725
9777
  const parsed = parseImageTransform(url.searchParams);
9726
9778
  if (!parsed.ok)
9727
9779
  return storageError(parsed.status, parsed.error, parsed.message);
9780
+ const declaredSize = objectSize(row);
9781
+ if (declaredSize !== undefined && declaredSize > this.transformLimits.maxInputBytes) {
9782
+ const rejected = imageTransformInputTooLarge(this.transformLimits.maxInputBytes);
9783
+ return storageError(rejected.status, rejected.error, rejected.message);
9784
+ }
9728
9785
  let result;
9729
9786
  try {
9730
9787
  result = await this.imageTransforms.getOrTransform(imageTransformCacheKey(row.version, parsed.value), async () => {
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/runtime/auth/handler.ts"],"names":[],"mappings":"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"}
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":"handler.d.ts","sourceRoot":"","sources":["../../../src/runtime/storage/handler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAKL,KAAK,oBAAoB,EAG1B,MAAM,sBAAsB,CAAA;AAE7B,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE5E,uDAAuD;AACvD,MAAM,WAAW,aAAa;IAC5B,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAA;IACjB,0GAA0G;IAC1G,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,oBAAoB,CAAC,EAAE,oBAAoB,CAAA;IAC3C,uFAAuF;IACvF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC;AAkJD,qEAAqE;AACrE,qBAAa,cAAc;IAOvB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;IARhB,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,eAAe,CAA4B;IACnD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgC;gBAGtD,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,aAAa;IAK/B,4FAA4F;IACtF,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAazD,8GAA8G;IACxG,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC;YAgH9D,YAAY;IAgB1B,OAAO,CAAC,cAAc;YAOR,YAAY;YA2BZ,WAAW;YAKX,SAAS;YAMT,YAAY;YAqBZ,YAAY;YAYZ,WAAW;YAUX,UAAU;YAKV,MAAM;YA0DN,sBAAsB;IA0BpC,gFAAgF;YAClE,aAAa;YAmDb,SAAS;IA8KvB,2EAA2E;YAC7D,SAAS;IA2CvB,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,sBAAsB;YAMhB,oBAAoB;YA8CpB,QAAQ;YAMR,uBAAuB;YAavB,cAAc;YAMd,gBAAgB;YAYhB,WAAW;YAWX,aAAa;YAeb,SAAS;YAUT,UAAU;YAiFV,gBAAgB;YAUhB,kBAAkB;YASlB,eAAe;YAIf,gBAAgB;YAKhB,iBAAiB;YAcjB,WAAW;YAuDX,UAAU;YAyBV,OAAO;YAmBP,QAAQ;YAiBR,eAAe;YAMf,gBAAgB;YAehB,aAAa;YAab,kBAAkB;IAehC,OAAO,CAAC,aAAa;CAUtB;AA6ID,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,UAAU,CAAA;CACjB;AAED,+FAA+F;AAC/F,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,EAAE,CAqCnF"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/runtime/storage/handler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAML,KAAK,oBAAoB,EAG1B,MAAM,sBAAsB,CAAA;AAE7B,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE5E,uDAAuD;AACvD,MAAM,WAAW,aAAa;IAC5B,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAA;IACjB,0GAA0G;IAC1G,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,oBAAoB,CAAC,EAAE,oBAAoB,CAAA;IAC3C,uFAAuF;IACvF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC;AAkJD,qEAAqE;AACrE,qBAAa,cAAc;IAOvB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;IARhB,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,eAAe,CAA4B;IACnD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgC;gBAGtD,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,aAAa;IAK/B,4FAA4F;IACtF,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAazD,8GAA8G;IACxG,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC;YAgH9D,YAAY;IAgB1B,OAAO,CAAC,cAAc;YAOR,YAAY;YA2BZ,WAAW;YAKX,SAAS;YAMT,YAAY;YAqBZ,YAAY;YAYZ,WAAW;YAUX,UAAU;YAKV,MAAM;YA0DN,sBAAsB;IA+BpC,gFAAgF;YAClE,aAAa;YAmDb,SAAS;IA8KvB,2EAA2E;YAC7D,SAAS;IA2CvB,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,sBAAsB;YAMhB,oBAAoB;YA8CpB,QAAQ;YAMR,uBAAuB;YAavB,cAAc;YAMd,gBAAgB;YAYhB,WAAW;YAWX,aAAa;YAeb,SAAS;YAUT,UAAU;YAiFV,gBAAgB;YAUhB,kBAAkB;YASlB,eAAe;YAIf,gBAAgB;YAKhB,iBAAiB;YAcjB,WAAW;YAuDX,UAAU;YAyBV,OAAO;YAmBP,QAAQ;YAiBR,eAAe;YAMf,gBAAgB;YAehB,aAAa;YAab,kBAAkB;IAehC,OAAO,CAAC,aAAa;CAUtB;AA6ID,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,UAAU,CAAA;CACjB;AAED,+FAA+F;AAC/F,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,EAAE,CAqCnF"}
@@ -35,6 +35,7 @@ export interface ImageTransformLimits {
35
35
  }
36
36
  /** Operator-owned limits, never taken from image URL parameters. */
37
37
  export declare function resolveImageTransformLimits(options?: ImageTransformLimits): Required<ImageTransformLimits>;
38
+ export declare function imageTransformInputTooLarge(maxInputBytes: number): ImageTransformError;
38
39
  /** Parse Supabase Storage image query parameters without decoding the source. */
39
40
  export declare function parseImageTransform(query: URLSearchParams): ImageTransformParseResult;
40
41
  /** Encode a transform object into the query shape used by render/image URLs. */
@@ -1 +1 @@
1
- {"version":3,"file":"image-transform.d.ts","sourceRoot":"","sources":["../../../src/runtime/storage/image-transform.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,MAAM,CAAA;AACrD,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAA;AAErE,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,oBAAoB,CAAA;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,oBAAoB,CAAA;CAC7B;AAED,MAAM,WAAW,4BAA4B;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAA;IACvC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,oBAAoB,CAAA;CAC9B;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,KAAK,CAAA;IACT,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,MAAM,yBAAyB,GACjC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,qBAAqB,CAAA;CAAE,GAC1C,mBAAmB,CAAA;AAEvB,MAAM,MAAM,oBAAoB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACpD,mBAAmB,CAAA;AAgBvB,MAAM,WAAW,oBAAoB;IACnC,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,oEAAoE;AACpE,wBAAgB,2BAA2B,CAAC,OAAO,GAAE,oBAAyB,GAAG,QAAQ,CAAC,oBAAoB,CAAC,CAS9G;AA6BD,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,eAAe,GAAG,yBAAyB,CAsCrF;AAED,gFAAgF;AAChF,wBAAgB,4BAA4B,CAAC,OAAO,CAAC,EAAE,4BAA4B,GAAG,eAAe,CASpG;AA0DD,iFAAiF;AACjF,wBAAsB,cAAc,CAClC,MAAM,EAAE,UAAU,GAAG,IAAI,EACzB,OAAO,EAAE,qBAAqB,EAC9B,eAAe,CAAC,EAAE,MAAM,EACxB,gBAAgB,GAAE,oBAAyB,GAC1C,OAAO,CAAC,oBAAoB,CAAC,CA2D/B"}
1
+ {"version":3,"file":"image-transform.d.ts","sourceRoot":"","sources":["../../../src/runtime/storage/image-transform.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,MAAM,CAAA;AACrD,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAA;AAErE,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,oBAAoB,CAAA;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,oBAAoB,CAAA;CAC7B;AAED,MAAM,WAAW,4BAA4B;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAA;IACvC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,oBAAoB,CAAA;CAC9B;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,KAAK,CAAA;IACT,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,MAAM,yBAAyB,GACjC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,qBAAqB,CAAA;CAAE,GAC1C,mBAAmB,CAAA;AAEvB,MAAM,MAAM,oBAAoB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACpD,mBAAmB,CAAA;AAgBvB,MAAM,WAAW,oBAAoB;IACnC,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,oEAAoE;AACpE,wBAAgB,2BAA2B,CAAC,OAAO,GAAE,oBAAyB,GAAG,QAAQ,CAAC,oBAAoB,CAAC,CAS9G;AAED,wBAAgB,2BAA2B,CAAC,aAAa,EAAE,MAAM,GAAG,mBAAmB,CAOtF;AA6BD,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,eAAe,GAAG,yBAAyB,CAsCrF;AAED,gFAAgF;AAChF,wBAAgB,4BAA4B,CAAC,OAAO,CAAC,EAAE,4BAA4B,GAAG,eAAe,CASpG;AA0DD,iFAAiF;AACjF,wBAAsB,cAAc,CAClC,MAAM,EAAE,UAAU,GAAG,IAAI,EACzB,OAAO,EAAE,qBAAqB,EAC9B,eAAe,CAAC,EAAE,MAAM,EACxB,gBAAgB,GAAE,oBAAyB,GAC1C,OAAO,CAAC,oBAAoB,CAAC,CAyD/B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/lite",
3
- "version": "0.31.1",
3
+ "version": "0.31.3",
4
4
  "description": "Bun-native, single-project Supabase-compatible backend powered by PGlite or native PostgreSQL",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -59,16 +59,16 @@
59
59
  "@electric-sql/pglite-pgmq": "0.0.8",
60
60
  "@electric-sql/pglite-pgvector": "0.0.11",
61
61
  "@electric-sql/pglite-postgis": "0.2.10",
62
- "@supacloud/db": "0.18.2",
62
+ "@supacloud/db": "0.18.4",
63
63
  "exact-mirror": "1.2.6",
64
64
  "tar": "^7.5.22",
65
65
  "typebox": "1.3.37"
66
66
  },
67
67
  "devDependencies": {
68
- "@supacloud/app": "0.28.1",
69
- "@supacloud/contracts": "0.11.3",
70
- "@supacloud/compiler": "0.47.1",
71
- "@supacloud/elysia": "0.33.3",
68
+ "@supacloud/app": "0.28.3",
69
+ "@supacloud/contracts": "0.11.5",
70
+ "@supacloud/compiler": "0.47.3",
71
+ "@supacloud/elysia": "0.33.5",
72
72
  "@supabase/supabase-js": "^2.117.3",
73
73
  "@types/bun": "^1.4.3",
74
74
  "effect": "4.0.5",
@@ -77,13 +77,13 @@
77
77
  "typescript": "^7.0.2"
78
78
  },
79
79
  "overrides": {
80
- "@supacloud/db": "0.18.2",
81
- "@supacloud/app": "0.28.1",
82
- "@supacloud/compiler": "0.47.1",
83
- "@supacloud/elysia": "0.33.3",
84
- "@supacloud/contracts": "0.11.3",
85
- "@supacloud/commands": "0.9.5",
86
- "@supacloud/delivery": "0.19.2",
80
+ "@supacloud/db": "0.18.4",
81
+ "@supacloud/app": "0.28.3",
82
+ "@supacloud/compiler": "0.47.3",
83
+ "@supacloud/elysia": "0.33.5",
84
+ "@supacloud/contracts": "0.11.5",
85
+ "@supacloud/commands": "0.9.7",
86
+ "@supacloud/delivery": "0.19.4",
87
87
  "@graphql-tools/utils": "^12.0.4"
88
88
  },
89
89
  "engines": {