modelence 0.17.0-dev.0 → 0.17.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/server.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { A as AppServer } from './index-CLpVWWuj.js';
2
- import { c as ConfigParams, C as ConfigSchema, A as AnyMethodShape, S as ServerChannel, V as ValueType, f as SignupProps, U as UpdateProfileProps, g as AuthSuccessProps, h as AuthErrorProps, i as User, j as OAuthErrorInfo, a as WebsocketServerProvider, R as RoleDefinition, M as MethodDefinition, b as ConfigKey, k as AppConfig, l as Session, m as UserInfo, n as Role } from './types-CTjq1HaP.js';
3
- export { d as ConfigType } from './types-CTjq1HaP.js';
4
- import { S as Store, R as RouteDefinition, C as CronJobInputParams, a as RateLimitRule, E as EmailProvider, I as InferDocumentType, b as RateLimitType, c as EmailPayload } from './types-DNZiaNSs.js';
5
- export { H as HttpMethod, d as RouteHandler, e as RouteParams, f as RouteResponse, s as schema } from './types-DNZiaNSs.js';
2
+ import { c as ConfigParams, C as ConfigSchema, A as AnyMethodShape, S as ServerChannel, V as ValueType, f as SignupProps, U as UpdateProfileProps, g as AuthSuccessProps, h as AuthErrorProps, i as ConnectionInfo, j as User, k as OAuthErrorInfo, a as WebsocketServerProvider, R as RoleDefinition, M as MethodDefinition, b as ConfigKey, l as AppConfig, m as Session, n as UserInfo, o as Role } from './types-Ba-XOoJD.js';
3
+ export { d as ConfigType } from './types-Ba-XOoJD.js';
4
+ import { S as Store, R as RouteDefinition, C as CronJobInputParams, a as RateLimitRule, E as EmailProvider, b as RateLimitType, I as InferDocumentType, c as EmailPayload } from './types-BrUcinD0.js';
5
+ export { H as HttpMethod, d as RouteHandler, e as RouteParams, f as RouteResponse, s as schema } from './types-BrUcinD0.js';
6
6
  import { ObjectId as ObjectId$1 } from 'mongodb';
7
7
  export { ObjectId } from 'mongodb';
8
8
  import * as zod from 'zod';
@@ -131,15 +131,66 @@ type EmailConfig = {
131
131
  };
132
132
 
133
133
  /**
134
- * Per-action rate limit overrides for authentication endpoints.
135
- * Every field is optional omitting it keeps the built-in default.
134
+ * A single rate-limit rule for an authentication bucket. The `bucket` is
135
+ * implied by which auth action you're configuring (e.g. `signup`), so callers
136
+ * only specify the actor type, window size, and limit.
136
137
  *
137
138
  * @example
138
139
  * ```typescript
140
+ * import { time } from 'modelence/server';
141
+ *
142
+ * const rule: AuthRateLimitOverride = {
143
+ * type: 'ip',
144
+ * window: time.minutes(15),
145
+ * limit: 10,
146
+ * };
147
+ * ```
148
+ */
149
+ type AuthRateLimitOverride = {
150
+ /** Identifier type of the actor this rule applies to. */
151
+ type: RateLimitType;
152
+ /** Time window size in milliseconds. Use `time.minutes(15)` etc. */
153
+ window: number;
154
+ /** Maximum allowed hits within the window. */
155
+ limit: number;
156
+ };
157
+ /**
158
+ * Per-action rate limit overrides for authentication endpoints.
159
+ *
160
+ * Each bucket accepts an array of rules that are merged into the built-in
161
+ * defaults by `(type, window)` tuple:
162
+ * - A rule whose `(type, window)` matches a default replaces that default's
163
+ * `limit`.
164
+ * - A rule whose `(type, window)` does not match any default is added as
165
+ * an extra rule for the bucket.
166
+ * - Defaults whose `(type, window)` is not overridden are kept.
167
+ *
168
+ * This means you can tighten a single window without accidentally dropping
169
+ * the other built-in protections for that bucket.
170
+ *
171
+ * @example Tighten the 15-minute signup cap; per-day default is preserved.
172
+ * ```typescript
173
+ * import { startApp, time } from 'modelence/server';
174
+ *
139
175
  * startApp({
140
176
  * auth: {
141
177
  * rateLimits: {
142
- * signup: { perIp15Minutes: 5, perIpPerDay: 50 },
178
+ * signup: [
179
+ * { type: 'ip', window: time.minutes(15), limit: 5 },
180
+ * ],
181
+ * },
182
+ * },
183
+ * });
184
+ * ```
185
+ *
186
+ * @example Add an extra window alongside the defaults.
187
+ * ```typescript
188
+ * startApp({
189
+ * auth: {
190
+ * rateLimits: {
191
+ * signup: [
192
+ * { type: 'ip', window: time.minutes(1), limit: 2 },
193
+ * ],
143
194
  * },
144
195
  * },
145
196
  * });
@@ -147,50 +198,38 @@ type EmailConfig = {
147
198
  */
148
199
  type AuthRateLimitsConfig = {
149
200
  /** Per-IP limits for the signup endpoint (successful signups only). */
150
- signup?: {
151
- /** Max signups per IP in a 15-minute window. @default 20 */
152
- perIp15Minutes?: number;
153
- /** Max signups per IP per day. @default 200 */
154
- perIpPerDay?: number;
155
- };
201
+ signup?: AuthRateLimitOverride[];
156
202
  /** Per-IP limits for signup attempts (checked before duplicate detection). */
157
- signupAttempt?: {
158
- /** Max signup attempts per IP in a 15-minute window. @default 50 */
159
- perIp15Minutes?: number;
160
- /** Max signup attempts per IP per day. @default 500 */
161
- perIpPerDay?: number;
162
- };
203
+ signupAttempt?: AuthRateLimitOverride[];
163
204
  /** Per-IP limits for login attempts. */
164
- signin?: {
165
- /** Max login attempts per IP in a 15-minute window. @default 50 */
166
- perIp15Minutes?: number;
167
- /** Max login attempts per IP per day. @default 500 */
168
- perIpPerDay?: number;
169
- };
205
+ signin?: AuthRateLimitOverride[];
170
206
  /** Per-user limits for email verification requests. */
171
- verification?: {
172
- /** Max verification emails per user per minute. @default 1 */
173
- perUserPerMinute?: number;
174
- /** Max verification emails per user per day. @default 10 */
175
- perUserPerDay?: number;
176
- };
207
+ verification?: AuthRateLimitOverride[];
177
208
  /** Rate limits for password reset requests. */
178
- passwordReset?: {
179
- /** Max password reset requests per IP in a 15-minute window. @default 10 */
180
- perIp15Minutes?: number;
181
- /** Max password reset requests per IP per day. @default 100 */
182
- perIpPerDay?: number;
183
- /** Max password reset requests per email address per hour. @default 5 */
184
- perEmailPerHour?: number;
185
- /** Max password reset requests per email address per day. @default 10 */
186
- perEmailPerDay?: number;
187
- };
209
+ passwordReset?: AuthRateLimitOverride[];
188
210
  };
189
211
  type GenerateHandleProps = {
190
212
  email: string;
191
213
  firstName?: string;
192
214
  lastName?: string;
193
215
  };
216
+ /**
217
+ * Props passed to {@link AuthConfig.onBeforeSignup}.
218
+ *
219
+ * The hook fires after validation and the built-in disposable-email check,
220
+ * but before the user document is inserted. Throwing aborts the signup —
221
+ * the thrown error is re-thrown to the caller and `onSignupError` fires.
222
+ */
223
+ type BeforeSignupProps = {
224
+ /** Lowercased, validated email address. */
225
+ email: string;
226
+ firstName?: string;
227
+ lastName?: string;
228
+ handle?: string;
229
+ /** Provider that initiated the signup. Currently only `'email'`. */
230
+ provider: 'email';
231
+ connectionInfo?: ConnectionInfo;
232
+ };
194
233
  /**
195
234
  * Callback options for authentication operations
196
235
  */
@@ -240,20 +279,91 @@ type AuthOption = {
240
279
  * ```
241
280
  */
242
281
  type AuthConfig = {
282
+ /**
283
+ * Pre-signup validation hook. Runs before a new user is created during
284
+ * email/password signup, after format checks but before duplicate detection.
285
+ * Throw to reject the signup — the thrown message is surfaced to the client.
286
+ *
287
+ * Receives the raw signup payload (`email`, `password`, and optional
288
+ * `firstName`, `lastName`, `avatarUrl`, `handle`). May be async.
289
+ */
243
290
  validateSignup?: (props: SignupProps) => void | Promise<void>;
291
+ /**
292
+ * Pre-update validation hook. Runs before a user's profile fields
293
+ * (`firstName`, `lastName`, `avatarUrl`, `handle`) are written.
294
+ * Throw to reject the update — the thrown message is surfaced to the client.
295
+ * May be async.
296
+ */
244
297
  validateProfileUpdate?: (props: UpdateProfileProps) => void | Promise<void>;
298
+ /**
299
+ * Fires after a successful login (email/password or OAuth) once the session
300
+ * has been linked to the user. Receives `{ provider, user, session, connectionInfo }`.
301
+ * Use for analytics, audit logging, or post-login side effects.
302
+ */
245
303
  onAfterLogin?: (props: AuthSuccessProps) => void;
304
+ /**
305
+ * Fires when a login attempt fails. Receives `{ provider, error, session, connectionInfo }`.
306
+ * Use for failure analytics or alerting — does NOT change the response sent to the client.
307
+ */
246
308
  onLoginError?: (props: AuthErrorProps) => void;
309
+ /**
310
+ * Hook fired after validation and the built-in disposable-email check, but
311
+ * before the new user document is inserted. Throwing aborts the signup —
312
+ * the thrown error is re-thrown to the caller and `onSignupError` fires.
313
+ *
314
+ * Use this to plug in a custom domain-policy check (e.g. a tenant-specific
315
+ * email-domain verification service) without having to disable the built-in
316
+ * disposable-email check.
317
+ *
318
+ * Currently only invoked for `'email'` provider signups. OAuth signups are
319
+ * not gated because OAuth providers (Google, GitHub, etc.) do not issue
320
+ * disposable accounts.
321
+ */
322
+ onBeforeSignup?: (props: BeforeSignupProps) => void | Promise<void>;
323
+ /**
324
+ * Fires after a successful signup once the user record is created and the
325
+ * session is linked. Receives `{ provider, user, session, connectionInfo }`.
326
+ * Common uses: send welcome email, create default workspace, track activation.
327
+ */
247
328
  onAfterSignup?: (props: AuthSuccessProps) => void;
329
+ /**
330
+ * Fires when a signup attempt fails (validation, duplicate email, etc.).
331
+ * Receives `{ provider, error, session, connectionInfo }`.
332
+ * Use for failure analytics — does NOT change the response sent to the client.
333
+ */
248
334
  onSignupError?: (props: AuthErrorProps) => void;
335
+ /**
336
+ * Fires after a user's email is successfully verified (via the verification
337
+ * link or implicitly via password reset). Receives `{ provider, user, session, connectionInfo }`.
338
+ */
249
339
  onAfterEmailVerification?: (props: AuthSuccessProps) => void;
340
+ /**
341
+ * Fires when email verification fails (invalid or expired token).
342
+ * Receives `{ provider, error, session, connectionInfo }`.
343
+ */
250
344
  onEmailVerificationError?: (props: AuthErrorProps) => void;
345
+ /**
346
+ * Fires after an OAuth provider is linked to an existing account
347
+ * (either automatically when `oauthAccountLinking: 'auto'` or via an
348
+ * explicit link flow). Receives `{ provider, user, session, connectionInfo }`.
349
+ */
251
350
  onAfterOAuthLink?: (props: AuthSuccessProps) => void;
351
+ /**
352
+ * Fires when OAuth account linking fails. Receives
353
+ * `{ provider, error, session, connectionInfo }`.
354
+ */
252
355
  onOAuthLinkError?: (props: AuthErrorProps) => void;
356
+ /**
357
+ * Custom handle generator. If provided, overrides the default behavior
358
+ * (which derives the handle from the email local-part). Receives
359
+ * `{ email, firstName?, lastName? }` and returns the desired handle
360
+ * synchronously or as a `Promise<string>`. If the returned handle collides
361
+ * with an existing one, Modelence appends a numeric suffix automatically.
362
+ */
253
363
  generateHandle?: (props: GenerateHandleProps) => Promise<string> | string;
254
- /** deprecated: use onAfterLogin and onLoginError */
364
+ /** @deprecated Use {@link AuthConfig.onAfterLogin} and {@link AuthConfig.onLoginError} instead. */
255
365
  login?: AuthOption;
256
- /** deprecated: user onAfterSignup and onSignupError */
366
+ /** @deprecated Use {@link AuthConfig.onAfterSignup} and {@link AuthConfig.onSignupError} instead. */
257
367
  signup?: AuthOption;
258
368
  /**
259
369
  * Controls how OAuth providers handle existing accounts with matching email.
@@ -262,12 +372,36 @@ type AuthConfig = {
262
372
  * if the provider email is verified.
263
373
  */
264
374
  oauthAccountLinking?: 'auto' | 'manual';
375
+ /**
376
+ * Customizes how OAuth authentication errors are rendered. By default,
377
+ * OAuth errors are returned as JSON; providing this returns a custom HTML
378
+ * response instead, which is useful when the OAuth flow runs in a browser
379
+ * context. Receives `{ error, statusCode }` and returns an HTML string
380
+ * (or `null`/`undefined` to fall back to the default JSON response).
381
+ *
382
+ * Always escape interpolated values to prevent XSS.
383
+ */
265
384
  errorComponent?: (props: OAuthErrorInfo) => string | null | undefined;
266
385
  /**
267
- * Overrides the built-in rate limits for authentication endpoints.
268
- * Only the fields you specify are overridden; all others keep their defaults.
386
+ * Overrides the built-in rate limits for authentication endpoints. Each rule
387
+ * you provide is merged into the defaults by `(bucket, type, window)`:
388
+ * matching tuples replace the default `limit`, new tuples are added, and
389
+ * unspecified defaults are preserved. See {@link AuthRateLimitsConfig} for
390
+ * full semantics and examples.
269
391
  */
270
392
  rateLimits?: AuthRateLimitsConfig;
393
+ /**
394
+ * When `true`, the built-in disposable-email check is skipped during signup.
395
+ * Defaults to `false` (built-in check enforced).
396
+ *
397
+ * Set this to `true` when you want to enforce your own domain-policy logic
398
+ * via {@link onBeforeSignup} — for example, a service that classifies
399
+ * domains as public/disposable/custom with its own data sources and cache.
400
+ *
401
+ * Skipping the built-in check without registering an `onBeforeSignup` hook
402
+ * means disposable emails will be allowed to sign up.
403
+ */
404
+ allowDisposableEmails?: boolean;
271
405
  };
272
406
 
273
407
  /**
@@ -784,4 +918,4 @@ declare function deleteFile(filePath: string): Promise<void>;
784
918
  declare function downloadFile(filePath: string): Promise<DownloadFileResult>;
785
919
  declare function getFileUrl(filePath: string): Promise<GetFileUrlResult>;
786
920
 
787
- export { type AppOptions, type AuthConfig, type AuthOption, type AuthRateLimitsConfig, type CloudBackendConnectResponse, ConfigSchema, CronJobInputParams, FileVisibility, LiveData, type LiveDataConfig, type LiveQueryCleanup, type LiveQueryPublish, type LiveQueryWatch, Module, RateLimitRule, RateLimitType, RoleDefinition, RouteDefinition, type SecurityConfig, ServerChannel, Store, UserInfo, ValueType, authenticate, consumeRateLimit, createQuery, usersCollection as dbUsers, deleteFile, deleteUser, disableUser, downloadFile, getConfig, getFileUrl, getUploadUrl, sendEmail, startApp };
921
+ export { type AppOptions, type AuthConfig, type AuthOption, type AuthRateLimitOverride, type AuthRateLimitsConfig, type CloudBackendConnectResponse, ConfigSchema, CronJobInputParams, FileVisibility, LiveData, type LiveDataConfig, type LiveQueryCleanup, type LiveQueryPublish, type LiveQueryWatch, Module, RateLimitRule, RateLimitType, RoleDefinition, RouteDefinition, type SecurityConfig, ServerChannel, Store, UserInfo, ValueType, authenticate, consumeRateLimit, createQuery, usersCollection as dbUsers, deleteFile, deleteUser, disableUser, downloadFile, getConfig, getFileUrl, getUploadUrl, sendEmail, startApp };