@rebasepro/server 0.10.0 → 0.10.1-canary.14e53ae

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.
@@ -3,6 +3,15 @@ import { HonoEnv } from "../api/types";
3
3
  interface MiddlewareConfig {
4
4
  maxBodySize?: number;
5
5
  compression?: boolean;
6
+ /**
7
+ * The caller already installed a CORS middleware.
8
+ *
9
+ * The framework does not install one itself, so it warns when it sees no
10
+ * sign of an origin policy. The bundle runtime always installs one, and a
11
+ * warning that is wrong in the common case is worse than no warning — it
12
+ * teaches people to skim past the ones that matter.
13
+ */
14
+ corsHandled?: boolean;
6
15
  csrf?: {
7
16
  origin: string | string[] | ((origin: string) => boolean);
8
17
  };
@@ -3,3 +3,30 @@ export declare function initializeStorage(storageConfig: BackendStorageConfig |
3
3
  storageRegistry?: StorageRegistry;
4
4
  storageController?: StorageController;
5
5
  }>;
6
+ /** Inputs that decide whether storage has an access-control model at all. */
7
+ export interface StorageAccessControlState {
8
+ /** A `storageAuthorize` hook was configured (per-object access control). */
9
+ hasAuthorize: boolean;
10
+ /** Reads are deliberately public (`storagePublicRead: true`). */
11
+ publicRead: boolean;
12
+ /** The legacy "any authenticated user may touch any key" behaviour was
13
+ * explicitly acknowledged (`storageInsecureAllowAnyAuthenticated: true`). */
14
+ allowAnyAuthenticated: boolean;
15
+ }
16
+ /**
17
+ * Refuse to boot storage in production with no access-control model.
18
+ *
19
+ * Storage is not under RLS and its keys share one flat namespace, so with no
20
+ * `storageAuthorize` hook the only thing separating two users' files is key
21
+ * unguessability — which a `GET /list` defeats. This is the storage analogue of
22
+ * the locked-by-default RLS on collections: rather than ship an allow-all
23
+ * default silently, make the deployment state its intent.
24
+ *
25
+ * In production a bare allow-all config is refused (throws, so the rollout
26
+ * fails loudly instead of serving everyone's files to everyone). Outside
27
+ * production it is a loud warning, so local development is not blocked.
28
+ *
29
+ * Any one of the three explicit choices — a hook, public-read, or the insecure
30
+ * opt-out — satisfies the guard.
31
+ */
32
+ export declare function assertStorageAccessControlConfigured(state: StorageAccessControlState, isProduction: boolean): void;
package/dist/init.d.ts CHANGED
@@ -306,8 +306,32 @@ export interface RebaseBackendConfig {
306
306
  *
307
307
  * Without it, any authenticated caller may read any key they can name, so
308
308
  * multi-tenant apps should treat this as required rather than optional.
309
+ *
310
+ * In production, storage refuses to boot unless one of `storageAuthorize`,
311
+ * {@link storagePublicRead}, or {@link storageInsecureAllowAnyAuthenticated}
312
+ * is set — see `assertStorageAccessControlConfigured`.
309
313
  */
310
314
  storageAuthorize?: import("./storage/types").StorageAuthorize;
315
+ /**
316
+ * Allow unauthenticated read access to stored files (default: false).
317
+ *
318
+ * Set this only when the bucket is genuinely a public, read-only CDN.
319
+ * Writes, deletes and listing still require authentication. Because it is a
320
+ * deliberate statement that reads are public, it also satisfies the
321
+ * production storage boot guard (see {@link storageAuthorize}).
322
+ */
323
+ storagePublicRead?: boolean;
324
+ /**
325
+ * Opt out of the storage access-control boot guard, keeping the legacy
326
+ * behaviour where **any** authenticated user can read, overwrite, delete or
327
+ * list **any** key (storage keys share one flat namespace and are not under
328
+ * RLS).
329
+ *
330
+ * Only safe for single-tenant apps where every signed-in user is trusted
331
+ * with every file. Multi-tenant apps must use `storageAuthorize` instead.
332
+ * Without one of these, storage refuses to boot in production.
333
+ */
334
+ storageInsecureAllowAnyAuthenticated?: boolean;
311
335
  /**
312
336
  * Entity history / audit-log configuration.
313
337
  *
@@ -381,6 +405,25 @@ export interface RebaseBackendConfig {
381
405
  * ```
382
406
  */
383
407
  callbacks?: CollectionCallbacks;
408
+ /**
409
+ * Declare that this application installs its own CORS middleware.
410
+ *
411
+ * Suppresses the "no CORS configuration detected" warning, which exists for
412
+ * hand-wired backends that genuinely have no origin policy.
413
+ */
414
+ corsHandled?: boolean;
415
+ /**
416
+ * The schema version this deployment serves, as recorded when it was built.
417
+ *
418
+ * Published by the contract endpoint so a client generated elsewhere can
419
+ * tell whether it is current. Leave unset and the runtime computes one from
420
+ * the live collections — correct, but it means the value moves whenever the
421
+ * collections do, which is exactly right for `baas` mode and slightly less
422
+ * useful for a built bundle that already knows its own answer.
423
+ */
424
+ schemaVersion?: string;
425
+ /** Runtime version reported by the contract endpoint. Informational. */
426
+ runtimeVersion?: string;
384
427
  }
385
428
  /**
386
429
  * Type guard to detect whether the `auth` config is an `AuthAdapter`
@@ -4165,6 +4165,7 @@ var require_jsonwebtoken = /* @__PURE__ */ __commonJSMin(((exports, module) => {
4165
4165
  //#endregion
4166
4166
  //#region src/auth/jwt.ts
4167
4167
  var jwt_exports = /* @__PURE__ */ __exportAll({
4168
+ MAX_COOKIE_AGE_MS: () => MAX_COOKIE_AGE_MS,
4168
4169
  configureJwt: () => configureJwt,
4169
4170
  generateAccessToken: () => generateAccessToken,
4170
4171
  generateDownloadToken: () => generateDownloadToken,
@@ -4172,6 +4173,7 @@ var jwt_exports = /* @__PURE__ */ __exportAll({
4172
4173
  getAccessTokenExpiry: () => getAccessTokenExpiry,
4173
4174
  getAccessTokenExpiryMs: () => getAccessTokenExpiryMs,
4174
4175
  getRefreshTokenExpiry: () => getRefreshTokenExpiry,
4176
+ getRefreshTokenTtlMs: () => getRefreshTokenTtlMs,
4175
4177
  hashRefreshToken: () => hashRefreshToken,
4176
4178
  verifyAccessToken: () => verifyAccessToken,
4177
4179
  verifyDownloadToken: () => verifyDownloadToken
@@ -4180,7 +4182,7 @@ var import_jsonwebtoken = /* @__PURE__ */ __toESM(require_jsonwebtoken(), 1);
4180
4182
  var jwtConfig = {
4181
4183
  secret: "",
4182
4184
  accessExpiresIn: "1h",
4183
- refreshExpiresIn: "30d"
4185
+ refreshExpiresIn: "400d"
4184
4186
  };
4185
4187
  /**
4186
4188
  * Configure JWT settings - call this during initialization.
@@ -4306,30 +4308,40 @@ function hashRefreshToken(token) {
4306
4308
  return createHash("sha256").update(token).digest("hex");
4307
4309
  }
4308
4310
  /**
4309
- * Calculate refresh token expiration date
4311
+ * The longest a cookie can live. Chrome (since 104) and RFC 6265bis silently
4312
+ * rewrite any `Max-Age` beyond 400 days down to 400 days, so promising a
4313
+ * browser more is not a stricter policy — it is a policy that differs from
4314
+ * what is actually enforced, which is worse than knowing the ceiling.
4310
4315
  */
4311
- function getRefreshTokenExpiry() {
4312
- const match = (jwtConfig.refreshExpiresIn || "30d").match(/^(\d+)([dhms])$/);
4313
- if (!match) return new Date(Date.now() + 720 * 60 * 60 * 1e3);
4316
+ var MAX_COOKIE_AGE_MS = 400 * 24 * 60 * 60 * 1e3;
4317
+ /** Fallback when `refreshExpiresIn` is unset or unparseable. */
4318
+ var DEFAULT_REFRESH_TTL_MS = MAX_COOKIE_AGE_MS;
4319
+ /**
4320
+ * How long a refresh token is valid for, in milliseconds.
4321
+ *
4322
+ * Every rotation issues a token with a fresh TTL, so this is a sliding window:
4323
+ * a user who visits at all keeps their session indefinitely, and one who
4324
+ * disappears loses it this long after their last visit. That is what both
4325
+ * Firebase and Supabase do by default, and it is the behaviour people mean
4326
+ * when they say they expect to still be signed in.
4327
+ */
4328
+ function getRefreshTokenTtlMs() {
4329
+ const match = jwtConfig.refreshExpiresIn?.match(/^(\d+)([dhms])$/);
4330
+ if (!match) return DEFAULT_REFRESH_TTL_MS;
4314
4331
  const value = parseInt(match[1], 10);
4315
- const unit = match[2];
4316
- let ms;
4317
- switch (unit) {
4318
- case "d":
4319
- ms = value * 24 * 60 * 60 * 1e3;
4320
- break;
4321
- case "h":
4322
- ms = value * 60 * 60 * 1e3;
4323
- break;
4324
- case "m":
4325
- ms = value * 60 * 1e3;
4326
- break;
4327
- case "s":
4328
- ms = value * 1e3;
4329
- break;
4330
- default: ms = 720 * 60 * 60 * 1e3;
4332
+ switch (match[2]) {
4333
+ case "d": return value * 24 * 60 * 60 * 1e3;
4334
+ case "h": return value * 60 * 60 * 1e3;
4335
+ case "m": return value * 60 * 1e3;
4336
+ case "s": return value * 1e3;
4337
+ default: return DEFAULT_REFRESH_TTL_MS;
4331
4338
  }
4332
- return new Date(Date.now() + ms);
4339
+ }
4340
+ /**
4341
+ * Calculate refresh token expiration date
4342
+ */
4343
+ function getRefreshTokenExpiry() {
4344
+ return new Date(Date.now() + getRefreshTokenTtlMs());
4333
4345
  }
4334
4346
  /**
4335
4347
  * Generate a short-lived download token scoped to a specific file path or prefix
@@ -4363,6 +4375,6 @@ function verifyDownloadToken(token) {
4363
4375
  }
4364
4376
  }
4365
4377
  //#endregion
4366
- export { getAccessTokenExpiry as a, jwt_exports as c, require_jsonwebtoken as d, __commonJSMin as f, __toESM as h, generateRefreshToken as i, verifyAccessToken as l, __require as m, generateAccessToken as n, getRefreshTokenExpiry as o, __exportAll as p, generateDownloadToken as r, hashRefreshToken as s, configureJwt as t, verifyDownloadToken as u };
4378
+ export { __toESM as _, generateRefreshToken as a, getRefreshTokenTtlMs as c, verifyAccessToken as d, verifyDownloadToken as f, __require as g, __exportAll as h, generateDownloadToken as i, hashRefreshToken as l, __commonJSMin as m, configureJwt as n, getAccessTokenExpiry as o, require_jsonwebtoken as p, generateAccessToken as r, getRefreshTokenExpiry as s, MAX_COOKIE_AGE_MS as t, jwt_exports as u };
4367
4379
 
4368
- //# sourceMappingURL=jwt-B3zjddCa.js.map
4380
+ //# sourceMappingURL=jwt-Dj7r7QX7.js.map