@syncello/auth 3.1.0 → 3.2.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/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { ColumnDefinition, ColumnType, EnumDefinition, EnumName, IndexDefinition, SCHEMA_VERSION, TableDefinition, TableName, enums, tableNames, tables } from './schema/index.cjs';
2
- import { PgTableWithColumns, PgTable } from 'drizzle-orm/pg-core';
2
+ import { PgTableWithColumns } from 'drizzle-orm/pg-core';
3
3
  import * as hono from 'hono';
4
4
  import { Context } from 'hono';
5
5
  import { InferInsertModel, InferSelectModel } from 'drizzle-orm';
@@ -68,33 +68,8 @@ declare function validatePasswordWithBreachCheck(password: string, checkBreaches
68
68
 
69
69
  type DrizzleDB$2 = any;
70
70
 
71
- type SessionsTable = PgTableWithColumns<{
72
- name: string;
73
- schema: undefined;
74
- columns: {
75
- id: any;
76
- userId: any;
77
- expiresAt: any;
78
- createdAt: any;
79
- lastActiveAt: any;
80
- fingerprint: any;
81
- ipAddress: any;
82
- };
83
- dialect: 'pg';
84
- }>;
85
- type UsersTable$4 = PgTableWithColumns<{
86
- name: string;
87
- schema: undefined;
88
- columns: {
89
- id: any;
90
- email: any;
91
- emailVerified: any;
92
- sessionVersion: any;
93
- createdAt: any;
94
- updatedAt: any;
95
- };
96
- dialect: 'pg';
97
- }>;
71
+ type SessionsTable = PgTableWithColumns<any>;
72
+ type UsersTable$4 = PgTableWithColumns<any>;
98
73
  interface SessionTables {
99
74
  sessions: SessionsTable;
100
75
  users: UsersTable$4;
@@ -194,9 +169,15 @@ declare const AUTH_DEFAULTS: {
194
169
  };
195
170
 
196
171
  /**
197
- * Base type for auth tables - any Postgres table
172
+ * Base type for auth tables.
173
+ *
174
+ * The library is schema-agnostic: consumers inject their own Drizzle tables,
175
+ * so the concrete column types are not known at compile time within the
176
+ * library. `PgTableWithColumns<any>` keeps column access available (e.g.
177
+ * `schema.users.email`) and stays assignable to the column-specific table
178
+ * types declared by the core modules.
198
179
  */
199
- type AuthTable = PgTable;
180
+ type AuthTable = PgTableWithColumns<any>;
200
181
  /**
201
182
  * Schema interface that consumers must provide.
202
183
  * Each property must be a Drizzle PgTable with the expected columns.
@@ -234,14 +215,19 @@ type InferSession<TSchema extends AuthSchema> = InferSelectModel<TSchema['sessio
234
215
  type InferNewSession<TSchema extends AuthSchema> = InferInsertModel<TSchema['sessions']>;
235
216
  /**
236
217
  * Database interface - accepts any Drizzle Postgres database.
218
+ *
237
219
  * Uses duck typing for flexibility across different Drizzle configurations.
220
+ * Because the consumer's concrete schema is injected at runtime, the query
221
+ * builder chains cannot be statically typed against specific tables here; the
222
+ * methods are intentionally permissive and rely on the consumer's real Drizzle
223
+ * instance for correctness.
238
224
  */
239
225
  interface AuthDatabase {
240
- select: <T extends PgTable>(from?: T) => unknown;
241
- insert: <T extends PgTable>(into: T) => unknown;
242
- update: <T extends PgTable>(table: T) => unknown;
243
- delete: <T extends PgTable>(from: T) => unknown;
244
- query: Record<string, unknown>;
226
+ select: (...args: any[]) => any;
227
+ insert: (...args: any[]) => any;
228
+ update: (...args: any[]) => any;
229
+ delete: (...args: any[]) => any;
230
+ query: Record<string, any>;
245
231
  }
246
232
  /**
247
233
  * Configuration for createAuth
@@ -335,6 +321,51 @@ declare function createAuthMiddleware<TEnv = Record<string, unknown>>(auth: Auth
335
321
  */
336
322
  declare function getAuthContext<TEnv = Record<string, unknown>>(c: Context): AuthContext<TEnv>;
337
323
 
324
+ /**
325
+ * Email adapter interface for provider abstraction
326
+ * Allows for provider abstraction (currently Resend)
327
+ */
328
+ interface EmailSendOptions {
329
+ from: string;
330
+ to: string;
331
+ subject: string;
332
+ html: string;
333
+ text?: string;
334
+ tags?: Record<string, string>;
335
+ }
336
+ interface EmailSendResult {
337
+ success: boolean;
338
+ emailId?: string;
339
+ error?: string;
340
+ }
341
+ interface EmailAdapter {
342
+ /**
343
+ * Send an email through the provider
344
+ */
345
+ send(options: EmailSendOptions): Promise<EmailSendResult>;
346
+ /**
347
+ * Provider name for logging
348
+ */
349
+ readonly providerName: string;
350
+ }
351
+ /**
352
+ * Structural type for the Cloudflare Email Service `send_email` Workers binding.
353
+ * Defined locally so consumers do not need a specific @cloudflare/workers-types
354
+ * version that includes Email Service (beta) types.
355
+ */
356
+ interface SendEmailBinding {
357
+ send(message: {
358
+ to: string;
359
+ from: string;
360
+ subject: string;
361
+ html?: string;
362
+ text?: string;
363
+ headers?: Record<string, string>;
364
+ }): Promise<{
365
+ messageId: string;
366
+ }>;
367
+ }
368
+
338
369
  /**
339
370
  * Environment variables available in Cloudflare Workers
340
371
  */
@@ -344,8 +375,11 @@ type Env = {
344
375
  SESSION_SECRET: string;
345
376
  PASSWORD_PEPPER_V1: string;
346
377
  PASSWORD_PEPPER_V2?: string;
378
+ EMAIL_PROVIDER?: 'resend' | 'cloudflare';
379
+ EMAIL_FROM?: string;
347
380
  RESEND_API_KEY?: string;
348
381
  RESEND_WEBHOOK_SECRET?: string;
382
+ EMAIL?: SendEmailBinding;
349
383
  DB: {
350
384
  connectionString: string;
351
385
  };
@@ -427,16 +461,7 @@ declare function generateFingerprint(request: Request): Promise<string>;
427
461
  declare function getClientIp(request: Request): string;
428
462
 
429
463
  type DrizzleDB$1 = any;
430
- type UsersTable$3 = PgTableWithColumns<{
431
- name: string;
432
- schema: undefined;
433
- columns: {
434
- id: any;
435
- lockedUntil: any;
436
- failedLoginCount: any;
437
- };
438
- dialect: 'pg';
439
- }>;
464
+ type UsersTable$3 = PgTableWithColumns<any>;
440
465
  interface AccountLockoutTables {
441
466
  users: UsersTable$3;
442
467
  }
@@ -486,31 +511,8 @@ declare function getMinutesUntilUnlock(unlockAt: number): number;
486
511
  declare function verifyTurnstileToken(token: string, secretKey: string, remoteIp?: string, environment?: 'development' | 'staging' | 'production'): Promise<boolean>;
487
512
 
488
513
  type DrizzleDB = any;
489
- type UsersTable$2 = PgTableWithColumns<{
490
- name: string;
491
- schema: undefined;
492
- columns: {
493
- id: any;
494
- email: any;
495
- hashedPassword: any;
496
- updatedAt: any;
497
- };
498
- dialect: 'pg';
499
- }>;
500
- type EmailChangeTokensTable = PgTableWithColumns<{
501
- name: string;
502
- schema: undefined;
503
- columns: {
504
- id: any;
505
- userId: any;
506
- newEmail: any;
507
- tokenHash: any;
508
- cancelTokenHash: any;
509
- expiresAt: any;
510
- createdAt: any;
511
- };
512
- dialect: 'pg';
513
- }>;
514
+ type UsersTable$2 = PgTableWithColumns<any>;
515
+ type EmailChangeTokensTable = PgTableWithColumns<any>;
514
516
  interface EmailChangeTables {
515
517
  users: UsersTable$2;
516
518
  emailChangeTokens: EmailChangeTokensTable;
@@ -2526,39 +2528,15 @@ interface ResendWebhookPayload {
2526
2528
  }
2527
2529
 
2528
2530
  /**
2529
- * Email adapter interface for provider abstraction
2530
- * Allows for provider abstraction (currently Resend)
2531
- */
2532
- interface EmailSendOptions {
2533
- from: string;
2534
- to: string;
2535
- subject: string;
2536
- html: string;
2537
- text?: string;
2538
- tags?: Record<string, string>;
2539
- }
2540
- interface EmailSendResult {
2541
- success: boolean;
2542
- emailId?: string;
2543
- error?: string;
2544
- }
2545
- interface EmailAdapter {
2546
- /**
2547
- * Send an email through the provider
2548
- */
2549
- send(options: EmailSendOptions): Promise<EmailSendResult>;
2550
- /**
2551
- * Provider name for logging
2552
- */
2553
- readonly providerName: string;
2554
- }
2555
-
2556
- /**
2557
- * Create the Resend email adapter
2531
+ * Create the configured email adapter.
2558
2532
  *
2559
- * @param env - Environment variables
2560
- * @returns ResendAdapter instance
2561
- * @throws Error if RESEND_API_KEY is missing
2533
+ * Provider is selected by EMAIL_PROVIDER (defaults to 'resend' for backward
2534
+ * compatibility):
2535
+ * - 'resend': requires RESEND_API_KEY
2536
+ * - 'cloudflare': requires the EMAIL send_email Workers binding; dry-runs
2537
+ * (logs instead of sending) outside production/staging
2538
+ *
2539
+ * @throws Error if the selected provider's configuration is missing
2562
2540
  */
2563
2541
  declare function createEmailAdapter(env: Env): EmailAdapter;
2564
2542
 
@@ -2573,6 +2551,26 @@ declare class ResendAdapter implements EmailAdapter {
2573
2551
  send(options: EmailSendOptions): Promise<EmailSendResult>;
2574
2552
  }
2575
2553
 
2554
+ /**
2555
+ * Cloudflare Email Service adapter
2556
+ * Sends through the Workers `send_email` binding. Cloudflare manages bounce and
2557
+ * complaint suppression at the account level; a send to a suppressed address is
2558
+ * rejected with error code E_RECIPIENT_SUPPRESSED.
2559
+ *
2560
+ * In dry-run mode (any environment other than production/staging) it logs the
2561
+ * email and reports success without sending: Cloudflare has no test inbox and
2562
+ * real bounces damage sender reputation.
2563
+ */
2564
+ declare class CloudflareEmailAdapter implements EmailAdapter {
2565
+ private readonly binding;
2566
+ private readonly options;
2567
+ readonly providerName = "cloudflare";
2568
+ constructor(binding: SendEmailBinding, options: {
2569
+ dryRun: boolean;
2570
+ });
2571
+ send(options: EmailSendOptions): Promise<EmailSendResult>;
2572
+ }
2573
+
2576
2574
  type UsersTable$1 = PgTableWithColumns<any>;
2577
2575
  declare class EmailService {
2578
2576
  private adapter;
@@ -2592,31 +2590,31 @@ declare class EmailService {
2592
2590
  /**
2593
2591
  * Send verification email
2594
2592
  */
2595
- sendVerificationEmail(data: VerificationEmailData, db: PostgresJsDatabase<Record<string, unknown>>, usersTable: UsersTable$1): Promise<SendEmailResult>;
2593
+ sendVerificationEmail(data: VerificationEmailData, db: AuthDatabase, usersTable: UsersTable$1): Promise<SendEmailResult>;
2596
2594
  /**
2597
2595
  * Send password reset email
2598
2596
  */
2599
- sendPasswordResetEmail(data: PasswordResetEmailData, db: PostgresJsDatabase<Record<string, unknown>>, usersTable: UsersTable$1): Promise<SendEmailResult>;
2597
+ sendPasswordResetEmail(data: PasswordResetEmailData, db: AuthDatabase, usersTable: UsersTable$1): Promise<SendEmailResult>;
2600
2598
  /**
2601
2599
  * Send email change confirmation email (to new email address)
2602
2600
  */
2603
- sendEmailChangeConfirmation(data: EmailChangeConfirmationData, db: PostgresJsDatabase<Record<string, unknown>>, usersTable: UsersTable$1): Promise<SendEmailResult>;
2601
+ sendEmailChangeConfirmation(data: EmailChangeConfirmationData, db: AuthDatabase, usersTable: UsersTable$1): Promise<SendEmailResult>;
2604
2602
  /**
2605
2603
  * Send email change notification email (to old email address)
2606
2604
  */
2607
- sendEmailChangeNotification(data: EmailChangeNotificationData, db: PostgresJsDatabase<Record<string, unknown>>, usersTable: UsersTable$1): Promise<SendEmailResult>;
2605
+ sendEmailChangeNotification(data: EmailChangeNotificationData, db: AuthDatabase, usersTable: UsersTable$1): Promise<SendEmailResult>;
2608
2606
  /**
2609
2607
  * Send 2FA verification code email
2610
2608
  */
2611
- send2faCodeEmail(data: TwoFactorCodeEmailData, db: PostgresJsDatabase<Record<string, unknown>>, usersTable: UsersTable$1): Promise<SendEmailResult>;
2609
+ send2faCodeEmail(data: TwoFactorCodeEmailData, db: AuthDatabase, usersTable: UsersTable$1): Promise<SendEmailResult>;
2612
2610
  /**
2613
2611
  * Send 2FA enabled confirmation email
2614
2612
  */
2615
- send2faEnabledEmail(data: TwoFactorEnabledEmailData, db: PostgresJsDatabase<Record<string, unknown>>, usersTable: UsersTable$1): Promise<SendEmailResult>;
2613
+ send2faEnabledEmail(data: TwoFactorEnabledEmailData, db: AuthDatabase, usersTable: UsersTable$1): Promise<SendEmailResult>;
2616
2614
  /**
2617
2615
  * Send 2FA disabled notification email
2618
2616
  */
2619
- send2faDisabledEmail(data: TwoFactorDisabledEmailData, db: PostgresJsDatabase<Record<string, unknown>>, usersTable: UsersTable$1): Promise<SendEmailResult>;
2617
+ send2faDisabledEmail(data: TwoFactorDisabledEmailData, db: AuthDatabase, usersTable: UsersTable$1): Promise<SendEmailResult>;
2620
2618
  }
2621
2619
 
2622
2620
  /**
@@ -2681,4 +2679,4 @@ declare function calculateBounceRate(db: PostgresJsDatabase<Record<string, unkno
2681
2679
  */
2682
2680
  declare function calculateComplaintRate(db: PostgresJsDatabase<Record<string, unknown>>, emailEventsTable: EmailEventsTable, hoursAgo?: number): Promise<number>;
2683
2681
 
2684
- export { AUTH_DEFAULTS, type AccountLockoutTables, type Auth, type AuthConfig, type AuthContext, type AuthDatabase, type AuthSchema, CHALLENGE_TTL_MS, type ChallengePayload, type DeviceType, type EmailAdapter, type EmailChangeConfirmationData, type EmailChangeNotificationData, type EmailChangeTables, type EmailSendOptions, type EmailSendResult, EmailService, type EmailTemplate, type EmailType, type Env, type InferNewSession, type InferNewUser, type InferSession, type InferUser, MAX_CHALLENGE_ATTEMPTS, type PasswordResetEmailData, type ProblemDetails, ProblemTypes, ResendAdapter, type ResendEventType, type ResendWebhookPayload, type SendEmailResult, type SessionData, type SessionTables, TRUSTED_DEVICE_COOKIE_BASE, TRUSTED_DEVICE_TTL_MS, type TotpVerifyResult, type TwoFactorCodeEmailData, type TwoFactorDisabledEmailData, type TwoFactorEnabledEmailData, type ValidationResult, type Variables, type VerificationEmailData, authRoutes, calculateBounceRate, calculateComplaintRate, cancelEmailChange, checkAccountLocked, checkBreachedPassword, clearAccountLockout, clearChallengeCookie, clearSessionCookie, clearTrustedDeviceCookie, confirmEmailChange, createAuth, createAuthMiddleware, createChallengeToken, createDeviceToken, createEmailAdapter, createProblemDetails, createSession, csrf, decryptTotpSecret, deleteAllUserSessions, deleteChallengeToken, deleteSession, encryptTotpSecret, extractAppUrl, formatBackupCode, generate2faCodeEmail, generate2faDisabledEmail, generate2faEnabledEmail, generateApiKey, generateBackupCodes, generateCodeChallenge, generateCodeVerifier, generateEmailChangeConfirmation, generateEmailChangeNotification, generateFingerprint, generatePasswordResetEmail, generateQrCodeUri, generateSecureToken, generateTotpSecret, generateTraceId, generateVerificationEmail, getAllowedOrigins, getAuthContext, getChallengeCookieName, getClientIp, getKeyPrefix, getMinutesUntilUnlock, getSessionCookieName, getTotpCounter, getTrustedDeviceCookieName, handleWebhookEvent, hashApiKey, hashBackupCode, hashPassword, hashToken, incrementFailedAttempts, invalidateAllUserSessions, isCapacitorApp, isCloudflarePreviewUrl, isDeepLinkUri, isValidApiKeyFormat, logError, logSecurityEvent, logger, normalizeBackupCode, optionalAuth, parseDeviceName, parseDeviceType, problemJson, problems, rateLimit, refreshSession, requestEmailChange, requireAuth, requireVerifiedEmail, retrieveChallengeToken, setChallengeCookie, setSessionCookie, setTrustedDeviceCookie, storeChallengeToken, updateChallengeAttempts, validateChallengePayload, validateOrigin, validatePassword, validatePasswordWithBreachCheck, validateSession, validateTrustedDevice, verifyBackupCode, verifyCodeChallenge, verifyPassword, verifyPasswordWithRotation, verifyTotpCode, verifyTurnstileToken, verifyWebhookSignature };
2682
+ export { AUTH_DEFAULTS, type AccountLockoutTables, type Auth, type AuthConfig, type AuthContext, type AuthDatabase, type AuthSchema, CHALLENGE_TTL_MS, type ChallengePayload, CloudflareEmailAdapter, type DeviceType, type EmailAdapter, type EmailChangeConfirmationData, type EmailChangeNotificationData, type EmailChangeTables, type EmailSendOptions, type EmailSendResult, EmailService, type EmailTemplate, type EmailType, type Env, type InferNewSession, type InferNewUser, type InferSession, type InferUser, MAX_CHALLENGE_ATTEMPTS, type PasswordResetEmailData, type ProblemDetails, ProblemTypes, ResendAdapter, type ResendEventType, type ResendWebhookPayload, type SendEmailBinding, type SendEmailResult, type SessionData, type SessionTables, TRUSTED_DEVICE_COOKIE_BASE, TRUSTED_DEVICE_TTL_MS, type TotpVerifyResult, type TwoFactorCodeEmailData, type TwoFactorDisabledEmailData, type TwoFactorEnabledEmailData, type ValidationResult, type Variables, type VerificationEmailData, authRoutes, calculateBounceRate, calculateComplaintRate, cancelEmailChange, checkAccountLocked, checkBreachedPassword, clearAccountLockout, clearChallengeCookie, clearSessionCookie, clearTrustedDeviceCookie, confirmEmailChange, createAuth, createAuthMiddleware, createChallengeToken, createDeviceToken, createEmailAdapter, createProblemDetails, createSession, csrf, decryptTotpSecret, deleteAllUserSessions, deleteChallengeToken, deleteSession, encryptTotpSecret, extractAppUrl, formatBackupCode, generate2faCodeEmail, generate2faDisabledEmail, generate2faEnabledEmail, generateApiKey, generateBackupCodes, generateCodeChallenge, generateCodeVerifier, generateEmailChangeConfirmation, generateEmailChangeNotification, generateFingerprint, generatePasswordResetEmail, generateQrCodeUri, generateSecureToken, generateTotpSecret, generateTraceId, generateVerificationEmail, getAllowedOrigins, getAuthContext, getChallengeCookieName, getClientIp, getKeyPrefix, getMinutesUntilUnlock, getSessionCookieName, getTotpCounter, getTrustedDeviceCookieName, handleWebhookEvent, hashApiKey, hashBackupCode, hashPassword, hashToken, incrementFailedAttempts, invalidateAllUserSessions, isCapacitorApp, isCloudflarePreviewUrl, isDeepLinkUri, isValidApiKeyFormat, logError, logSecurityEvent, logger, normalizeBackupCode, optionalAuth, parseDeviceName, parseDeviceType, problemJson, problems, rateLimit, refreshSession, requestEmailChange, requireAuth, requireVerifiedEmail, retrieveChallengeToken, setChallengeCookie, setSessionCookie, setTrustedDeviceCookie, storeChallengeToken, updateChallengeAttempts, validateChallengePayload, validateOrigin, validatePassword, validatePasswordWithBreachCheck, validateSession, validateTrustedDevice, verifyBackupCode, verifyCodeChallenge, verifyPassword, verifyPasswordWithRotation, verifyTotpCode, verifyTurnstileToken, verifyWebhookSignature };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { ColumnDefinition, ColumnType, EnumDefinition, EnumName, IndexDefinition, SCHEMA_VERSION, TableDefinition, TableName, enums, tableNames, tables } from './schema/index.js';
2
- import { PgTableWithColumns, PgTable } from 'drizzle-orm/pg-core';
2
+ import { PgTableWithColumns } from 'drizzle-orm/pg-core';
3
3
  import * as hono from 'hono';
4
4
  import { Context } from 'hono';
5
5
  import { InferInsertModel, InferSelectModel } from 'drizzle-orm';
@@ -68,33 +68,8 @@ declare function validatePasswordWithBreachCheck(password: string, checkBreaches
68
68
 
69
69
  type DrizzleDB$2 = any;
70
70
 
71
- type SessionsTable = PgTableWithColumns<{
72
- name: string;
73
- schema: undefined;
74
- columns: {
75
- id: any;
76
- userId: any;
77
- expiresAt: any;
78
- createdAt: any;
79
- lastActiveAt: any;
80
- fingerprint: any;
81
- ipAddress: any;
82
- };
83
- dialect: 'pg';
84
- }>;
85
- type UsersTable$4 = PgTableWithColumns<{
86
- name: string;
87
- schema: undefined;
88
- columns: {
89
- id: any;
90
- email: any;
91
- emailVerified: any;
92
- sessionVersion: any;
93
- createdAt: any;
94
- updatedAt: any;
95
- };
96
- dialect: 'pg';
97
- }>;
71
+ type SessionsTable = PgTableWithColumns<any>;
72
+ type UsersTable$4 = PgTableWithColumns<any>;
98
73
  interface SessionTables {
99
74
  sessions: SessionsTable;
100
75
  users: UsersTable$4;
@@ -194,9 +169,15 @@ declare const AUTH_DEFAULTS: {
194
169
  };
195
170
 
196
171
  /**
197
- * Base type for auth tables - any Postgres table
172
+ * Base type for auth tables.
173
+ *
174
+ * The library is schema-agnostic: consumers inject their own Drizzle tables,
175
+ * so the concrete column types are not known at compile time within the
176
+ * library. `PgTableWithColumns<any>` keeps column access available (e.g.
177
+ * `schema.users.email`) and stays assignable to the column-specific table
178
+ * types declared by the core modules.
198
179
  */
199
- type AuthTable = PgTable;
180
+ type AuthTable = PgTableWithColumns<any>;
200
181
  /**
201
182
  * Schema interface that consumers must provide.
202
183
  * Each property must be a Drizzle PgTable with the expected columns.
@@ -234,14 +215,19 @@ type InferSession<TSchema extends AuthSchema> = InferSelectModel<TSchema['sessio
234
215
  type InferNewSession<TSchema extends AuthSchema> = InferInsertModel<TSchema['sessions']>;
235
216
  /**
236
217
  * Database interface - accepts any Drizzle Postgres database.
218
+ *
237
219
  * Uses duck typing for flexibility across different Drizzle configurations.
220
+ * Because the consumer's concrete schema is injected at runtime, the query
221
+ * builder chains cannot be statically typed against specific tables here; the
222
+ * methods are intentionally permissive and rely on the consumer's real Drizzle
223
+ * instance for correctness.
238
224
  */
239
225
  interface AuthDatabase {
240
- select: <T extends PgTable>(from?: T) => unknown;
241
- insert: <T extends PgTable>(into: T) => unknown;
242
- update: <T extends PgTable>(table: T) => unknown;
243
- delete: <T extends PgTable>(from: T) => unknown;
244
- query: Record<string, unknown>;
226
+ select: (...args: any[]) => any;
227
+ insert: (...args: any[]) => any;
228
+ update: (...args: any[]) => any;
229
+ delete: (...args: any[]) => any;
230
+ query: Record<string, any>;
245
231
  }
246
232
  /**
247
233
  * Configuration for createAuth
@@ -335,6 +321,51 @@ declare function createAuthMiddleware<TEnv = Record<string, unknown>>(auth: Auth
335
321
  */
336
322
  declare function getAuthContext<TEnv = Record<string, unknown>>(c: Context): AuthContext<TEnv>;
337
323
 
324
+ /**
325
+ * Email adapter interface for provider abstraction
326
+ * Allows for provider abstraction (currently Resend)
327
+ */
328
+ interface EmailSendOptions {
329
+ from: string;
330
+ to: string;
331
+ subject: string;
332
+ html: string;
333
+ text?: string;
334
+ tags?: Record<string, string>;
335
+ }
336
+ interface EmailSendResult {
337
+ success: boolean;
338
+ emailId?: string;
339
+ error?: string;
340
+ }
341
+ interface EmailAdapter {
342
+ /**
343
+ * Send an email through the provider
344
+ */
345
+ send(options: EmailSendOptions): Promise<EmailSendResult>;
346
+ /**
347
+ * Provider name for logging
348
+ */
349
+ readonly providerName: string;
350
+ }
351
+ /**
352
+ * Structural type for the Cloudflare Email Service `send_email` Workers binding.
353
+ * Defined locally so consumers do not need a specific @cloudflare/workers-types
354
+ * version that includes Email Service (beta) types.
355
+ */
356
+ interface SendEmailBinding {
357
+ send(message: {
358
+ to: string;
359
+ from: string;
360
+ subject: string;
361
+ html?: string;
362
+ text?: string;
363
+ headers?: Record<string, string>;
364
+ }): Promise<{
365
+ messageId: string;
366
+ }>;
367
+ }
368
+
338
369
  /**
339
370
  * Environment variables available in Cloudflare Workers
340
371
  */
@@ -344,8 +375,11 @@ type Env = {
344
375
  SESSION_SECRET: string;
345
376
  PASSWORD_PEPPER_V1: string;
346
377
  PASSWORD_PEPPER_V2?: string;
378
+ EMAIL_PROVIDER?: 'resend' | 'cloudflare';
379
+ EMAIL_FROM?: string;
347
380
  RESEND_API_KEY?: string;
348
381
  RESEND_WEBHOOK_SECRET?: string;
382
+ EMAIL?: SendEmailBinding;
349
383
  DB: {
350
384
  connectionString: string;
351
385
  };
@@ -427,16 +461,7 @@ declare function generateFingerprint(request: Request): Promise<string>;
427
461
  declare function getClientIp(request: Request): string;
428
462
 
429
463
  type DrizzleDB$1 = any;
430
- type UsersTable$3 = PgTableWithColumns<{
431
- name: string;
432
- schema: undefined;
433
- columns: {
434
- id: any;
435
- lockedUntil: any;
436
- failedLoginCount: any;
437
- };
438
- dialect: 'pg';
439
- }>;
464
+ type UsersTable$3 = PgTableWithColumns<any>;
440
465
  interface AccountLockoutTables {
441
466
  users: UsersTable$3;
442
467
  }
@@ -486,31 +511,8 @@ declare function getMinutesUntilUnlock(unlockAt: number): number;
486
511
  declare function verifyTurnstileToken(token: string, secretKey: string, remoteIp?: string, environment?: 'development' | 'staging' | 'production'): Promise<boolean>;
487
512
 
488
513
  type DrizzleDB = any;
489
- type UsersTable$2 = PgTableWithColumns<{
490
- name: string;
491
- schema: undefined;
492
- columns: {
493
- id: any;
494
- email: any;
495
- hashedPassword: any;
496
- updatedAt: any;
497
- };
498
- dialect: 'pg';
499
- }>;
500
- type EmailChangeTokensTable = PgTableWithColumns<{
501
- name: string;
502
- schema: undefined;
503
- columns: {
504
- id: any;
505
- userId: any;
506
- newEmail: any;
507
- tokenHash: any;
508
- cancelTokenHash: any;
509
- expiresAt: any;
510
- createdAt: any;
511
- };
512
- dialect: 'pg';
513
- }>;
514
+ type UsersTable$2 = PgTableWithColumns<any>;
515
+ type EmailChangeTokensTable = PgTableWithColumns<any>;
514
516
  interface EmailChangeTables {
515
517
  users: UsersTable$2;
516
518
  emailChangeTokens: EmailChangeTokensTable;
@@ -2526,39 +2528,15 @@ interface ResendWebhookPayload {
2526
2528
  }
2527
2529
 
2528
2530
  /**
2529
- * Email adapter interface for provider abstraction
2530
- * Allows for provider abstraction (currently Resend)
2531
- */
2532
- interface EmailSendOptions {
2533
- from: string;
2534
- to: string;
2535
- subject: string;
2536
- html: string;
2537
- text?: string;
2538
- tags?: Record<string, string>;
2539
- }
2540
- interface EmailSendResult {
2541
- success: boolean;
2542
- emailId?: string;
2543
- error?: string;
2544
- }
2545
- interface EmailAdapter {
2546
- /**
2547
- * Send an email through the provider
2548
- */
2549
- send(options: EmailSendOptions): Promise<EmailSendResult>;
2550
- /**
2551
- * Provider name for logging
2552
- */
2553
- readonly providerName: string;
2554
- }
2555
-
2556
- /**
2557
- * Create the Resend email adapter
2531
+ * Create the configured email adapter.
2558
2532
  *
2559
- * @param env - Environment variables
2560
- * @returns ResendAdapter instance
2561
- * @throws Error if RESEND_API_KEY is missing
2533
+ * Provider is selected by EMAIL_PROVIDER (defaults to 'resend' for backward
2534
+ * compatibility):
2535
+ * - 'resend': requires RESEND_API_KEY
2536
+ * - 'cloudflare': requires the EMAIL send_email Workers binding; dry-runs
2537
+ * (logs instead of sending) outside production/staging
2538
+ *
2539
+ * @throws Error if the selected provider's configuration is missing
2562
2540
  */
2563
2541
  declare function createEmailAdapter(env: Env): EmailAdapter;
2564
2542
 
@@ -2573,6 +2551,26 @@ declare class ResendAdapter implements EmailAdapter {
2573
2551
  send(options: EmailSendOptions): Promise<EmailSendResult>;
2574
2552
  }
2575
2553
 
2554
+ /**
2555
+ * Cloudflare Email Service adapter
2556
+ * Sends through the Workers `send_email` binding. Cloudflare manages bounce and
2557
+ * complaint suppression at the account level; a send to a suppressed address is
2558
+ * rejected with error code E_RECIPIENT_SUPPRESSED.
2559
+ *
2560
+ * In dry-run mode (any environment other than production/staging) it logs the
2561
+ * email and reports success without sending: Cloudflare has no test inbox and
2562
+ * real bounces damage sender reputation.
2563
+ */
2564
+ declare class CloudflareEmailAdapter implements EmailAdapter {
2565
+ private readonly binding;
2566
+ private readonly options;
2567
+ readonly providerName = "cloudflare";
2568
+ constructor(binding: SendEmailBinding, options: {
2569
+ dryRun: boolean;
2570
+ });
2571
+ send(options: EmailSendOptions): Promise<EmailSendResult>;
2572
+ }
2573
+
2576
2574
  type UsersTable$1 = PgTableWithColumns<any>;
2577
2575
  declare class EmailService {
2578
2576
  private adapter;
@@ -2592,31 +2590,31 @@ declare class EmailService {
2592
2590
  /**
2593
2591
  * Send verification email
2594
2592
  */
2595
- sendVerificationEmail(data: VerificationEmailData, db: PostgresJsDatabase<Record<string, unknown>>, usersTable: UsersTable$1): Promise<SendEmailResult>;
2593
+ sendVerificationEmail(data: VerificationEmailData, db: AuthDatabase, usersTable: UsersTable$1): Promise<SendEmailResult>;
2596
2594
  /**
2597
2595
  * Send password reset email
2598
2596
  */
2599
- sendPasswordResetEmail(data: PasswordResetEmailData, db: PostgresJsDatabase<Record<string, unknown>>, usersTable: UsersTable$1): Promise<SendEmailResult>;
2597
+ sendPasswordResetEmail(data: PasswordResetEmailData, db: AuthDatabase, usersTable: UsersTable$1): Promise<SendEmailResult>;
2600
2598
  /**
2601
2599
  * Send email change confirmation email (to new email address)
2602
2600
  */
2603
- sendEmailChangeConfirmation(data: EmailChangeConfirmationData, db: PostgresJsDatabase<Record<string, unknown>>, usersTable: UsersTable$1): Promise<SendEmailResult>;
2601
+ sendEmailChangeConfirmation(data: EmailChangeConfirmationData, db: AuthDatabase, usersTable: UsersTable$1): Promise<SendEmailResult>;
2604
2602
  /**
2605
2603
  * Send email change notification email (to old email address)
2606
2604
  */
2607
- sendEmailChangeNotification(data: EmailChangeNotificationData, db: PostgresJsDatabase<Record<string, unknown>>, usersTable: UsersTable$1): Promise<SendEmailResult>;
2605
+ sendEmailChangeNotification(data: EmailChangeNotificationData, db: AuthDatabase, usersTable: UsersTable$1): Promise<SendEmailResult>;
2608
2606
  /**
2609
2607
  * Send 2FA verification code email
2610
2608
  */
2611
- send2faCodeEmail(data: TwoFactorCodeEmailData, db: PostgresJsDatabase<Record<string, unknown>>, usersTable: UsersTable$1): Promise<SendEmailResult>;
2609
+ send2faCodeEmail(data: TwoFactorCodeEmailData, db: AuthDatabase, usersTable: UsersTable$1): Promise<SendEmailResult>;
2612
2610
  /**
2613
2611
  * Send 2FA enabled confirmation email
2614
2612
  */
2615
- send2faEnabledEmail(data: TwoFactorEnabledEmailData, db: PostgresJsDatabase<Record<string, unknown>>, usersTable: UsersTable$1): Promise<SendEmailResult>;
2613
+ send2faEnabledEmail(data: TwoFactorEnabledEmailData, db: AuthDatabase, usersTable: UsersTable$1): Promise<SendEmailResult>;
2616
2614
  /**
2617
2615
  * Send 2FA disabled notification email
2618
2616
  */
2619
- send2faDisabledEmail(data: TwoFactorDisabledEmailData, db: PostgresJsDatabase<Record<string, unknown>>, usersTable: UsersTable$1): Promise<SendEmailResult>;
2617
+ send2faDisabledEmail(data: TwoFactorDisabledEmailData, db: AuthDatabase, usersTable: UsersTable$1): Promise<SendEmailResult>;
2620
2618
  }
2621
2619
 
2622
2620
  /**
@@ -2681,4 +2679,4 @@ declare function calculateBounceRate(db: PostgresJsDatabase<Record<string, unkno
2681
2679
  */
2682
2680
  declare function calculateComplaintRate(db: PostgresJsDatabase<Record<string, unknown>>, emailEventsTable: EmailEventsTable, hoursAgo?: number): Promise<number>;
2683
2681
 
2684
- export { AUTH_DEFAULTS, type AccountLockoutTables, type Auth, type AuthConfig, type AuthContext, type AuthDatabase, type AuthSchema, CHALLENGE_TTL_MS, type ChallengePayload, type DeviceType, type EmailAdapter, type EmailChangeConfirmationData, type EmailChangeNotificationData, type EmailChangeTables, type EmailSendOptions, type EmailSendResult, EmailService, type EmailTemplate, type EmailType, type Env, type InferNewSession, type InferNewUser, type InferSession, type InferUser, MAX_CHALLENGE_ATTEMPTS, type PasswordResetEmailData, type ProblemDetails, ProblemTypes, ResendAdapter, type ResendEventType, type ResendWebhookPayload, type SendEmailResult, type SessionData, type SessionTables, TRUSTED_DEVICE_COOKIE_BASE, TRUSTED_DEVICE_TTL_MS, type TotpVerifyResult, type TwoFactorCodeEmailData, type TwoFactorDisabledEmailData, type TwoFactorEnabledEmailData, type ValidationResult, type Variables, type VerificationEmailData, authRoutes, calculateBounceRate, calculateComplaintRate, cancelEmailChange, checkAccountLocked, checkBreachedPassword, clearAccountLockout, clearChallengeCookie, clearSessionCookie, clearTrustedDeviceCookie, confirmEmailChange, createAuth, createAuthMiddleware, createChallengeToken, createDeviceToken, createEmailAdapter, createProblemDetails, createSession, csrf, decryptTotpSecret, deleteAllUserSessions, deleteChallengeToken, deleteSession, encryptTotpSecret, extractAppUrl, formatBackupCode, generate2faCodeEmail, generate2faDisabledEmail, generate2faEnabledEmail, generateApiKey, generateBackupCodes, generateCodeChallenge, generateCodeVerifier, generateEmailChangeConfirmation, generateEmailChangeNotification, generateFingerprint, generatePasswordResetEmail, generateQrCodeUri, generateSecureToken, generateTotpSecret, generateTraceId, generateVerificationEmail, getAllowedOrigins, getAuthContext, getChallengeCookieName, getClientIp, getKeyPrefix, getMinutesUntilUnlock, getSessionCookieName, getTotpCounter, getTrustedDeviceCookieName, handleWebhookEvent, hashApiKey, hashBackupCode, hashPassword, hashToken, incrementFailedAttempts, invalidateAllUserSessions, isCapacitorApp, isCloudflarePreviewUrl, isDeepLinkUri, isValidApiKeyFormat, logError, logSecurityEvent, logger, normalizeBackupCode, optionalAuth, parseDeviceName, parseDeviceType, problemJson, problems, rateLimit, refreshSession, requestEmailChange, requireAuth, requireVerifiedEmail, retrieveChallengeToken, setChallengeCookie, setSessionCookie, setTrustedDeviceCookie, storeChallengeToken, updateChallengeAttempts, validateChallengePayload, validateOrigin, validatePassword, validatePasswordWithBreachCheck, validateSession, validateTrustedDevice, verifyBackupCode, verifyCodeChallenge, verifyPassword, verifyPasswordWithRotation, verifyTotpCode, verifyTurnstileToken, verifyWebhookSignature };
2682
+ export { AUTH_DEFAULTS, type AccountLockoutTables, type Auth, type AuthConfig, type AuthContext, type AuthDatabase, type AuthSchema, CHALLENGE_TTL_MS, type ChallengePayload, CloudflareEmailAdapter, type DeviceType, type EmailAdapter, type EmailChangeConfirmationData, type EmailChangeNotificationData, type EmailChangeTables, type EmailSendOptions, type EmailSendResult, EmailService, type EmailTemplate, type EmailType, type Env, type InferNewSession, type InferNewUser, type InferSession, type InferUser, MAX_CHALLENGE_ATTEMPTS, type PasswordResetEmailData, type ProblemDetails, ProblemTypes, ResendAdapter, type ResendEventType, type ResendWebhookPayload, type SendEmailBinding, type SendEmailResult, type SessionData, type SessionTables, TRUSTED_DEVICE_COOKIE_BASE, TRUSTED_DEVICE_TTL_MS, type TotpVerifyResult, type TwoFactorCodeEmailData, type TwoFactorDisabledEmailData, type TwoFactorEnabledEmailData, type ValidationResult, type Variables, type VerificationEmailData, authRoutes, calculateBounceRate, calculateComplaintRate, cancelEmailChange, checkAccountLocked, checkBreachedPassword, clearAccountLockout, clearChallengeCookie, clearSessionCookie, clearTrustedDeviceCookie, confirmEmailChange, createAuth, createAuthMiddleware, createChallengeToken, createDeviceToken, createEmailAdapter, createProblemDetails, createSession, csrf, decryptTotpSecret, deleteAllUserSessions, deleteChallengeToken, deleteSession, encryptTotpSecret, extractAppUrl, formatBackupCode, generate2faCodeEmail, generate2faDisabledEmail, generate2faEnabledEmail, generateApiKey, generateBackupCodes, generateCodeChallenge, generateCodeVerifier, generateEmailChangeConfirmation, generateEmailChangeNotification, generateFingerprint, generatePasswordResetEmail, generateQrCodeUri, generateSecureToken, generateTotpSecret, generateTraceId, generateVerificationEmail, getAllowedOrigins, getAuthContext, getChallengeCookieName, getClientIp, getKeyPrefix, getMinutesUntilUnlock, getSessionCookieName, getTotpCounter, getTrustedDeviceCookieName, handleWebhookEvent, hashApiKey, hashBackupCode, hashPassword, hashToken, incrementFailedAttempts, invalidateAllUserSessions, isCapacitorApp, isCloudflarePreviewUrl, isDeepLinkUri, isValidApiKeyFormat, logError, logSecurityEvent, logger, normalizeBackupCode, optionalAuth, parseDeviceName, parseDeviceType, problemJson, problems, rateLimit, refreshSession, requestEmailChange, requireAuth, requireVerifiedEmail, retrieveChallengeToken, setChallengeCookie, setSessionCookie, setTrustedDeviceCookie, storeChallengeToken, updateChallengeAttempts, validateChallengePayload, validateOrigin, validatePassword, validatePasswordWithBreachCheck, validateSession, validateTrustedDevice, verifyBackupCode, verifyCodeChallenge, verifyPassword, verifyPasswordWithRotation, verifyTotpCode, verifyTurnstileToken, verifyWebhookSignature };