@rebasepro/server 0.12.1-canary.g4e7bcbf → 0.12.1-canary.g52d71ee

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.
@@ -28,7 +28,7 @@ export type { AuthModuleConfig, CookieAuthConfig } from "./routes";
28
28
  export { mountMagicLinkRoutes } from "./magic-link-routes";
29
29
  export { createResetPasswordRoute } from "./reset-password-admin";
30
30
  export type { ResetPasswordRouteConfig } from "./reset-password-admin";
31
- export { createRateLimiter, defaultAuthLimiter, strictAuthLimiter, createApiKeyRateLimiter, createDataRateLimiter, apiKeyKeyGenerator } from "./rate-limiter";
31
+ export { createRateLimiter, defaultAuthLimiter, strictAuthLimiter, createDataRateLimiter, apiKeyKeyGenerator } from "./rate-limiter";
32
32
  export type { DataRateLimitConfig } from "./rate-limiter";
33
33
  export { MemoryRateLimitStore } from "./rate-limit-store";
34
34
  export type { RateLimitStore, RateLimitDecision } from "./rate-limit-store";
@@ -98,15 +98,4 @@ export interface DataRateLimitConfig {
98
98
  * `enabled: false` rather than pay for it twice.
99
99
  */
100
100
  export declare function createDataRateLimiter(config?: DataRateLimitConfig): MiddlewareHandler<HonoEnv>;
101
- /**
102
- * Create a rate limiter specifically for API key requests.
103
- *
104
- * @deprecated Use {@link createDataRateLimiter}, which limits signed-in users
105
- * and anonymous callers too. This one skips every request that is not
106
- * API-key-authenticated, which was most of them.
107
- *
108
- * @param defaultLimit - Fallback limit when the key has no `rate_limit` set.
109
- * @param windowMs - Time window in milliseconds (default: 15 minutes).
110
- */
111
- export declare function createApiKeyRateLimiter(defaultLimit?: number, windowMs?: number): MiddlewareHandler<HonoEnv>;
112
101
  export {};
@@ -2,8 +2,8 @@ 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 } from "./rolldown-runtime-DSJWtz9O.js";
5
+ import { _ as ANONYMOUS_USER_ID, v as isAnonymousUid } from "./src-Cum9kox5.js";
5
6
  import "./src-_qQ3RNCK.js";
6
- import { n as isAnonymousUid, t as ANONYMOUS_USER_ID } from "./policy-B5d-asZT.js";
7
7
  import { t as isSQLAdmin } from "./backend-CIxN4FVm.js";
8
8
  import { t as logger } from "./logger-BYU66ENZ.js";
9
9
  import { n as errorHandler, t as ApiError } from "./errors-CgkCzoj7.js";
@@ -61,6 +61,39 @@ function isPublicStoragePath(path) {
61
61
  return p.startsWith("public/") || p.startsWith(`default/public/`);
62
62
  }
63
63
  //#endregion
64
+ //#region ../common/src/util/email.ts
65
+ /**
66
+ * Email normalization — one implementation, because the database enforces it.
67
+ *
68
+ * `ensureAuthTablesExist` puts a `UNIQUE INDEX ON users (lower(email))` on the
69
+ * auth table. That index decides what "the same address" means, and it does not
70
+ * trim: to Postgres, `' foo@bar.com'` and `'foo@bar.com'` are two addresses and
71
+ * both may exist. So every write that reaches the column has to agree with
72
+ * every read, exactly, or the two disagree in the one direction that matters —
73
+ * a row that exists and cannot be found.
74
+ *
75
+ * That is not hypothetical. The lookup path trimmed and the admin create paths
76
+ * did not, so a user created through `POST /api/data/users` or
77
+ * `POST /api/auth/admin/users` with a stray space was stored untrimmed,
78
+ * survived the unique index alongside the real address, and was unreachable by
79
+ * login forever after. The HTTP auth routes were unaffected only because Zod's
80
+ * `.email()` happens to reject surrounding whitespace — a guard on a different
81
+ * layer, for a different reason, that the admin paths do not sit behind.
82
+ *
83
+ * It lives in `common` because `server`, `server-postgres` and `server-mongo`
84
+ * all write this column and must agree exactly, and `common` is the only
85
+ * package all three already depend on.
86
+ */
87
+ /**
88
+ * Canonical form of an email address: trimmed, lower-cased.
89
+ *
90
+ * Non-strings pass through untouched, so this is safe to apply to a value out
91
+ * of a partial update payload whose type is not known yet.
92
+ */
93
+ function normalizeEmail(email) {
94
+ return typeof email === "string" ? email.trim().toLowerCase() : email;
95
+ }
96
+ //#endregion
64
97
  //#region src/auth/api-keys/api-key-permission-guard.ts
65
98
  /**
66
99
  * Map an HTTP method string to an `ApiKeyOperation`.
@@ -1399,7 +1432,7 @@ async function prepareAdminUserValues(body, ctx) {
1399
1432
  const passwordHash = await resolvedHooks.hashPassword(clearPassword);
1400
1433
  const values = { ...body };
1401
1434
  values.passwordHash = passwordHash;
1402
- if (values.email) values.email = values.email.toLowerCase();
1435
+ if (values.email) values.email = normalizeEmail(values.email);
1403
1436
  values.emailVerified = true;
1404
1437
  delete values.password;
1405
1438
  return {
@@ -1744,28 +1777,6 @@ function createDataRateLimiter(config = {}) {
1744
1777
  }
1745
1778
  });
1746
1779
  }
1747
- /**
1748
- * Create a rate limiter specifically for API key requests.
1749
- *
1750
- * @deprecated Use {@link createDataRateLimiter}, which limits signed-in users
1751
- * and anonymous callers too. This one skips every request that is not
1752
- * API-key-authenticated, which was most of them.
1753
- *
1754
- * @param defaultLimit - Fallback limit when the key has no `rate_limit` set.
1755
- * @param windowMs - Time window in milliseconds (default: 15 minutes).
1756
- */
1757
- function createApiKeyRateLimiter(defaultLimit = 1e3, windowMs = 900 * 1e3) {
1758
- return createRateLimiter({
1759
- windowMs,
1760
- message: "API key rate limit exceeded, please try again later.",
1761
- keyGenerator: apiKeyKeyGenerator,
1762
- resolveLimit: (c) => {
1763
- const apiKey = c.get("apiKey");
1764
- if (!apiKey) return null;
1765
- return apiKey.rate_limit ?? defaultLimit;
1766
- }
1767
- });
1768
- }
1769
1780
  //#endregion
1770
1781
  //#region ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/core.js
1771
1782
  var _a$1;
@@ -6254,7 +6265,7 @@ function mountSessionRoutes(opts) {
6254
6265
  if (config.allowUserLookup) router.post("/find-user", defaultAuthLimiter, requireAuth, async (c) => {
6255
6266
  if (!c.get("user")) throw ApiError.unauthorized("Not authenticated");
6256
6267
  const { email } = parseBody(findUserSchema, await c.req.json());
6257
- const user = await authRepo.getUserByEmail(email.toLowerCase());
6268
+ const user = await authRepo.getUserByEmail(normalizeEmail(email));
6258
6269
  return c.json({ user: user ? {
6259
6270
  uid: user.id,
6260
6271
  displayName: user.displayName ?? null,
@@ -6362,10 +6373,10 @@ function mountSessionRoutes(opts) {
6362
6373
  const { email, password } = parseBody(linkSchema, await c.req.json());
6363
6374
  const passwordValidation = ops.validatePasswordStrength(password);
6364
6375
  if (!passwordValidation.valid) throw ApiError.badRequest(passwordValidation.errors.join(". "), "WEAK_PASSWORD");
6365
- if (await authRepo.getUserByEmail(email.toLowerCase())) throw ApiError.conflict("Email already registered", "EMAIL_EXISTS");
6376
+ if (await authRepo.getUserByEmail(normalizeEmail(email))) throw ApiError.conflict("Email already registered", "EMAIL_EXISTS");
6366
6377
  const passwordHash = await ops.hashPassword(password);
6367
6378
  const updatedUser = await authRepo.updateUser(user.id, {
6368
- email: email.toLowerCase(),
6379
+ email: normalizeEmail(email),
6369
6380
  passwordHash,
6370
6381
  isAnonymous: false
6371
6382
  });
@@ -6641,7 +6652,7 @@ function createAuthRoutes(config) {
6641
6652
  if (await authRepo.getUserByEmail(email)) throw ApiError.conflict("Email already registered", "EMAIL_EXISTS");
6642
6653
  const passwordHash = await ops.hashPassword(password);
6643
6654
  let createData = {
6644
- email: email.toLowerCase(),
6655
+ email: normalizeEmail(email),
6645
6656
  passwordHash,
6646
6657
  displayName: displayName || void 0
6647
6658
  };
@@ -6733,7 +6744,7 @@ function createAuthRoutes(config) {
6733
6744
  });
6734
6745
  } else {
6735
6746
  user = await authRepo.createUser({
6736
- email: externalUser.email.toLowerCase(),
6747
+ email: normalizeEmail(externalUser.email),
6737
6748
  displayName: externalUser.displayName || void 0,
6738
6749
  photoUrl: externalUser.photoUrl || void 0
6739
6750
  });
@@ -7307,7 +7318,7 @@ function createAdminUsersRoute(config) {
7307
7318
  const body = await c.req.json();
7308
7319
  const { email, roles } = body;
7309
7320
  if (!email) throw ApiError.badRequest("Email is required");
7310
- if (await authRepo.getUserByEmail(email.toLowerCase())) throw ApiError.conflict("A user with this email already exists");
7321
+ if (await authRepo.getUserByEmail(normalizeEmail(email))) throw ApiError.conflict("A user with this email already exists");
7311
7322
  const prepResult = await prepareAdminUserValues(body, {
7312
7323
  authRepo,
7313
7324
  emailService,
@@ -7346,7 +7357,7 @@ function createAdminUsersRoute(config) {
7346
7357
  const { password, email, displayName, roles } = await c.req.json();
7347
7358
  if (!await authRepo.getUserById(uid)) throw ApiError.notFound("User not found");
7348
7359
  const updates = {};
7349
- if (email !== void 0) updates.email = email.toLowerCase();
7360
+ if (email !== void 0) updates.email = normalizeEmail(email);
7350
7361
  if (displayName !== void 0) updates.displayName = displayName;
7351
7362
  if (password) {
7352
7363
  const validation = ops.validatePasswordStrength(password);
@@ -8891,7 +8902,6 @@ var auth_exports = /* @__PURE__ */ __exportAll({
8891
8902
  apiKeyKeyGenerator: () => apiKeyKeyGenerator,
8892
8903
  configureJwt: () => configureJwt,
8893
8904
  createAdapterAuthMiddleware: () => createAdapterAuthMiddleware,
8894
- createApiKeyRateLimiter: () => createApiKeyRateLimiter,
8895
8905
  createApiKeyRoutes: () => createApiKeyRoutes,
8896
8906
  createApiKeyStore: () => createApiKeyStore,
8897
8907
  createAppleProvider: () => createAppleProvider,
@@ -8948,4 +8958,4 @@ var auth_exports = /* @__PURE__ */ __exportAll({
8948
8958
  //#endregion
8949
8959
  export { httpMethodToOperation as $, getEmailVerificationTemplate as A, optionalAuth as B, createDataRateLimiter as C, validatePasswordStrength as D, hashPassword as E, createAdapterAuthMiddleware as F, createApiKeyPreAuth as G, queryTokenAuth as H, createAuthMiddleware as I, isApiKeyToken as J, createFunctionApiKeyGuard as K, createRequireAuth as L, getPasswordResetTemplate as M, getUserInvitationTemplate as N, verifyPassword as O, getWelcomeEmailTemplate as P, scopeDataDriver as Q, extractUserFromToken as R, _coercedNumber as S, resolveAuthHooks as T, requireAdmin as U, publicObjectAuth as V, requireAuth as W, extractBearerToken as X, validateApiKey as Y, safeCompare as Z, createBuiltinAuthAdapter as _, createSpotifyProvider as a, object as b, createGitLabProvider as c, createFacebookProvider as d, isOperationAllowed as et, createAppleProvider as f, createGoogleProvider as g, createLinkedinProvider as h, createApiKeyStore as i, resolveClientListLimit as it, getMagicLinkTemplate as j, generateSecurePassword as k, createDiscordProvider as l, createGitHubProvider as m, createCustomAuthAdapter as n, isPublicStoragePath as nt, createSlackProvider as o, createMicrosoftProvider as p, createStorageApiKeyGuard as q, createApiKeyRoutes as r, MAX_LIST_LIMIT as rt, createBitbucketProvider as s, auth_exports as t, PUBLIC_STORAGE_PREFIX as tt, createTwitterProvider as u, ZodNumber as v, MemoryRateLimitStore as w, string as x, _enum as y, fileTokenAuth as z };
8950
8960
 
8951
- //# sourceMappingURL=auth-B9AJsH3u.js.map
8961
+ //# sourceMappingURL=auth-CuC9M2x6.js.map