@payez/next-mvp 4.4.5 → 4.4.6

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.
Files changed (189) hide show
  1. package/README.md +10 -3
  2. package/dist/api/auth-handler.js +5 -3
  3. package/dist/api-handlers/account/change-password.js +6 -3
  4. package/dist/api-handlers/account/masked-info.js +2 -1
  5. package/dist/api-handlers/account/recovery/forward.d.ts +14 -0
  6. package/dist/api-handlers/account/recovery/forward.js +105 -0
  7. package/dist/api-handlers/account/recovery/initiate.js +4 -0
  8. package/dist/api-handlers/account/recovery/send-code.d.ts +12 -2
  9. package/dist/api-handlers/account/recovery/send-code.js +11 -84
  10. package/dist/api-handlers/account/recovery/verify-code.d.ts +11 -2
  11. package/dist/api-handlers/account/recovery/verify-code.js +10 -84
  12. package/dist/api-handlers/account/reset-password.js +24 -1
  13. package/dist/api-handlers/account/send-code.d.ts +1 -15
  14. package/dist/api-handlers/account/send-code.js +3 -6
  15. package/dist/api-handlers/account/update-phone.js +6 -1
  16. package/dist/api-handlers/account/validate-password.js +3 -1
  17. package/dist/api-handlers/account/verify-email.d.ts +1 -17
  18. package/dist/api-handlers/account/verify-email.js +4 -6
  19. package/dist/api-handlers/account/verify-sms.d.ts +1 -17
  20. package/dist/api-handlers/account/verify-sms.js +4 -6
  21. package/dist/api-handlers/admin/analytics.js +12 -4
  22. package/dist/api-handlers/admin/audit.js +12 -4
  23. package/dist/api-handlers/admin/redis-sessions.js +16 -8
  24. package/dist/api-handlers/admin/sessions.js +14 -6
  25. package/dist/api-handlers/admin/site-logs.js +39 -16
  26. package/dist/api-handlers/admin/stats.js +14 -4
  27. package/dist/api-handlers/admin/users.js +14 -6
  28. package/dist/api-handlers/admin/vibe-data.js +19 -11
  29. package/dist/api-handlers/auth/jwks.js +2 -1
  30. package/dist/api-handlers/auth/login.js +13 -4
  31. package/dist/api-handlers/auth/passkey-signin.js +6 -0
  32. package/dist/api-handlers/auth/refresh.js +38 -11
  33. package/dist/api-handlers/auth/signout.js +2 -1
  34. package/dist/api-handlers/auth/status.js +4 -1
  35. package/dist/api-handlers/auth/update-session.d.ts +25 -4
  36. package/dist/api-handlers/auth/update-session.js +38 -11
  37. package/dist/api-handlers/auth/validate.js +4 -2
  38. package/dist/api-handlers/auth/verify-code.js +3 -2
  39. package/dist/api-handlers/mfa/backup-code-verify.d.ts +1 -18
  40. package/dist/api-handlers/mfa/backup-code-verify.js +4 -6
  41. package/dist/api-handlers/mfa/backup-codes.js +2 -1
  42. package/dist/api-handlers/mfa/methods.js +2 -1
  43. package/dist/api-handlers/mfa/totp-confirm.js +2 -1
  44. package/dist/api-handlers/mfa/totp-enroll.js +2 -1
  45. package/dist/api-handlers/mfa/totp-verify.d.ts +1 -19
  46. package/dist/api-handlers/mfa/totp-verify.js +4 -6
  47. package/dist/api-handlers/passkeys/list.js +2 -1
  48. package/dist/api-handlers/passkeys/manage.js +2 -1
  49. package/dist/api-handlers/passkeys/register-options.js +2 -1
  50. package/dist/api-handlers/passkeys/register-verify.js +2 -1
  51. package/dist/api-handlers/session/refresh-viability.d.ts +4 -2
  52. package/dist/api-handlers/session/refresh-viability.js +10 -7
  53. package/dist/api-handlers/session/viability.js +4 -3
  54. package/dist/api-handlers/test/force-expire.js +5 -3
  55. package/dist/auth/auth-decision.js +2 -1
  56. package/dist/auth/better-auth.d.ts +14 -0
  57. package/dist/auth/better-auth.js +35 -49
  58. package/dist/auth/utils/idp-client.js +2 -1
  59. package/dist/components/admin/DataBrowserTab.js +4 -1
  60. package/dist/components/admin/SessionsTab.js +9 -3
  61. package/dist/components/recovery/RequestedStep.d.ts +11 -0
  62. package/dist/components/recovery/RequestedStep.js +14 -0
  63. package/dist/components/recovery/SetPasswordStep.js +10 -1
  64. package/dist/lib/app-slug.d.ts +21 -0
  65. package/dist/lib/app-slug.js +51 -0
  66. package/dist/lib/ensure-fresh-access-token.d.ts +26 -0
  67. package/dist/lib/ensure-fresh-access-token.js +105 -4
  68. package/dist/lib/idp-client-config.d.ts +20 -0
  69. package/dist/lib/idp-client-config.js +66 -45
  70. package/dist/lib/idp-fetch.js +1 -1
  71. package/dist/lib/password-rules.d.ts +22 -0
  72. package/dist/lib/password-rules.js +43 -0
  73. package/dist/lib/safe-error-response.d.ts +67 -0
  74. package/dist/lib/safe-error-response.js +130 -0
  75. package/dist/lib/session-cookie-shape.d.ts +22 -19
  76. package/dist/lib/session-cookie-shape.js +14 -18
  77. package/dist/lib/session-store.d.ts +8 -1
  78. package/dist/lib/session-store.js +170 -24
  79. package/dist/lib/startup-init.d.ts +6 -0
  80. package/dist/lib/startup-init.js +30 -4
  81. package/dist/lib/token-lifecycle.js +2 -1
  82. package/dist/lib/token-log-id.d.ts +18 -0
  83. package/dist/lib/token-log-id.js +84 -0
  84. package/dist/lib/two-factor-verify-failure.d.ts +45 -0
  85. package/dist/lib/two-factor-verify-failure.js +143 -0
  86. package/dist/middleware/create-middleware.d.ts +2 -1
  87. package/dist/middleware/create-middleware.js +43 -8
  88. package/dist/pages/recovery/page.js +14 -4
  89. package/dist/pages/test-env/JwtInspectPage.js +7 -149
  90. package/dist/pages/test-env/RefreshTokenPage.js +4 -1
  91. package/dist/pages/test-env/redact-credentials.d.ts +6 -0
  92. package/dist/pages/test-env/redact-credentials.js +101 -0
  93. package/dist/pages/verify-code/page.js +2 -1
  94. package/dist/routes/auth/logout.d.ts +2 -1
  95. package/dist/routes/auth/logout.js +4 -2
  96. package/dist/routes/auth/session.d.ts +0 -3
  97. package/dist/routes/auth/session.js +16 -10
  98. package/dist/routes/auth/viability.d.ts +3 -2
  99. package/dist/routes/auth/viability.js +11 -7
  100. package/dist/server/auth.js +10 -6
  101. package/dist/server/decode-session.js +15 -26
  102. package/dist/server/verified-session-token.d.ts +13 -0
  103. package/dist/server/verified-session-token.js +103 -0
  104. package/dist/stores/authStore.js +14 -3
  105. package/dist/types/recovery.d.ts +1 -1
  106. package/dist/utils/api.d.ts +18 -0
  107. package/dist/utils/api.js +51 -9
  108. package/dist/vibe/sessions.js +2 -1
  109. package/package.json +2 -1
  110. package/scripts/verify-release-provenance.mjs +410 -0
  111. package/src/api/auth-handler.ts +5 -3
  112. package/src/api-handlers/account/change-password.ts +6 -3
  113. package/src/api-handlers/account/masked-info.ts +2 -1
  114. package/src/api-handlers/account/recovery/forward.ts +117 -0
  115. package/src/api-handlers/account/recovery/initiate.ts +3 -0
  116. package/src/api-handlers/account/recovery/send-code.ts +13 -99
  117. package/src/api-handlers/account/recovery/verify-code.ts +12 -99
  118. package/src/api-handlers/account/reset-password.ts +30 -1
  119. package/src/api-handlers/account/send-code.ts +3 -9
  120. package/src/api-handlers/account/update-phone.ts +6 -1
  121. package/src/api-handlers/account/validate-password.ts +3 -1
  122. package/src/api-handlers/account/verify-email.ts +4 -9
  123. package/src/api-handlers/account/verify-sms.ts +4 -9
  124. package/src/api-handlers/admin/analytics.ts +13 -5
  125. package/src/api-handlers/admin/audit.ts +13 -5
  126. package/src/api-handlers/admin/redis-sessions.ts +16 -8
  127. package/src/api-handlers/admin/sessions.ts +15 -7
  128. package/src/api-handlers/admin/site-logs.ts +39 -16
  129. package/src/api-handlers/admin/stats.ts +15 -5
  130. package/src/api-handlers/admin/users.ts +15 -7
  131. package/src/api-handlers/admin/vibe-data.ts +20 -12
  132. package/src/api-handlers/auth/jwks.ts +2 -1
  133. package/src/api-handlers/auth/login.ts +13 -4
  134. package/src/api-handlers/auth/passkey-signin.ts +4 -0
  135. package/src/api-handlers/auth/refresh.ts +38 -11
  136. package/src/api-handlers/auth/signout.ts +2 -1
  137. package/src/api-handlers/auth/status.ts +4 -1
  138. package/src/api-handlers/auth/update-session.ts +45 -11
  139. package/src/api-handlers/auth/validate.ts +4 -2
  140. package/src/api-handlers/auth/verify-code.ts +3 -2
  141. package/src/api-handlers/mfa/backup-code-verify.ts +4 -9
  142. package/src/api-handlers/mfa/backup-codes.ts +2 -1
  143. package/src/api-handlers/mfa/methods.ts +2 -1
  144. package/src/api-handlers/mfa/totp-confirm.ts +2 -1
  145. package/src/api-handlers/mfa/totp-enroll.ts +2 -1
  146. package/src/api-handlers/mfa/totp-verify.ts +4 -9
  147. package/src/api-handlers/passkeys/list.ts +2 -1
  148. package/src/api-handlers/passkeys/manage.ts +2 -1
  149. package/src/api-handlers/passkeys/register-options.ts +2 -1
  150. package/src/api-handlers/passkeys/register-verify.ts +2 -1
  151. package/src/api-handlers/session/refresh-viability.ts +10 -7
  152. package/src/api-handlers/session/viability.ts +4 -3
  153. package/src/api-handlers/test/force-expire.ts +5 -3
  154. package/src/auth/auth-decision.ts +2 -1
  155. package/src/auth/better-auth.ts +37 -55
  156. package/src/auth/utils/idp-client.ts +2 -1
  157. package/src/components/admin/DataBrowserTab.tsx +4 -1
  158. package/src/components/admin/SessionsTab.tsx +10 -3
  159. package/src/components/recovery/RequestedStep.tsx +30 -0
  160. package/src/components/recovery/SetPasswordStep.tsx +24 -3
  161. package/src/hooks/useViabilitySession.ts +2 -1
  162. package/src/lib/app-slug.ts +50 -0
  163. package/src/lib/ensure-fresh-access-token.ts +133 -4
  164. package/src/lib/idp-client-config.ts +91 -45
  165. package/src/lib/idp-fetch.ts +1 -1
  166. package/src/lib/password-rules.ts +50 -0
  167. package/src/lib/safe-error-response.ts +126 -0
  168. package/src/lib/session-cookie-shape.ts +23 -22
  169. package/src/lib/session-store.ts +167 -24
  170. package/src/lib/startup-init.ts +29 -4
  171. package/src/lib/token-lifecycle.ts +2 -1
  172. package/src/lib/token-log-id.ts +69 -0
  173. package/src/lib/two-factor-verify-failure.ts +167 -0
  174. package/src/middleware/create-middleware.ts +55 -9
  175. package/src/pages/recovery/page.tsx +21 -4
  176. package/src/pages/test-env/JwtInspectPage.tsx +11 -233
  177. package/src/pages/test-env/RefreshTokenPage.tsx +9 -4
  178. package/src/pages/test-env/redact-credentials.ts +96 -0
  179. package/src/pages/verify-code/page.tsx +2 -1
  180. package/src/routes/auth/logout.ts +4 -2
  181. package/src/routes/auth/session.ts +16 -10
  182. package/src/routes/auth/viability.ts +11 -7
  183. package/src/server/auth.ts +10 -6
  184. package/src/server/decode-session.ts +16 -26
  185. package/src/server/verified-session-token.ts +103 -0
  186. package/src/stores/authStore.ts +16 -5
  187. package/src/types/recovery.ts +1 -1
  188. package/src/utils/api.ts +47 -8
  189. package/src/vibe/sessions.ts +2 -1
package/src/utils/api.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { ENV_CONFIG, API_ENDPOINTS } from '../config/env';
2
2
  import { TwoFactorMethod } from '../types/security';
3
3
  import { standardizedApi, isApiSuccess, isApiError, extractApiData } from '../lib/standardized-client-api';
4
+ import { knownPasswordRules, passwordRuleSentences } from '../lib/password-rules';
4
5
 
5
6
  export class ApiError extends Error {
6
7
  type: string;
@@ -96,6 +97,35 @@ export async function apiFetch<T>(url: string, options: ApiOptions = {}): Promis
96
97
  // DELETED: apiFetchAuth - Use clientApi from @/lib/client-api instead for proper token refresh handling
97
98
 
98
99
  // Account API for masked info and 2FA
100
+ /**
101
+ * PAY-1591: what the user reads when the LAST recovery step fails. Four outcomes, told apart only by codes the IdP really sends
102
+ * (see resetFailureText): a password-policy refusal names the failed rules; an explicit expired/used token says so and links back
103
+ * to recovery; any other 400/422 gets a neutral 'check the requirements and try again' (the user's recovery session is kept); and
104
+ * a server or transport failure gets a retry sentence. None of them is the old fixed "Failed to reset password".
105
+ */
106
+ export const RECOVERY_EXPIRED_TEXT = 'This reset link has expired or was already used. Start password recovery again.';
107
+
108
+ export const RESET_NEUTRAL_TEXT = "We couldn't set that password. Check it meets the requirements shown and try again.";
109
+
110
+ /**
111
+ * Three tiers for a 400/422 from reset (rigpert 60822, QAPert 60820), decided ONLY on codes the IdP actually sends:
112
+ * policy details.code password_policy (projected by the handler as password_policy) -> the rule sentences
113
+ * tokenInvalid an EXPLICIT expired/used signal (token_expired / token_used / Identity InvalidToken, projected as
114
+ * reset_token_invalid) -> 'link expired, start again'
115
+ * anything else -> NEUTRAL, which must NOT tell the user their link is dead: the served IdP sends a weak-password refusal with
116
+ * no code, and 'expired' there loops them after they spent their emailed code. The recovery session is kept, so
117
+ * they can retry.
118
+ */
119
+ export function resetFailureText(status: number, rules: string[] = [], policy = false, tokenInvalid = false): string {
120
+ if (status === 400 || status === 422) {
121
+ if (tokenInvalid && !policy) return RECOVERY_EXPIRED_TEXT;
122
+ if (!policy) return RESET_NEUTRAL_TEXT;
123
+ const base = "That password wasn't accepted.";
124
+ return rules.length ? `${base} ${passwordRuleSentences(rules)}` : `${base} Try a different one; the rules are shown above.`;
125
+ }
126
+ return "We couldn't reset your password just now. Please try again.";
127
+ }
128
+
99
129
  export class AccountApi {
100
130
  /**
101
131
  * Get masked user info (email, phone, authenticator status)
@@ -116,18 +146,16 @@ export class AccountApi {
116
146
  // Empty body: user info comes from JWT token
117
147
  const result = await standardizedApi.post<any>('/api/account/masked-info', {}, accessToken);
118
148
 
149
+ // PAY-1427: masked email/phone are still user data - log the response shape, never its values.
119
150
  console.log('[DEBUG] getMaskedInfo result:', {
120
151
  success: isApiSuccess(result),
121
152
  hasData: isApiSuccess(result) && !!result.data,
122
- rawData: isApiSuccess(result) ? result.data : null,
123
153
  dataFields: isApiSuccess(result) && result.data ? Object.keys(result.data) : []
124
154
  });
125
155
 
126
- console.log('[DEBUG] getMaskedInfo raw data structure:', JSON.stringify(isApiSuccess(result) ? result.data : result, null, 2));
127
-
128
156
  if (!isApiSuccess(result)) {
129
157
  const errorMessage = isApiError(result) ? result.message : 'Failed to get masked info';
130
- console.error('[DEBUG] getMaskedInfo failed:', result);
158
+ console.error('[DEBUG] getMaskedInfo failed:', { keys: result && typeof result === 'object' ? Object.keys(result) : typeof result });
131
159
  throw new ApiError(errorMessage, result);
132
160
  }
133
161
  // Use only snake_case fields from backend response
@@ -149,6 +177,8 @@ export class AccountApi {
149
177
  headers: { 'Content-Type': 'application/json' },
150
178
  body: JSON.stringify({ email }),
151
179
  });
180
+ // PAY-1588: a throttled caller (429) must look exactly like an unknown one - no session, no distinguishing error.
181
+ if (res.status === 429) return { success: false, data: {} } as any;
152
182
  if (!res.ok) throw new Error('Failed to initiate recovery');
153
183
  return res.json();
154
184
  }
@@ -193,12 +223,21 @@ export class AccountApi {
193
223
  headers: { 'Content-Type': 'application/json' },
194
224
  body: JSON.stringify({
195
225
  email,
196
- password_reset_token: resetToken,
226
+ token: resetToken,
197
227
  new_password: newPassword,
198
228
  confirm_password: confirmPassword,
199
229
  }),
200
230
  });
201
- if (!res.ok) throw new Error('Failed to reset password');
231
+ if (!res.ok) {
232
+ const body = await res.json().catch(() => null);
233
+ const policy = !!body?.password_policy;
234
+ const rules = knownPasswordRules(body?.password_policy?.rules);
235
+ const tokenInvalid = body?.reset_token_invalid === true;
236
+ const err = new Error(resetFailureText(res.status, rules, policy, tokenInvalid)) as Error & { rules?: string[]; code?: string };
237
+ if (rules.length) err.rules = rules;
238
+ if ((res.status === 400 || res.status === 422) && tokenInvalid && !policy) err.code = 'RECOVERY_EXPIRED';
239
+ throw err;
240
+ }
202
241
  return res.json();
203
242
  }
204
243
 
@@ -210,8 +249,8 @@ export class AccountApi {
210
249
  body: JSON.stringify({
211
250
  email: data.email,
212
251
  token: data.token,
213
- password: data.password,
214
- password_confirmation: data.password_confirmation
252
+ new_password: data.password,
253
+ confirm_password: data.password_confirmation
215
254
  })
216
255
  })
217
256
  const result = await res.json().catch(() => ({}))
@@ -116,7 +116,8 @@ async function vibeProxyRequest<T>(
116
116
 
117
117
  if (!response.ok) {
118
118
  const errorText = await response.text();
119
- console.error(`[vibe-sessions] Proxy error ${response.status}:`, errorText);
119
+ // PAY-1427: never the raw proxy body - the request carried a Bearer token and an error page can echo it.
120
+ console.error(`[vibe-sessions] Proxy error ${response.status}:`, { bodyLength: errorText.length });
120
121
  return null;
121
122
  }
122
123