@rebasepro/server 0.9.1-canary.fd3754b → 0.10.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/api/errors.d.ts +16 -1
- package/dist/api/rest/api-generator.d.ts +13 -1
- package/dist/api/rest/write-validation.d.ts +22 -0
- package/dist/api/types.d.ts +2 -2
- package/dist/auth/admin-users-route.d.ts +3 -3
- package/dist/auth/api-keys/api-key-middleware.d.ts +60 -1
- package/dist/auth/api-keys/api-key-permission-guard.d.ts +33 -0
- package/dist/auth/api-keys/api-key-types.d.ts +21 -8
- package/dist/auth/api-keys/index.d.ts +2 -2
- package/dist/auth/auth-hooks.d.ts +7 -7
- package/dist/auth/collection-callback-warning.d.ts +21 -0
- package/dist/auth/index.d.ts +4 -1
- package/dist/auth/interfaces.d.ts +28 -28
- package/dist/auth/jwt.d.ts +20 -4
- package/dist/auth/magic-link-routes.d.ts +2 -2
- package/dist/auth/mfa-routes.d.ts +1 -1
- package/dist/auth/middleware.d.ts +24 -3
- package/dist/auth/rate-limit-store.d.ts +49 -0
- package/dist/auth/rate-limiter.d.ts +68 -6
- package/dist/auth/reset-password-admin.d.ts +1 -1
- package/dist/auth/session-routes.d.ts +2 -2
- package/dist/cron/cron-store.d.ts +18 -0
- package/dist/env.d.ts +4 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.es.js +2124 -505
- package/dist/index.es.js.map +1 -1
- package/dist/init/middlewares.d.ts +1 -0
- package/dist/init.d.ts +62 -0
- package/dist/{jwt-BwIn8xmk.js → jwt-B3zjddCa.js} +177 -9
- package/dist/jwt-B3zjddCa.js.map +1 -0
- package/dist/{openapi-generator-Z9oYWLf_.js → openapi-generator-DqSIwNLV.js} +8 -2
- package/dist/openapi-generator-DqSIwNLV.js.map +1 -0
- package/dist/{src-B4OLmNVa.js → src-CsHhSKbi.js} +60 -2
- package/dist/src-CsHhSKbi.js.map +1 -0
- package/dist/storage/LocalStorageController.d.ts +19 -2
- package/dist/storage/routes.d.ts +8 -1
- package/dist/storage/tus-handler.d.ts +21 -1
- package/dist/storage/types.d.ts +33 -0
- package/dist/utils/compression.d.ts +16 -0
- package/dist/utils/sql.d.ts +2 -2
- package/package.json +12 -11
- package/dist/index.umd.js +0 -48745
- package/dist/index.umd.js.map +0 -1
- package/dist/jwt-BwIn8xmk.js.map +0 -1
- package/dist/ms-DnYXB-Wd.js +0 -162
- package/dist/ms-DnYXB-Wd.js.map +0 -1
- package/dist/openapi-generator-Z9oYWLf_.js.map +0 -1
- package/dist/src-B4OLmNVa.js.map +0 -1
- package/dist/src-B9tjYmqP.js +0 -24598
- package/dist/src-B9tjYmqP.js.map +0 -1
package/dist/init.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { Server } from "http";
|
|
|
5
5
|
import { Hono } from "hono";
|
|
6
6
|
import { HonoEnv } from "./api/types";
|
|
7
7
|
import { BackendStorageConfig, StorageController, StorageRegistry } from "./storage";
|
|
8
|
+
import { type DataRateLimitConfig } from "./auth/rate-limiter";
|
|
8
9
|
import { EmailConfig } from "./email";
|
|
9
10
|
import type { OAuthProvider } from "./auth/interfaces";
|
|
10
11
|
import type { AuthHooks } from "./auth/auth-hooks";
|
|
@@ -193,6 +194,17 @@ export interface RebaseBackendConfig {
|
|
|
193
194
|
server: Server;
|
|
194
195
|
app: Hono<HonoEnv>;
|
|
195
196
|
basePath?: string;
|
|
197
|
+
/**
|
|
198
|
+
* Rate limiting for the data API, per caller: an API key by its id, a
|
|
199
|
+
* signed-in user by their uid, anyone else by IP.
|
|
200
|
+
*
|
|
201
|
+
* On by default with loose limits — a floor against a runaway client, not a
|
|
202
|
+
* quota. Counts live in this process's memory unless you pass a `store`, so
|
|
203
|
+
* N replicas enforce N times the limit between them; set real quotas at a
|
|
204
|
+
* proxy or supply a shared store if that matters. `{ enabled: false }` for
|
|
205
|
+
* a deployment whose edge already does this.
|
|
206
|
+
*/
|
|
207
|
+
rateLimit?: DataRateLimitConfig;
|
|
196
208
|
/**
|
|
197
209
|
* How much of Rebase to run.
|
|
198
210
|
*
|
|
@@ -275,6 +287,27 @@ export interface RebaseBackendConfig {
|
|
|
275
287
|
* external storage) that the backend does not proxy.
|
|
276
288
|
*/
|
|
277
289
|
storageSources?: import("@rebasepro/types").StorageSourceDefinition[];
|
|
290
|
+
/**
|
|
291
|
+
* Per-object access control for storage — the analogue of a collection's
|
|
292
|
+
* security rules, and the thing `requireAuth` / `publicRead` cannot
|
|
293
|
+
* express because they are global switches.
|
|
294
|
+
*
|
|
295
|
+
* Called after authentication on every storage route with the key, bucket,
|
|
296
|
+
* operation (`read` / `write` / `delete` / `list`) and resolved user.
|
|
297
|
+
* Return false to deny with a 403; throwing denies too.
|
|
298
|
+
*
|
|
299
|
+
* ```ts
|
|
300
|
+
* storageAuthorize: async ({ key, user, operation }) => {
|
|
301
|
+
* if (!user) return false;
|
|
302
|
+
* const [ownerId] = key.split("/");
|
|
303
|
+
* return ownerId === user.uid || operation === "read";
|
|
304
|
+
* }
|
|
305
|
+
* ```
|
|
306
|
+
*
|
|
307
|
+
* Without it, any authenticated caller may read any key they can name, so
|
|
308
|
+
* multi-tenant apps should treat this as required rather than optional.
|
|
309
|
+
*/
|
|
310
|
+
storageAuthorize?: import("./storage/types").StorageAuthorize;
|
|
278
311
|
/**
|
|
279
312
|
* Entity history / audit-log configuration.
|
|
280
313
|
*
|
|
@@ -299,6 +332,20 @@ export interface RebaseBackendConfig {
|
|
|
299
332
|
* `maxFileSize` property (default: 50MB), which takes precedence over this.
|
|
300
333
|
*/
|
|
301
334
|
maxBodySize?: number;
|
|
335
|
+
/**
|
|
336
|
+
* Response compression for API routes. **Enabled by default.**
|
|
337
|
+
*
|
|
338
|
+
* Compresses responses with gzip/deflate, negotiated from the request's
|
|
339
|
+
* `Accept-Encoding`. Bodies that are already compressed (images, video),
|
|
340
|
+
* streamed (`text/event-stream`), or explicitly marked
|
|
341
|
+
* `Cache-Control: no-transform` are left untouched, so this is safe to
|
|
342
|
+
* leave on — a large JSON list response typically drops by ~20x.
|
|
343
|
+
*
|
|
344
|
+
* Set to `false` when something in front of the app already compresses
|
|
345
|
+
* (nginx, Cloudflare, or another reverse proxy / load balancer), to avoid
|
|
346
|
+
* paying for it twice.
|
|
347
|
+
*/
|
|
348
|
+
compression?: boolean;
|
|
302
349
|
/**
|
|
303
350
|
* CSRF protection configuration. **Opt-in** — disabled by default.
|
|
304
351
|
*
|
|
@@ -357,6 +404,21 @@ export interface RebaseBackendInstance {
|
|
|
357
404
|
storageController?: StorageController;
|
|
358
405
|
collectionRegistry: BackendCollectionRegistry;
|
|
359
406
|
cronScheduler?: import("./cron").CronScheduler;
|
|
407
|
+
/**
|
|
408
|
+
* Attach collection callbacks AFTER initialization.
|
|
409
|
+
*
|
|
410
|
+
* Use this instead of mutating `collectionRegistry.get(slug).callbacks`.
|
|
411
|
+
* Every registry normalizes its collections through `{ ...c }`, so the
|
|
412
|
+
* backend registry and each driver's registry hold **separate copies** of
|
|
413
|
+
* the same collection — assigning callbacks to one is invisible to the
|
|
414
|
+
* driver that actually invokes them, and the hooks silently never fire.
|
|
415
|
+
* This writes to all of them.
|
|
416
|
+
*
|
|
417
|
+
* (Assignment, not `Object.defineProperty`: the driver resolves callbacks
|
|
418
|
+
* with a spread, which copies only enumerable properties, and
|
|
419
|
+
* defineProperty defaults `enumerable` to false.)
|
|
420
|
+
*/
|
|
421
|
+
setCollectionCallbacks(slug: string, callbacks: import("@rebasepro/types").CollectionCallbacks): void;
|
|
360
422
|
/**
|
|
361
423
|
* Deep health check that verifies database connectivity.
|
|
362
424
|
* Returns latency and component status.
|
|
@@ -1,9 +1,44 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "module";
|
|
2
2
|
import process from "process";
|
|
3
|
-
__createRequire(import.meta.url);
|
|
4
|
-
import { a as __require, i as __exportAll, n as __commonJSMin, s as __toESM, t as require_ms } from "./ms-DnYXB-Wd.js";
|
|
3
|
+
const require = __createRequire(import.meta.url);
|
|
5
4
|
import { t as logger } from "./logger-BYU66ENZ.js";
|
|
6
5
|
import { createHash, randomBytes } from "crypto";
|
|
6
|
+
//#region \0rolldown/runtime.js
|
|
7
|
+
var __create = Object.create;
|
|
8
|
+
var __defProp = Object.defineProperty;
|
|
9
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
10
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
11
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
12
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
13
|
+
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
14
|
+
var __exportAll = (all, no_symbols) => {
|
|
15
|
+
let target = {};
|
|
16
|
+
for (var name in all) __defProp(target, name, {
|
|
17
|
+
get: all[name],
|
|
18
|
+
enumerable: true
|
|
19
|
+
});
|
|
20
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
21
|
+
return target;
|
|
22
|
+
};
|
|
23
|
+
var __copyProps = (to, from, except, desc) => {
|
|
24
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
25
|
+
key = keys[i];
|
|
26
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
27
|
+
get: ((k) => from[k]).bind(null, key),
|
|
28
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return to;
|
|
32
|
+
};
|
|
33
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
34
|
+
value: mod,
|
|
35
|
+
enumerable: true
|
|
36
|
+
}) : target, mod));
|
|
37
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x)(function(x) {
|
|
38
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
39
|
+
throw Error("Calling `require` for \"" + x + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
|
|
40
|
+
});
|
|
41
|
+
//#endregion
|
|
7
42
|
//#region ../../node_modules/.pnpm/safe-buffer@5.2.1/node_modules/safe-buffer/index.js
|
|
8
43
|
var require_safe_buffer = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
9
44
|
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
|
@@ -674,6 +709,124 @@ var require_TokenExpiredError = /* @__PURE__ */ __commonJSMin(((exports, module)
|
|
|
674
709
|
module.exports = TokenExpiredError;
|
|
675
710
|
}));
|
|
676
711
|
//#endregion
|
|
712
|
+
//#region ../../node_modules/.pnpm/ms@2.1.3/node_modules/ms/index.js
|
|
713
|
+
var require_ms = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
714
|
+
/**
|
|
715
|
+
* Helpers.
|
|
716
|
+
*/
|
|
717
|
+
var s = 1e3;
|
|
718
|
+
var m = s * 60;
|
|
719
|
+
var h = m * 60;
|
|
720
|
+
var d = h * 24;
|
|
721
|
+
var w = d * 7;
|
|
722
|
+
var y = d * 365.25;
|
|
723
|
+
/**
|
|
724
|
+
* Parse or format the given `val`.
|
|
725
|
+
*
|
|
726
|
+
* Options:
|
|
727
|
+
*
|
|
728
|
+
* - `long` verbose formatting [false]
|
|
729
|
+
*
|
|
730
|
+
* @param {String|Number} val
|
|
731
|
+
* @param {Object} [options]
|
|
732
|
+
* @throws {Error} throw an error if val is not a non-empty string or a number
|
|
733
|
+
* @return {String|Number}
|
|
734
|
+
* @api public
|
|
735
|
+
*/
|
|
736
|
+
module.exports = function(val, options) {
|
|
737
|
+
options = options || {};
|
|
738
|
+
var type = typeof val;
|
|
739
|
+
if (type === "string" && val.length > 0) return parse(val);
|
|
740
|
+
else if (type === "number" && isFinite(val)) return options.long ? fmtLong(val) : fmtShort(val);
|
|
741
|
+
throw new Error("val is not a non-empty string or a valid number. val=" + JSON.stringify(val));
|
|
742
|
+
};
|
|
743
|
+
/**
|
|
744
|
+
* Parse the given `str` and return milliseconds.
|
|
745
|
+
*
|
|
746
|
+
* @param {String} str
|
|
747
|
+
* @return {Number}
|
|
748
|
+
* @api private
|
|
749
|
+
*/
|
|
750
|
+
function parse(str) {
|
|
751
|
+
str = String(str);
|
|
752
|
+
if (str.length > 100) return;
|
|
753
|
+
var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(str);
|
|
754
|
+
if (!match) return;
|
|
755
|
+
var n = parseFloat(match[1]);
|
|
756
|
+
switch ((match[2] || "ms").toLowerCase()) {
|
|
757
|
+
case "years":
|
|
758
|
+
case "year":
|
|
759
|
+
case "yrs":
|
|
760
|
+
case "yr":
|
|
761
|
+
case "y": return n * y;
|
|
762
|
+
case "weeks":
|
|
763
|
+
case "week":
|
|
764
|
+
case "w": return n * w;
|
|
765
|
+
case "days":
|
|
766
|
+
case "day":
|
|
767
|
+
case "d": return n * d;
|
|
768
|
+
case "hours":
|
|
769
|
+
case "hour":
|
|
770
|
+
case "hrs":
|
|
771
|
+
case "hr":
|
|
772
|
+
case "h": return n * h;
|
|
773
|
+
case "minutes":
|
|
774
|
+
case "minute":
|
|
775
|
+
case "mins":
|
|
776
|
+
case "min":
|
|
777
|
+
case "m": return n * m;
|
|
778
|
+
case "seconds":
|
|
779
|
+
case "second":
|
|
780
|
+
case "secs":
|
|
781
|
+
case "sec":
|
|
782
|
+
case "s": return n * s;
|
|
783
|
+
case "milliseconds":
|
|
784
|
+
case "millisecond":
|
|
785
|
+
case "msecs":
|
|
786
|
+
case "msec":
|
|
787
|
+
case "ms": return n;
|
|
788
|
+
default: return;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Short format for `ms`.
|
|
793
|
+
*
|
|
794
|
+
* @param {Number} ms
|
|
795
|
+
* @return {String}
|
|
796
|
+
* @api private
|
|
797
|
+
*/
|
|
798
|
+
function fmtShort(ms) {
|
|
799
|
+
var msAbs = Math.abs(ms);
|
|
800
|
+
if (msAbs >= d) return Math.round(ms / d) + "d";
|
|
801
|
+
if (msAbs >= h) return Math.round(ms / h) + "h";
|
|
802
|
+
if (msAbs >= m) return Math.round(ms / m) + "m";
|
|
803
|
+
if (msAbs >= s) return Math.round(ms / s) + "s";
|
|
804
|
+
return ms + "ms";
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* Long format for `ms`.
|
|
808
|
+
*
|
|
809
|
+
* @param {Number} ms
|
|
810
|
+
* @return {String}
|
|
811
|
+
* @api private
|
|
812
|
+
*/
|
|
813
|
+
function fmtLong(ms) {
|
|
814
|
+
var msAbs = Math.abs(ms);
|
|
815
|
+
if (msAbs >= d) return plural(ms, msAbs, d, "day");
|
|
816
|
+
if (msAbs >= h) return plural(ms, msAbs, h, "hour");
|
|
817
|
+
if (msAbs >= m) return plural(ms, msAbs, m, "minute");
|
|
818
|
+
if (msAbs >= s) return plural(ms, msAbs, s, "second");
|
|
819
|
+
return ms + " ms";
|
|
820
|
+
}
|
|
821
|
+
/**
|
|
822
|
+
* Pluralization helper.
|
|
823
|
+
*/
|
|
824
|
+
function plural(ms, msAbs, n, name) {
|
|
825
|
+
var isPlural = msAbs >= n * 1.5;
|
|
826
|
+
return Math.round(ms / n) + " " + name + (isPlural ? "s" : "");
|
|
827
|
+
}
|
|
828
|
+
}));
|
|
829
|
+
//#endregion
|
|
677
830
|
//#region ../../node_modules/.pnpm/jsonwebtoken@9.0.3/node_modules/jsonwebtoken/lib/timespan.js
|
|
678
831
|
var require_timespan = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
679
832
|
var ms = require_ms();
|
|
@@ -4065,10 +4218,10 @@ function configureJwt(config) {
|
|
|
4065
4218
|
/**
|
|
4066
4219
|
* Generate an access token (short-lived, 1 hour by default)
|
|
4067
4220
|
*/
|
|
4068
|
-
function generateAccessToken(
|
|
4221
|
+
function generateAccessToken(uid, roles, aal = "aal1", customClaims) {
|
|
4069
4222
|
if (!jwtConfig.secret) throw new Error("JWT secret not configured. Call configureJwt() first.");
|
|
4070
4223
|
const payload = {
|
|
4071
|
-
|
|
4224
|
+
uid,
|
|
4072
4225
|
roles,
|
|
4073
4226
|
aal,
|
|
4074
4227
|
...customClaims
|
|
@@ -4100,20 +4253,35 @@ function getAccessTokenExpiry() {
|
|
|
4100
4253
|
return Date.now() + getAccessTokenExpiryMs();
|
|
4101
4254
|
}
|
|
4102
4255
|
/**
|
|
4103
|
-
* Verify and decode an access token
|
|
4256
|
+
* Verify and decode an access token.
|
|
4257
|
+
*
|
|
4258
|
+
* Every token this server issues is signed with the same secret, so what a
|
|
4259
|
+
* token *is* comes from its claims, not from its signature. A download token
|
|
4260
|
+
* ({@link generateDownloadToken}) is therefore a validly-signed string that
|
|
4261
|
+
* must never authenticate anybody: it is scoped to one file path and handed out
|
|
4262
|
+
* in URLs, which is a far weaker thing to hold than a session.
|
|
4263
|
+
*
|
|
4264
|
+
* Today it is rejected below for want of an id — but only by luck, since
|
|
4265
|
+
* nothing stops a future download token from carrying one. So the purpose is
|
|
4266
|
+
* checked explicitly: a token minted for reading a file is not a token for
|
|
4267
|
+
* being a user.
|
|
4104
4268
|
*/
|
|
4105
4269
|
function verifyAccessToken(token) {
|
|
4106
4270
|
if (!jwtConfig.secret) throw new Error("JWT secret not configured. Call configureJwt() first.");
|
|
4107
4271
|
try {
|
|
4108
4272
|
const decoded = import_jsonwebtoken.default.verify(token, jwtConfig.secret, { algorithms: ["HS256"] });
|
|
4109
|
-
|
|
4273
|
+
if (decoded.purpose) {
|
|
4274
|
+
logger.error("[JWT] Verification failed: a purpose-scoped token is not an access token", { purpose: decoded.purpose });
|
|
4275
|
+
return null;
|
|
4276
|
+
}
|
|
4277
|
+
const id = decoded.uid || decoded.userId || decoded.sub;
|
|
4110
4278
|
if (!id) {
|
|
4111
4279
|
logger.error("[JWT] Verification failed: missing id in payload", { detail: decoded });
|
|
4112
4280
|
return null;
|
|
4113
4281
|
}
|
|
4114
4282
|
const aal = decoded.aal === "aal1" || decoded.aal === "aal2" ? decoded.aal : "aal1";
|
|
4115
4283
|
return {
|
|
4116
|
-
|
|
4284
|
+
uid: id,
|
|
4117
4285
|
roles: decoded.roles || [],
|
|
4118
4286
|
aal
|
|
4119
4287
|
};
|
|
@@ -4195,6 +4363,6 @@ function verifyDownloadToken(token) {
|
|
|
4195
4363
|
}
|
|
4196
4364
|
}
|
|
4197
4365
|
//#endregion
|
|
4198
|
-
export { getAccessTokenExpiry as a, jwt_exports as c, require_jsonwebtoken as d, generateRefreshToken as i, verifyAccessToken as l, generateAccessToken as n, getRefreshTokenExpiry as o, generateDownloadToken as r, hashRefreshToken as s, configureJwt as t, verifyDownloadToken as u };
|
|
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 };
|
|
4199
4367
|
|
|
4200
|
-
//# sourceMappingURL=jwt-
|
|
4368
|
+
//# sourceMappingURL=jwt-B3zjddCa.js.map
|