Files
TREK/shared/src/trip-invite/trip-invite.schema.ts
T
jubnl 9650ad4597 feat(server): adopt zod DTOs for the trip-invite body contracts
New tripInviteLinkCreateRequestSchema in @trek/shared (single source of
truth), a createZodDto wrapper on the controller's raw @Body(), and the
TripInviteLinkController.create entry dropped from the body-contract
allow-list (the boot ratchet enforces it).

expires_in_days accepts number | digits-only string | null | absent — the
string branch is digits-only so garbage like "7abc" is a 400 instead of
silently parseInt-ing to 7; the empty string (blank form input, meaning no
expiry) stays accepted. The e2e registers ZodValidationPipe and pins both
the bounded-expiry and 400 paths.
2026-07-26 18:21:18 +02:00

19 lines
940 B
TypeScript

import { z } from 'zod';
/**
* Trip invite-link API contract (#1143).
*
* Members with 'share_manage' create/rotate the trip's single invite token
* under POST /api/trips/:tripId/invite-link. `expires_in_days` accepts
* number | digits-only string | null | absent on the wire: the client always
* sends the key (null when no expiry was chosen — see tripInviteApi.createLink),
* and the legacy raw-body route also took numeric strings from form input (the
* empty string meaning "no expiry"). The string branch is digits-only so
* garbage like "7abc" is a 400 instead of silently parseInt-ing to 7; the
* controller still owns the number coercion (non-positive → no expiry).
*/
export const tripInviteLinkCreateRequestSchema = z.object({
expires_in_days: z.union([z.number(), z.string().regex(/^\d*$/), z.null()]).optional(),
});
export type TripInviteLinkCreateRequest = z.infer<typeof tripInviteLinkCreateRequestSchema>;