@rebasepro/server 0.9.1-canary.ff338b5 → 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.
@@ -9,9 +9,24 @@ export declare class ApiError extends Error {
9
9
  readonly statusCode: number;
10
10
  readonly code: string;
11
11
  readonly details?: unknown;
12
- constructor(statusCode: number, code: string, message: string, details?: unknown);
12
+ /**
13
+ * Whether this outcome is a routine part of normal operation rather than
14
+ * something an operator should look at. Expected errors log at debug; every
15
+ * other operational error logs at warn.
16
+ *
17
+ * The motivating case is `POST /auth/refresh` with no session: clients
18
+ * refresh on page load before they know whether one exists, so every
19
+ * anonymous page view is a 401 — correct, and not worth a warning line.
20
+ */
21
+ readonly expected: boolean;
22
+ constructor(statusCode: number, code: string, message: string, details?: unknown, expected?: boolean);
13
23
  static badRequest(message: string, code?: string, details?: unknown): ApiError;
14
24
  static unauthorized(message: string, code?: string): ApiError;
25
+ /**
26
+ * A 401 that is a normal outcome, not an incident — logged at debug.
27
+ * See {@link ApiError.expected}.
28
+ */
29
+ static unauthenticated(message: string, code?: string): ApiError;
15
30
  static forbidden(message: string, code?: string): ApiError;
16
31
  static notFound(message: string, code?: string): ApiError;
17
32
  static conflict(message: string, code?: string): ApiError;
@@ -12,8 +12,11 @@ import { CollectionConfig } from "@rebasepro/types";
12
12
  * columns, so the set is exact);
13
13
  * - the foreign-key column behind an owning relation, which callers may write
14
14
  * directly instead of through the relation property;
15
+ * - anything named in `options.extraKnownFields` — for an auth collection the
16
+ * credential keys the auth adapter consumes before a row is ever built;
15
17
  * - nothing else. `id` in particular is not automatically known — see below.
16
18
  */
17
19
  export declare function assertKnownWriteFields(values: Record<string, unknown>, collection: CollectionConfig, options?: {
18
20
  rowIndex?: number;
21
+ extraKnownFields?: readonly string[];
19
22
  }): void;
@@ -1,5 +1,5 @@
1
1
  import { VectorSearchParams, LogicalCondition, FilterValues } from "@rebasepro/types";
2
- import { AuthResult } from "../auth/middleware";
2
+ import type { AuthResult } from "../auth/middleware";
3
3
  import { DataDriver } from "@rebasepro/types";
4
4
  import type { ApiKeyMasked } from "../auth/api-keys/api-key-types";
5
5
  /**
@@ -9,7 +9,7 @@ import type { ApiKeyMasked } from "../auth/api-keys/api-key-types";
9
9
  export type HonoEnv = {
10
10
  Variables: {
11
11
  user?: AuthResult | {
12
- userId?: string;
12
+ uid?: string;
13
13
  roles?: string[];
14
14
  };
15
15
  driver?: DataDriver;
@@ -3,10 +3,10 @@
3
3
  *
4
4
  * Mounts:
5
5
  * GET /users
6
- * GET /users/:userId
6
+ * GET /users/:uid
7
7
  * POST /users
8
- * PUT /users/:userId
9
- * DELETE /users/:userId
8
+ * PUT /users/:uid
9
+ * DELETE /users/:uid
10
10
  * POST /bootstrap
11
11
  */
12
12
  import { Hono } from "hono";
@@ -135,7 +135,7 @@ export interface AuthHooks {
135
135
  *
136
136
  * This is fire-and-forget — errors are logged but do not fail the request.
137
137
  */
138
- afterLogout?(userId: string): Promise<void>;
138
+ afterLogout?(uid: string): Promise<void>;
139
139
  /**
140
140
  * Called after successful MFA verification.
141
141
  *
@@ -143,12 +143,12 @@ export interface AuthHooks {
143
143
  *
144
144
  * This is fire-and-forget — errors are logged but do not fail the request.
145
145
  */
146
- onMfaVerified?(userId: string, factorId: string): Promise<void>;
146
+ onMfaVerified?(uid: string, factorId: string): Promise<void>;
147
147
  /**
148
148
  * Customize JWT access token claims before signing.
149
149
  *
150
150
  * Return the modified claims object. The returned claims are merged
151
- * into the JWT payload alongside standard claims (userId, roles).
151
+ * into the JWT payload alongside standard claims (uid, roles).
152
152
  *
153
153
  * @param claims - The default claims that would be included.
154
154
  * @param user - The authenticated user data.
@@ -178,14 +178,14 @@ export interface AuthHooks {
178
178
  *
179
179
  * This is fire-and-forget — errors are logged but do not fail the request.
180
180
  */
181
- onPasswordReset?(userId: string): Promise<void>;
181
+ onPasswordReset?(uid: string): Promise<void>;
182
182
  /**
183
183
  * Called before a user is deleted.
184
184
  *
185
185
  * Throw an error to prevent deletion (e.g. for users with active
186
186
  * subscriptions, pending transactions, etc.).
187
187
  */
188
- beforeUserDelete?(userId: string): Promise<void>;
188
+ beforeUserDelete?(uid: string): Promise<void>;
189
189
  /**
190
190
  * Called after a user is deleted.
191
191
  *
@@ -193,7 +193,7 @@ export interface AuthHooks {
193
193
  *
194
194
  * This is fire-and-forget — errors are logged but do not fail the request.
195
195
  */
196
- afterUserDelete?(userId: string): Promise<void>;
196
+ afterUserDelete?(uid: string): Promise<void>;
197
197
  /**
198
198
  * Optional hook to customize or override the default user creation flow via the admin panel/REST API.
199
199
  * When provided, this replaces the built-in password generation, hashing, and invitation email logic.
@@ -212,7 +212,7 @@ export interface AuthHooks {
212
212
  * Optional hook to customize or override the default password reset flow via the admin panel.
213
213
  * When provided, this replaces the built-in password reset token generation, hashing, and email logic.
214
214
  */
215
- onAdminResetPassword?(userId: string, ctx: {
215
+ onAdminResetPassword?(uid: string, ctx: {
216
216
  authRepo: AuthRepository;
217
217
  emailService?: EmailService;
218
218
  emailConfig?: EmailConfig;
@@ -40,7 +40,7 @@ export interface CreateUserData {
40
40
  */
41
41
  export interface UserIdentityData {
42
42
  id: string;
43
- userId: string;
43
+ uid: string;
44
44
  provider: string;
45
45
  providerId: string;
46
46
  profileData?: Record<string, unknown> | null;
@@ -113,7 +113,7 @@ export interface CreateRoleData {
113
113
  */
114
114
  export interface RefreshTokenInfo {
115
115
  id: string;
116
- userId: string;
116
+ uid: string;
117
117
  tokenHash: string;
118
118
  expiresAt: Date;
119
119
  createdAt: Date;
@@ -124,14 +124,14 @@ export interface RefreshTokenInfo {
124
124
  * Password reset token info
125
125
  */
126
126
  export interface PasswordResetTokenInfo {
127
- userId: string;
127
+ uid: string;
128
128
  expiresAt: Date;
129
129
  }
130
130
  /**
131
131
  * Magic link token info
132
132
  */
133
133
  export interface MagicLinkTokenInfo {
134
- userId: string;
134
+ uid: string;
135
135
  expiresAt: Date;
136
136
  }
137
137
  /**
@@ -185,11 +185,11 @@ export interface UserRepository {
185
185
  /**
186
186
  * Get all identities linked to a user
187
187
  */
188
- getUserIdentities(userId: string): Promise<UserIdentityData[]>;
188
+ getUserIdentities(uid: string): Promise<UserIdentityData[]>;
189
189
  /**
190
190
  * Link a new OAuth identity to a user
191
191
  */
192
- linkUserIdentity(userId: string, provider: string, providerId: string, profileData?: Record<string, unknown>): Promise<void>;
192
+ linkUserIdentity(uid: string, provider: string, providerId: string, profileData?: Record<string, unknown>): Promise<void>;
193
193
  /**
194
194
  * Update a user
195
195
  */
@@ -225,23 +225,23 @@ export interface UserRepository {
225
225
  /**
226
226
  * Get roles for a user
227
227
  */
228
- getUserRoles(userId: string): Promise<RoleData[]>;
228
+ getUserRoles(uid: string): Promise<RoleData[]>;
229
229
  /**
230
230
  * Get role IDs for a user
231
231
  */
232
- getUserRoleIds(userId: string): Promise<string[]>;
232
+ getUserRoleIds(uid: string): Promise<string[]>;
233
233
  /**
234
234
  * Set roles for a user (replaces existing roles)
235
235
  */
236
- setUserRoles(userId: string, roleIds: string[]): Promise<void>;
236
+ setUserRoles(uid: string, roleIds: string[]): Promise<void>;
237
237
  /**
238
238
  * Assign a specific role to a new user
239
239
  */
240
- assignDefaultRole(userId: string, roleId: string): Promise<void>;
240
+ assignDefaultRole(uid: string, roleId: string): Promise<void>;
241
241
  /**
242
242
  * Get user with their roles
243
243
  */
244
- getUserWithRoles(userId: string): Promise<{
244
+ getUserWithRoles(uid: string): Promise<{
245
245
  user: UserData;
246
246
  roles: RoleData[];
247
247
  } | null>;
@@ -280,7 +280,7 @@ export interface TokenRepository {
280
280
  /**
281
281
  * Create a new refresh token
282
282
  */
283
- createRefreshToken(userId: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string): Promise<void>;
283
+ createRefreshToken(uid: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string): Promise<void>;
284
284
  /**
285
285
  * Find a refresh token by hash
286
286
  */
@@ -292,19 +292,19 @@ export interface TokenRepository {
292
292
  /**
293
293
  * Delete all refresh tokens for a user
294
294
  */
295
- deleteAllRefreshTokensForUser(userId: string): Promise<void>;
295
+ deleteAllRefreshTokensForUser(uid: string): Promise<void>;
296
296
  /**
297
297
  * List all refresh tokens for a user
298
298
  */
299
- listRefreshTokensForUser(userId: string): Promise<RefreshTokenInfo[]>;
299
+ listRefreshTokensForUser(uid: string): Promise<RefreshTokenInfo[]>;
300
300
  /**
301
301
  * Delete a specific refresh token by its primary key ID
302
302
  */
303
- deleteRefreshTokenById(id: string, userId: string): Promise<void>;
303
+ deleteRefreshTokenById(id: string, uid: string): Promise<void>;
304
304
  /**
305
305
  * Create a password reset token
306
306
  */
307
- createPasswordResetToken(userId: string, tokenHash: string, expiresAt: Date): Promise<void>;
307
+ createPasswordResetToken(uid: string, tokenHash: string, expiresAt: Date): Promise<void>;
308
308
  /**
309
309
  * Find a valid (not expired, not used) password reset token by hash
310
310
  */
@@ -316,7 +316,7 @@ export interface TokenRepository {
316
316
  /**
317
317
  * Delete all password reset tokens for a user
318
318
  */
319
- deleteAllPasswordResetTokensForUser(userId: string): Promise<void>;
319
+ deleteAllPasswordResetTokensForUser(uid: string): Promise<void>;
320
320
  /**
321
321
  * Clean up expired tokens
322
322
  */
@@ -324,7 +324,7 @@ export interface TokenRepository {
324
324
  /**
325
325
  * Create a magic link token
326
326
  */
327
- createMagicLinkToken(userId: string, tokenHash: string, expiresAt: Date): Promise<void>;
327
+ createMagicLinkToken(uid: string, tokenHash: string, expiresAt: Date): Promise<void>;
328
328
  /**
329
329
  * Find a valid (not expired, not used) magic link token by hash
330
330
  */
@@ -339,7 +339,7 @@ export interface TokenRepository {
339
339
  */
340
340
  export interface MfaFactor {
341
341
  id: string;
342
- userId: string;
342
+ uid: string;
343
343
  factorType: "totp";
344
344
  friendlyName?: string;
345
345
  verified: boolean;
@@ -361,7 +361,7 @@ export interface MfaChallengeInfo {
361
361
  */
362
362
  export interface RecoveryCode {
363
363
  id: string;
364
- userId: string;
364
+ uid: string;
365
365
  usedAt?: Date;
366
366
  }
367
367
  /**
@@ -372,11 +372,11 @@ export interface MfaRepository {
372
372
  /**
373
373
  * Create a new MFA factor for a user
374
374
  */
375
- createMfaFactor(userId: string, factorType: "totp", secretEncrypted: string, friendlyName?: string): Promise<MfaFactor>;
375
+ createMfaFactor(uid: string, factorType: "totp", secretEncrypted: string, friendlyName?: string): Promise<MfaFactor>;
376
376
  /**
377
377
  * Get all MFA factors for a user
378
378
  */
379
- getMfaFactors(userId: string): Promise<MfaFactor[]>;
379
+ getMfaFactors(uid: string): Promise<MfaFactor[]>;
380
380
  /**
381
381
  * Get a specific MFA factor by ID
382
382
  */
@@ -390,7 +390,7 @@ export interface MfaRepository {
390
390
  /**
391
391
  * Delete an MFA factor
392
392
  */
393
- deleteMfaFactor(factorId: string, userId: string): Promise<void>;
393
+ deleteMfaFactor(factorId: string, uid: string): Promise<void>;
394
394
  /**
395
395
  * Create an MFA challenge
396
396
  */
@@ -406,23 +406,23 @@ export interface MfaRepository {
406
406
  /**
407
407
  * Create recovery codes for a user
408
408
  */
409
- createRecoveryCodes(userId: string, codeHashes: string[]): Promise<void>;
409
+ createRecoveryCodes(uid: string, codeHashes: string[]): Promise<void>;
410
410
  /**
411
411
  * Use a recovery code (mark as used)
412
412
  */
413
- useRecoveryCode(userId: string, codeHash: string): Promise<boolean>;
413
+ useRecoveryCode(uid: string, codeHash: string): Promise<boolean>;
414
414
  /**
415
415
  * Get unused recovery code count for a user
416
416
  */
417
- getUnusedRecoveryCodeCount(userId: string): Promise<number>;
417
+ getUnusedRecoveryCodeCount(uid: string): Promise<number>;
418
418
  /**
419
419
  * Delete all recovery codes for a user
420
420
  */
421
- deleteAllRecoveryCodes(userId: string): Promise<void>;
421
+ deleteAllRecoveryCodes(uid: string): Promise<void>;
422
422
  /**
423
423
  * Check if a user has any verified MFA factors
424
424
  */
425
- hasVerifiedMfaFactors(userId: string): Promise<boolean>;
425
+ hasVerifiedMfaFactors(uid: string): Promise<boolean>;
426
426
  }
427
427
  /**
428
428
  * Combined auth repository interface for convenience
@@ -4,9 +4,14 @@ export interface JwtConfig {
4
4
  refreshExpiresIn?: string;
5
5
  }
6
6
  export interface AccessTokenPayload {
7
- userId: string;
7
+ /**
8
+ * The user's id — the same spelling the domain model, the auth adapters and
9
+ * the RLS layer (`auth.uid()`) all use. Tokens minted before this rename
10
+ * carry `uid` instead, and older external IdPs may send `sub`;
11
+ * {@link verifyAccessToken} accepts all three and normalises to this.
12
+ */
13
+ uid: string;
8
14
  roles: string[];
9
- uid?: string;
10
15
  /** Authentication Assurance Level: aal1 = password/oauth, aal2 = MFA verified */
11
16
  aal?: "aal1" | "aal2";
12
17
  /** Email claim from the JWT, if present */
@@ -28,7 +33,7 @@ export declare function configureJwt(config: JwtConfig): void;
28
33
  /**
29
34
  * Generate an access token (short-lived, 1 hour by default)
30
35
  */
31
- export declare function generateAccessToken(userId: string, roles: string[], aal?: "aal1" | "aal2", customClaims?: Record<string, unknown>): string;
36
+ export declare function generateAccessToken(uid: string, roles: string[], aal?: "aal1" | "aal2", customClaims?: Record<string, unknown>): string;
32
37
  /**
33
38
  * Get the expiration time of an access token in milliseconds from now
34
39
  */
@@ -23,10 +23,10 @@ export declare function mountMagicLinkRoutes(deps: {
23
23
  isAnonymous?: boolean;
24
24
  metadata?: Record<string, unknown> | null;
25
25
  }, roleIds: string[], accessToken: string, refreshToken: string, providerId: string) => unknown;
26
- createSessionAndTokens: (userId: string, userAgent: string, ipAddress: string) => Promise<{
26
+ createSessionAndTokens: (uid: string, userAgent: string, ipAddress: string) => Promise<{
27
27
  roleIds: string[];
28
28
  accessToken: string;
29
29
  refreshToken: string;
30
30
  }>;
31
- applyTransformHook: (response: AuthResponsePayload, method: TransformAuthResponseContext["method"], request: Request, userId: string) => Promise<AuthResponsePayload>;
31
+ applyTransformHook: (response: AuthResponsePayload, method: TransformAuthResponseContext["method"], request: Request, uid: string) => Promise<AuthResponsePayload>;
32
32
  }): void;
@@ -4,4 +4,4 @@ import { HonoEnv } from "../api/types";
4
4
  import type { AuthModuleConfig } from "./routes";
5
5
  import { resolveAuthHooks } from "./auth-hooks";
6
6
  import type { AuthResponsePayload, TransformAuthResponseContext } from "@rebasepro/types";
7
- export declare function mountMfaRoutes(router: Hono<HonoEnv>, config: AuthModuleConfig, ops: ReturnType<typeof resolveAuthHooks>, parseBody: <T>(schema: z.ZodSchema<T>, body: unknown) => T, applyTransformHook?: (response: AuthResponsePayload, method: TransformAuthResponseContext["method"], request: Request, userId: string) => Promise<AuthResponsePayload>): void;
7
+ export declare function mountMfaRoutes(router: Hono<HonoEnv>, config: AuthModuleConfig, ops: ReturnType<typeof resolveAuthHooks>, parseBody: <T>(schema: z.ZodSchema<T>, body: unknown) => T, applyTransformHook?: (response: AuthResponsePayload, method: TransformAuthResponseContext["method"], request: Request, uid: string) => Promise<AuthResponsePayload>): void;
@@ -1,17 +1,17 @@
1
1
  import { MiddlewareHandler, Context } from "hono";
2
2
  import { DataDriver } from "@rebasepro/types";
3
3
  import { AccessTokenPayload } from "./jwt";
4
- import { HonoEnv } from "../api/types";
4
+ import type { HonoEnv } from "../api/types";
5
5
  import type { ApiKeyStore } from "./api-keys/api-key-store";
6
6
  /**
7
7
  * Result from a custom auth validator.
8
8
  * - `false`/`null`/`undefined` = not authenticated
9
9
  * - `true` = authenticated as default user
10
- * - object with `userId` or `uid` = authenticated with user info
10
+ * - object with `uid` (or legacy `userId`) = authenticated with user info
11
11
  */
12
12
  export type AuthResult = boolean | null | undefined | {
13
- userId?: string;
14
13
  uid?: string;
14
+ userId?: string;
15
15
  roles?: string[];
16
16
  [key: string]: unknown;
17
17
  };
@@ -24,6 +24,6 @@ export interface ResetPasswordRouteConfig {
24
24
  /**
25
25
  * Create a standalone admin route for resetting user passwords.
26
26
  *
27
- * Mounts: POST /users/:userId/reset-password
27
+ * Mounts: POST /users/:uid/reset-password
28
28
  */
29
29
  export declare function createResetPasswordRoute(config: ResetPasswordRouteConfig): Hono<HonoEnv>;
@@ -18,12 +18,12 @@ interface SessionRoutesConfig {
18
18
  isAnonymous?: boolean;
19
19
  metadata?: Record<string, unknown> | null;
20
20
  }, roleIds: string[], accessToken: string, refreshToken: string, providerId: string) => unknown;
21
- createSessionAndTokens: (userId: string, userAgent: string, ipAddress: string) => Promise<{
21
+ createSessionAndTokens: (uid: string, userAgent: string, ipAddress: string) => Promise<{
22
22
  roleIds: string[];
23
23
  accessToken: string;
24
24
  refreshToken: string;
25
25
  }>;
26
- applyTransformHook: (response: AuthResponsePayload, method: TransformAuthResponseContext["method"], request: Request, userId: string) => Promise<AuthResponsePayload>;
26
+ applyTransformHook: (response: AuthResponsePayload, method: TransformAuthResponseContext["method"], request: Request, uid: string) => Promise<AuthResponsePayload>;
27
27
  }
28
28
  export declare function mountSessionRoutes(opts: SessionRoutesConfig): void;
29
29
  export {};