@supacloud/lite 0.33.2 → 0.34.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/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export { S3StorageDriver, type S3StorageClientLike, type S3StorageDriverOptions,
6
6
  export type { EdgeFunction, FunctionContext } from './runtime/functions/handler.js';
7
7
  export type { PgredisCacheBinding } from './runtime/functions/pgredis.js';
8
8
  export { createSupAuthLiteIdentity, type ExternalIdentityVerifier, type VerifiedSupAuthContext } from './runtime/identity.js';
9
+ export { createExternalAuthProxy, type ExternalAuthProxy, type ExternalAuthProxyOptions, } from './runtime/auth/proxy.js';
9
10
  export { inspectGraphql, type GraphqlCapability, type GraphqlOptions } from './runtime/graphql.js';
10
11
  export type { RuntimeMode } from './runtime/functions/profile.js';
11
12
  export { SUPACLOUD_LITE_VERSION } from './version.js';
@@ -14,6 +15,7 @@ export { serveBun } from './runtime/node/bun-server.js';
14
15
  export type { RunningServer, ServerHandle, ServeOptions } from './runtime/node/bun-server.js';
15
16
  export { createNativeEngine, ensurePostgres, isNativeEngineSupported, type NativeEngineOptions, } from './runtime/node/native/engine.js';
16
17
  export { POWERSYNC_PUBLICATION, POWERSYNC_REPLICATION_ROLE, buildPowerSyncPostgresArgs, ensurePowerSyncReplicationCatalog, validatePowerSyncReplicationOptions, writePowerSyncHba, type NativeReplicationOptions, type NativeReplicationTlsOptions, type PowerSyncReplicationOptions, } from './runtime/node/native/replication.js';
18
+ export { productionReadiness, type ProductionReadiness, type ProductionReadinessInput, } from './runtime/node/production-readiness.js';
17
19
  export { inspectPowerSyncReadiness, liteCapabilities, type LiteCapabilityStatus, type LiteDoctorReport, type PowerSyncReadiness, } from './runtime/node/native/readiness.js';
18
20
  export { inspectPostgresExtensions, type ExtensionInventorySource, type ExtensionInventoryStatus, type PostgresExtension, type PostgresExtensionInventory, } from './runtime/node/native/extensions.js';
19
21
  export { createProjectBackend, ensureProjectSecrets, mintProjectKeys, resolveDatabaseEngine, resolveNativeReplicationOptions, resolveStorageBackend, resolveProjectPaths, startProjectServer, } from './project-runtime.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,IAAI,iBAAiB,EAClC,kBAAkB,EAClB,SAAS,EACT,aAAa,EACb,SAAS,EACT,OAAO,EACP,SAAS,GACV,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,aAAa,IAAI,mBAAmB,EACpC,oBAAoB,GACrB,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,UAAU,EACV,MAAM,EACN,WAAW,EACX,UAAU,EACV,SAAS,EACT,aAAa,EACb,cAAc,EACd,aAAa,GACd,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACjE,OAAO,EACL,eAAe,EACf,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,GACvB,MAAM,gCAAgC,CAAA;AACvC,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AACnF,YAAY,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAA;AACzE,OAAO,EAAE,yBAAyB,EAAE,KAAK,wBAAwB,EAAE,KAAK,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC7H,OAAO,EAAE,cAAc,EAAE,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAClG,YAAY,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAA;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AACvD,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAC7F,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,uBAAuB,EACvB,KAAK,mBAAmB,GACzB,MAAM,iCAAiC,CAAA;AACxC,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,0BAA0B,EAC1B,iCAAiC,EACjC,mCAAmC,EACnC,iBAAiB,EACjB,KAAK,wBAAwB,EAC7B,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,GACjC,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EACL,yBAAyB,EACzB,gBAAgB,EAChB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,GACxB,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EACL,yBAAyB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACtB,KAAK,0BAA0B,GAChC,MAAM,qCAAqC,CAAA;AAC5C,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,eAAe,EACf,qBAAqB,EACrB,+BAA+B,EAC/B,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,cAAc,EACd,eAAe,EACf,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,GACtB,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,wBAAwB,EACxB,cAAc,EACd,cAAc,EACd,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,GACf,MAAM,sBAAsB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,IAAI,iBAAiB,EAClC,kBAAkB,EAClB,SAAS,EACT,aAAa,EACb,SAAS,EACT,OAAO,EACP,SAAS,GACV,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,aAAa,IAAI,mBAAmB,EACpC,oBAAoB,GACrB,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,UAAU,EACV,MAAM,EACN,WAAW,EACX,UAAU,EACV,SAAS,EACT,aAAa,EACb,cAAc,EACd,aAAa,GACd,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACjE,OAAO,EACL,eAAe,EACf,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,GACvB,MAAM,gCAAgC,CAAA;AACvC,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AACnF,YAAY,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAA;AACzE,OAAO,EAAE,yBAAyB,EAAE,KAAK,wBAAwB,EAAE,KAAK,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC7H,OAAO,EACL,uBAAuB,EACvB,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,GAC9B,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,cAAc,EAAE,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAClG,YAAY,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAA;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AACvD,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAC7F,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,uBAAuB,EACvB,KAAK,mBAAmB,GACzB,MAAM,iCAAiC,CAAA;AACxC,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,0BAA0B,EAC1B,iCAAiC,EACjC,mCAAmC,EACnC,iBAAiB,EACjB,KAAK,wBAAwB,EAC7B,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,GACjC,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EACL,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,GAC9B,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EACL,yBAAyB,EACzB,gBAAgB,EAChB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,GACxB,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EACL,yBAAyB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACtB,KAAK,0BAA0B,GAChC,MAAM,qCAAqC,CAAA;AAC5C,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,eAAe,EACf,qBAAqB,EACrB,+BAA+B,EAC/B,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,cAAc,EACd,eAAe,EACf,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,GACtB,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,wBAAwB,EACxB,cAAc,EACd,cAAc,EACd,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,GACf,MAAM,sBAAsB,CAAA"}
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.33.2",
91
+ version: "0.34.0",
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",
@@ -108,6 +108,7 @@ var package_default = {
108
108
  "dist",
109
109
  "!dist/standalone",
110
110
  "README.md",
111
+ "deploy",
111
112
  "CHANGELOG.md",
112
113
  "RELEASING.md",
113
114
  "THIRD_PARTY_NOTICES.md",
@@ -9524,10 +9525,21 @@ async function sha256Hex2(text) {
9524
9525
  }
9525
9526
 
9526
9527
  // src/runtime/realtime/engine.ts
9528
+ function normalizeBroadcastTopic(raw) {
9529
+ const topic = raw.trim().replace(/^realtime:/, "");
9530
+ if (!topic)
9531
+ throw new Error("broadcast topic is required");
9532
+ return topic;
9533
+ }
9534
+
9527
9535
  class RealtimeEngine {
9528
9536
  db;
9529
9537
  jwtSecret;
9530
9538
  resolveExternalToken;
9539
+ static MAX_HTTP_BROADCAST_MESSAGES = 100;
9540
+ static MAX_HTTP_BROADCAST_TOPIC_BYTES = 256;
9541
+ static MAX_HTTP_BROADCAST_EVENT_BYTES = 256;
9542
+ static MAX_HTTP_BROADCAST_PAYLOAD_BYTES = 1024 * 1024;
9531
9543
  connections = new Set;
9532
9544
  bindingCounter = 1;
9533
9545
  phxRefCounter = 1;
@@ -9574,6 +9586,47 @@ class RealtimeEngine {
9574
9586
  return { read: false, write: false };
9575
9587
  }
9576
9588
  }
9589
+ async broadcastHttp(messages, ctx) {
9590
+ if (messages.length === 0)
9591
+ throw new Error("messages must not be empty");
9592
+ if (messages.length > RealtimeEngine.MAX_HTTP_BROADCAST_MESSAGES) {
9593
+ throw new Error(`messages must contain at most ${RealtimeEngine.MAX_HTTP_BROADCAST_MESSAGES} items`);
9594
+ }
9595
+ const normalized = [];
9596
+ for (const message of messages) {
9597
+ if (typeof message.topic !== "string")
9598
+ throw new Error("broadcast topic must be a string");
9599
+ if (typeof message.event !== "string")
9600
+ throw new Error("broadcast event must be a string");
9601
+ const topic = normalizeBroadcastTopic(message.topic);
9602
+ if (new TextEncoder().encode(topic).byteLength > RealtimeEngine.MAX_HTTP_BROADCAST_TOPIC_BYTES) {
9603
+ throw new Error("broadcast topic is too large");
9604
+ }
9605
+ const event = message.event.trim();
9606
+ if (!event)
9607
+ throw new Error("broadcast event is required");
9608
+ if (new TextEncoder().encode(event).byteLength > RealtimeEngine.MAX_HTTP_BROADCAST_EVENT_BYTES) {
9609
+ throw new Error("broadcast event is too large");
9610
+ }
9611
+ let payloadText;
9612
+ try {
9613
+ payloadText = JSON.stringify(message.payload ?? null);
9614
+ } catch {
9615
+ throw new Error("broadcast payload must be JSON serializable");
9616
+ }
9617
+ if (new TextEncoder().encode(payloadText).byteLength > RealtimeEngine.MAX_HTTP_BROADCAST_PAYLOAD_BYTES) {
9618
+ throw new Error("broadcast payload is too large");
9619
+ }
9620
+ if (message.private === true) {
9621
+ const access = await this.authorizePrivate(topic, ctx);
9622
+ if (!access.write)
9623
+ throw new Error(`not authorized to broadcast on private topic: ${topic}`);
9624
+ }
9625
+ normalized.push({ topic, event, payload: message.payload ?? null });
9626
+ }
9627
+ for (const message of normalized)
9628
+ this.dispatchDbBroadcast(message);
9629
+ }
9577
9630
  dispatchDbBroadcast(msg) {
9578
9631
  const full = `realtime:${msg.topic}`;
9579
9632
  for (const conn of this.connections) {
@@ -11936,6 +11989,11 @@ class StorageHandler {
11936
11989
  const rest = url.pathname.replace(/^\/storage\/v1\/?/, "").replace(/\/+$/, "");
11937
11990
  const method = req.method.toUpperCase();
11938
11991
  try {
11992
+ if (rest === "status" && method === "GET") {
11993
+ return json3(200, { status: "ok", name: "supacloud-lite-storage", version: SUPACLOUD_LITE_VERSION });
11994
+ }
11995
+ if (rest === "metrics" && method === "GET")
11996
+ return await this.metrics(ctx);
11939
11997
  if (rest === "bucket" && method === "POST")
11940
11998
  return await this.createBucket(req, ctx);
11941
11999
  if (rest === "bucket" && method === "GET")
@@ -12056,6 +12114,37 @@ class StorageHandler {
12056
12114
  release();
12057
12115
  }
12058
12116
  }
12117
+ async metrics(ctx) {
12118
+ const denied = this.requireService(ctx);
12119
+ if (denied)
12120
+ return denied;
12121
+ const [buckets, objects] = await Promise.all([
12122
+ this.db.query(`select count(*)::int as count from storage.buckets`),
12123
+ this.db.query(`select count(*)::int as count,
12124
+ coalesce(sum(case when metadata->>'size' ~ '^[0-9]+$' then (metadata->>'size')::bigint else 0 end), 0) as bytes
12125
+ from storage.objects`)
12126
+ ]);
12127
+ const bucketCount = buckets.rows[0]?.count ?? 0;
12128
+ const objectCount = objects.rows[0]?.count ?? 0;
12129
+ const objectBytes = Number(objects.rows[0]?.bytes ?? 0);
12130
+ const body = [
12131
+ "# HELP storage_buckets_total Number of storage buckets.",
12132
+ "# TYPE storage_buckets_total gauge",
12133
+ `storage_buckets_total ${bucketCount}`,
12134
+ "# HELP storage_objects_total Number of storage object metadata rows.",
12135
+ "# TYPE storage_objects_total gauge",
12136
+ `storage_objects_total ${objectCount}`,
12137
+ "# HELP storage_object_bytes_total Sum of declared object sizes in bytes.",
12138
+ "# TYPE storage_object_bytes_total gauge",
12139
+ `storage_object_bytes_total ${Number.isFinite(objectBytes) ? objectBytes : 0}`,
12140
+ ""
12141
+ ].join(`
12142
+ `);
12143
+ return new Response(body, {
12144
+ status: 200,
12145
+ headers: { "content-type": "text/plain; version=0.0.4; charset=utf-8" }
12146
+ });
12147
+ }
12059
12148
  requireService(ctx) {
12060
12149
  if (ctx.role !== "service_role") {
12061
12150
  return storageError(403, "Unauthorized", "Bucket management requires the service_role key");
@@ -14174,6 +14263,9 @@ ${msg.text}` : `[mail] to=${msg.to} subject="${msg.subject}"`));
14174
14263
  if (smsInbox && (path === "/sms-inbox" || path.startsWith("/sms-inbox/"))) {
14175
14264
  return withCors(smsInbox.serve(req, url));
14176
14265
  }
14266
+ if (path === "/storage/v1/status" && req.method === "GET") {
14267
+ return withCors(await storage.handle(req, { role: "anon", claims: null }, url));
14268
+ }
14177
14269
  if (path.startsWith("/storage/v1/object/public/") || path.startsWith("/storage/v1/object/sign/") || path.startsWith("/storage/v1/render/image/public/") || path.startsWith("/storage/v1/render/image/sign/")) {
14178
14270
  if (req.method === "GET" || req.method === "HEAD") {
14179
14271
  return withCors(await storage.handle(req, { role: "anon", claims: null }, url));
@@ -14209,6 +14301,50 @@ ${msg.text}` : `[mail] to=${msg.to} subject="${msg.subject}"`));
14209
14301
  const ctx = await resolveContext(req, url);
14210
14302
  if (ctx instanceof Response)
14211
14303
  return ctx;
14304
+ if (path === "/realtime/v1/api/broadcast" || path === "/realtime/v1/api/broadcast/") {
14305
+ if (req.method !== "POST") {
14306
+ return withCors(new Response(JSON.stringify({ message: "Method not allowed" }), {
14307
+ status: 405,
14308
+ headers: { "content-type": "application/json", allow: "POST" }
14309
+ }));
14310
+ }
14311
+ const contentType = req.headers.get("content-type") ?? "";
14312
+ if (contentType && !contentType.includes("application/json")) {
14313
+ return withCors(new Response(JSON.stringify({ message: "Content-Type must be application/json" }), {
14314
+ status: 415,
14315
+ headers: { "content-type": "application/json" }
14316
+ }));
14317
+ }
14318
+ let body;
14319
+ try {
14320
+ body = await req.json();
14321
+ } catch {
14322
+ return withCors(new Response(JSON.stringify({ message: "Invalid JSON body" }), {
14323
+ status: 400,
14324
+ headers: { "content-type": "application/json" }
14325
+ }));
14326
+ }
14327
+ const messages = typeof body === "object" && body !== null && "messages" in body ? body.messages : undefined;
14328
+ if (!Array.isArray(messages)) {
14329
+ return withCors(new Response(JSON.stringify({ message: "messages must be an array" }), {
14330
+ status: 400,
14331
+ headers: { "content-type": "application/json" }
14332
+ }));
14333
+ }
14334
+ try {
14335
+ await realtime.broadcastHttp(messages, ctx);
14336
+ } catch (error) {
14337
+ const message = error instanceof Error ? error.message : "Broadcast failed";
14338
+ return withCors(new Response(JSON.stringify({ message }), {
14339
+ status: message.startsWith("not authorized") ? 403 : 400,
14340
+ headers: { "content-type": "application/json" }
14341
+ }));
14342
+ }
14343
+ return withCors(new Response(JSON.stringify({ message: "Broadcast sent" }), {
14344
+ status: 202,
14345
+ headers: { "content-type": "application/json" }
14346
+ }));
14347
+ }
14212
14348
  if (path.startsWith("/rest/v1"))
14213
14349
  return withCors(await rest.handle(req, ctx, url));
14214
14350
  if (path === "/graphql/v1" || path === "/graphql/v1/")
@@ -14410,6 +14546,118 @@ class S3StorageDriver {
14410
14546
  return `${this.prefix}${normalizeKey(key)}`;
14411
14547
  }
14412
14548
  }
14549
+ // src/runtime/auth/proxy.ts
14550
+ var ALLOWED_ROUTES = {
14551
+ "/auth/v1/oauth/token": new Set(["POST"]),
14552
+ "/auth/v1/oauth/userinfo": new Set(["GET"]),
14553
+ "/auth/v1/logout": new Set(["GET", "POST"])
14554
+ };
14555
+ var FORWARD_REQUEST_HEADERS = ["accept", "authorization", "content-type", "apikey"];
14556
+ var FORWARD_RESPONSE_HEADERS = [
14557
+ "content-type",
14558
+ "cache-control",
14559
+ "retry-after",
14560
+ "www-authenticate"
14561
+ ];
14562
+ function proxyError(status, code, message, allow) {
14563
+ const headers = new Headers({
14564
+ "content-type": "application/json; charset=utf-8",
14565
+ "cache-control": "no-store"
14566
+ });
14567
+ if (allow)
14568
+ headers.set("allow", allow);
14569
+ return new Response(JSON.stringify({ code, message }), { status, headers });
14570
+ }
14571
+ function upstreamBase(issuer) {
14572
+ let url;
14573
+ try {
14574
+ url = new URL(issuer);
14575
+ } catch {
14576
+ throw new TypeError("External auth issuer must be an absolute URL");
14577
+ }
14578
+ const loopback = url.hostname === "127.0.0.1" || url.hostname === "localhost" || url.hostname === "[::1]" || url.hostname === "::1";
14579
+ if (url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) {
14580
+ throw new TypeError("External auth issuer must use HTTPS (HTTP is allowed only on loopback)");
14581
+ }
14582
+ if (url.username || url.password || url.search || url.hash) {
14583
+ throw new TypeError("External auth issuer must not contain credentials, query or fragment");
14584
+ }
14585
+ if (url.pathname.replace(/\/+$/, "") !== "/auth/v1") {
14586
+ throw new TypeError("External auth issuer must end with /auth/v1");
14587
+ }
14588
+ return url;
14589
+ }
14590
+ function redirectOrigins(base, extra = []) {
14591
+ const origins = new Set([base.origin]);
14592
+ for (const value of extra) {
14593
+ let origin;
14594
+ try {
14595
+ origin = new URL(value);
14596
+ } catch {
14597
+ throw new TypeError("External auth redirect origin must be an absolute URL");
14598
+ }
14599
+ const loopback = origin.hostname === "127.0.0.1" || origin.hostname === "localhost" || origin.hostname === "[::1]" || origin.hostname === "::1";
14600
+ if (origin.protocol !== "https:" && !(origin.protocol === "http:" && loopback)) {
14601
+ throw new TypeError("External auth redirect origin must use HTTPS (HTTP is allowed only on loopback)");
14602
+ }
14603
+ if (origin.username || origin.password || origin.search || origin.hash) {
14604
+ throw new TypeError("External auth redirect origin must not contain credentials, query or fragment");
14605
+ }
14606
+ origins.add(origin.origin);
14607
+ }
14608
+ return origins;
14609
+ }
14610
+ function createExternalAuthProxy(options) {
14611
+ const base = upstreamBase(options.issuer);
14612
+ const allowedRedirects = redirectOrigins(base, options.allowedRedirectOrigins);
14613
+ const fetcher = options.fetch ?? globalThis.fetch;
14614
+ if (typeof fetcher !== "function")
14615
+ throw new TypeError("External auth proxy requires fetch");
14616
+ return async (request) => {
14617
+ const source = new URL(request.url);
14618
+ const methods = ALLOWED_ROUTES[source.pathname];
14619
+ if (!methods)
14620
+ return null;
14621
+ if (!methods.has(request.method)) {
14622
+ return proxyError(405, "AUTH_PROXY_METHOD_NOT_ALLOWED", "Auth proxy method is not allowed", [...methods].join(", "));
14623
+ }
14624
+ const target = new URL(source.pathname + source.search, base.origin);
14625
+ const headers = new Headers;
14626
+ for (const name of FORWARD_REQUEST_HEADERS) {
14627
+ const value = request.headers.get(name);
14628
+ if (value !== null)
14629
+ headers.set(name, value);
14630
+ }
14631
+ const body = request.method === "GET" || request.method === "HEAD" ? undefined : await request.arrayBuffer();
14632
+ let upstream;
14633
+ try {
14634
+ upstream = await fetcher(target, {
14635
+ method: request.method,
14636
+ headers,
14637
+ body,
14638
+ redirect: "manual"
14639
+ });
14640
+ } catch {
14641
+ return proxyError(503, "AUTH_PROXY_UNAVAILABLE", "Identity service is temporarily unavailable");
14642
+ }
14643
+ const responseHeaders = new Headers;
14644
+ for (const name of FORWARD_RESPONSE_HEADERS) {
14645
+ const value = upstream.headers.get(name);
14646
+ if (value !== null)
14647
+ responseHeaders.set(name, value);
14648
+ }
14649
+ const location = upstream.headers.get("location");
14650
+ if (location !== null) {
14651
+ const resolved = new URL(location, base.origin);
14652
+ if (!allowedRedirects.has(resolved.origin)) {
14653
+ return proxyError(502, "AUTH_PROXY_REDIRECT_REJECTED", "Identity service redirect was rejected");
14654
+ }
14655
+ responseHeaders.set("location", resolved.href);
14656
+ }
14657
+ responseHeaders.set("cache-control", "no-store");
14658
+ return new Response(upstream.body, { status: upstream.status, headers: responseHeaders });
14659
+ };
14660
+ }
14413
14661
  // src/runtime/node/fs-driver.ts
14414
14662
  import { mkdir as mkdir2, readFile as readFile2, rename, rm, writeFile } from "fs/promises";
14415
14663
  import { dirname as dirname2, isAbsolute, join, relative, resolve as resolvePath, sep } from "path";
@@ -14480,7 +14728,11 @@ async function serveBun(backend, opts = {}) {
14480
14728
  const ip = srv.requestIP(req)?.address;
14481
14729
  if (ip)
14482
14730
  headers.set("x-supacloud-lite-remote-addr", ip);
14483
- return backend.fetch(new Request(req, { headers }));
14731
+ const request = new Request(req, { headers });
14732
+ const hookResponse = await opts.beforeRequest?.(request);
14733
+ if (hookResponse)
14734
+ return hookResponse;
14735
+ return backend.fetch(request);
14484
14736
  },
14485
14737
  websocket: {
14486
14738
  open(ws) {
@@ -15614,6 +15866,80 @@ function removeStalePidFile(pidPath) {
15614
15866
  }
15615
15867
  } catch {}
15616
15868
  }
15869
+ // src/runtime/node/production-readiness.ts
15870
+ import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve3 } from "path";
15871
+ var SNAPSHOT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
15872
+ function within(parent, child) {
15873
+ const rel = relative2(resolve3(parent), resolve3(child));
15874
+ return rel === "" || !rel.startsWith("..") && !isAbsolute2(rel);
15875
+ }
15876
+ function loopback(host) {
15877
+ return host === "127.0.0.1" || host === "localhost" || host === "::1" || host === "[::1]";
15878
+ }
15879
+ function absoluteHttpUrl(value) {
15880
+ try {
15881
+ const url = new URL(value);
15882
+ return (url.protocol === "https:" || url.protocol === "http:" && loopback(url.hostname)) && !url.username && !url.password;
15883
+ } catch {
15884
+ return false;
15885
+ }
15886
+ }
15887
+ function productionReadiness(input) {
15888
+ const blockers = [];
15889
+ const warnings = [];
15890
+ const now = input.now ?? Date.now();
15891
+ if (input.runtimeMode !== "strict") {
15892
+ blockers.push("RUNTIME_MODE_NOT_STRICT: production functions require strict runtime mode");
15893
+ }
15894
+ if (input.storageBackend === "memory") {
15895
+ blockers.push("MEMORY_STORAGE_NOT_DURABLE: memory storage loses objects on restart");
15896
+ }
15897
+ if (input.storageBackend === "fs") {
15898
+ warnings.push("LOCAL_STORAGE_REQUIRES_DURABLE_VOLUME_AND_BACKUP");
15899
+ }
15900
+ if (input.storageBackend === "s3") {
15901
+ warnings.push("S3_OBJECTS_NOT_INCLUDED_IN_SNAPSHOT: back up the bucket/prefix separately");
15902
+ }
15903
+ if (!loopback(input.host)) {
15904
+ warnings.push("DIRECT_NETWORK_BIND_WITHOUT_LITE_TLS: terminate TLS in a trusted proxy or restrict the network boundary");
15905
+ }
15906
+ if (input.engine === "pglite") {
15907
+ warnings.push("PGLITE_SINGLE_PROCESS_CAPACITY: validate the real schema, concurrency and Realtime load");
15908
+ }
15909
+ if (input.identityMode === "local") {
15910
+ warnings.push("LOCAL_AUTH_IN_PRODUCTION: own account lifecycle, confirmation and password reset");
15911
+ }
15912
+ if (input.identityMode === "external" && !input.externalAuthProxyIssuer) {
15913
+ warnings.push("EXTERNAL_AUTH_PROXY_NOT_CONFIGURED: cross-origin browser token/userinfo calls may fail CORS");
15914
+ }
15915
+ if (input.externalAuthProxyIssuer && !absoluteHttpUrl(input.externalAuthProxyIssuer)) {
15916
+ blockers.push("EXTERNAL_AUTH_PROXY_ISSUER_INVALID: use an HTTPS issuer, or HTTP only on loopback");
15917
+ }
15918
+ if (!input.siteUrl) {
15919
+ warnings.push("SITE_URL_NOT_CONFIGURED: set [auth].site_url for stable redirects");
15920
+ } else if (!absoluteHttpUrl(input.siteUrl)) {
15921
+ warnings.push("SITE_URL_NOT_HTTPS: production redirects should use HTTPS");
15922
+ }
15923
+ if (!input.apiUrl) {
15924
+ warnings.push("API_URL_NOT_CONFIGURED: set the public API URL used by Auth and Functions");
15925
+ } else if (!absoluteHttpUrl(input.apiUrl)) {
15926
+ warnings.push("API_URL_NOT_HTTPS: production API URLs should use HTTPS");
15927
+ }
15928
+ if (within(input.projectDir, input.stateDir)) {
15929
+ warnings.push("STATE_INSIDE_PROJECT: keep mutable state outside the reviewed project checkout");
15930
+ }
15931
+ if (input.dataDir && input.dataDir === input.storageDir) {
15932
+ blockers.push("DATABASE_AND_STORAGE_PATH_OVERLAP: use separate directories");
15933
+ } else if (input.dataDir && (within(input.dataDir, input.storageDir) || within(input.storageDir, input.dataDir))) {
15934
+ warnings.push("DATABASE_AND_STORAGE_PATH_NESTED: keep database and storage trees independent");
15935
+ }
15936
+ if (input.latestSnapshotAt === undefined) {
15937
+ warnings.push("NO_SNAPSHOT_FOUND: create and test a restore snapshot before promotion");
15938
+ } else if (now - input.latestSnapshotAt > SNAPSHOT_MAX_AGE_MS) {
15939
+ warnings.push("SNAPSHOT_STALE: newest snapshot is older than 7 days");
15940
+ }
15941
+ return { ready: blockers.length === 0, blockers, warnings };
15942
+ }
15617
15943
  // src/runtime/node/native/readiness.ts
15618
15944
  function liteCapabilities(engine, replicationProfile, authEnabled = true) {
15619
15945
  const extensionSource = engine === "native" ? "native-postgresql" : "pglite-bundled";
@@ -15902,7 +16228,7 @@ async function inspectPostgresExtensions(engine, source) {
15902
16228
  }
15903
16229
  // src/project-runtime.ts
15904
16230
  import { chmod, link, lstat as lstat2, mkdir as mkdir4, readFile as readFile6, realpath as realpath2, unlink as unlink2, writeFile as writeFile4 } from "fs/promises";
15905
- import { dirname as dirname4, isAbsolute as isAbsolute2, join as join7, parse, relative as relative2, resolve as resolve3 } from "path";
16231
+ import { dirname as dirname4, isAbsolute as isAbsolute3, join as join7, parse, relative as relative3, resolve as resolve4 } from "path";
15906
16232
  import { pathToFileURL as pathToFileURL2 } from "url";
15907
16233
 
15908
16234
  // src/runtime/node/config-toml.ts
@@ -17093,7 +17419,7 @@ function isNotFound(error) {
17093
17419
 
17094
17420
  // src/project-runtime.ts
17095
17421
  function resolveProjectPaths(options = {}) {
17096
- const projectDir = resolve3(options.projectDir ?? process.cwd());
17422
+ const projectDir = resolve4(options.projectDir ?? process.cwd());
17097
17423
  const stateDir = resolvePath2(projectDir, options.stateDir ?? process.env.SUPACLOUD_LITE_STATE_DIR ?? ".supacloud-lite");
17098
17424
  const databaseEngine = resolveDatabaseEngine(options.engine, options.memory);
17099
17425
  const dataDir = options.memory ? undefined : resolvePath2(projectDir, options.dataDir ?? process.env.SUPACLOUD_LITE_DATA_DIR ?? join7(stateDir, databaseEngine === "native" ? "pgdata" : "db"));
@@ -17263,7 +17589,7 @@ async function loadProjectBindings(projectDir, config) {
17263
17589
  const bindings = config.lite.migrationBindings;
17264
17590
  if (!bindings)
17265
17591
  return;
17266
- const manifest = JSON.parse(await readFile6(resolve3(projectDir, bindings.manifest), "utf8"));
17592
+ const manifest = JSON.parse(await readFile6(resolve4(projectDir, bindings.manifest), "utf8"));
17267
17593
  return {
17268
17594
  manifest,
17269
17595
  target: { environment: bindings.environment, projectRef: bindings.projectRef },
@@ -17273,7 +17599,7 @@ async function loadProjectBindings(projectDir, config) {
17273
17599
  async function loadProjectIdentity(projectDir, module) {
17274
17600
  if (!module)
17275
17601
  return;
17276
- const imported = await import(pathToFileURL2(resolve3(projectDir, module)).href);
17602
+ const imported = await import(pathToFileURL2(resolve4(projectDir, module)).href);
17277
17603
  if (!isRecord(imported) || typeof imported["default"] !== "function") {
17278
17604
  throw new Error("Lite identity module must default-export an external identity verifier");
17279
17605
  }
@@ -17339,7 +17665,11 @@ async function startProjectServer(options = {}) {
17339
17665
  const resolvedOptions = options.port === 0 ? { ...options, port: await findEphemeralPort(options.host) } : options;
17340
17666
  const project = await createProjectBackend({ ...resolvedOptions, startRuntimeServices: true });
17341
17667
  try {
17342
- const server = await serveBun(project.backend, { host: project.host, port: project.port });
17668
+ const beforeRequest = options.externalAuthProxyIssuer ? createExternalAuthProxy({
17669
+ issuer: options.externalAuthProxyIssuer,
17670
+ allowedRedirectOrigins: options.externalAuthProxyRedirectOrigins
17671
+ }) : undefined;
17672
+ const server = await serveBun(project.backend, { host: project.host, port: project.port, beforeRequest });
17343
17673
  let closePromise = null;
17344
17674
  return {
17345
17675
  ...project,
@@ -17381,7 +17711,7 @@ async function loadWebhooks(projectDir) {
17381
17711
  }
17382
17712
  }
17383
17713
  function resolvePath2(projectDir, path) {
17384
- return isAbsolute2(path) ? path : resolve3(projectDir, path);
17714
+ return isAbsolute3(path) ? path : resolve4(projectDir, path);
17385
17715
  }
17386
17716
  function randomHex(bytes) {
17387
17717
  const value = crypto.getRandomValues(new Uint8Array(bytes));
@@ -17426,7 +17756,7 @@ async function findEphemeralPort(host = "127.0.0.1") {
17426
17756
  }
17427
17757
  // src/snapshot.ts
17428
17758
  import { chmod as chmod2, copyFile, lstat as lstat3, mkdir as mkdir5, mkdtemp, readdir as readdir3, readFile as readFile7, rename as rename2, rm as rm4, writeFile as writeFile5 } from "fs/promises";
17429
- import { dirname as dirname5, join as join8, parse as parse2, relative as relative3, resolve as resolve4, sep as sep2 } from "path";
17759
+ import { dirname as dirname5, join as join8, parse as parse2, relative as relative4, resolve as resolve5, sep as sep2 } from "path";
17430
17760
  import { create as createTar, extract as extractTar2 } from "tar";
17431
17761
  var SNAPSHOT_FORMAT = "supacloud-lite-snapshot";
17432
17762
  var SNAPSHOT_VERSION = 1;
@@ -17450,7 +17780,7 @@ async function createSnapshot(options) {
17450
17780
  postgresMajor: await readPostgresMajor(paths.dataDir)
17451
17781
  } : {}
17452
17782
  };
17453
- const output = resolve4(options.output);
17783
+ const output = resolve5(options.output);
17454
17784
  if (await existingInfo(output))
17455
17785
  throw new Error(`snapshot output already exists: ${output}`);
17456
17786
  await mkdir5(dirname5(output), { recursive: true });
@@ -17491,7 +17821,7 @@ async function restoreSnapshot(options) {
17491
17821
  await mkdir5(payloadRoot, { recursive: true });
17492
17822
  await extractTar2({
17493
17823
  cwd: payloadRoot,
17494
- file: resolve4(options.input),
17824
+ file: resolve5(options.input),
17495
17825
  preserveOwner: false,
17496
17826
  preservePaths: false,
17497
17827
  strict: true,
@@ -17534,10 +17864,10 @@ async function restoreSnapshot(options) {
17534
17864
  await mkdir5(stateStage, { recursive: true });
17535
17865
  await copyEntry(join8(payloadRoot, "secrets.json"), join8(stateStage, "secrets.json"));
17536
17866
  if (paths.dataDir && isWithin(paths.stateDir, paths.dataDir)) {
17537
- await copyEntry(join8(payloadRoot, "database"), join8(stateStage, relative3(paths.stateDir, paths.dataDir)));
17867
+ await copyEntry(join8(payloadRoot, "database"), join8(stateStage, relative4(paths.stateDir, paths.dataDir)));
17538
17868
  }
17539
17869
  if (options.storageBackend === "fs" && isWithin(paths.stateDir, paths.storageDir)) {
17540
- await copyEntry(join8(payloadRoot, "storage"), join8(stateStage, relative3(paths.stateDir, paths.storageDir)));
17870
+ await copyEntry(join8(payloadRoot, "storage"), join8(stateStage, relative4(paths.stateDir, paths.storageDir)));
17541
17871
  }
17542
17872
  const swaps = [];
17543
17873
  try {
@@ -17571,11 +17901,11 @@ async function restoreSnapshot(options) {
17571
17901
  function normalizePaths(paths) {
17572
17902
  return {
17573
17903
  ...paths,
17574
- projectDir: resolve4(paths.projectDir),
17575
- stateDir: resolve4(paths.stateDir),
17576
- dataDir: paths.dataDir ? resolve4(paths.dataDir) : undefined,
17577
- storageDir: resolve4(paths.storageDir),
17578
- secretsFile: resolve4(paths.secretsFile)
17904
+ projectDir: resolve5(paths.projectDir),
17905
+ stateDir: resolve5(paths.stateDir),
17906
+ dataDir: paths.dataDir ? resolve5(paths.dataDir) : undefined,
17907
+ storageDir: resolve5(paths.storageDir),
17908
+ secretsFile: resolve5(paths.secretsFile)
17579
17909
  };
17580
17910
  }
17581
17911
  async function assertSnapshotPaths(paths, options = {}) {
@@ -17605,7 +17935,7 @@ async function assertSnapshotPaths(paths, options = {}) {
17605
17935
  async function assertDirectoryOrMissing(path) {
17606
17936
  if (!path)
17607
17937
  return;
17608
- if (resolve4(path) === parse2(resolve4(path)).root)
17938
+ if (resolve5(path) === parse2(resolve5(path)).root)
17609
17939
  throw new Error(`snapshot path must not be the filesystem root: ${path}`);
17610
17940
  try {
17611
17941
  const info = await lstat3(path);
@@ -17828,13 +18158,13 @@ async function assertNoSymlinks(root) {
17828
18158
  }
17829
18159
  }
17830
18160
  function isWithin(parent, child) {
17831
- const normalizedParent = resolve4(parent);
17832
- const normalizedChild = resolve4(child);
18161
+ const normalizedParent = resolve5(parent);
18162
+ const normalizedChild = resolve5(child);
17833
18163
  return normalizedChild !== normalizedParent && normalizedChild.startsWith(`${normalizedParent}${sep2}`);
17834
18164
  }
17835
18165
  function pathsOverlap(left, right) {
17836
- const normalizedLeft = resolve4(left);
17837
- const normalizedRight = resolve4(right);
18166
+ const normalizedLeft = resolve5(left);
18167
+ const normalizedRight = resolve5(right);
17838
18168
  return normalizedLeft === normalizedRight || isWithin(normalizedLeft, normalizedRight) || isWithin(normalizedRight, normalizedLeft);
17839
18169
  }
17840
18170
  export {
@@ -17845,6 +18175,7 @@ export {
17845
18175
  S3StorageDriver,
17846
18176
  SUPACLOUD_LITE_VERSION,
17847
18177
  buildPowerSyncPostgresArgs,
18178
+ createExternalAuthProxy,
17848
18179
  createBackend as createLiteBackend,
17849
18180
  createNativeEngine,
17850
18181
  createPgliteEngine,
@@ -17863,6 +18194,7 @@ export {
17863
18194
  isNativeEngineSupported,
17864
18195
  liteCapabilities,
17865
18196
  mintProjectKeys,
18197
+ productionReadiness,
17866
18198
  resolveDatabaseEngine,
17867
18199
  resolveNativeReplicationOptions,
17868
18200
  resolveProjectPaths,
@@ -27,6 +27,8 @@ export interface ProjectRuntimeOptions {
27
27
  graphql?: GraphqlOptions;
28
28
  externalIdentity?: ExternalIdentityVerifier;
29
29
  identityModule?: string;
30
+ externalAuthProxyIssuer?: string;
31
+ externalAuthProxyRedirectOrigins?: string[];
30
32
  postgresDir?: string;
31
33
  migrationBindings?: SeedOptions['bindings'];
32
34
  projectDir?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"project-runtime.d.ts","sourceRoot":"","sources":["../src/project-runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"project-runtime.d.ts","sourceRoot":"","sources":["../src/project-runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Same-origin reverse proxy for an external SupAuth / GoTrue OAuth runtime.
3
+ *
4
+ * Browser applications often run on a business origin that the identity
5
+ * service does not allow via CORS. The authorization request is a top-level
6
+ * navigation and needs no proxy; token exchange, userinfo and logout are
7
+ * browser API calls and can be routed through this handler instead.
8
+ *
9
+ * This is deliberately not a general-purpose proxy: only exact OAuth paths and
10
+ * methods are accepted, the upstream origin is fixed by configuration, and
11
+ * credentials, cookies and hop-by-hop headers are never forwarded.
12
+ */
13
+ export type ExternalAuthFetch = (input: URL | RequestInfo, init?: RequestInit) => Promise<Response>;
14
+ export interface ExternalAuthProxyOptions {
15
+ /** Issuer URL, for example https://auth.example.com/auth/v1. */
16
+ issuer: string;
17
+ /** Extra origins allowed as logout redirect targets, such as the application origin. */
18
+ allowedRedirectOrigins?: readonly string[];
19
+ /** Trusted host override for tests. */
20
+ fetch?: ExternalAuthFetch;
21
+ }
22
+ export type ExternalAuthProxy = (request: Request) => Promise<Response | null>;
23
+ /**
24
+ * Create a request handler that returns `null` for requests it does not own, so
25
+ * the caller can continue normal Lite routing.
26
+ */
27
+ export declare function createExternalAuthProxy(options: ExternalAuthProxyOptions): ExternalAuthProxy;
28
+ //# sourceMappingURL=proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../../src/runtime/auth/proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAgBH,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,GAAG,GAAG,WAAW,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;AAEnG,MAAM,WAAW,wBAAwB;IACvC,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAA;IACd,wFAAwF;IACxF,sBAAsB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1C,uCAAuC;IACvC,KAAK,CAAC,EAAE,iBAAiB,CAAA;CAC1B;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAA;AA0D9E;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,wBAAwB,GAAG,iBAAiB,CAoD5F"}