fix(contracts): add verify-email and resend-verification schemas

verify-email.ts and resend-verification.ts both import Zod schemas
and response-data types that did not exist in contracts/auth/schema.ts.
That left the two controllers uncompilable and blocked any attempt to
hit the REST verification endpoints (the OIDC flow renders
verify-pending.hbs via the controller, so the same schemas are part
of the contract for the email-verification flow from PROGRESS.md §13).

Adds:
- VerifyEmailQuerySchema — { token }
- VerifyEmailResponseDataSchema + VerifyEmailResponseData type
- VerifyEmailResponseSchema (envelope)
- ResendVerificationBodySchema — { email }
- ResendVerificationResponseDataSchema + ResendVerificationResponseData
  type — expires_at is nullable because the controller returns null
  when the user is unknown or already verified (PLANS.md §3 ADR — no
  email enumeration)
- ResendVerificationResponseSchema (envelope)

Each schema follows the conventions in the rest of schema.ts: z.iso
for datetimes, z.email() for email fields, .openapi(...) for Swagger
metadata, and the ApiResponseSchema envelope wrapper.
Co-authored-by: 's avatarCursor <cursoragent@cursor.com>
parent 7fe848d5
...@@ -345,3 +345,78 @@ export const PasswordResetRequestResponseSchema = ApiResponseSchema(PasswordRese ...@@ -345,3 +345,78 @@ export const PasswordResetRequestResponseSchema = ApiResponseSchema(PasswordRese
'PasswordResetRequestResponse', 'PasswordResetRequestResponse',
); );
export type PasswordResetRequestResponse = z.infer<typeof PasswordResetRequestResponseSchema>; export type PasswordResetRequestResponse = z.infer<typeof PasswordResetRequestResponseSchema>;
// ---------------------------------------------------------------------------
// Email verification schemas
// ---------------------------------------------------------------------------
/**
* Query string for GET /api/v1/auth/verify-email — the only thing the
* public verification endpoint reads is the opaque token.
*/
export const VerifyEmailQuerySchema = z
.object({
token: z
.string()
.min(1)
.max(512)
.openapi({ example: 'a1b2c3d4...' }),
})
.openapi('VerifyEmailQuery');
/**
* Response body for GET /api/v1/auth/verify-email on a fresh token.
* `email_verified_at` is the new ISO timestamp the server just stamped
* on the user record; `status` reflects the flip from
* `pending_verification` to `active`.
*/
export const VerifyEmailResponseDataSchema = z
.object({
verified: z.literal(true),
email: z.email(),
status: z.string(),
email_verified_at: z.iso.datetime(),
message: z.string(),
})
.openapi('VerifyEmailResponseData');
export type VerifyEmailResponseData = z.infer<typeof VerifyEmailResponseDataSchema>;
export const VerifyEmailResponseSchema = ApiResponseSchema(VerifyEmailResponseDataSchema).openapi(
'VerifyEmailResponse',
);
export type VerifyEmailResponse = z.infer<typeof VerifyEmailResponseSchema>;
/**
* Body for POST /api/v1/auth/resend-verification. Email is the only field
* we need; everything else is looked up server-side.
*/
export const ResendVerificationBodySchema = z
.object({
email: z.email().openapi({ example: 'user@example.com' }),
})
.openapi('ResendVerificationBody');
/**
* Response body for POST /api/v1/auth/resend-verification. Always returns
* `sent: true` regardless of whether the email exists, to avoid leaking
* which addresses are registered. `expires_at` is null when no email
* was actually dispatched (unknown user or already verified). `email_mode`
* is the transport that handled the mail: 'smtp' in production, 'fallback'
* when dev mode wrote to dev-mail.log.
*/
export const ResendVerificationResponseDataSchema = z
.object({
sent: z.literal(true),
expires_at: z.iso.datetime().nullable(),
email_mode: z.string(),
message: z.string(),
})
.openapi('ResendVerificationResponseData');
export type ResendVerificationResponseData = z.infer<typeof ResendVerificationResponseDataSchema>;
export const ResendVerificationResponseSchema = ApiResponseSchema(ResendVerificationResponseDataSchema).openapi(
'ResendVerificationResponse',
);
export type ResendVerificationResponse = z.infer<typeof ResendVerificationResponseSchema>;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment