@fonderie/auth 7.22.1 → 7.24.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/brain/outcomes.md CHANGED
@@ -9,6 +9,17 @@ downloading tarballs.
9
9
 
10
10
  ## Database tables (after all migrations)
11
11
 
12
+ ### `fonderie_account_deletion_codes`
13
+
14
+ ```sql
15
+ user_id UUID PRIMARY KEY REFERENCES fonderie_users(id) ON DELETE CASCADE
16
+ code_hash TEXT NOT NULL
17
+ channel TEXT NOT NULL CHECK (channel IN ('email', 'sms'))
18
+ attempts INT NOT NULL DEFAULT 0
19
+ expires_at TIMESTAMPTZ NOT NULL
20
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
21
+ ```
22
+
12
23
  ### `fonderie_consumed_tokens`
13
24
 
14
25
  ```sql
@@ -133,6 +144,8 @@ IF NOT EXISTS phone_verified_at TIMESTAMPTZ
133
144
  CONSTRAINT fonderie_users_phone_unique UNIQUE (phone)
134
145
  mfa_secret_pending TEXT
135
146
  mfa_secret_pending_expires_at TIMESTAMPTZ
147
+ deletion_channel TEXT
148
+ deletion_reminded_at TIMESTAMPTZ
136
149
  -- INDEX idx_fonderie_users_email (email)
137
150
  ```
138
151
 
@@ -149,6 +162,7 @@ Raw SQL ships in `node_modules/@fonderie/auth/dist/migrations/sql/` — read it
149
162
  | GET | `/_admin/users/:id/sessions` | `async (ctx) => { if (!(await users.findById(idOf(ctx)))) return NOT_FOUND(); const rows = await sessions.listLiveByUser(idOf(ctx)); return setApiResponse( HTTP.OK, 'SESSIONS', 'Live sessions', rows.map((r) => toSessionDTO(r, null)), ); }` |
150
163
  | POST | `/_admin/users/:id/suspend` | `setSuspended(true)` |
151
164
  | POST | `/_admin/users/:id/unsuspend` | `setSuspended(false)` |
165
+ | POST | `/auth/account/restore` | `ipLimit('login') → validate(restoreAccountSchema) → auth.restoreAccount` |
152
166
  | GET | `/auth/apple` | `oauth.appleInit` |
153
167
  | POST | `/auth/apple/callback` | `ipLimit('login') → oauth.appleCallback` |
154
168
  | POST | `/auth/apple/native` | `ipLimit('login') → validate(appleNativeSchema) → oauth.appleNative` |
@@ -177,6 +191,8 @@ Raw SQL ships in `node_modules/@fonderie/auth/dist/migrations/sql/` — read it
177
191
  | GET | `/users` | `requireAuth → user.me` |
178
192
  | PUT | `/users/email` | `requireAuth → verifyGate → validate(updateEmailSchema) → user.updateEmail` |
179
193
  | GET | `/users/export` | `requireAuth → user.exportMe` |
194
+ | POST | `/users/me/deletion` | `requireAuth → verifyGate → validate(requestDeletionSchema) → user.requestDeletion` |
195
+ | POST | `/users/me/deletion/confirm` | `ipLimit('verify') → requireAuth → verifyGate → validate(confirmDeletionSchema) → user.confirmDeletion` |
180
196
  | PUT | `/users/password` | `requireAuth → validate(changePasswordSchema) → user.changePassword` |
181
197
  | PUT | `/users/phone` | `requireAuth → verifyGate → validate(updatePhoneSchema) → user.updatePhone` |
182
198
  | PUT | `/users/preferences` | `requireAuth → verifyGate → validate(updatePreferencesSchema) → user.updatePreferences` |
@@ -70,6 +70,7 @@ interface IAuthConfig extends IAuthSecrets, IAuthRuntimeConfig {
70
70
  routes?: Partial<Record<AuthRouteId, AuthRouteOverride>>;
71
71
  legacyVerify?: (plain: string, hash: string) => boolean | Promise<boolean>;
72
72
  dataExportContributors?: IDataExportContributor[];
73
+ accountDeletion?: IAccountDeletionConfig;
73
74
  }
74
75
 
75
76
  interface IAuthSecrets {
@@ -108,11 +109,11 @@ interface IDataExportContributor {
108
109
 
109
110
  const AUTH_CONFIG_KEYS: Record<Exclude<keyof IAuthRuntimeConfig, 'sessionPolicies'>, string>
110
111
 
111
- const MESSAGE_KEYS: { readonly emailRegistration: "email-registration"; readonly emailVerification: "email-verification"; readonly passwordReset: "password-reset"; readonly phoneOtp: "phone-otp"; readonly mfaEnabled: "mfa-enabled"; readonly mfaDisabled: "mfa-disabled"; readonly mfaBackupCodesRegenerated: "mfa-backup-codes-regenerated"; readonly emailChanged: "email-changed"; readonly phoneChanged: "phone-changed"; readonly passwordRevoked: "password-revoked"; readonly oauthRegistration: "oauth-registration"; readonly oauthLinked: "oauth-linked"; readonly oauthUnlinked: "oauth-unlinked"; }
112
+ const MESSAGE_KEYS: { readonly emailRegistration: "email-registration"; readonly emailVerification: "email-verification"; readonly passwordReset: "password-reset"; readonly phoneOtp: "phone-otp"; readonly mfaEnabled: "mfa-enabled"; readonly mfaDisabled: "mfa-disabled"; readonly mfaBackupCodesRegenerated: "mfa-backup-codes-regenerated"; readonly emailChanged: "email-changed"; readonly phoneChanged: "phone-changed"; readonly passwordRevoked: "password-revoked"; readonly oauthRegistration: "oauth-registration"; readonly oauthLinked: "oauth-linked"; readonly oauthUnlinked: "oauth-unlinked"; readonly accountDeletionCode: "account-deletion-code"; readonly accountDeletionScheduled: "account-deletion-scheduled"; readonly accountRestored: "account-restored"; }
112
113
 
113
114
  type AuthMessageKey = (typeof MESSAGE_KEYS)[keyof typeof MESSAGE_KEYS];
114
115
 
115
- const DEFAULT_TEMPLATES: { "email-registration": IDefaultTemplate; "email-verification": IDefaultTemplate; "password-reset": IDefaultTemplate; "phone-otp": IDefaultTemplate; "mfa-enabled": IDefaultTemplate; "mfa-disabled": IDefaultTemplate; "mfa-backup-codes-regenerated": IDefaultTemplate; "email-changed": IDefaultTemplate; "phone-changed": IDefaultTemplate; "password-revoked": IDefaultTemplate; "oauth-registration": IDefaultTemplate; "oauth-linked": IDefaultTemplate; "oauth-unlinked": IDefaultTemplate; }
116
+ const DEFAULT_TEMPLATES: { "email-registration": IDefaultTemplate; "email-verification": IDefaultTemplate; "password-reset": IDefaultTemplate; "phone-otp": IDefaultTemplate; "mfa-enabled": IDefaultTemplate; "mfa-disabled": IDefaultTemplate; "mfa-backup-codes-regenerated": IDefaultTemplate; "email-changed": IDefaultTemplate; "phone-changed": IDefaultTemplate; "password-revoked": IDefaultTemplate; "oauth-registration": IDefaultTemplate; "oauth-linked": IDefaultTemplate; "oauth-unlinked": IDefaultTemplate; "account-deletion-code": IDefaultTemplate; "account-deletion-scheduled": IDefaultTemplate; "account-restored": IDefaultTemplate; }
116
117
 
117
118
  interface IUserDTO {
118
119
  id: string;
@@ -199,7 +200,7 @@ type LocationResolver = (req: ILocationRequest) => IRequestLocation | null | und
199
200
 
200
201
  function validate(schema: IRequestSchema): Middleware
201
202
 
202
- namespace schemas — exports: ChangePasswordInput, LoginInput, RegisterInput, ResetPasswordInput, appleNativeSchema, changePasswordSchema, forgotPasswordSchema, googleNativeSchema, loginSchema, mfaTokenSchema, refreshSchema, registerSchema, resetPasswordSchema, updateEmailSchema, updatePhoneSchema, updatePreferencesSchema, updateProfileSchema, verifySchema
203
+ namespace schemas — exports: ChangePasswordInput, LoginInput, RegisterInput, ResetPasswordInput, appleNativeSchema, changePasswordSchema, confirmDeletionSchema, forgotPasswordSchema, googleNativeSchema, loginSchema, mfaTokenSchema, refreshSchema, registerSchema, requestDeletionSchema, resetPasswordSchema, restoreAccountSchema, updateEmailSchema, updatePhoneSchema, updatePreferencesSchema, updateProfileSchema, verifySchema
203
204
 
204
205
  type RegisterInput = z.infer<typeof registerSchema>;
205
206