@rebasepro/server 0.13.1-canary.gef9608c → 0.14.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.
Files changed (132) hide show
  1. package/dist/{admin_block-EmIHae6X.js → admin_block-H86dCPsj.js} +61 -2
  2. package/dist/admin_block-H86dCPsj.js.map +1 -0
  3. package/dist/api/ast-schema-editor.d.ts +74 -6
  4. package/dist/api/errors.d.ts +12 -0
  5. package/dist/api/rest/api-generator.d.ts +26 -1
  6. package/dist/api/rest/idempotency.d.ts +25 -4
  7. package/dist/api/rest/query-parser.d.ts +15 -1
  8. package/dist/api/rest/write-validation.d.ts +40 -4
  9. package/dist/auth/adapter-middleware.d.ts +3 -1
  10. package/dist/auth/admin-roles.d.ts +24 -0
  11. package/dist/auth/apple-oauth.d.ts +16 -11
  12. package/dist/auth/bitbucket-oauth.d.ts +2 -4
  13. package/dist/auth/builtin-auth-adapter.d.ts +11 -0
  14. package/dist/auth/discord-oauth.d.ts +5 -6
  15. package/dist/auth/facebook-oauth.d.ts +2 -4
  16. package/dist/auth/github-oauth.d.ts +2 -4
  17. package/dist/auth/gitlab-oauth.d.ts +6 -4
  18. package/dist/auth/google-oauth.d.ts +1 -0
  19. package/dist/auth/index.d.ts +7 -0
  20. package/dist/auth/interfaces.d.ts +81 -1
  21. package/dist/auth/jwt.d.ts +40 -0
  22. package/dist/auth/linkedin-oauth.d.ts +2 -4
  23. package/dist/auth/mfa-crypto.d.ts +54 -3
  24. package/dist/auth/mfa-gate.d.ts +42 -0
  25. package/dist/auth/mfa-routes.d.ts +26 -1
  26. package/dist/auth/mfa.d.ts +16 -0
  27. package/dist/auth/microsoft-oauth.d.ts +19 -4
  28. package/dist/auth/middleware.d.ts +26 -0
  29. package/dist/auth/oauth-code-flow.d.ts +66 -0
  30. package/dist/auth/oauth-signin-policy.d.ts +61 -0
  31. package/dist/auth/oidc-id-token.d.ts +61 -0
  32. package/dist/auth/rate-limiter.d.ts +62 -5
  33. package/dist/auth/registration-policy.d.ts +31 -0
  34. package/dist/auth/rls-scope.d.ts +25 -0
  35. package/dist/auth/routes.d.ts +15 -0
  36. package/dist/auth/slack-oauth.d.ts +2 -4
  37. package/dist/auth/spotify-oauth.d.ts +2 -4
  38. package/dist/auth/token-revocation.d.ts +38 -0
  39. package/dist/auth/twitter-oauth.d.ts +2 -5
  40. package/dist/{auth-DU4ShERo.js → auth-CYoPVf-E.js} +1985 -395
  41. package/dist/auth-CYoPVf-E.js.map +1 -0
  42. package/dist/{backup-BJiY_mM-.js → backup-C6ljYVTp.js} +2 -2
  43. package/dist/{backup-BJiY_mM-.js.map → backup-C6ljYVTp.js.map} +1 -1
  44. package/dist/boot/ddl-bootstrap.d.ts +70 -0
  45. package/dist/{contract-routes-Dj8i5AiM.js → contract-routes-Bet-eCNJ.js} +3 -3
  46. package/dist/{contract-routes-Dj8i5AiM.js.map → contract-routes-Bet-eCNJ.js.map} +1 -1
  47. package/dist/cron/cron-loader.d.ts +26 -1
  48. package/dist/cron/cron-routes.d.ts +1 -1
  49. package/dist/cron/cron-scheduler.d.ts +13 -3
  50. package/dist/cron/define-cron.d.ts +17 -3
  51. package/dist/cron/index.d.ts +2 -2
  52. package/dist/{cron-loader-B1S2MCSl.js → cron-loader-YhhQeVBM.js} +43 -8
  53. package/dist/cron-loader-YhhQeVBM.js.map +1 -0
  54. package/dist/{cron-routes-D5a9v1HY.js → cron-routes-maM_RlUu.js} +10 -4
  55. package/dist/cron-routes-maM_RlUu.js.map +1 -0
  56. package/dist/{cron-scheduler-BhFZWR0T.js → cron-scheduler-DIpYBmZP.js} +20 -8
  57. package/dist/cron-scheduler-DIpYBmZP.js.map +1 -0
  58. package/dist/{cron-store-Cu4sOseb.js → cron-store-Dvr4Y1sZ.js} +60 -51
  59. package/dist/cron-store-Dvr4Y1sZ.js.map +1 -0
  60. package/dist/ddl-bootstrap-BhXbTnBl.js +183 -0
  61. package/dist/ddl-bootstrap-BhXbTnBl.js.map +1 -0
  62. package/dist/email/html.d.ts +54 -0
  63. package/dist/email/index.d.ts +3 -0
  64. package/dist/email/link-base.d.ts +39 -0
  65. package/dist/email/smtp-email-service.d.ts +7 -1
  66. package/dist/email/templates.d.ts +9 -1
  67. package/dist/email/types.d.ts +11 -1
  68. package/dist/env.d.ts +5 -0
  69. package/dist/{errors-BpudWAVU.js → errors-EBYiaJ2E.js} +14 -2
  70. package/dist/errors-EBYiaJ2E.js.map +1 -0
  71. package/dist/function-loader-DDS1v7YX.js +139 -0
  72. package/dist/function-loader-DDS1v7YX.js.map +1 -0
  73. package/dist/{function-routes-C0cLIy3N.js → function-routes-Btcez1T-.js} +18 -6
  74. package/dist/function-routes-Btcez1T-.js.map +1 -0
  75. package/dist/functions/define-function.d.ts +25 -6
  76. package/dist/functions/function-loader.d.ts +23 -0
  77. package/dist/functions/function-routes.d.ts +7 -1
  78. package/dist/functions/request-timeout.d.ts +34 -0
  79. package/dist/history/history-routes.d.ts +6 -0
  80. package/dist/index.d.ts +3 -2
  81. package/dist/index.es.js +1893 -714
  82. package/dist/index.es.js.map +1 -1
  83. package/dist/init/docs.d.ts +10 -1
  84. package/dist/init/process-safety.d.ts +25 -0
  85. package/dist/init.d.ts +38 -0
  86. package/dist/{jwt-CzeviDcB.js → jwt-_IFqfTOg.js} +57 -9
  87. package/dist/jwt-_IFqfTOg.js.map +1 -0
  88. package/dist/logger-DfvF_8r-.js +190 -0
  89. package/dist/logger-DfvF_8r-.js.map +1 -0
  90. package/dist/{openapi-generator-D5xsfVJY.js → openapi-generator-DPKtUC9X.js} +326 -55
  91. package/dist/openapi-generator-DPKtUC9X.js.map +1 -0
  92. package/dist/request-timeout-RivJsME0.js +65 -0
  93. package/dist/request-timeout-RivJsME0.js.map +1 -0
  94. package/dist/schema-editor-routes-CRcS3ArS.js +437 -0
  95. package/dist/schema-editor-routes-CRcS3ArS.js.map +1 -0
  96. package/dist/serve-spa.d.ts +5 -4
  97. package/dist/services/outbound-url-guard.d.ts +53 -0
  98. package/dist/services/routed-realtime-service.d.ts +10 -2
  99. package/dist/services/webhook-service.d.ts +76 -1
  100. package/dist/singleton.d.ts +25 -8
  101. package/dist/{src-CKOZBpeJ.js → src-C7rkDGxA.js} +619 -70
  102. package/dist/src-C7rkDGxA.js.map +1 -0
  103. package/dist/{src-_qQ3RNCK.js → src-Cz9nMgUR.js} +93 -3
  104. package/dist/src-Cz9nMgUR.js.map +1 -0
  105. package/dist/storage/LocalStorageController.d.ts +12 -1
  106. package/dist/storage/image-transform.d.ts +57 -0
  107. package/dist/storage/keys.d.ts +98 -0
  108. package/dist/storage/routes.d.ts +11 -0
  109. package/dist/storage/tus-handler.d.ts +22 -2
  110. package/dist/utils/logger.d.ts +18 -0
  111. package/dist/utils/sql.d.ts +11 -6
  112. package/package.json +6 -5
  113. package/dist/admin_block-EmIHae6X.js.map +0 -1
  114. package/dist/auth-DU4ShERo.js.map +0 -1
  115. package/dist/backend-CIxN4FVm.js +0 -15
  116. package/dist/backend-CIxN4FVm.js.map +0 -1
  117. package/dist/cron-loader-B1S2MCSl.js.map +0 -1
  118. package/dist/cron-routes-D5a9v1HY.js.map +0 -1
  119. package/dist/cron-scheduler-BhFZWR0T.js.map +0 -1
  120. package/dist/cron-store-Cu4sOseb.js.map +0 -1
  121. package/dist/errors-BpudWAVU.js.map +0 -1
  122. package/dist/function-loader-B_1fYfUY.js +0 -86
  123. package/dist/function-loader-B_1fYfUY.js.map +0 -1
  124. package/dist/function-routes-C0cLIy3N.js.map +0 -1
  125. package/dist/jwt-CzeviDcB.js.map +0 -1
  126. package/dist/logger-BYU66ENZ.js +0 -94
  127. package/dist/logger-BYU66ENZ.js.map +0 -1
  128. package/dist/openapi-generator-D5xsfVJY.js.map +0 -1
  129. package/dist/schema-editor-routes-C1DxDnDR.js +0 -248
  130. package/dist/schema-editor-routes-C1DxDnDR.js.map +0 -1
  131. package/dist/src-CKOZBpeJ.js.map +0 -1
  132. package/dist/src-_qQ3RNCK.js.map +0 -1
@@ -1,4 +1,13 @@
1
1
  import { Hono } from "hono";
2
2
  import { CollectionConfig } from "@rebasepro/types";
3
3
  import { HonoEnv } from "../api/types";
4
- export declare function mountOpenApiDocs(app: Hono<HonoEnv>, basePath: string, enableSwagger: boolean | undefined, activeCollections: CollectionConfig[], requireAuth: boolean): Promise<void>;
4
+ /**
5
+ * Serve the OpenAPI document, and Swagger UI outside production.
6
+ *
7
+ * `serverCollections` must be the collections the REST routes were generated
8
+ * from — the ones whose data source has a `"server"` transport — not every
9
+ * active collection. A direct-transport collection is served by the client
10
+ * against its own backend; documenting it here publishes a full set of CRUD
11
+ * paths that 404, with a Try-It button next to each.
12
+ */
13
+ export declare function mountOpenApiDocs(app: Hono<HonoEnv>, basePath: string, enableSwagger: boolean | undefined, serverCollections: CollectionConfig[], requireAuth: boolean): Promise<void>;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Log unhandled promise rejections instead of letting Node terminate the
3
+ * process.
4
+ *
5
+ * Node has terminated on an unhandled rejection since v15. Hono catches
6
+ * anything thrown or rejected inside an awaited handler, so the ordinary
7
+ * request path is covered — but a fire-and-forget `void syncToCrm(body)`, a
8
+ * `setTimeout(async () => …)`, or an unawaited `.then()` in one custom function
9
+ * rejects outside Hono's frame. The default outcome is that one project's
10
+ * floating promise ends the process; on the managed runtime that process is
11
+ * shared, so every other tenant on the pod goes with it, and the request log
12
+ * points nowhere because the request itself succeeded.
13
+ *
14
+ * A logged rejection is the better trade here: the process keeps serving, and
15
+ * the stack reaches the operator. `uncaughtException` is deliberately **not**
16
+ * handled — a synchronous throw that escaped every frame leaves the process in
17
+ * a state we cannot reason about, and swallowing it would be a worse bargain
18
+ * than a restart.
19
+ *
20
+ * Set `REBASE_EXIT_ON_UNHANDLED_REJECTION=1` to restore Node's default.
21
+ *
22
+ * @returns An uninstall function (used by tests), or `undefined` when nothing
23
+ * was installed.
24
+ */
25
+ export declare function installUnhandledRejectionHandler(): (() => void) | undefined;
package/dist/init.d.ts CHANGED
@@ -49,6 +49,17 @@ export interface RebaseAuthConfig {
49
49
  * create the first user with the CLI or a seed script.
50
50
  */
51
51
  disableSelfRegistration?: boolean;
52
+ /**
53
+ * Opt-in: allow `POST /auth/anonymous` to mint a user with no credentials.
54
+ *
55
+ * Off by default. Anonymous sign-in inserts a `users` row and assigns
56
+ * `defaultRole` exactly as registration does, so leaving it always-on meant
57
+ * a backend with `allowRegistration: false` and `disableSelfRegistration:
58
+ * true` still handed out permanent accounts: `/auth/anonymous` for the row
59
+ * and the session, then `/auth/anonymous/link` to put an email and password
60
+ * on it. `disableSelfRegistration` overrides this key.
61
+ */
62
+ allowAnonymous?: boolean;
52
63
  /**
53
64
  * Opt-in: expose `POST /auth/find-user` so an authenticated user can resolve
54
65
  * an email address to a minimal public profile (`uid`, `displayName`,
@@ -149,6 +160,22 @@ export interface RebaseAuthConfig {
149
160
  * ```
150
161
  */
151
162
  providers?: OAuthProvider<unknown>[];
163
+ /**
164
+ * Redirect URIs the OAuth sign-in routes will accept, for every provider.
165
+ *
166
+ * Left unset, the only check is the provider's own registered-URI match —
167
+ * which authorises *every* URI registered on that OAuth client, including
168
+ * the `localhost` entry someone added for development and the staging host
169
+ * nobody removed. List the origins this backend actually serves to narrow
170
+ * it. Compared on origin plus path; query, fragment and a trailing slash
171
+ * are ignored.
172
+ *
173
+ * @example
174
+ * ```ts
175
+ * auth: { allowedRedirectUris: ["https://admin.example.com/"] }
176
+ * ```
177
+ */
178
+ allowedRedirectUris?: string[];
152
179
  /**
153
180
  * Override specific parts of the built-in auth implementation.
154
181
  *
@@ -344,6 +371,17 @@ export interface RebaseBackendConfig {
344
371
  history?: HistoryConfig;
345
372
  enableSwagger?: boolean;
346
373
  functionsDir?: string;
374
+ /**
375
+ * Per-request ceiling for `/api/functions/*`, in milliseconds.
376
+ *
377
+ * Custom functions run code the framework did not write, and nothing else
378
+ * in the stack bounds it. Defaults to 30000 (or
379
+ * `REBASE_FUNCTIONS_TIMEOUT_MS`). `0` disables the ceiling — for a function
380
+ * that legitimately runs long, or a deployment whose proxy already imposes
381
+ * one. Timed-out requests answer 504; the handler itself cannot be
382
+ * cancelled, so give outbound calls an `AbortSignal`.
383
+ */
384
+ functionsTimeoutMs?: number;
347
385
  cronsDir?: string;
348
386
  /**
349
387
  * Enable/disable database persistence for cron job execution logs.
@@ -2,7 +2,7 @@ import { createRequire as __createRequire } from "module";
2
2
  import process from "process";
3
3
  __createRequire(import.meta.url);
4
4
  import { i as __toESM, n as __exportAll, r as __require, t as __commonJSMin } from "./rolldown-runtime-DSJWtz9O.js";
5
- import { t as logger } from "./logger-BYU66ENZ.js";
5
+ import { t as logger } from "./logger-DfvF_8r-.js";
6
6
  import { createHash, randomBytes } from "crypto";
7
7
  //#region ../../node_modules/.pnpm/safe-buffer@5.2.1/node_modules/safe-buffer/index.js
8
8
  var require_safe_buffer = /* @__PURE__ */ __commonJSMin(((exports, module) => {
@@ -2275,7 +2275,7 @@ var require_verify = /* @__PURE__ */ __commonJSMin(((exports, module) => {
2275
2275
  var validateAsymmetricKey = require_validateAsymmetricKey();
2276
2276
  var PS_SUPPORTED = require_psSupported();
2277
2277
  var jws = require_jws();
2278
- var { KeyObject: KeyObject$1, createSecretKey: createSecretKey$1, createPublicKey } = __require("crypto");
2278
+ var { KeyObject: KeyObject$1, createSecretKey: createSecretKey$1, createPublicKey: createPublicKey$1 } = __require("crypto");
2279
2279
  var PUB_KEY_ALGS = [
2280
2280
  "RS256",
2281
2281
  "RS384",
@@ -2343,7 +2343,7 @@ var require_verify = /* @__PURE__ */ __commonJSMin(((exports, module) => {
2343
2343
  if (hasSignature && !secretOrPublicKey) return done(new JsonWebTokenError("secret or public key must be provided"));
2344
2344
  if (!hasSignature && !options.algorithms) return done(new JsonWebTokenError("please specify \"none\" in \"algorithms\" to verify unsigned tokens"));
2345
2345
  if (secretOrPublicKey != null && !(secretOrPublicKey instanceof KeyObject$1)) try {
2346
- secretOrPublicKey = createPublicKey(secretOrPublicKey);
2346
+ secretOrPublicKey = createPublicKey$1(secretOrPublicKey);
2347
2347
  } catch (_) {
2348
2348
  try {
2349
2349
  secretOrPublicKey = createSecretKey$1(typeof secretOrPublicKey === "string" ? Buffer.from(secretOrPublicKey) : secretOrPublicKey);
@@ -4150,9 +4150,11 @@ var require_jsonwebtoken = /* @__PURE__ */ __commonJSMin(((exports, module) => {
4150
4150
  //#region src/auth/jwt.ts
4151
4151
  var jwt_exports = /* @__PURE__ */ __exportAll({
4152
4152
  MAX_COOKIE_AGE_MS: () => MAX_COOKIE_AGE_MS,
4153
+ MFA_PENDING_PURPOSE: () => MFA_PENDING_PURPOSE,
4153
4154
  configureJwt: () => configureJwt,
4154
4155
  generateAccessToken: () => generateAccessToken,
4155
4156
  generateDownloadToken: () => generateDownloadToken,
4157
+ generateMfaPendingToken: () => generateMfaPendingToken,
4156
4158
  generateRefreshToken: () => generateRefreshToken,
4157
4159
  getAccessTokenExpiry: () => getAccessTokenExpiry,
4158
4160
  getAccessTokenExpiryMs: () => getAccessTokenExpiryMs,
@@ -4161,7 +4163,8 @@ var jwt_exports = /* @__PURE__ */ __exportAll({
4161
4163
  hashRefreshToken: () => hashRefreshToken,
4162
4164
  isJwtConfigured: () => isJwtConfigured,
4163
4165
  verifyAccessToken: () => verifyAccessToken,
4164
- verifyDownloadToken: () => verifyDownloadToken
4166
+ verifyDownloadToken: () => verifyDownloadToken,
4167
+ verifyMfaPendingToken: () => verifyMfaPendingToken
4165
4168
  });
4166
4169
  var import_jsonwebtoken = /* @__PURE__ */ __toESM(require_jsonwebtoken(), 1);
4167
4170
  var jwtConfig = {
@@ -4224,8 +4227,8 @@ function generateAccessToken(uid, roles, aal = "aal1", customClaims) {
4224
4227
  const payload = {
4225
4228
  uid,
4226
4229
  roles,
4227
- aal,
4228
- ...customClaims
4230
+ ...customClaims,
4231
+ aal
4229
4232
  };
4230
4233
  return import_jsonwebtoken.default.sign(payload, jwtConfig.secret, {
4231
4234
  expiresIn: jwtConfig.accessExpiresIn,
@@ -4284,7 +4287,8 @@ function verifyAccessToken(token) {
4284
4287
  return {
4285
4288
  uid: id,
4286
4289
  roles: decoded.roles || [],
4287
- aal
4290
+ aal,
4291
+ iat: decoded.iat
4288
4292
  };
4289
4293
  } catch (error) {
4290
4294
  logger.error("[JWT] Verification failed", {
@@ -4343,6 +4347,50 @@ function getRefreshTokenExpiry() {
4343
4347
  return new Date(Date.now() + getRefreshTokenTtlMs());
4344
4348
  }
4345
4349
  /**
4350
+ * The `purpose` claim carried by a credential that stands between "first factor
4351
+ * accepted" and "session issued".
4352
+ *
4353
+ * A pre-auth token is NOT a session and must never be usable as one:
4354
+ * {@link verifyAccessToken} refuses any token carrying a `purpose`, so this
4355
+ * value cannot authenticate a request no matter which route it is presented to.
4356
+ * The only thing that reads it is the MFA challenge pair, which exchanges it —
4357
+ * plus a second factor — for a real session.
4358
+ */
4359
+ var MFA_PENDING_PURPOSE = "mfa-pending";
4360
+ /**
4361
+ * Mint the short-lived credential handed back with an `MFA_REQUIRED` response.
4362
+ *
4363
+ * Short-lived on purpose: it is the window in which a caller who has proven the
4364
+ * first factor may present the second, not a session to be carried around. Five
4365
+ * minutes matches the challenge TTL.
4366
+ */
4367
+ function generateMfaPendingToken(uid, expiresInSeconds = 300) {
4368
+ if (!jwtConfig.secret) throw new Error("JWT secret not configured. Call configureJwt() first.");
4369
+ return import_jsonwebtoken.default.sign({
4370
+ purpose: MFA_PENDING_PURPOSE,
4371
+ uid
4372
+ }, jwtConfig.secret, {
4373
+ expiresIn: expiresInSeconds,
4374
+ algorithm: "HS256"
4375
+ });
4376
+ }
4377
+ /**
4378
+ * Verify a pre-auth token and return the user it was minted for.
4379
+ *
4380
+ * Returns `null` for anything else — including a perfectly valid *access*
4381
+ * token, which must not be interchangeable with this one in either direction.
4382
+ */
4383
+ function verifyMfaPendingToken(token) {
4384
+ if (!jwtConfig.secret) throw new Error("JWT secret not configured. Call configureJwt() first.");
4385
+ try {
4386
+ const decoded = import_jsonwebtoken.default.verify(token, jwtConfig.secret, { algorithms: ["HS256"] });
4387
+ if (decoded.purpose !== "mfa-pending" || !decoded.uid) return null;
4388
+ return { uid: decoded.uid };
4389
+ } catch {
4390
+ return null;
4391
+ }
4392
+ }
4393
+ /**
4346
4394
  * Generate a short-lived download token scoped to a specific file path or prefix
4347
4395
  */
4348
4396
  function generateDownloadToken(path, expiresInSeconds = 300) {
@@ -4374,6 +4422,6 @@ function verifyDownloadToken(token) {
4374
4422
  }
4375
4423
  }
4376
4424
  //#endregion
4377
- export { generateRefreshToken as a, getRefreshTokenTtlMs as c, jwt_exports as d, verifyAccessToken as f, generateDownloadToken as i, hashRefreshToken as l, require_jsonwebtoken as m, configureJwt as n, getAccessTokenExpiry as o, verifyDownloadToken as p, generateAccessToken as r, getRefreshTokenExpiry as s, MAX_COOKIE_AGE_MS as t, isJwtConfigured as u };
4425
+ export { generateMfaPendingToken as a, getRefreshTokenExpiry as c, isJwtConfigured as d, jwt_exports as f, require_jsonwebtoken as g, verifyMfaPendingToken as h, generateDownloadToken as i, getRefreshTokenTtlMs as l, verifyDownloadToken as m, configureJwt as n, generateRefreshToken as o, verifyAccessToken as p, generateAccessToken as r, getAccessTokenExpiry as s, MAX_COOKIE_AGE_MS as t, hashRefreshToken as u };
4378
4426
 
4379
- //# sourceMappingURL=jwt-CzeviDcB.js.map
4427
+ //# sourceMappingURL=jwt-_IFqfTOg.js.map