@supacloud/lite 0.28.0 → 0.28.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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.28.1](https://github.com/vibeunion/supacloud/compare/supacloud-lite-v0.28.0...supacloud-lite-v0.28.1) (2026-10-15)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **lite:** roll back rejected singular REST writes ([#1925](https://github.com/vibeunion/supacloud/issues/1925)) ([0af235d](https://github.com/vibeunion/supacloud/commit/0af235d55a3619ffd150e4b16751a27a32d1f2e0))
9
+
3
10
  ## [0.28.0](https://github.com/vibeunion/supacloud/compare/supacloud-lite-v0.27.1...supacloud-lite-v0.28.0) (2026-10-14)
4
11
 
5
12
 
package/RELEASING.md CHANGED
@@ -30,6 +30,15 @@ bun run build:standalone:host
30
30
  bun run test:standalone
31
31
  ```
32
32
 
33
+ 针对本地 Auth 的聚焦回归,只构建 host 产物并运行单个脚本的 Auth 入口:
34
+
35
+ ```bash
36
+ bun run build:standalone:host
37
+ bun run scripts/standalone-smoke.ts --auth-only
38
+ ```
39
+
40
+ 该入口在不含 Bun/Node/npm 的子进程 `PATH` 下启动二进制,通过真实 HTTP 和 `supabase-js` 验证注册、密码登录、刷新轮换、退出撤销,以及进程重启后的会话恢复、刷新与撤销保留。成功标记为 `standalone-auth-smoke-ok`。可用 `SUPACLOUD_LITE_STANDALONE_BINARY` 指定待验收产物。它不执行 Functions、扩展、升级、快照或恢复,不能替代完整发布验收;默认完整 smoke 也会在升级和快照恢复阶段验证同一 Auth 状态。
41
+
33
42
  Release workflow 为 Linux x64 baseline/arm64、macOS x64/arm64 和 Windows x64 baseline 构建独立产物。Linux x64 产物必须在发布 runner 上完成真实黑盒测试;其他交叉编译产物在具备对应原生 runner 前只视为已构建,不能替代平台验收。
34
43
 
35
44
  Lite release 会同时上传 `SHA256SUMS`、项目自身的 `SUPACLOUD-LITE-APACHE-2.0.txt`、`NOTICE`、`THIRD_PARTY_NOTICES.md` 和 `LICENSES/*.txt`,并为发布资产生成 provenance。正式对外分发 macOS 或 Windows 产物前,还应按项目发布策略完成代码签名;构建成功不代表已经签名或公证。
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.28.0",
11
+ version: "0.28.1",
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",
@@ -8620,7 +8620,10 @@ class RestHandler {
8620
8620
  const { rows, affected } = await this.db.withContext(ctx, async (query) => {
8621
8621
  const res = await query(built.sql, built.params);
8622
8622
  if (opts.queryReturning) {
8623
- return { rows: res.rows[0].body, affected: null };
8623
+ const rows = res.rows[0].body;
8624
+ if (opts.wantsObject && !opts.wantsCsv)
8625
+ assertObjectCardinality(rows);
8626
+ return { rows, affected: null };
8624
8627
  }
8625
8628
  return { rows: null, affected: res.affectedRows ?? 0 };
8626
8629
  });
@@ -8652,14 +8655,7 @@ class RestHandler {
8652
8655
  return new Response(opts.head ? null : rowsToCsv(rows), { status: opts.status, headers });
8653
8656
  }
8654
8657
  if (opts.wantsObject) {
8655
- if (rows.length !== 1) {
8656
- return jsonResponse(406, {
8657
- code: "PGRST116",
8658
- message: "JSON object requested, multiple (or no) rows returned",
8659
- details: `The result contains ${rows.length} rows`,
8660
- hint: null
8661
- });
8662
- }
8658
+ assertObjectCardinality(rows);
8663
8659
  headers["content-type"] = `${OBJECT_MEDIA}; charset=utf-8`;
8664
8660
  return new Response(opts.head ? null : JSON.stringify(rows[0]), {
8665
8661
  status: opts.status,
@@ -8756,17 +8752,18 @@ class RestHandler {
8756
8752
  const where = conds.length > 0 ? ` where ${conds.join(" and ")}` : "";
8757
8753
  const order = builder.renderOrder([], alias);
8758
8754
  const limitOffset = builder.renderLimitOffset("");
8759
- const core = `select ${exprs.join(", ")} from ${call} as ${quoteIdent(alias)}${where}${order}${limitOffset}`;
8760
- const sql = `select coalesce(json_agg(row_to_json(_r)), '[]'::json) as body from (${core}) _r`;
8761
- const countSql = prefer.count !== undefined ? `select count(*)::int as count from ${call} as ${quoteIdent(alias)}${where}` : undefined;
8755
+ const wantsCount = prefer.count !== undefined;
8756
+ const resultSource = wantsCount ? quoteIdent("_rpc_result") : call;
8757
+ const core = `select ${exprs.join(", ")} from ${resultSource} as ${quoteIdent(alias)}${where}${order}${limitOffset}`;
8758
+ const bodySql = `select coalesce(json_agg(row_to_json(_r)), '[]'::json) as body from (${core}) _r`;
8759
+ const sql = wantsCount ? `with ${quoteIdent("_rpc_result")} as (select * from ${call}) select (${bodySql}) as body, (select count(*)::int from ${resultSource} as ${quoteIdent(alias)}${where}) as count` : bodySql;
8762
8760
  const { rows, count } = await this.db.withContext(ctx, async (query) => {
8763
8761
  const res = await query(sql, []);
8764
- let count = null;
8765
- if (countSql) {
8766
- const c = await query(countSql, []);
8767
- count = c.rows[0].count;
8768
- }
8769
- return { rows: res.rows[0].body, count };
8762
+ const rows = res.rows[0].body;
8763
+ if (wantsObject && !wantsCsv)
8764
+ assertObjectCardinality(rows);
8765
+ const count = wantsCount ? res.rows[0].count : null;
8766
+ return { rows, count };
8770
8767
  });
8771
8768
  return this.dataResponse(rows, {
8772
8769
  status: 200,
@@ -8778,6 +8775,16 @@ class RestHandler {
8778
8775
  });
8779
8776
  }
8780
8777
  }
8778
+ function assertObjectCardinality(rows) {
8779
+ if (rows.length !== 1) {
8780
+ throw new ApiError(406, {
8781
+ code: "PGRST116",
8782
+ message: "JSON object requested, multiple (or no) rows returned",
8783
+ details: `The result contains ${rows.length} rows`,
8784
+ hint: null
8785
+ });
8786
+ }
8787
+ }
8781
8788
  function pickOverload(fns, providedNames) {
8782
8789
  const provided = new Set(providedNames);
8783
8790
  let best = null;
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.28.0",
91
+ version: "0.28.1",
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",
@@ -8614,7 +8614,10 @@ class RestHandler {
8614
8614
  const { rows, affected } = await this.db.withContext(ctx, async (query) => {
8615
8615
  const res = await query(built.sql, built.params);
8616
8616
  if (opts.queryReturning) {
8617
- return { rows: res.rows[0].body, affected: null };
8617
+ const rows = res.rows[0].body;
8618
+ if (opts.wantsObject && !opts.wantsCsv)
8619
+ assertObjectCardinality(rows);
8620
+ return { rows, affected: null };
8618
8621
  }
8619
8622
  return { rows: null, affected: res.affectedRows ?? 0 };
8620
8623
  });
@@ -8646,14 +8649,7 @@ class RestHandler {
8646
8649
  return new Response(opts.head ? null : rowsToCsv(rows), { status: opts.status, headers });
8647
8650
  }
8648
8651
  if (opts.wantsObject) {
8649
- if (rows.length !== 1) {
8650
- return jsonResponse(406, {
8651
- code: "PGRST116",
8652
- message: "JSON object requested, multiple (or no) rows returned",
8653
- details: `The result contains ${rows.length} rows`,
8654
- hint: null
8655
- });
8656
- }
8652
+ assertObjectCardinality(rows);
8657
8653
  headers["content-type"] = `${OBJECT_MEDIA}; charset=utf-8`;
8658
8654
  return new Response(opts.head ? null : JSON.stringify(rows[0]), {
8659
8655
  status: opts.status,
@@ -8750,17 +8746,18 @@ class RestHandler {
8750
8746
  const where = conds.length > 0 ? ` where ${conds.join(" and ")}` : "";
8751
8747
  const order = builder.renderOrder([], alias);
8752
8748
  const limitOffset = builder.renderLimitOffset("");
8753
- const core = `select ${exprs.join(", ")} from ${call} as ${quoteIdent(alias)}${where}${order}${limitOffset}`;
8754
- const sql = `select coalesce(json_agg(row_to_json(_r)), '[]'::json) as body from (${core}) _r`;
8755
- const countSql = prefer.count !== undefined ? `select count(*)::int as count from ${call} as ${quoteIdent(alias)}${where}` : undefined;
8749
+ const wantsCount = prefer.count !== undefined;
8750
+ const resultSource = wantsCount ? quoteIdent("_rpc_result") : call;
8751
+ const core = `select ${exprs.join(", ")} from ${resultSource} as ${quoteIdent(alias)}${where}${order}${limitOffset}`;
8752
+ const bodySql = `select coalesce(json_agg(row_to_json(_r)), '[]'::json) as body from (${core}) _r`;
8753
+ const sql = wantsCount ? `with ${quoteIdent("_rpc_result")} as (select * from ${call}) select (${bodySql}) as body, (select count(*)::int from ${resultSource} as ${quoteIdent(alias)}${where}) as count` : bodySql;
8756
8754
  const { rows, count } = await this.db.withContext(ctx, async (query) => {
8757
8755
  const res = await query(sql, []);
8758
- let count = null;
8759
- if (countSql) {
8760
- const c = await query(countSql, []);
8761
- count = c.rows[0].count;
8762
- }
8763
- return { rows: res.rows[0].body, count };
8756
+ const rows = res.rows[0].body;
8757
+ if (wantsObject && !wantsCsv)
8758
+ assertObjectCardinality(rows);
8759
+ const count = wantsCount ? res.rows[0].count : null;
8760
+ return { rows, count };
8764
8761
  });
8765
8762
  return this.dataResponse(rows, {
8766
8763
  status: 200,
@@ -8772,6 +8769,16 @@ class RestHandler {
8772
8769
  });
8773
8770
  }
8774
8771
  }
8772
+ function assertObjectCardinality(rows) {
8773
+ if (rows.length !== 1) {
8774
+ throw new ApiError(406, {
8775
+ code: "PGRST116",
8776
+ message: "JSON object requested, multiple (or no) rows returned",
8777
+ details: `The result contains ${rows.length} rows`,
8778
+ hint: null
8779
+ });
8780
+ }
8781
+ }
8775
8782
  function pickOverload(fns, providedNames) {
8776
8783
  const provided = new Set(providedNames);
8777
8784
  let best = null;
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/runtime/rest/handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAA4B,KAAK,QAAQ,EAAqB,MAAM,mBAAmB,CAAA;AAC9F,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,aAAa,CAAA;AAyF3D,oFAAoF;AACpF,qBAAa,WAAW;IAOpB,OAAO,CAAC,EAAE;IANZ,8FAA8F;IAC9F,OAAO,CAAC,cAAc,CAAU;IAChC,8EAA8E;IAC9E,OAAO,CAAC,OAAO,CAAC,CAAQ;gBAGd,EAAE,EAAE,QAAQ,EACpB,IAAI,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;IAMxD,4FAA4F;IACtF,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC;YAmC9D,WAAW;YAsHX,WAAW;IA6CzB,OAAO,CAAC,YAAY;YA4CN,SAAS;YAqET,MAAM;CAmFrB"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/runtime/rest/handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAA4B,KAAK,QAAQ,EAAqB,MAAM,mBAAmB,CAAA;AAC9F,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,aAAa,CAAA;AAyF3D,oFAAoF;AACpF,qBAAa,WAAW;IAOpB,OAAO,CAAC,EAAE;IANZ,8FAA8F;IAC9F,OAAO,CAAC,cAAc,CAAU;IAChC,8EAA8E;IAC9E,OAAO,CAAC,OAAO,CAAC,CAAQ;gBAGd,EAAE,EAAE,QAAQ,EACpB,IAAI,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;IAMxD,4FAA4F;IACtF,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC;YAmC9D,WAAW;YAsHX,WAAW;IAgDzB,OAAO,CAAC,YAAY;YAqCN,SAAS;YAqET,MAAM;CAqFrB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/lite",
3
- "version": "0.28.0",
3
+ "version": "0.28.1",
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",