@fonderie/auth 7.23.0 → 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,9 +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?: {
74
- gracePeriodDays?: number;
75
- };
73
+ accountDeletion?: IAccountDeletionConfig;
76
74
  }
77
75
 
78
76
  interface IAuthSecrets {
@@ -111,11 +109,11 @@ interface IDataExportContributor {
111
109
 
112
110
  const AUTH_CONFIG_KEYS: Record<Exclude<keyof IAuthRuntimeConfig, 'sessionPolicies'>, string>
113
111
 
114
- 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"; }
115
113
 
116
114
  type AuthMessageKey = (typeof MESSAGE_KEYS)[keyof typeof MESSAGE_KEYS];
117
115
 
118
- 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; }
119
117
 
120
118
  interface IUserDTO {
121
119
  id: string;
@@ -202,7 +200,7 @@ type LocationResolver = (req: ILocationRequest) => IRequestLocation | null | und
202
200
 
203
201
  function validate(schema: IRequestSchema): Middleware
204
202
 
205
- 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
206
204
 
207
205
  type RegisterInput = z.infer<typeof registerSchema>;
208
206