import * as z from "zod"; import { ClockTimeSchema } from "./clock-time.js"; /** How many nudges the main agent may send per day in the user's time zone. */ export const NUDGES_PER_DAY = 3; /** A daily range in the user's profile time zone; it may cross midnight ("22:00"–"07:00"). */ export const QuietHoursSchema = z .object({ start: ClockTimeSchema, end: ClockTimeSchema }) .refine((range) => range.start !== range.end, "Start and end must differ"); export type QuietHours = z.infer; export const NotificationSettingsSchema = z.object({ /** Every push is held back during quiet hours; the inbox still lists what happened. */ quietHours: QuietHoursSchema.nullable(), /** Whether the main agent may notify the user on its own initiative. */ nudges: z.boolean(), }); export type NotificationSettings = z.infer; export const UpdateNotificationSettingsInput = NotificationSettingsSchema.partial(); export type NotificationSettingsPatch = z.infer; /** What a browser needs to subscribe; `available` is false when the server cannot send. */ export const WebPushConfigSchema = z.object({ available: z.boolean(), publicKey: z.string().nullable(), }); export type WebPushConfig = z.infer; /** A push service URL. Browsers only hand out https endpoints. */ export const WebPushEndpointSchema = z .string() .max(2048) .refine((value) => { try { const url = new URL(value); return url.protocol === "https:" && !url.username && !url.password; } catch { return false; } }, "Endpoint must be an https URL"); /** The mobile app's Expo push token, e.g. "ExponentPushToken[xxxxxxxx]". */ export const ExpoPushTokenSchema = z .string() .trim() .max(512) .regex(/^Expo(nent)?PushToken\[[^\]\s]+\]$/, "Invalid Expo push token"); /** The JSON form of a browser PushSubscription (RFC 8291 keys, base64url). */ export const WebPushSubscriptionInput = z.object({ endpoint: WebPushEndpointSchema, keys: z.object({ /** An uncompressed P-256 public key: 65 bytes. */ p256dh: z.string().regex(/^[A-Za-z0-9_-]{87}=?$/, "Invalid p256dh key"), /** A 16-byte authentication secret. */ auth: z.string().regex(/^[A-Za-z0-9_-]{22}(==)?$/, "Invalid auth secret"), }), }); export type WebPushSubscriptionJson = z.infer;