@supacloud/lite 0.33.2 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/README.md +135 -2
- package/deploy/README.md +110 -0
- package/deploy/caddy/Caddyfile +15 -0
- package/deploy/systemd/supacloud-lite.service +32 -0
- package/dist/cli.js +4928 -167
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4870 -160
- package/dist/project-runtime.d.ts +8 -0
- package/dist/project-runtime.d.ts.map +1 -1
- package/dist/runtime/auth/proxy.d.ts +28 -0
- package/dist/runtime/auth/proxy.d.ts.map +1 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/node/bun-server.d.ts +2 -0
- package/dist/runtime/node/bun-server.d.ts.map +1 -1
- package/dist/runtime/node/native/readiness.d.ts +2 -0
- package/dist/runtime/node/native/readiness.d.ts.map +1 -1
- package/dist/runtime/node/production-readiness.d.ts +31 -0
- package/dist/runtime/node/production-readiness.d.ts.map +1 -0
- package/dist/runtime/realtime/engine.d.ts +22 -0
- package/dist/runtime/realtime/engine.d.ts.map +1 -1
- package/dist/runtime/rest/handler.d.ts.map +1 -1
- package/dist/runtime/storage/handler.d.ts +26 -0
- package/dist/runtime/storage/handler.d.ts.map +1 -1
- package/dist/runtime/storage/s3.d.ts +69 -0
- package/dist/runtime/storage/s3.d.ts.map +1 -0
- package/dist/runtime/types.d.ts +11 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/package.json +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.35.0](https://github.com/vibeunion/supacloud/compare/supacloud-lite-v0.34.0...supacloud-lite-v0.35.0) (2026-10-26)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **lite:** add PostgREST count strategies and rollback preference ([#2253](https://github.com/vibeunion/supacloud/issues/2253)) ([b87ef01](https://github.com/vibeunion/supacloud/commit/b87ef01f320cb1ed5b94cd16ea0412cf798fe5c9))
|
|
9
|
+
* **lite:** add S3-compatible storage endpoint ([#2252](https://github.com/vibeunion/supacloud/issues/2252)) ([37a37b3](https://github.com/vibeunion/supacloud/commit/37a37b3e193cd328a5ef5e852d927b594ad1856f))
|
|
10
|
+
|
|
11
|
+
## [0.34.0](https://github.com/vibeunion/supacloud/compare/supacloud-lite-v0.33.2...supacloud-lite-v0.34.0) (2026-10-26)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* **lite:** add authorized realtime HTTP broadcast ([#2250](https://github.com/vibeunion/supacloud/issues/2250)) ([405747c](https://github.com/vibeunion/supacloud/commit/405747cce8f055c371e8f76c38a862aaf480f94c))
|
|
17
|
+
* **lite:** add production readiness doctor checks ([#2249](https://github.com/vibeunion/supacloud/issues/2249)) ([d9f09f2](https://github.com/vibeunion/supacloud/commit/d9f09f2ff797898af9a68d2c261b9d66e0eea001))
|
|
18
|
+
* **lite:** add restricted same-origin external auth proxy ([#2247](https://github.com/vibeunion/supacloud/issues/2247)) ([10e420e](https://github.com/vibeunion/supacloud/commit/10e420e700f206a8f190e6d51622c980d867fc68))
|
|
19
|
+
* **lite:** add storage status and metrics endpoints ([#2251](https://github.com/vibeunion/supacloud/issues/2251)) ([183b323](https://github.com/vibeunion/supacloud/commit/183b32397006a2b80d9961e7ae26d5779654b064))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Documentation
|
|
23
|
+
|
|
24
|
+
* **lite:** add single-node production deployment assets ([#2248](https://github.com/vibeunion/supacloud/issues/2248)) ([1e36554](https://github.com/vibeunion/supacloud/commit/1e36554cbbdbfecbb1e2a4974af560e8fa62124a))
|
|
25
|
+
|
|
3
26
|
## [0.33.2](https://github.com/vibeunion/supacloud/compare/supacloud-lite-v0.33.1...supacloud-lite-v0.33.2) (2026-10-25)
|
|
4
27
|
|
|
5
28
|
|
package/README.md
CHANGED
|
@@ -166,8 +166,23 @@ Lite 支持平铺 SQL 与 `时间戳目录/migration.sql`,执行前检查重
|
|
|
166
166
|
|
|
167
167
|
`/graphql/v1` 使用真正的 `pg_graphql` 扩展和调用者的数据库角色/RLS,不模拟扩展。默认 PGlite 和标准 native 下载包均不包含该扩展;native 可通过 `--postgres-dir` 选择已经安装匹配扩展的 PostgreSQL。配置 `[lite.graphql] enabled = true` 会在运行时启动前验证扩展,`doctor --json` 区分已支持、缺失与尚未验证。
|
|
168
168
|
|
|
169
|
+
`doctor --production` 在能力报告之外检查单机生产阻断项和运维义务:strict 运行时、非内存存储、外部身份同源代理、公开地址、数据库/存储目录隔离、状态目录位置和快照新鲜度。阻断项使命令以非零退出码结束;警告项表示必须由部署方承担的运维责任(例如 S3 对象不在快照内、PGlite 容量验证、TLS 必须由反代终止)。
|
|
170
|
+
|
|
169
171
|
外部 SupAuth 可通过 `createSupAuthLiteIdentity` 复用 `@supacloud/elysia` 的验证和业务侧本地用户映射;本地 Auth 仍是默认模式。外部模式不会把本地令牌降级当成 SupAuth,也不会根据请求头授予权限。
|
|
170
172
|
|
|
173
|
+
如果浏览器应用与身份服务不同源,且身份服务没有为业务域名开放 CORS,可在 Lite 前面启用受限的同源 OAuth 反代:
|
|
174
|
+
|
|
175
|
+
```sh
|
|
176
|
+
supacloud-lite start \
|
|
177
|
+
--external-auth-proxy-issuer https://auth.example.com/auth/v1 \
|
|
178
|
+
--external-auth-proxy-redirect-origin https://app.example.com
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
反代只接受 `/auth/v1/oauth/token`(POST)、`/auth/v1/oauth/userinfo`(GET)和
|
|
182
|
+
`/auth/v1/logout`(GET/POST),不会转发 cookie、`x-forwarded-*` 或任意上游地址。
|
|
183
|
+
授权请求仍由浏览器顶层跳转到身份服务;应用端把 token/userinfo 指向 Lite 同源地址。
|
|
184
|
+
嵌入宿主也可以直接调用 `createExternalAuthProxy()`。
|
|
185
|
+
|
|
171
186
|
完整配置、边界和回归方法见仓库文档 `docs/lite-runtime-compatibility.md`。性能基线可在源码目录运行 `bun run benchmark`,native 模式加 `--native`。
|
|
172
187
|
|
|
173
188
|
### CLI
|
|
@@ -187,7 +202,7 @@ supacloud-lite snapshot create [-o backup.tar.gz]
|
|
|
187
202
|
supacloud-lite snapshot restore <backup.tar.gz> [--force]
|
|
188
203
|
supacloud-lite upgrade [-o pre-upgrade.tar.gz]
|
|
189
204
|
supacloud-lite inspect
|
|
190
|
-
supacloud-lite doctor [--json]
|
|
205
|
+
supacloud-lite doctor [--json] [--production]
|
|
191
206
|
supacloud-lite version
|
|
192
207
|
```
|
|
193
208
|
|
|
@@ -238,6 +253,9 @@ supacloud-lite auth create-user --project-dir ./my-project \
|
|
|
238
253
|
- `SUPACLOUD_LITE_STORAGE_DIR`
|
|
239
254
|
- `SUPACLOUD_LITE_STORAGE_BACKEND`:`fs`(默认)、`memory` 或 `s3`
|
|
240
255
|
- `SUPACLOUD_LITE_S3_PREFIX`:S3 对象 key 前缀,可被 `--s3-prefix` 覆盖
|
|
256
|
+
- `SUPACLOUD_LITE_S3_ENDPOINT_ACCESS_KEY_ID` / `SUPACLOUD_LITE_S3_ENDPOINT_SECRET_ACCESS_KEY`:启用入站 `/storage/v1/s3` 的 SigV4 凭据,必须成对设置
|
|
257
|
+
- `SUPACLOUD_LITE_S3_ENDPOINT_REGION`:入站 S3 期望的 SigV4 region,默认 `us-east-1`
|
|
258
|
+
- `SUPACLOUD_LITE_S3_ENDPOINT_BUCKETS`:逗号分隔的入站 S3 bucket allowlist;为空表示项目内全部 bucket
|
|
241
259
|
- `SUPACLOUD_LITE_POSTGRES_MIRROR`:native 引擎下载 PostgreSQL 发布包时使用的 HTTPS 镜像前缀,例如 `https://ghproxy.net/`
|
|
242
260
|
- `SUPACLOUD_LITE_ENGINE`:`pglite`(默认)或 `native`
|
|
243
261
|
- `SUPACLOUD_LITE_REPLICATION_PROFILE`:仅支持显式值 `powersync`,且仅用于 native 引擎
|
|
@@ -351,6 +369,26 @@ S3 模式的快照只包含数据库中的 Storage 元数据和密钥,不复
|
|
|
351
369
|
|
|
352
370
|
内存数据库没有可持久化的数据,因此 `snapshot` 和 `upgrade` 会拒绝 `--memory`。
|
|
353
371
|
|
|
372
|
+
### S3 兼容入口
|
|
373
|
+
|
|
374
|
+
设置 `SUPACLOUD_LITE_S3_ENDPOINT_ACCESS_KEY_ID` 和 `SUPACLOUD_LITE_S3_ENDPOINT_SECRET_ACCESS_KEY` 后,Lite 会在 `/storage/v1/s3` 挂载 SigV4 + XML 的 S3 协议入口。AWS SDK 使用 path-style endpoint:
|
|
375
|
+
|
|
376
|
+
```ts
|
|
377
|
+
const s3 = new S3Client({
|
|
378
|
+
endpoint: 'https://example.com/storage/v1/s3',
|
|
379
|
+
region: 'us-east-1',
|
|
380
|
+
forcePathStyle: true,
|
|
381
|
+
credentials: { accessKeyId, secretAccessKey },
|
|
382
|
+
})
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
支持 `ListBuckets`、Bucket 创建/HEAD/删除、`PutObject`、`GetObject`/Range、`HeadObject`、`DeleteObject`、`DeleteObjects`、`ListObjectsV2`、`CopyObject`、Presigned GET,以及最多 10000 个 part 的 multipart 上传。Multipart part 会先写入 StorageDriver 的临时 key,完成时按顺序合并;因此它适合单机 Lite,不是大规模并行对象组装服务。
|
|
386
|
+
|
|
387
|
+
S3 对象和 multipart 完成后的总大小上限为 64 MiB,同时遵守 bucket 的大小、MIME 类型限制及项目默认大小限制。Multipart 完成请求必须明确列出升序且不重复的 part;XML 请求体上限为 2 MiB。
|
|
388
|
+
项目最多保留 128 个活跃 multipart 上传、10000 个临时 part 和 256 MiB 临时数据。上传 24 小时后过期,启动和后续 multipart 请求会清理过期数据;删除 bucket 时也会清理其临时分片。
|
|
389
|
+
|
|
390
|
+
第一版明确限制:只支持 path-style,不支持 virtual-hosted-style、S3 ACL/Bucket Policy、Versioning、Object Lock、Replication、S3 Select 和 `STREAMING-*` SigV4 payload。S3 凭据是服务级凭据,默认绕过 RLS;需要隔离时用 `SUPACLOUD_LITE_S3_ENDPOINT_BUCKETS` 限定 bucket。S3 写入仍使用与普通 Storage API 相同的 bucket/object 元数据和 StorageDriver。
|
|
391
|
+
|
|
354
392
|
### 兼容范围
|
|
355
393
|
|
|
356
394
|
| 能力 | V1 状态 | 说明 |
|
|
@@ -374,6 +412,21 @@ S3 模式的快照只包含数据库中的 Storage 元数据和密钥,不复
|
|
|
374
412
|
|
|
375
413
|
RLS 表的 Realtime DELETE 无法在行删除后安全重放 SELECT policy,因此 V1 只向 `service_role` 订阅者发送这类 DELETE 事件。普通用户仍可收到通过逐行 RLS 校验的 INSERT/UPDATE 事件。
|
|
376
414
|
|
|
415
|
+
PostgREST 的边缘语义补充:表和 view 的 `Prefer: count=planned` 和 `count=estimated` 都在当前角色与 JWT claims 的只读事务中读取最外层 `count(*)` 输入节点的 `Plan Rows`(该计数聚合节点本身恒为 1),保留过滤条件、RLS、inner embed、view 和查询本身的 GROUP BY 聚合。Lite 不直接读取全表 `pg_class.reltuples`;`estimated` 是保守的 planner 兼容实现,不实现 PostgREST 按阈值切换精确计数的行为,估算值仍可能不准确。两者都只用于 GET/HEAD,结果仍写入 `Content-Range`。`Prefer: tx=rollback` 可包裹成功的 POST/PATCH/DELETE,返回与实际提交相同的状态和 representation,但事务最终回滚且不触发 CDC/webhook。其他 `Prefer` 值(`return`、`resolution`、`missing`)行为不变。
|
|
416
|
+
|
|
417
|
+
Realtime 也支持服务端 HTTP 广播:
|
|
418
|
+
|
|
419
|
+
```http
|
|
420
|
+
POST /realtime/v1/api/broadcast
|
|
421
|
+
apikey: <project-anon-key>
|
|
422
|
+
authorization: Bearer <access-token>
|
|
423
|
+
content-type: application/json
|
|
424
|
+
|
|
425
|
+
{"messages":[{"topic":"room:42","event":"notice","payload":{"text":"hello"},"private":false}]}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
请求沿用 Realtime 的 `messages` 数组格式,单次最多 100 条,每条 `event` 最多 256 字节、`topic` 最多 256 字节、`payload` 最多 1 MiB。`private: true` 会按 `realtime.messages` 的 INSERT policy 校验调用者;整个批次先完成校验再发送,任一主题无写权限时返回 `403`,不会部分广播。成功返回 `202 {"message":"Broadcast sent"}`。该端点只做实时投递,不持久化消息;需要离线补偿时仍应使用数据库表或 outbox。
|
|
429
|
+
|
|
377
430
|
### Capability doctor 与 PowerSync profile
|
|
378
431
|
|
|
379
432
|
`doctor` 输出 Lite 自己的稳定能力契约,不复制完整 Management API:
|
|
@@ -508,6 +561,10 @@ Lite 的缓存调用是进程内数据库操作,不具备标准版跨进程 HT
|
|
|
508
561
|
|
|
509
562
|
V1 不在一个进程内复用多个 PGlite 项目。需要多个项目时,为每个项目配置独立的工作目录、端口和 `.supacloud-lite` 状态目录,并用进程管理器分别启动。这样可保持数据库、JWT、Storage 和 Realtime 的故障域隔离。
|
|
510
563
|
|
|
564
|
+
### 生产部署
|
|
565
|
+
|
|
566
|
+
`deploy/` 提供单机生产部署模板:systemd 用户/目录/状态目录约定、Caddy TLS 反代、外部 SupAuth 同源代理、快照维护窗口、S3 对象单独备份和回滚步骤。Lite 不自带 TLS、HA 或控制面;必须保持单进程单状态目录,并由 Caddy/Nginx 终止 TLS。生产前至少应完成容量测试、恢复演练和未认证请求失败关闭验证。
|
|
567
|
+
|
|
511
568
|
### 资源边界
|
|
512
569
|
|
|
513
570
|
PGlite 是 WebAssembly PostgreSQL,不是 SQLite。它换来了 PostgreSQL SQL、角色、RLS 和 Supabase 迁移兼容性,但内存占用通常高于 PocketBase/SQLite。生产部署前应按真实 schema、并发和 Realtime 负载做容量测试。
|
|
@@ -531,6 +588,8 @@ await running.close()
|
|
|
531
588
|
|
|
532
589
|
图片变换目前提供 Bun.Image 的兼容子集:`width`、`height`、`resize=fill|contain`,以及 `format=origin|jpeg|png|webp` 和 JPEG/WebP `quality`。`resize=cover` 需要裁剪能力,当前 Bun 运行时没有对应 API,因此会明确返回不支持错误,不会错误地把图片拉伸成 `cover`。
|
|
533
590
|
|
|
591
|
+
Storage 还提供两个运维端点:`GET /storage/v1/status` 无需项目 API key,返回服务名称、版本和健康状态;`GET /storage/v1/metrics` 需要 `service_role`,以 Prometheus 文本格式输出 bucket 数、对象元数据行数和声明对象总字节数。指标只统计 Lite 自己的 `storage` schema,不代表远端 S3 bucket 的真实用量或后台清理延迟。
|
|
592
|
+
|
|
534
593
|
也可以使用 `createLiteBackend()` 直接创建内存或自定义目录的嵌入式后端,并把它的 `fetch` 传给自定义宿主。
|
|
535
594
|
|
|
536
595
|
### 来源与许可
|
|
@@ -662,7 +721,7 @@ supacloud-lite snapshot create [-o backup.tar.gz]
|
|
|
662
721
|
supacloud-lite snapshot restore <backup.tar.gz> [--force]
|
|
663
722
|
supacloud-lite upgrade [-o pre-upgrade.tar.gz]
|
|
664
723
|
supacloud-lite inspect
|
|
665
|
-
supacloud-lite doctor [--json]
|
|
724
|
+
supacloud-lite doctor [--json] [--production]
|
|
666
725
|
supacloud-lite version
|
|
667
726
|
```
|
|
668
727
|
|
|
@@ -707,6 +766,9 @@ Environment variables:
|
|
|
707
766
|
- `SUPACLOUD_LITE_STORAGE_DIR`
|
|
708
767
|
- `SUPACLOUD_LITE_STORAGE_BACKEND`: `fs` (default), `memory`, or `s3`
|
|
709
768
|
- `SUPACLOUD_LITE_S3_PREFIX`: S3 object key prefix, can be overridden by `--s3-prefix`
|
|
769
|
+
- `SUPACLOUD_LITE_S3_ENDPOINT_ACCESS_KEY_ID` / `SUPACLOUD_LITE_S3_ENDPOINT_SECRET_ACCESS_KEY`: SigV4 credentials enabling the inbound `/storage/v1/s3` endpoint; set both together
|
|
770
|
+
- `SUPACLOUD_LITE_S3_ENDPOINT_REGION`: SigV4 region expected by the inbound S3 endpoint, default `us-east-1`
|
|
771
|
+
- `SUPACLOUD_LITE_S3_ENDPOINT_BUCKETS`: comma-separated bucket allowlist for the inbound endpoint; empty means every project bucket
|
|
710
772
|
- `SUPACLOUD_LITE_POSTGRES_MIRROR`: HTTPS prefix used to proxy native-engine PostgreSQL release downloads, for example `https://ghproxy.net/`
|
|
711
773
|
- `SUPACLOUD_LITE_ENGINE`: `pglite` (default) or `native`
|
|
712
774
|
- `SUPACLOUD_LITE_REPLICATION_PROFILE`: explicit `powersync` opt-in for the native engine only
|
|
@@ -853,10 +915,54 @@ GraphQL fails startup when missing; `doctor --json` reports actual or unverified
|
|
|
853
915
|
capability. External SupAuth can reuse the shared Elysia verifier through
|
|
854
916
|
`createSupAuthLiteIdentity` and an explicit application-owned local user mapping.
|
|
855
917
|
|
|
918
|
+
When the browser application and the identity service have different origins and
|
|
919
|
+
the identity service does not allow the application origin via CORS, Lite can
|
|
920
|
+
serve a restricted same-origin OAuth proxy:
|
|
921
|
+
|
|
922
|
+
```sh
|
|
923
|
+
supacloud-lite start \
|
|
924
|
+
--external-auth-proxy-issuer https://auth.example.com/auth/v1 \
|
|
925
|
+
--external-auth-proxy-redirect-origin https://app.example.com
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
The proxy accepts only `/auth/v1/oauth/token` (POST),
|
|
929
|
+
`/auth/v1/oauth/userinfo` (GET) and `/auth/v1/logout` (GET/POST). It never
|
|
930
|
+
forwards cookies, `x-forwarded-*`, or arbitrary upstream URLs. Authorization
|
|
931
|
+
remains a top-level navigation to the identity service; the application points
|
|
932
|
+
token/userinfo at the Lite same-origin address. Embedded hosts can call
|
|
933
|
+
`createExternalAuthProxy()` directly.
|
|
934
|
+
|
|
935
|
+
`doctor --production` adds single-node production policy checks: strict runtime,
|
|
936
|
+
non-memory storage, external identity proxying, public URLs, database/storage
|
|
937
|
+
path separation, state-directory location and snapshot freshness. Blockers exit
|
|
938
|
+
non-zero; warnings are operational obligations such as backing up S3 objects
|
|
939
|
+
outside the Lite snapshot, capacity-testing PGlite, and terminating TLS at the
|
|
940
|
+
proxy.
|
|
941
|
+
|
|
856
942
|
See repository document `docs/lite-runtime-compatibility.md` for configuration
|
|
857
943
|
and acceptance boundaries. Run `bun run benchmark` (or add `--native`) in the
|
|
858
944
|
source package for a synthetic baseline, not a production performance claim.
|
|
859
945
|
|
|
946
|
+
### S3-compatible endpoint
|
|
947
|
+
|
|
948
|
+
When `SUPACLOUD_LITE_S3_ENDPOINT_ACCESS_KEY_ID` and `SUPACLOUD_LITE_S3_ENDPOINT_SECRET_ACCESS_KEY` are set, Lite mounts a SigV4 + XML S3 endpoint at `/storage/v1/s3`. Configure AWS SDKs with a path-style endpoint:
|
|
949
|
+
|
|
950
|
+
```ts
|
|
951
|
+
const s3 = new S3Client({
|
|
952
|
+
endpoint: 'https://example.com/storage/v1/s3',
|
|
953
|
+
region: 'us-east-1',
|
|
954
|
+
forcePathStyle: true,
|
|
955
|
+
credentials: { accessKeyId, secretAccessKey },
|
|
956
|
+
})
|
|
957
|
+
```
|
|
958
|
+
|
|
959
|
+
It supports `ListBuckets`, bucket create/HEAD/delete, `PutObject`, `GetObject`/Range, `HeadObject`, `DeleteObject`, `DeleteObjects`, `ListObjectsV2`, `CopyObject`, presigned GET, and multipart uploads with up to 10000 parts. Multipart parts are staged in the StorageDriver and concatenated on completion; this is suitable for single-node Lite, not a distributed object-assembly service.
|
|
960
|
+
|
|
961
|
+
S3 objects, including completed multipart uploads, are limited to 64 MiB and also honor bucket size/MIME restrictions and the project default size limit. Completion requests must explicitly list unique parts in ascending order. XML request bodies are limited to 2 MiB.
|
|
962
|
+
Each project allows at most 128 active uploads, 10000 staged parts and 256 MiB of staged bytes. Uploads expire after 24 hours and are reclaimed at startup and on subsequent multipart requests. Bucket deletion also removes its staged multipart data.
|
|
963
|
+
|
|
964
|
+
The first version deliberately excludes virtual-hosted-style addressing, S3 ACL/Bucket Policy, Versioning, Object Lock, Replication, S3 Select, and `STREAMING-*` SigV4 payloads. S3 credentials are service-level and bypass RLS by default; use `SUPACLOUD_LITE_S3_ENDPOINT_BUCKETS` to restrict buckets. S3 writes use the same bucket/object metadata and StorageDriver as the normal Storage API.
|
|
965
|
+
|
|
860
966
|
### Compatibility Scope
|
|
861
967
|
|
|
862
968
|
| Capability | V1 Status | Notes |
|
|
@@ -880,6 +986,21 @@ source package for a synthetic baseline, not a production performance claim.
|
|
|
880
986
|
|
|
881
987
|
Realtime DELETE on RLS tables cannot safely replay SELECT policies after a row is deleted, so V1 only sends such DELETE events to `service_role` subscribers. Regular users can still receive INSERT/UPDATE events that pass row-by-row RLS validation.
|
|
882
988
|
|
|
989
|
+
PostgREST edge semantics: for tables and views, `Prefer: count=planned` and `count=estimated` both read the `Plan Rows` of the outermost `count(*)` input inside the current role and JWT-claims read-only transaction (that counting aggregate itself always produces one row). This preserves filters, RLS, inner embeds, views, and the query's own GROUP BY aggregates. Lite does not read relation-wide `pg_class.reltuples` directly; `estimated` is a conservative planner-based compatibility implementation, not PostgREST's threshold-based switch to exact counting, and estimates may still be inaccurate. Both are only evaluated for GET/HEAD and still populate `Content-Range`. `Prefer: tx=rollback` wraps a successful POST/PATCH/DELETE, returns the same status and representation as a commit, then rolls the transaction back without firing CDC/webhooks. Other `Prefer` values (`return`, `resolution`, `missing`) keep their existing behavior.
|
|
990
|
+
|
|
991
|
+
Realtime also exposes server-side HTTP broadcast:
|
|
992
|
+
|
|
993
|
+
```http
|
|
994
|
+
POST /realtime/v1/api/broadcast
|
|
995
|
+
apikey: <project-anon-key>
|
|
996
|
+
authorization: Bearer <access-token>
|
|
997
|
+
content-type: application/json
|
|
998
|
+
|
|
999
|
+
{"messages":[{"topic":"room:42","event":"notice","payload":{"text":"hello"},"private":false}]}
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
It uses Realtime's `messages` envelope: at most 100 messages per request, each `event` and `topic` at most 256 bytes, and each `payload` at most 1 MiB. `private: true` authorizes the caller through the `realtime.messages` INSERT policy. The whole batch is authorized before any delivery, so one denied topic returns `403` without partially broadcasting. Success returns `202 {"message":"Broadcast sent"}`. This endpoint delivers live events only; use a database table or outbox when messages must survive disconnects.
|
|
1003
|
+
|
|
883
1004
|
### Capability doctor and PowerSync profile
|
|
884
1005
|
|
|
885
1006
|
`supacloud-lite doctor --json` reports a stable Lite capability contract without copying the full Management API. PGlite explicitly reports Logical Replication and PowerSync source support as `unsupported`; it never emulates WAL, publications, or slots. Multi-device offline deployments should use central SupaCloud + PowerSync, while a single field workstation can use Lite as a local project server or upload through an application-owned outbox.
|
|
@@ -998,6 +1119,16 @@ Lite's cache calls are in-process database operations and do not have the timeou
|
|
|
998
1119
|
|
|
999
1120
|
V1 does not multiplex multiple PGlite projects within a single process. When multiple projects are needed, configure an independent working directory, port, and `.supacloud-lite` state directory for each project, and start them separately with a process manager. This keeps the database, JWT, Storage, and Realtime failure domains isolated.
|
|
1000
1121
|
|
|
1122
|
+
### Production Deployment
|
|
1123
|
+
|
|
1124
|
+
The `deploy/` directory documents a single-node production contract: systemd
|
|
1125
|
+
service account/state directories, Caddy TLS termination, external SupAuth
|
|
1126
|
+
same-origin proxying, snapshot maintenance windows, separate S3 object backup,
|
|
1127
|
+
and rollback. Lite does not bundle TLS, HA, or a control plane. Keep one process
|
|
1128
|
+
per state directory and terminate TLS at Caddy/Nginx. Before production, run
|
|
1129
|
+
capacity tests, a restore drill, and an unauthenticated-request fail-closed
|
|
1130
|
+
check.
|
|
1131
|
+
|
|
1001
1132
|
### Resource Boundaries
|
|
1002
1133
|
|
|
1003
1134
|
PGlite is WebAssembly PostgreSQL, not SQLite. It trades off for PostgreSQL SQL, roles, RLS, and Supabase migration compatibility, but its memory footprint is typically higher than PocketBase/SQLite. Before production deployment, you should perform capacity testing against the real schema, concurrency, and Realtime load.
|
|
@@ -1021,6 +1152,8 @@ await running.close()
|
|
|
1021
1152
|
|
|
1022
1153
|
Image transforms currently provide a compatible subset of Bun.Image: `width`, `height`, `resize=fill|contain`, as well as `format=origin|jpeg|png|webp` and JPEG/WebP `quality`. `resize=cover` requires cropping capability, which the current Bun runtime does not have a corresponding API for, so it explicitly returns an unsupported error instead of incorrectly stretching the image to `cover`.
|
|
1023
1154
|
|
|
1155
|
+
Storage also exposes two operational endpoints: `GET /storage/v1/status` needs no project API key and returns the service name, version, and health; `GET /storage/v1/metrics` requires `service_role` and returns Prometheus text with bucket count, object metadata rows, and declared object bytes. These metrics cover Lite's `storage` schema only; they do not claim the real usage of a remote S3 bucket or background cleanup latency.
|
|
1156
|
+
|
|
1024
1157
|
You can also use `createLiteBackend()` to directly create an embedded backend with an in-memory or custom directory, and pass its `fetch` to a custom host.
|
|
1025
1158
|
|
|
1026
1159
|
### Provenance and License
|
package/deploy/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# SupaCloud Lite production deployment
|
|
2
|
+
|
|
3
|
+
This directory contains a minimal single-project deployment contract. It is not
|
|
4
|
+
a multi-tenant control plane. Run one Lite process per state directory and put
|
|
5
|
+
TLS plus a reverse proxy in front of it.
|
|
6
|
+
|
|
7
|
+
## Layout
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
/opt/supacloud-lite/project reviewed migrations, seed and functions (read-only at runtime)
|
|
11
|
+
/var/lib/supacloud-lite database, storage and snapshots (persistent)
|
|
12
|
+
/etc/supacloud-lite/env secrets and runtime configuration (root:root 0600)
|
|
13
|
+
/usr/local/bin/supacloud-lite installed CLI / standalone binary
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The systemd unit sets `SUPACLOUD_LITE_STATE_DIR=/var/lib/supacloud-lite`, so the
|
|
17
|
+
project checkout does not contain mutable data.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
1. Install the pinned Lite release and verify its version.
|
|
22
|
+
2. Create a service account and directories:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
sudo useradd --system --home /var/lib/supacloud-lite --shell /usr/sbin/nologin supacloud-lite
|
|
26
|
+
sudo install -d -o supacloud-lite -g supacloud-lite -m 0750 /var/lib/supacloud-lite
|
|
27
|
+
sudo install -d -o root -g root -m 0755 /opt/supacloud-lite/project /etc/supacloud-lite
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
3. Put the reviewed project files under `/opt/supacloud-lite/project`.
|
|
31
|
+
4. Create `/etc/supacloud-lite/env` from the project's deployment secret store.
|
|
32
|
+
Keep it `root:root` and `0600`. Supported values include `S3_*` credentials,
|
|
33
|
+
`SUPACLOUD_LITE_S3_PREFIX`, `SUPACLOUD_LITE_STORAGE_BACKEND=s3`, and the
|
|
34
|
+
trusted external identity module setting.
|
|
35
|
+
5. Run migrations and create the first local account **before** starting the
|
|
36
|
+
service:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
sudo -u supacloud-lite env SUPACLOUD_LITE_STATE_DIR=/var/lib/supacloud-lite \
|
|
40
|
+
supacloud-lite migrate --project-dir /opt/supacloud-lite/project
|
|
41
|
+
sudo -u supacloud-lite env SUPACLOUD_LITE_STATE_DIR=/var/lib/supacloud-lite \
|
|
42
|
+
supacloud-lite auth create-user --project-dir /opt/supacloud-lite/project \
|
|
43
|
+
--email operator@example.com --password-stdin --email-confirm < /secure/password.txt
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
6. Install the unit and reload systemd:
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
sudo install -m 0644 deploy/systemd/supacloud-lite.service /etc/systemd/system/
|
|
50
|
+
sudo systemctl daemon-reload
|
|
51
|
+
sudo systemctl enable --now supacloud-lite
|
|
52
|
+
curl -fsS http://127.0.0.1:54321/health
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
7. Install the Caddy site from `deploy/caddy/Caddyfile`, replace the hostname,
|
|
56
|
+
and verify HTTPS plus an authenticated API request.
|
|
57
|
+
|
|
58
|
+
## External SupAuth
|
|
59
|
+
|
|
60
|
+
If the browser application and identity service are on different origins and
|
|
61
|
+
the identity service does not allow the application origin via CORS, use the
|
|
62
|
+
restricted same-origin proxy documented in the package README:
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
supacloud-lite start \
|
|
66
|
+
--external-auth-proxy-issuer https://auth.example.com/auth/v1 \
|
|
67
|
+
--external-auth-proxy-redirect-origin https://app.example.com
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The proxy handles only OAuth token, userinfo and logout. Authorization remains a
|
|
71
|
+
top-level navigation. Membership and application permissions stay in the
|
|
72
|
+
application-owned data and RLS model; Lite does not grant them from token claims.
|
|
73
|
+
|
|
74
|
+
## Backup, upgrade and restore
|
|
75
|
+
|
|
76
|
+
Lite snapshots require the process to be stopped. Use a maintenance window:
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
sudo systemctl stop supacloud-lite
|
|
80
|
+
sudo -u supacloud-lite env SUPACLOUD_LITE_STATE_DIR=/var/lib/supacloud-lite \
|
|
81
|
+
supacloud-lite snapshot create \
|
|
82
|
+
--project-dir /opt/supacloud-lite/project \
|
|
83
|
+
-o /var/lib/supacloud-lite/backups/pre-upgrade.tar.gz
|
|
84
|
+
sudo systemctl start supacloud-lite
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
For an upgrade, stop the service, install the pinned candidate, run
|
|
88
|
+
`supacloud-lite upgrade`, start the service, and verify `/health` and a real
|
|
89
|
+
authenticated read. If the upgrade fails, restore the pre-upgrade snapshot with
|
|
90
|
+
`snapshot restore --force` and restart the previous binary.
|
|
91
|
+
|
|
92
|
+
When using S3, snapshots contain database metadata and secrets but **not remote
|
|
93
|
+
objects**. Back up the bucket/prefix separately and restore it before starting
|
|
94
|
+
the service. `db reset` is intentionally rejected in S3 mode.
|
|
95
|
+
|
|
96
|
+
## Production checks
|
|
97
|
+
|
|
98
|
+
Before exposing the service:
|
|
99
|
+
|
|
100
|
+
- keep the process bound to loopback and terminate TLS at the proxy;
|
|
101
|
+
- use `--runtime-mode strict` for functions;
|
|
102
|
+
- set an explicit snapshot retention period and test a restore drill;
|
|
103
|
+
- use S3/MinIO or a durable mounted volume for storage, not an ephemeral disk;
|
|
104
|
+
- use native PostgreSQL when the project needs extensions such as `pg_graphql`;
|
|
105
|
+
- keep one process per state directory; Lite is not a multi-writer cluster;
|
|
106
|
+
- verify unauthenticated API calls fail closed and authenticated reads succeed.
|
|
107
|
+
|
|
108
|
+
`supacloud-lite doctor --json` reports the selected engine, extension inventory,
|
|
109
|
+
identity mode and replication readiness. It is a capability report, not a
|
|
110
|
+
production security certification.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Replace app.example.com with the real public hostname.
|
|
2
|
+
# Lite must remain bound to 127.0.0.1:54321 behind this proxy.
|
|
3
|
+
https://app.example.com {
|
|
4
|
+
encode zstd gzip
|
|
5
|
+
|
|
6
|
+
# Caddy terminates TLS and forwards WebSocket/Realtime upgrades by default.
|
|
7
|
+
reverse_proxy 127.0.0.1:54321
|
|
8
|
+
|
|
9
|
+
header {
|
|
10
|
+
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
|
11
|
+
X-Content-Type-Options "nosniff"
|
|
12
|
+
Referrer-Policy "strict-origin-when-cross-origin"
|
|
13
|
+
-Server
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[Unit]
|
|
2
|
+
Description=SupaCloud Lite (single-project backend)
|
|
3
|
+
Documentation=https://github.com/vibeunion/supacloud/tree/main/packages/supacloud-lite
|
|
4
|
+
After=network-online.target
|
|
5
|
+
Wants=network-online.target
|
|
6
|
+
|
|
7
|
+
[Service]
|
|
8
|
+
Type=simple
|
|
9
|
+
User=supacloud-lite
|
|
10
|
+
Group=supacloud-lite
|
|
11
|
+
WorkingDirectory=/opt/supacloud-lite/project
|
|
12
|
+
EnvironmentFile=/etc/supacloud-lite/env
|
|
13
|
+
Environment=SUPACLOUD_LITE_STATE_DIR=/var/lib/supacloud-lite
|
|
14
|
+
Environment=SUPACLOUD_LITE_HOST=127.0.0.1
|
|
15
|
+
Environment=SUPACLOUD_LITE_PORT=54321
|
|
16
|
+
Environment=SUPACLOUD_LITE_RUNTIME_MODE=strict
|
|
17
|
+
ExecStart=/usr/local/bin/supacloud-lite start --project-dir /opt/supacloud-lite/project
|
|
18
|
+
Restart=on-failure
|
|
19
|
+
RestartSec=3
|
|
20
|
+
# Lite has no bundled TLS termination. Keep it on loopback and terminate TLS in
|
|
21
|
+
# Caddy/Nginx; bind a non-loopback address only when another trusted proxy or
|
|
22
|
+
# network boundary protects it.
|
|
23
|
+
UMask=0077
|
|
24
|
+
NoNewPrivileges=true
|
|
25
|
+
PrivateTmp=true
|
|
26
|
+
ProtectHome=true
|
|
27
|
+
ProtectSystem=strict
|
|
28
|
+
StateDirectory=supacloud-lite
|
|
29
|
+
ReadWritePaths=/var/lib/supacloud-lite
|
|
30
|
+
|
|
31
|
+
[Install]
|
|
32
|
+
WantedBy=multi-user.target
|