@sunsteel/contracts 0.45.0 → 0.47.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/dist/index.cjs CHANGED
@@ -38,11 +38,13 @@ __export(index_exports, {
38
38
  MEASURABLE_GOALS_MAX: () => MEASURABLE_GOALS_MAX,
39
39
  MEASURABLE_GOAL_DIRECTIONS: () => MEASURABLE_GOAL_DIRECTIONS,
40
40
  MEASURABLE_GOAL_TYPES: () => MEASURABLE_GOAL_TYPES,
41
+ MINUTES_IN_DAY: () => MINUTES_IN_DAY,
41
42
  MOVEMENT_PATTERNS: () => MOVEMENT_PATTERNS,
42
43
  MUSCLE_GROUPS: () => MUSCLE_GROUPS,
43
44
  NOTIFICATIONS_LIST_LIMIT: () => NOTIFICATIONS_LIST_LIMIT,
44
45
  NOTIFICATIONS_LOOKBACK_DAYS: () => NOTIFICATIONS_LOOKBACK_DAYS,
45
46
  NOTIFICATIONS_RETENTION_DAYS: () => NOTIFICATIONS_RETENTION_DAYS,
47
+ NOTIFICATION_CATEGORIES: () => NOTIFICATION_CATEGORIES,
46
48
  NOTIFICATION_KINDS: () => NOTIFICATION_KINDS,
47
49
  PLATEAU_MIN_DAYS_SINCE_BEST: () => PLATEAU_MIN_DAYS_SINCE_BEST,
48
50
  PLATEAU_MIN_SESSIONS: () => PLATEAU_MIN_SESSIONS,
@@ -59,12 +61,17 @@ __export(index_exports, {
59
61
  PROFILE_VISIBILITY_VALUES: () => PROFILE_VISIBILITY_VALUES,
60
62
  PROGRESSION_SCHEMES: () => PROGRESSION_SCHEMES,
61
63
  PROGRESS_TIMELINE_EVENT_TYPES: () => PROGRESS_TIMELINE_EVENT_TYPES,
64
+ PUSH_PAYLOAD_KINDS: () => PUSH_PAYLOAD_KINDS,
65
+ PUSH_SUBSCRIPTIONS_MAX: () => PUSH_SUBSCRIPTIONS_MAX,
62
66
  RELATIONSHIP_LIST_DEFAULT_LIMIT: () => RELATIONSHIP_LIST_DEFAULT_LIMIT,
63
67
  RELATIONSHIP_LIST_KINDS: () => RELATIONSHIP_LIST_KINDS,
64
68
  RELATIONSHIP_LIST_MAX_LIMIT: () => RELATIONSHIP_LIST_MAX_LIMIT,
65
69
  RENAISSANCE_RANK_DEFINITIONS: () => RENAISSANCE_RANK_DEFINITIONS,
66
70
  REP_TYPES: () => REP_TYPES,
67
71
  RESERVED_USERNAMES: () => RESERVED_USERNAMES,
72
+ REST_ALERT_MAX_LEAD_SECONDS: () => REST_ALERT_MAX_LEAD_SECONDS,
73
+ REST_ALERT_MIN_LEAD_SECONDS: () => REST_ALERT_MIN_LEAD_SECONDS,
74
+ REST_ALERT_REFUSALS: () => REST_ALERT_REFUSALS,
68
75
  ROUTINE_DAYS_MAX: () => ROUTINE_DAYS_MAX,
69
76
  ROUTINE_DAY_NAME_MAX: () => ROUTINE_DAY_NAME_MAX,
70
77
  ROUTINE_SCHEDULE_MODES: () => ROUTINE_SCHEDULE_MODES,
@@ -89,6 +96,7 @@ __export(index_exports, {
89
96
  USERNAME_PATTERN_SOURCE: () => USERNAME_PATTERN_SOURCE,
90
97
  WEIGHT_UNITS: () => WEIGHT_UNITS,
91
98
  WORKOUT_SESSION_STATUSES: () => WORKOUT_SESSION_STATUSES,
99
+ isWithinQuietHours: () => isWithinQuietHours,
92
100
  routineDayLabel: () => routineDayLabel
93
101
  });
94
102
  module.exports = __toCommonJS(index_exports);
@@ -462,6 +470,37 @@ var NOTIFICATION_KINDS = [
462
470
  var NOTIFICATIONS_LOOKBACK_DAYS = 30;
463
471
  var NOTIFICATIONS_RETENTION_DAYS = 90;
464
472
  var NOTIFICATIONS_LIST_LIMIT = 50;
473
+
474
+ // src/push.ts
475
+ var PUSH_SUBSCRIPTIONS_MAX = 10;
476
+ var PUSH_PAYLOAD_KINDS = ["REST_ALERT", "TRAINING_REMINDER"];
477
+ var REST_ALERT_MAX_LEAD_SECONDS = 3600;
478
+ var REST_ALERT_MIN_LEAD_SECONDS = 5;
479
+ var REST_ALERT_REFUSALS = [
480
+ /** The account has no subscribed device. */
481
+ "NO_SUBSCRIPTION",
482
+ /** The server holds no VAPID key pair. */
483
+ "PUSH_UNAVAILABLE",
484
+ /** Rest ends too soon for a push to beat it. */
485
+ "TOO_SOON",
486
+ /** NOTIF-05: the owner switched rest alerts off. */
487
+ "CATEGORY_OFF",
488
+ /** NOTIF-05: rest would end inside the owner's quiet hours. */
489
+ "QUIET_HOURS"
490
+ ];
491
+
492
+ // src/notification-preferences.ts
493
+ var NOTIFICATION_CATEGORIES = [
494
+ "REST_ALERT",
495
+ "TRAINING_REMINDER"
496
+ ];
497
+ var MINUTES_IN_DAY = 1440;
498
+ function isWithinQuietHours(minuteOfDay, quietHours) {
499
+ if (!quietHours) return false;
500
+ const { startMinute, endMinute } = quietHours;
501
+ if (startMinute === endMinute) return false;
502
+ return startMinute < endMinute ? minuteOfDay >= startMinute && minuteOfDay < endMinute : minuteOfDay >= startMinute || minuteOfDay < endMinute;
503
+ }
465
504
  // Annotate the CommonJS export names for ESM import in node:
466
505
  0 && (module.exports = {
467
506
  ACHIEVEMENT_CATEGORIES,
@@ -482,11 +521,13 @@ var NOTIFICATIONS_LIST_LIMIT = 50;
482
521
  MEASURABLE_GOALS_MAX,
483
522
  MEASURABLE_GOAL_DIRECTIONS,
484
523
  MEASURABLE_GOAL_TYPES,
524
+ MINUTES_IN_DAY,
485
525
  MOVEMENT_PATTERNS,
486
526
  MUSCLE_GROUPS,
487
527
  NOTIFICATIONS_LIST_LIMIT,
488
528
  NOTIFICATIONS_LOOKBACK_DAYS,
489
529
  NOTIFICATIONS_RETENTION_DAYS,
530
+ NOTIFICATION_CATEGORIES,
490
531
  NOTIFICATION_KINDS,
491
532
  PLATEAU_MIN_DAYS_SINCE_BEST,
492
533
  PLATEAU_MIN_SESSIONS,
@@ -503,12 +544,17 @@ var NOTIFICATIONS_LIST_LIMIT = 50;
503
544
  PROFILE_VISIBILITY_VALUES,
504
545
  PROGRESSION_SCHEMES,
505
546
  PROGRESS_TIMELINE_EVENT_TYPES,
547
+ PUSH_PAYLOAD_KINDS,
548
+ PUSH_SUBSCRIPTIONS_MAX,
506
549
  RELATIONSHIP_LIST_DEFAULT_LIMIT,
507
550
  RELATIONSHIP_LIST_KINDS,
508
551
  RELATIONSHIP_LIST_MAX_LIMIT,
509
552
  RENAISSANCE_RANK_DEFINITIONS,
510
553
  REP_TYPES,
511
554
  RESERVED_USERNAMES,
555
+ REST_ALERT_MAX_LEAD_SECONDS,
556
+ REST_ALERT_MIN_LEAD_SECONDS,
557
+ REST_ALERT_REFUSALS,
512
558
  ROUTINE_DAYS_MAX,
513
559
  ROUTINE_DAY_NAME_MAX,
514
560
  ROUTINE_SCHEDULE_MODES,
@@ -533,5 +579,6 @@ var NOTIFICATIONS_LIST_LIMIT = 50;
533
579
  USERNAME_PATTERN_SOURCE,
534
580
  WEIGHT_UNITS,
535
581
  WORKOUT_SESSION_STATUSES,
582
+ isWithinQuietHours,
536
583
  routineDayLabel
537
584
  });
package/dist/index.d.cts CHANGED
@@ -1485,4 +1485,187 @@ interface MarkNotificationsReadResponse {
1485
1485
  unreadCount: number;
1486
1486
  }
1487
1487
 
1488
- export { ACHIEVEMENT_CATEGORIES, ACHIEVEMENT_DEFINITIONS, type AchievementCategory, type AchievementCategoryProgress, type AchievementDefinition, type AchievementNotification, type AchievementUnlockedEventPayload, type AchievementsResponse, type AppNotification, type Brand, COMEBACK_MIN_INACTIVE_DAYS, COMEBACK_RECOGNITION_LIMIT, COMEBACK_REQUIRED_ACTIVE_DAYS, COMEBACK_SESSION_LOOKBACK, COMEBACK_WINDOW_DAYS, type CalendarDate, type ComebackRecognition, type ComebackRecognitionSummary, type CreateRoutineDayInput, type CreateRoutineExerciseInput, type CreateRoutineRequest, type CreateRoutineVersionRequest, type CreateSessionShareRequest, EXERCISE_EQUIPMENT, EXERCISE_MECHANICS, type EarnedAchievement, type EarnedPersonalRecord, type Exercise, type ExerciseEquipment, type ExerciseId, type ExerciseMechanic, type ExercisePerformanceHistoryQuery, type ExercisePerformanceHistoryResponse, type ExercisePerformancePrescription, type ExercisePerformancePrescriptionSet, type ExercisePerformanceSession, type ExercisePerformanceSet, type ExercisePerformanceSummary, type ExercisePlateau, type ExerciseStrengthSummary, type ExerciseStrengthTrendPoint, type ExerciseStrengthTrendQuery, type ExerciseStrengthTrendResponse, FEATURED_PROFILE_ITEMS_MAX, FEATURED_PROFILE_ITEM_KINDS, FEATURED_PROFILE_REFERENCE_MAX_LENGTH, FOLLOW_SUGGESTIONS_DEFAULT_LIMIT, FOLLOW_SUGGESTIONS_MAX_LIMIT, FOLLOW_SUGGESTION_REASONS, type FeaturedProfileAchievementItem, type FeaturedProfileItem, type FeaturedProfileItemKind, type FeaturedProfileRankItem, type FeaturedProfileRecordItem, type FeaturedProfileSelection, type FeaturedProfileSelectionInput, type FeaturedProfileSelectionsResponse, type FinishStatus, type FinishWorkoutRequest, type FinishWorkoutResponse, type FollowSuggestion, type FollowSuggestionReason, type FollowSuggestionsResponse, type IsoDateString, type ListSessionsParams, MEASURABLE_GOALS_MAX, MEASURABLE_GOAL_DIRECTIONS, MEASURABLE_GOAL_TYPES, MOVEMENT_PATTERNS, MUSCLE_GROUPS, type MarkNotificationsReadRequest, type MarkNotificationsReadResponse, type MeasurableGoal, type MeasurableGoalDirection, type MeasurableGoalExercise, type MeasurableGoalInput, type MeasurableGoalType, type MoveOccurrenceRequest, type MovementPattern, type MuscleGroup, type MuscleGroupHeatmapQuery, type MuscleGroupHeatmapResponse, type MuscleGroupHeatmapValue, type MuscleGroupHeatmapWeek, type MuscleVolumeTrendSeries, NOTIFICATIONS_LIST_LIMIT, NOTIFICATIONS_LOOKBACK_DAYS, NOTIFICATIONS_RETENTION_DAYS, NOTIFICATION_KINDS, type NewFollowerNotification, type NotificationKind, type NotificationsResponse, PLATEAU_MIN_DAYS_SINCE_BEST, PLATEAU_MIN_SESSIONS, PLATEAU_MIN_SESSIONS_MAX, PLATEAU_MIN_SESSIONS_MIN, PLATEAU_RECENT_DAYS, PLATEAU_WINDOW_DAYS, PREFERRED_TRAINING_STYLE_VALUES, PROFILE_BIO_MAX_LENGTH, PROFILE_FAVORITE_EXERCISES_MAX, PROFILE_LOCATION_MAX_LENGTH, PROFILE_TRAINING_DISCIPLINES_MAX, PROFILE_TRAINING_GOALS_MAX, PROFILE_VISIBILITY_VALUES, PROGRESSION_SCHEMES, PROGRESS_TIMELINE_EVENT_TYPES, type PaginatedResponse, type PersonalGoalProgress, type PersonalGoalsResponse, type PersonalRecordEntry, type PersonalRecordKind, type PlatePairInventory, type PlateauPreferences, type PlateauSet, type PlateausResponse, type PreferredTrainingStyle, type PreviousPerformanceResponse, type PreviousSessionRecap, type PreviousSetPerformance, type ProfileDiscoverySettings, type ProfileFavoriteExercise, type ProfilePrivacySettings, type ProfileViewerAccess, type ProfileVisibility, type ProgressTimelineEventType, type ProgressTimelineItem, type ProgressTimelinePersonalRecordItem, type ProgressTimelineProgressionItem, type ProgressTimelineQuery, type ProgressTimelineRecordPerformance, type ProgressTimelineRecordReason, type ProgressTimelineResponse, type ProgressTimelineSessionContext, type ProgressionChange, type ProgressionRule, type ProgressionScheme, type ProgressionSetChange, type PublicBodyMetrics, type PublicProfileAchievements, type PublicTrainingSummary, type PublicUserProfile, RELATIONSHIP_LIST_DEFAULT_LIMIT, RELATIONSHIP_LIST_KINDS, RELATIONSHIP_LIST_MAX_LIMIT, RENAISSANCE_RANK_DEFINITIONS, REP_TYPES, RESERVED_USERNAMES, ROUTINE_DAYS_MAX, ROUTINE_DAY_NAME_MAX, ROUTINE_SCHEDULE_MODES, ROUTINE_VERSIONS_MAX, ROUTINE_VERSION_KINDS, ROUTINE_VERSION_NAME_MAX, type RecentActivityEntry, type RelationshipListKind, type RelationshipListQuery, type RelationshipListResponse, type RelationshipMember, type RenaissanceRankDefinition, type RenaissanceRankProgress, type RepType, type ReplaceFeaturedProfileItemsRequest, type ReplaceMeasurableGoalsRequest, type ReplaceTrainingLocationsRequest, type RestoreRoutineVersionResponse, type Routine, type RoutineDay, type RoutineDayId, type RoutineExercise, type RoutineId, type RoutineScheduleMode, type RoutineSet, type RoutineVersion, type RoutineVersionDay, type RoutineVersionExercise, type RoutineVersionKind, type RoutineVersionSetup, type RoutineVersionsResponse, SCHEDULE_MOVE_MAX_DAYS, SCHEDULE_OVERRIDES_MAX_RANGE_DAYS, SCHEDULE_OVERRIDE_KINDS, SCHEDULE_SKIP_PAST_DAYS, SESSION_SHARE_DEFAULT_FIELDS, SESSION_SHARE_FIELDS, SESSION_SHARE_MAX_ACTIVE_LINKS, SEXES, STARRED_EXERCISES_MAX, type ScheduleOverride, type ScheduleOverrideKind, type ScheduleOverridesQuery, type ScheduleOverridesResponse, type SessionComparisonExercise, type SessionComparisonQuery, type SessionComparisonResponse, type SessionComparisonRoutineDay, type SessionComparisonSession, type SessionComparisonSet, type SessionExerciseSubstitution, type SessionProgressNotification, type SessionRecapRecord, type SessionShare, type SessionShareField, type SessionShareListResponse, type SetAccountTimeZoneRequest, type SetLog, type Sex, type SharedSessionOwner, type SharedSessionRecap, type SkipOccurrenceRequest, type StarredExercise, type StarredExercisesResponse, type StartWorkoutRequest, type StartWorkoutResponse, type StreakMilestoneEventPayload, type SubstituteSessionExerciseRequest, type SubstituteSessionExerciseResponse, type SupabaseAuthResponse, type SupabaseAuthUser, type SupabaseMigrationResponse, TRAINING_DISCIPLINE_VALUES, TRAINING_EVENT_TYPES, TRAINING_EXPERIENCE_LEVEL_VALUES, TRAINING_GOAL_VALUES, type TrainingDiscipline, type TrainingEventType, type TrainingExperienceLevel, type TrainingGoal, type TrainingIdentity, type TrainingLocationPreference, type TrainingLocationPreferenceInput, USERNAME_MAX_LENGTH, USERNAME_MIN_LENGTH, USERNAME_PATTERN_SOURCE, type UpdateProfileDiscoveryRequest, type UpdateProfilePrivacyRequest, type UpdateProfileRequest, type UpdateRoutineRequest, type UpsertSetLogRequest, type UpsertSetLogResponse, type UserId, type UserProfile, type UserSearchResponse, type VolumeTrendPoint, type VolumeTrendQuery, type VolumeTrendResponse, type VolumeTrendSeries, WEIGHT_UNITS, WORKOUT_SESSION_STATUSES, type WeightUnit, type WorkoutAnalyticsStatus, type WorkoutProgressQuery, type WorkoutProgressResponse, type WorkoutSession, type WorkoutSessionId, type WorkoutSessionListResponse, type WorkoutSessionRecap, type WorkoutSessionSnapshotV1, type WorkoutSessionStatus, type WorkoutSessionSummary, type WorkoutStatsQuery, type WorkoutStatsResponse, routineDayLabel };
1488
+ /**
1489
+ * The two keys a browser's `PushSubscription` carries. They are the encryption
1490
+ * material for that endpoint, not an identifier, and are never returned to a
1491
+ * client — only accepted.
1492
+ */
1493
+ interface PushSubscriptionKeys {
1494
+ p256dh: string;
1495
+ auth: string;
1496
+ }
1497
+ /** One account keeps at most this many devices subscribed. */
1498
+ declare const PUSH_SUBSCRIPTIONS_MAX = 10;
1499
+ /** POST /notifications/push/subscriptions — idempotent on `endpoint`. */
1500
+ interface RegisterPushSubscriptionRequest {
1501
+ endpoint: string;
1502
+ /** The browser's own expiry, almost always null. */
1503
+ expirationTime: number | null;
1504
+ keys: PushSubscriptionKeys;
1505
+ /**
1506
+ * A short device label the owner can recognise in their own list. It is
1507
+ * derived by the client from the user agent, never the raw string.
1508
+ */
1509
+ deviceLabel?: string;
1510
+ }
1511
+ /**
1512
+ * What the owner sees about one of their own subscribed devices. The endpoint
1513
+ * is a bearer capability for sending that device notifications, so it is
1514
+ * deliberately absent.
1515
+ */
1516
+ interface PushSubscriptionSummary {
1517
+ id: string;
1518
+ deviceLabel: string | null;
1519
+ createdAt: IsoDateString;
1520
+ /** Refreshed whenever the same endpoint registers again. */
1521
+ lastSeenAt: IsoDateString;
1522
+ /** True for the subscription the requesting device just sent. */
1523
+ isCurrentDevice: boolean;
1524
+ }
1525
+ /** GET /notifications/push/subscriptions */
1526
+ interface PushSubscriptionsResponse {
1527
+ subscriptions: PushSubscriptionSummary[];
1528
+ /**
1529
+ * Null when the server holds no VAPID key pair. The client must treat that
1530
+ * as "push is unavailable" and never prompt for permission.
1531
+ */
1532
+ vapidPublicKey: string | null;
1533
+ }
1534
+ /** DELETE /notifications/push/subscriptions */
1535
+ interface DeletePushSubscriptionRequest {
1536
+ endpoint: string;
1537
+ }
1538
+ /**
1539
+ * What a delivered push asks the service worker to show. `kind` exists so the
1540
+ * worker can branch without guessing from the copy.
1541
+ */
1542
+ declare const PUSH_PAYLOAD_KINDS: readonly ["REST_ALERT", "TRAINING_REMINDER"];
1543
+ type PushPayloadKind = (typeof PUSH_PAYLOAD_KINDS)[number];
1544
+ interface RestAlertPushPayload {
1545
+ kind: 'REST_ALERT';
1546
+ title: string;
1547
+ /**
1548
+ * A static line. The Web Notifications API has no chronometer field, so this
1549
+ * never contains a number that ticks down — see the NOTIF-03 scope limit.
1550
+ */
1551
+ body: string;
1552
+ sessionId: string;
1553
+ /** Where clicking the notification goes. */
1554
+ url: string;
1555
+ /** Collapses an older alert for the same session instead of stacking. */
1556
+ tag: string;
1557
+ }
1558
+ /** NOTIF-04. Planned for a local date, so it names days, never an hour. */
1559
+ interface TrainingReminderPushPayload {
1560
+ kind: 'TRAINING_REMINDER';
1561
+ title: string;
1562
+ body: string;
1563
+ url: string;
1564
+ tag: string;
1565
+ }
1566
+ type PushPayload = RestAlertPushPayload | TrainingReminderPushPayload;
1567
+ /** A rest alert is refused beyond this far ahead. */
1568
+ declare const REST_ALERT_MAX_LEAD_SECONDS = 3600;
1569
+ /**
1570
+ * Scheduling closer than this cannot beat the sweep interval, so the request
1571
+ * is accepted and reported as not scheduled rather than silently dropped.
1572
+ */
1573
+ declare const REST_ALERT_MIN_LEAD_SECONDS = 5;
1574
+ /**
1575
+ * PUT /workouts/sessions/:id/rest-alert
1576
+ *
1577
+ * One pending alert per session: a new rest period replaces the last one, so a
1578
+ * session holds at most one scheduled push however many sets it logs.
1579
+ */
1580
+ interface ScheduleRestAlertRequest {
1581
+ /** When the rest period ends, at second-level precision. */
1582
+ endsAt: IsoDateString;
1583
+ /** Named in the notification so the athlete knows which lift resumes. */
1584
+ exerciseName: string;
1585
+ }
1586
+ interface ScheduleRestAlertResponse {
1587
+ /** Null when nothing was scheduled; `reason` then says why. */
1588
+ scheduledFor: IsoDateString | null;
1589
+ reason: RestAlertRefusal | null;
1590
+ }
1591
+ declare const REST_ALERT_REFUSALS: readonly ["NO_SUBSCRIPTION", "PUSH_UNAVAILABLE", "TOO_SOON", "CATEGORY_OFF", "QUIET_HOURS"];
1592
+ type RestAlertRefusal = (typeof REST_ALERT_REFUSALS)[number];
1593
+
1594
+ /**
1595
+ * What a notification can be about. Every delivered payload names one, and an
1596
+ * owner can switch each off independently.
1597
+ *
1598
+ * There is deliberately no "channel" axis beside this. Web Push is the only
1599
+ * delivery channel that exists, so a channel switch would be the same switch
1600
+ * twice; the NOTIF-01 centre is gathered on read rather than delivered, and is
1601
+ * not something to turn off.
1602
+ */
1603
+ declare const NOTIFICATION_CATEGORIES: readonly ["REST_ALERT", "TRAINING_REMINDER"];
1604
+ type NotificationCategory = (typeof NOTIFICATION_CATEGORIES)[number];
1605
+ /**
1606
+ * A local-clock window in which nothing is delivered, as minutes from
1607
+ * midnight. It may wrap past midnight (22:00 to 07:00 is `1320` to `420`),
1608
+ * which is the normal case, so a plain `start <= x < end` test is wrong.
1609
+ */
1610
+ interface QuietHours {
1611
+ startMinute: number;
1612
+ endMinute: number;
1613
+ }
1614
+ declare const MINUTES_IN_DAY = 1440;
1615
+ /** True when a local minute-of-day falls inside the window, wrap included. */
1616
+ declare function isWithinQuietHours(minuteOfDay: number, quietHours: QuietHours | null): boolean;
1617
+ /**
1618
+ * NOTIF-04's reminder time, as minutes from local midnight.
1619
+ *
1620
+ * It is a time of day, not a lead time before a session, because the product
1621
+ * does not know what hour anyone trains: a routine day carries a weekday and
1622
+ * nothing stores an intended start. Counting back from a session would mean
1623
+ * inventing the session's hour.
1624
+ */
1625
+ interface TrainingReminderPreference {
1626
+ /** Null switches reminders off without discarding the chosen time. */
1627
+ minuteOfDay: number | null;
1628
+ }
1629
+ interface NotificationPreferences {
1630
+ /** Every category, so a client never has to assume a default. */
1631
+ categories: Record<NotificationCategory, boolean>;
1632
+ quietHours: QuietHours | null;
1633
+ reminder: TrainingReminderPreference;
1634
+ /**
1635
+ * The zone every local rule above is evaluated in. Read-only here; it is
1636
+ * owned by `PUT /users/time-zone` and registered by the device.
1637
+ */
1638
+ timeZone: string | null;
1639
+ }
1640
+ /** PUT /notifications/preferences. Every field is optional and partial. */
1641
+ interface UpdateNotificationPreferencesRequest {
1642
+ categories?: Partial<Record<NotificationCategory, boolean>>;
1643
+ /** Null clears the window; omitting it leaves the stored one alone. */
1644
+ quietHours?: QuietHours | null;
1645
+ reminder?: TrainingReminderPreference;
1646
+ }
1647
+ /**
1648
+ * GET /notifications/preferences
1649
+ *
1650
+ * Carries the delivery state beside the preferences so one read answers both
1651
+ * "what did I choose" and "can any of it actually reach me" — a category left
1652
+ * on while no device is subscribed would otherwise read as working.
1653
+ */
1654
+ interface NotificationPreferencesResponse {
1655
+ preferences: NotificationPreferences;
1656
+ /** False when the account has no subscribed device. */
1657
+ hasSubscribedDevice: boolean;
1658
+ /** False when the server holds no VAPID key pair. */
1659
+ pushAvailable: boolean;
1660
+ }
1661
+ /**
1662
+ * A reminder is planned for a whole local date, not a session: the schedule
1663
+ * knows which days an account trains, never at what hour.
1664
+ */
1665
+ interface PlannedReminder {
1666
+ date: CalendarDate;
1667
+ /** The routines planned that day, named in the notification. */
1668
+ routineNames: string[];
1669
+ }
1670
+
1671
+ export { ACHIEVEMENT_CATEGORIES, ACHIEVEMENT_DEFINITIONS, type AchievementCategory, type AchievementCategoryProgress, type AchievementDefinition, type AchievementNotification, type AchievementUnlockedEventPayload, type AchievementsResponse, type AppNotification, type Brand, COMEBACK_MIN_INACTIVE_DAYS, COMEBACK_RECOGNITION_LIMIT, COMEBACK_REQUIRED_ACTIVE_DAYS, COMEBACK_SESSION_LOOKBACK, COMEBACK_WINDOW_DAYS, type CalendarDate, type ComebackRecognition, type ComebackRecognitionSummary, type CreateRoutineDayInput, type CreateRoutineExerciseInput, type CreateRoutineRequest, type CreateRoutineVersionRequest, type CreateSessionShareRequest, type DeletePushSubscriptionRequest, EXERCISE_EQUIPMENT, EXERCISE_MECHANICS, type EarnedAchievement, type EarnedPersonalRecord, type Exercise, type ExerciseEquipment, type ExerciseId, type ExerciseMechanic, type ExercisePerformanceHistoryQuery, type ExercisePerformanceHistoryResponse, type ExercisePerformancePrescription, type ExercisePerformancePrescriptionSet, type ExercisePerformanceSession, type ExercisePerformanceSet, type ExercisePerformanceSummary, type ExercisePlateau, type ExerciseStrengthSummary, type ExerciseStrengthTrendPoint, type ExerciseStrengthTrendQuery, type ExerciseStrengthTrendResponse, FEATURED_PROFILE_ITEMS_MAX, FEATURED_PROFILE_ITEM_KINDS, FEATURED_PROFILE_REFERENCE_MAX_LENGTH, FOLLOW_SUGGESTIONS_DEFAULT_LIMIT, FOLLOW_SUGGESTIONS_MAX_LIMIT, FOLLOW_SUGGESTION_REASONS, type FeaturedProfileAchievementItem, type FeaturedProfileItem, type FeaturedProfileItemKind, type FeaturedProfileRankItem, type FeaturedProfileRecordItem, type FeaturedProfileSelection, type FeaturedProfileSelectionInput, type FeaturedProfileSelectionsResponse, type FinishStatus, type FinishWorkoutRequest, type FinishWorkoutResponse, type FollowSuggestion, type FollowSuggestionReason, type FollowSuggestionsResponse, type IsoDateString, type ListSessionsParams, MEASURABLE_GOALS_MAX, MEASURABLE_GOAL_DIRECTIONS, MEASURABLE_GOAL_TYPES, MINUTES_IN_DAY, MOVEMENT_PATTERNS, MUSCLE_GROUPS, type MarkNotificationsReadRequest, type MarkNotificationsReadResponse, type MeasurableGoal, type MeasurableGoalDirection, type MeasurableGoalExercise, type MeasurableGoalInput, type MeasurableGoalType, type MoveOccurrenceRequest, type MovementPattern, type MuscleGroup, type MuscleGroupHeatmapQuery, type MuscleGroupHeatmapResponse, type MuscleGroupHeatmapValue, type MuscleGroupHeatmapWeek, type MuscleVolumeTrendSeries, NOTIFICATIONS_LIST_LIMIT, NOTIFICATIONS_LOOKBACK_DAYS, NOTIFICATIONS_RETENTION_DAYS, NOTIFICATION_CATEGORIES, NOTIFICATION_KINDS, type NewFollowerNotification, type NotificationCategory, type NotificationKind, type NotificationPreferences, type NotificationPreferencesResponse, type NotificationsResponse, PLATEAU_MIN_DAYS_SINCE_BEST, PLATEAU_MIN_SESSIONS, PLATEAU_MIN_SESSIONS_MAX, PLATEAU_MIN_SESSIONS_MIN, PLATEAU_RECENT_DAYS, PLATEAU_WINDOW_DAYS, PREFERRED_TRAINING_STYLE_VALUES, PROFILE_BIO_MAX_LENGTH, PROFILE_FAVORITE_EXERCISES_MAX, PROFILE_LOCATION_MAX_LENGTH, PROFILE_TRAINING_DISCIPLINES_MAX, PROFILE_TRAINING_GOALS_MAX, PROFILE_VISIBILITY_VALUES, PROGRESSION_SCHEMES, PROGRESS_TIMELINE_EVENT_TYPES, PUSH_PAYLOAD_KINDS, PUSH_SUBSCRIPTIONS_MAX, type PaginatedResponse, type PersonalGoalProgress, type PersonalGoalsResponse, type PersonalRecordEntry, type PersonalRecordKind, type PlannedReminder, type PlatePairInventory, type PlateauPreferences, type PlateauSet, type PlateausResponse, type PreferredTrainingStyle, type PreviousPerformanceResponse, type PreviousSessionRecap, type PreviousSetPerformance, type ProfileDiscoverySettings, type ProfileFavoriteExercise, type ProfilePrivacySettings, type ProfileViewerAccess, type ProfileVisibility, type ProgressTimelineEventType, type ProgressTimelineItem, type ProgressTimelinePersonalRecordItem, type ProgressTimelineProgressionItem, type ProgressTimelineQuery, type ProgressTimelineRecordPerformance, type ProgressTimelineRecordReason, type ProgressTimelineResponse, type ProgressTimelineSessionContext, type ProgressionChange, type ProgressionRule, type ProgressionScheme, type ProgressionSetChange, type PublicBodyMetrics, type PublicProfileAchievements, type PublicTrainingSummary, type PublicUserProfile, type PushPayload, type PushPayloadKind, type PushSubscriptionKeys, type PushSubscriptionSummary, type PushSubscriptionsResponse, type QuietHours, RELATIONSHIP_LIST_DEFAULT_LIMIT, RELATIONSHIP_LIST_KINDS, RELATIONSHIP_LIST_MAX_LIMIT, RENAISSANCE_RANK_DEFINITIONS, REP_TYPES, RESERVED_USERNAMES, REST_ALERT_MAX_LEAD_SECONDS, REST_ALERT_MIN_LEAD_SECONDS, REST_ALERT_REFUSALS, ROUTINE_DAYS_MAX, ROUTINE_DAY_NAME_MAX, ROUTINE_SCHEDULE_MODES, ROUTINE_VERSIONS_MAX, ROUTINE_VERSION_KINDS, ROUTINE_VERSION_NAME_MAX, type RecentActivityEntry, type RegisterPushSubscriptionRequest, type RelationshipListKind, type RelationshipListQuery, type RelationshipListResponse, type RelationshipMember, type RenaissanceRankDefinition, type RenaissanceRankProgress, type RepType, type ReplaceFeaturedProfileItemsRequest, type ReplaceMeasurableGoalsRequest, type ReplaceTrainingLocationsRequest, type RestAlertPushPayload, type RestAlertRefusal, type RestoreRoutineVersionResponse, type Routine, type RoutineDay, type RoutineDayId, type RoutineExercise, type RoutineId, type RoutineScheduleMode, type RoutineSet, type RoutineVersion, type RoutineVersionDay, type RoutineVersionExercise, type RoutineVersionKind, type RoutineVersionSetup, type RoutineVersionsResponse, SCHEDULE_MOVE_MAX_DAYS, SCHEDULE_OVERRIDES_MAX_RANGE_DAYS, SCHEDULE_OVERRIDE_KINDS, SCHEDULE_SKIP_PAST_DAYS, SESSION_SHARE_DEFAULT_FIELDS, SESSION_SHARE_FIELDS, SESSION_SHARE_MAX_ACTIVE_LINKS, SEXES, STARRED_EXERCISES_MAX, type ScheduleOverride, type ScheduleOverrideKind, type ScheduleOverridesQuery, type ScheduleOverridesResponse, type ScheduleRestAlertRequest, type ScheduleRestAlertResponse, type SessionComparisonExercise, type SessionComparisonQuery, type SessionComparisonResponse, type SessionComparisonRoutineDay, type SessionComparisonSession, type SessionComparisonSet, type SessionExerciseSubstitution, type SessionProgressNotification, type SessionRecapRecord, type SessionShare, type SessionShareField, type SessionShareListResponse, type SetAccountTimeZoneRequest, type SetLog, type Sex, type SharedSessionOwner, type SharedSessionRecap, type SkipOccurrenceRequest, type StarredExercise, type StarredExercisesResponse, type StartWorkoutRequest, type StartWorkoutResponse, type StreakMilestoneEventPayload, type SubstituteSessionExerciseRequest, type SubstituteSessionExerciseResponse, type SupabaseAuthResponse, type SupabaseAuthUser, type SupabaseMigrationResponse, TRAINING_DISCIPLINE_VALUES, TRAINING_EVENT_TYPES, TRAINING_EXPERIENCE_LEVEL_VALUES, TRAINING_GOAL_VALUES, type TrainingDiscipline, type TrainingEventType, type TrainingExperienceLevel, type TrainingGoal, type TrainingIdentity, type TrainingLocationPreference, type TrainingLocationPreferenceInput, type TrainingReminderPreference, type TrainingReminderPushPayload, USERNAME_MAX_LENGTH, USERNAME_MIN_LENGTH, USERNAME_PATTERN_SOURCE, type UpdateNotificationPreferencesRequest, type UpdateProfileDiscoveryRequest, type UpdateProfilePrivacyRequest, type UpdateProfileRequest, type UpdateRoutineRequest, type UpsertSetLogRequest, type UpsertSetLogResponse, type UserId, type UserProfile, type UserSearchResponse, type VolumeTrendPoint, type VolumeTrendQuery, type VolumeTrendResponse, type VolumeTrendSeries, WEIGHT_UNITS, WORKOUT_SESSION_STATUSES, type WeightUnit, type WorkoutAnalyticsStatus, type WorkoutProgressQuery, type WorkoutProgressResponse, type WorkoutSession, type WorkoutSessionId, type WorkoutSessionListResponse, type WorkoutSessionRecap, type WorkoutSessionSnapshotV1, type WorkoutSessionStatus, type WorkoutSessionSummary, type WorkoutStatsQuery, type WorkoutStatsResponse, isWithinQuietHours, routineDayLabel };
package/dist/index.d.ts CHANGED
@@ -1485,4 +1485,187 @@ interface MarkNotificationsReadResponse {
1485
1485
  unreadCount: number;
1486
1486
  }
1487
1487
 
1488
- export { ACHIEVEMENT_CATEGORIES, ACHIEVEMENT_DEFINITIONS, type AchievementCategory, type AchievementCategoryProgress, type AchievementDefinition, type AchievementNotification, type AchievementUnlockedEventPayload, type AchievementsResponse, type AppNotification, type Brand, COMEBACK_MIN_INACTIVE_DAYS, COMEBACK_RECOGNITION_LIMIT, COMEBACK_REQUIRED_ACTIVE_DAYS, COMEBACK_SESSION_LOOKBACK, COMEBACK_WINDOW_DAYS, type CalendarDate, type ComebackRecognition, type ComebackRecognitionSummary, type CreateRoutineDayInput, type CreateRoutineExerciseInput, type CreateRoutineRequest, type CreateRoutineVersionRequest, type CreateSessionShareRequest, EXERCISE_EQUIPMENT, EXERCISE_MECHANICS, type EarnedAchievement, type EarnedPersonalRecord, type Exercise, type ExerciseEquipment, type ExerciseId, type ExerciseMechanic, type ExercisePerformanceHistoryQuery, type ExercisePerformanceHistoryResponse, type ExercisePerformancePrescription, type ExercisePerformancePrescriptionSet, type ExercisePerformanceSession, type ExercisePerformanceSet, type ExercisePerformanceSummary, type ExercisePlateau, type ExerciseStrengthSummary, type ExerciseStrengthTrendPoint, type ExerciseStrengthTrendQuery, type ExerciseStrengthTrendResponse, FEATURED_PROFILE_ITEMS_MAX, FEATURED_PROFILE_ITEM_KINDS, FEATURED_PROFILE_REFERENCE_MAX_LENGTH, FOLLOW_SUGGESTIONS_DEFAULT_LIMIT, FOLLOW_SUGGESTIONS_MAX_LIMIT, FOLLOW_SUGGESTION_REASONS, type FeaturedProfileAchievementItem, type FeaturedProfileItem, type FeaturedProfileItemKind, type FeaturedProfileRankItem, type FeaturedProfileRecordItem, type FeaturedProfileSelection, type FeaturedProfileSelectionInput, type FeaturedProfileSelectionsResponse, type FinishStatus, type FinishWorkoutRequest, type FinishWorkoutResponse, type FollowSuggestion, type FollowSuggestionReason, type FollowSuggestionsResponse, type IsoDateString, type ListSessionsParams, MEASURABLE_GOALS_MAX, MEASURABLE_GOAL_DIRECTIONS, MEASURABLE_GOAL_TYPES, MOVEMENT_PATTERNS, MUSCLE_GROUPS, type MarkNotificationsReadRequest, type MarkNotificationsReadResponse, type MeasurableGoal, type MeasurableGoalDirection, type MeasurableGoalExercise, type MeasurableGoalInput, type MeasurableGoalType, type MoveOccurrenceRequest, type MovementPattern, type MuscleGroup, type MuscleGroupHeatmapQuery, type MuscleGroupHeatmapResponse, type MuscleGroupHeatmapValue, type MuscleGroupHeatmapWeek, type MuscleVolumeTrendSeries, NOTIFICATIONS_LIST_LIMIT, NOTIFICATIONS_LOOKBACK_DAYS, NOTIFICATIONS_RETENTION_DAYS, NOTIFICATION_KINDS, type NewFollowerNotification, type NotificationKind, type NotificationsResponse, PLATEAU_MIN_DAYS_SINCE_BEST, PLATEAU_MIN_SESSIONS, PLATEAU_MIN_SESSIONS_MAX, PLATEAU_MIN_SESSIONS_MIN, PLATEAU_RECENT_DAYS, PLATEAU_WINDOW_DAYS, PREFERRED_TRAINING_STYLE_VALUES, PROFILE_BIO_MAX_LENGTH, PROFILE_FAVORITE_EXERCISES_MAX, PROFILE_LOCATION_MAX_LENGTH, PROFILE_TRAINING_DISCIPLINES_MAX, PROFILE_TRAINING_GOALS_MAX, PROFILE_VISIBILITY_VALUES, PROGRESSION_SCHEMES, PROGRESS_TIMELINE_EVENT_TYPES, type PaginatedResponse, type PersonalGoalProgress, type PersonalGoalsResponse, type PersonalRecordEntry, type PersonalRecordKind, type PlatePairInventory, type PlateauPreferences, type PlateauSet, type PlateausResponse, type PreferredTrainingStyle, type PreviousPerformanceResponse, type PreviousSessionRecap, type PreviousSetPerformance, type ProfileDiscoverySettings, type ProfileFavoriteExercise, type ProfilePrivacySettings, type ProfileViewerAccess, type ProfileVisibility, type ProgressTimelineEventType, type ProgressTimelineItem, type ProgressTimelinePersonalRecordItem, type ProgressTimelineProgressionItem, type ProgressTimelineQuery, type ProgressTimelineRecordPerformance, type ProgressTimelineRecordReason, type ProgressTimelineResponse, type ProgressTimelineSessionContext, type ProgressionChange, type ProgressionRule, type ProgressionScheme, type ProgressionSetChange, type PublicBodyMetrics, type PublicProfileAchievements, type PublicTrainingSummary, type PublicUserProfile, RELATIONSHIP_LIST_DEFAULT_LIMIT, RELATIONSHIP_LIST_KINDS, RELATIONSHIP_LIST_MAX_LIMIT, RENAISSANCE_RANK_DEFINITIONS, REP_TYPES, RESERVED_USERNAMES, ROUTINE_DAYS_MAX, ROUTINE_DAY_NAME_MAX, ROUTINE_SCHEDULE_MODES, ROUTINE_VERSIONS_MAX, ROUTINE_VERSION_KINDS, ROUTINE_VERSION_NAME_MAX, type RecentActivityEntry, type RelationshipListKind, type RelationshipListQuery, type RelationshipListResponse, type RelationshipMember, type RenaissanceRankDefinition, type RenaissanceRankProgress, type RepType, type ReplaceFeaturedProfileItemsRequest, type ReplaceMeasurableGoalsRequest, type ReplaceTrainingLocationsRequest, type RestoreRoutineVersionResponse, type Routine, type RoutineDay, type RoutineDayId, type RoutineExercise, type RoutineId, type RoutineScheduleMode, type RoutineSet, type RoutineVersion, type RoutineVersionDay, type RoutineVersionExercise, type RoutineVersionKind, type RoutineVersionSetup, type RoutineVersionsResponse, SCHEDULE_MOVE_MAX_DAYS, SCHEDULE_OVERRIDES_MAX_RANGE_DAYS, SCHEDULE_OVERRIDE_KINDS, SCHEDULE_SKIP_PAST_DAYS, SESSION_SHARE_DEFAULT_FIELDS, SESSION_SHARE_FIELDS, SESSION_SHARE_MAX_ACTIVE_LINKS, SEXES, STARRED_EXERCISES_MAX, type ScheduleOverride, type ScheduleOverrideKind, type ScheduleOverridesQuery, type ScheduleOverridesResponse, type SessionComparisonExercise, type SessionComparisonQuery, type SessionComparisonResponse, type SessionComparisonRoutineDay, type SessionComparisonSession, type SessionComparisonSet, type SessionExerciseSubstitution, type SessionProgressNotification, type SessionRecapRecord, type SessionShare, type SessionShareField, type SessionShareListResponse, type SetAccountTimeZoneRequest, type SetLog, type Sex, type SharedSessionOwner, type SharedSessionRecap, type SkipOccurrenceRequest, type StarredExercise, type StarredExercisesResponse, type StartWorkoutRequest, type StartWorkoutResponse, type StreakMilestoneEventPayload, type SubstituteSessionExerciseRequest, type SubstituteSessionExerciseResponse, type SupabaseAuthResponse, type SupabaseAuthUser, type SupabaseMigrationResponse, TRAINING_DISCIPLINE_VALUES, TRAINING_EVENT_TYPES, TRAINING_EXPERIENCE_LEVEL_VALUES, TRAINING_GOAL_VALUES, type TrainingDiscipline, type TrainingEventType, type TrainingExperienceLevel, type TrainingGoal, type TrainingIdentity, type TrainingLocationPreference, type TrainingLocationPreferenceInput, USERNAME_MAX_LENGTH, USERNAME_MIN_LENGTH, USERNAME_PATTERN_SOURCE, type UpdateProfileDiscoveryRequest, type UpdateProfilePrivacyRequest, type UpdateProfileRequest, type UpdateRoutineRequest, type UpsertSetLogRequest, type UpsertSetLogResponse, type UserId, type UserProfile, type UserSearchResponse, type VolumeTrendPoint, type VolumeTrendQuery, type VolumeTrendResponse, type VolumeTrendSeries, WEIGHT_UNITS, WORKOUT_SESSION_STATUSES, type WeightUnit, type WorkoutAnalyticsStatus, type WorkoutProgressQuery, type WorkoutProgressResponse, type WorkoutSession, type WorkoutSessionId, type WorkoutSessionListResponse, type WorkoutSessionRecap, type WorkoutSessionSnapshotV1, type WorkoutSessionStatus, type WorkoutSessionSummary, type WorkoutStatsQuery, type WorkoutStatsResponse, routineDayLabel };
1488
+ /**
1489
+ * The two keys a browser's `PushSubscription` carries. They are the encryption
1490
+ * material for that endpoint, not an identifier, and are never returned to a
1491
+ * client — only accepted.
1492
+ */
1493
+ interface PushSubscriptionKeys {
1494
+ p256dh: string;
1495
+ auth: string;
1496
+ }
1497
+ /** One account keeps at most this many devices subscribed. */
1498
+ declare const PUSH_SUBSCRIPTIONS_MAX = 10;
1499
+ /** POST /notifications/push/subscriptions — idempotent on `endpoint`. */
1500
+ interface RegisterPushSubscriptionRequest {
1501
+ endpoint: string;
1502
+ /** The browser's own expiry, almost always null. */
1503
+ expirationTime: number | null;
1504
+ keys: PushSubscriptionKeys;
1505
+ /**
1506
+ * A short device label the owner can recognise in their own list. It is
1507
+ * derived by the client from the user agent, never the raw string.
1508
+ */
1509
+ deviceLabel?: string;
1510
+ }
1511
+ /**
1512
+ * What the owner sees about one of their own subscribed devices. The endpoint
1513
+ * is a bearer capability for sending that device notifications, so it is
1514
+ * deliberately absent.
1515
+ */
1516
+ interface PushSubscriptionSummary {
1517
+ id: string;
1518
+ deviceLabel: string | null;
1519
+ createdAt: IsoDateString;
1520
+ /** Refreshed whenever the same endpoint registers again. */
1521
+ lastSeenAt: IsoDateString;
1522
+ /** True for the subscription the requesting device just sent. */
1523
+ isCurrentDevice: boolean;
1524
+ }
1525
+ /** GET /notifications/push/subscriptions */
1526
+ interface PushSubscriptionsResponse {
1527
+ subscriptions: PushSubscriptionSummary[];
1528
+ /**
1529
+ * Null when the server holds no VAPID key pair. The client must treat that
1530
+ * as "push is unavailable" and never prompt for permission.
1531
+ */
1532
+ vapidPublicKey: string | null;
1533
+ }
1534
+ /** DELETE /notifications/push/subscriptions */
1535
+ interface DeletePushSubscriptionRequest {
1536
+ endpoint: string;
1537
+ }
1538
+ /**
1539
+ * What a delivered push asks the service worker to show. `kind` exists so the
1540
+ * worker can branch without guessing from the copy.
1541
+ */
1542
+ declare const PUSH_PAYLOAD_KINDS: readonly ["REST_ALERT", "TRAINING_REMINDER"];
1543
+ type PushPayloadKind = (typeof PUSH_PAYLOAD_KINDS)[number];
1544
+ interface RestAlertPushPayload {
1545
+ kind: 'REST_ALERT';
1546
+ title: string;
1547
+ /**
1548
+ * A static line. The Web Notifications API has no chronometer field, so this
1549
+ * never contains a number that ticks down — see the NOTIF-03 scope limit.
1550
+ */
1551
+ body: string;
1552
+ sessionId: string;
1553
+ /** Where clicking the notification goes. */
1554
+ url: string;
1555
+ /** Collapses an older alert for the same session instead of stacking. */
1556
+ tag: string;
1557
+ }
1558
+ /** NOTIF-04. Planned for a local date, so it names days, never an hour. */
1559
+ interface TrainingReminderPushPayload {
1560
+ kind: 'TRAINING_REMINDER';
1561
+ title: string;
1562
+ body: string;
1563
+ url: string;
1564
+ tag: string;
1565
+ }
1566
+ type PushPayload = RestAlertPushPayload | TrainingReminderPushPayload;
1567
+ /** A rest alert is refused beyond this far ahead. */
1568
+ declare const REST_ALERT_MAX_LEAD_SECONDS = 3600;
1569
+ /**
1570
+ * Scheduling closer than this cannot beat the sweep interval, so the request
1571
+ * is accepted and reported as not scheduled rather than silently dropped.
1572
+ */
1573
+ declare const REST_ALERT_MIN_LEAD_SECONDS = 5;
1574
+ /**
1575
+ * PUT /workouts/sessions/:id/rest-alert
1576
+ *
1577
+ * One pending alert per session: a new rest period replaces the last one, so a
1578
+ * session holds at most one scheduled push however many sets it logs.
1579
+ */
1580
+ interface ScheduleRestAlertRequest {
1581
+ /** When the rest period ends, at second-level precision. */
1582
+ endsAt: IsoDateString;
1583
+ /** Named in the notification so the athlete knows which lift resumes. */
1584
+ exerciseName: string;
1585
+ }
1586
+ interface ScheduleRestAlertResponse {
1587
+ /** Null when nothing was scheduled; `reason` then says why. */
1588
+ scheduledFor: IsoDateString | null;
1589
+ reason: RestAlertRefusal | null;
1590
+ }
1591
+ declare const REST_ALERT_REFUSALS: readonly ["NO_SUBSCRIPTION", "PUSH_UNAVAILABLE", "TOO_SOON", "CATEGORY_OFF", "QUIET_HOURS"];
1592
+ type RestAlertRefusal = (typeof REST_ALERT_REFUSALS)[number];
1593
+
1594
+ /**
1595
+ * What a notification can be about. Every delivered payload names one, and an
1596
+ * owner can switch each off independently.
1597
+ *
1598
+ * There is deliberately no "channel" axis beside this. Web Push is the only
1599
+ * delivery channel that exists, so a channel switch would be the same switch
1600
+ * twice; the NOTIF-01 centre is gathered on read rather than delivered, and is
1601
+ * not something to turn off.
1602
+ */
1603
+ declare const NOTIFICATION_CATEGORIES: readonly ["REST_ALERT", "TRAINING_REMINDER"];
1604
+ type NotificationCategory = (typeof NOTIFICATION_CATEGORIES)[number];
1605
+ /**
1606
+ * A local-clock window in which nothing is delivered, as minutes from
1607
+ * midnight. It may wrap past midnight (22:00 to 07:00 is `1320` to `420`),
1608
+ * which is the normal case, so a plain `start <= x < end` test is wrong.
1609
+ */
1610
+ interface QuietHours {
1611
+ startMinute: number;
1612
+ endMinute: number;
1613
+ }
1614
+ declare const MINUTES_IN_DAY = 1440;
1615
+ /** True when a local minute-of-day falls inside the window, wrap included. */
1616
+ declare function isWithinQuietHours(minuteOfDay: number, quietHours: QuietHours | null): boolean;
1617
+ /**
1618
+ * NOTIF-04's reminder time, as minutes from local midnight.
1619
+ *
1620
+ * It is a time of day, not a lead time before a session, because the product
1621
+ * does not know what hour anyone trains: a routine day carries a weekday and
1622
+ * nothing stores an intended start. Counting back from a session would mean
1623
+ * inventing the session's hour.
1624
+ */
1625
+ interface TrainingReminderPreference {
1626
+ /** Null switches reminders off without discarding the chosen time. */
1627
+ minuteOfDay: number | null;
1628
+ }
1629
+ interface NotificationPreferences {
1630
+ /** Every category, so a client never has to assume a default. */
1631
+ categories: Record<NotificationCategory, boolean>;
1632
+ quietHours: QuietHours | null;
1633
+ reminder: TrainingReminderPreference;
1634
+ /**
1635
+ * The zone every local rule above is evaluated in. Read-only here; it is
1636
+ * owned by `PUT /users/time-zone` and registered by the device.
1637
+ */
1638
+ timeZone: string | null;
1639
+ }
1640
+ /** PUT /notifications/preferences. Every field is optional and partial. */
1641
+ interface UpdateNotificationPreferencesRequest {
1642
+ categories?: Partial<Record<NotificationCategory, boolean>>;
1643
+ /** Null clears the window; omitting it leaves the stored one alone. */
1644
+ quietHours?: QuietHours | null;
1645
+ reminder?: TrainingReminderPreference;
1646
+ }
1647
+ /**
1648
+ * GET /notifications/preferences
1649
+ *
1650
+ * Carries the delivery state beside the preferences so one read answers both
1651
+ * "what did I choose" and "can any of it actually reach me" — a category left
1652
+ * on while no device is subscribed would otherwise read as working.
1653
+ */
1654
+ interface NotificationPreferencesResponse {
1655
+ preferences: NotificationPreferences;
1656
+ /** False when the account has no subscribed device. */
1657
+ hasSubscribedDevice: boolean;
1658
+ /** False when the server holds no VAPID key pair. */
1659
+ pushAvailable: boolean;
1660
+ }
1661
+ /**
1662
+ * A reminder is planned for a whole local date, not a session: the schedule
1663
+ * knows which days an account trains, never at what hour.
1664
+ */
1665
+ interface PlannedReminder {
1666
+ date: CalendarDate;
1667
+ /** The routines planned that day, named in the notification. */
1668
+ routineNames: string[];
1669
+ }
1670
+
1671
+ export { ACHIEVEMENT_CATEGORIES, ACHIEVEMENT_DEFINITIONS, type AchievementCategory, type AchievementCategoryProgress, type AchievementDefinition, type AchievementNotification, type AchievementUnlockedEventPayload, type AchievementsResponse, type AppNotification, type Brand, COMEBACK_MIN_INACTIVE_DAYS, COMEBACK_RECOGNITION_LIMIT, COMEBACK_REQUIRED_ACTIVE_DAYS, COMEBACK_SESSION_LOOKBACK, COMEBACK_WINDOW_DAYS, type CalendarDate, type ComebackRecognition, type ComebackRecognitionSummary, type CreateRoutineDayInput, type CreateRoutineExerciseInput, type CreateRoutineRequest, type CreateRoutineVersionRequest, type CreateSessionShareRequest, type DeletePushSubscriptionRequest, EXERCISE_EQUIPMENT, EXERCISE_MECHANICS, type EarnedAchievement, type EarnedPersonalRecord, type Exercise, type ExerciseEquipment, type ExerciseId, type ExerciseMechanic, type ExercisePerformanceHistoryQuery, type ExercisePerformanceHistoryResponse, type ExercisePerformancePrescription, type ExercisePerformancePrescriptionSet, type ExercisePerformanceSession, type ExercisePerformanceSet, type ExercisePerformanceSummary, type ExercisePlateau, type ExerciseStrengthSummary, type ExerciseStrengthTrendPoint, type ExerciseStrengthTrendQuery, type ExerciseStrengthTrendResponse, FEATURED_PROFILE_ITEMS_MAX, FEATURED_PROFILE_ITEM_KINDS, FEATURED_PROFILE_REFERENCE_MAX_LENGTH, FOLLOW_SUGGESTIONS_DEFAULT_LIMIT, FOLLOW_SUGGESTIONS_MAX_LIMIT, FOLLOW_SUGGESTION_REASONS, type FeaturedProfileAchievementItem, type FeaturedProfileItem, type FeaturedProfileItemKind, type FeaturedProfileRankItem, type FeaturedProfileRecordItem, type FeaturedProfileSelection, type FeaturedProfileSelectionInput, type FeaturedProfileSelectionsResponse, type FinishStatus, type FinishWorkoutRequest, type FinishWorkoutResponse, type FollowSuggestion, type FollowSuggestionReason, type FollowSuggestionsResponse, type IsoDateString, type ListSessionsParams, MEASURABLE_GOALS_MAX, MEASURABLE_GOAL_DIRECTIONS, MEASURABLE_GOAL_TYPES, MINUTES_IN_DAY, MOVEMENT_PATTERNS, MUSCLE_GROUPS, type MarkNotificationsReadRequest, type MarkNotificationsReadResponse, type MeasurableGoal, type MeasurableGoalDirection, type MeasurableGoalExercise, type MeasurableGoalInput, type MeasurableGoalType, type MoveOccurrenceRequest, type MovementPattern, type MuscleGroup, type MuscleGroupHeatmapQuery, type MuscleGroupHeatmapResponse, type MuscleGroupHeatmapValue, type MuscleGroupHeatmapWeek, type MuscleVolumeTrendSeries, NOTIFICATIONS_LIST_LIMIT, NOTIFICATIONS_LOOKBACK_DAYS, NOTIFICATIONS_RETENTION_DAYS, NOTIFICATION_CATEGORIES, NOTIFICATION_KINDS, type NewFollowerNotification, type NotificationCategory, type NotificationKind, type NotificationPreferences, type NotificationPreferencesResponse, type NotificationsResponse, PLATEAU_MIN_DAYS_SINCE_BEST, PLATEAU_MIN_SESSIONS, PLATEAU_MIN_SESSIONS_MAX, PLATEAU_MIN_SESSIONS_MIN, PLATEAU_RECENT_DAYS, PLATEAU_WINDOW_DAYS, PREFERRED_TRAINING_STYLE_VALUES, PROFILE_BIO_MAX_LENGTH, PROFILE_FAVORITE_EXERCISES_MAX, PROFILE_LOCATION_MAX_LENGTH, PROFILE_TRAINING_DISCIPLINES_MAX, PROFILE_TRAINING_GOALS_MAX, PROFILE_VISIBILITY_VALUES, PROGRESSION_SCHEMES, PROGRESS_TIMELINE_EVENT_TYPES, PUSH_PAYLOAD_KINDS, PUSH_SUBSCRIPTIONS_MAX, type PaginatedResponse, type PersonalGoalProgress, type PersonalGoalsResponse, type PersonalRecordEntry, type PersonalRecordKind, type PlannedReminder, type PlatePairInventory, type PlateauPreferences, type PlateauSet, type PlateausResponse, type PreferredTrainingStyle, type PreviousPerformanceResponse, type PreviousSessionRecap, type PreviousSetPerformance, type ProfileDiscoverySettings, type ProfileFavoriteExercise, type ProfilePrivacySettings, type ProfileViewerAccess, type ProfileVisibility, type ProgressTimelineEventType, type ProgressTimelineItem, type ProgressTimelinePersonalRecordItem, type ProgressTimelineProgressionItem, type ProgressTimelineQuery, type ProgressTimelineRecordPerformance, type ProgressTimelineRecordReason, type ProgressTimelineResponse, type ProgressTimelineSessionContext, type ProgressionChange, type ProgressionRule, type ProgressionScheme, type ProgressionSetChange, type PublicBodyMetrics, type PublicProfileAchievements, type PublicTrainingSummary, type PublicUserProfile, type PushPayload, type PushPayloadKind, type PushSubscriptionKeys, type PushSubscriptionSummary, type PushSubscriptionsResponse, type QuietHours, RELATIONSHIP_LIST_DEFAULT_LIMIT, RELATIONSHIP_LIST_KINDS, RELATIONSHIP_LIST_MAX_LIMIT, RENAISSANCE_RANK_DEFINITIONS, REP_TYPES, RESERVED_USERNAMES, REST_ALERT_MAX_LEAD_SECONDS, REST_ALERT_MIN_LEAD_SECONDS, REST_ALERT_REFUSALS, ROUTINE_DAYS_MAX, ROUTINE_DAY_NAME_MAX, ROUTINE_SCHEDULE_MODES, ROUTINE_VERSIONS_MAX, ROUTINE_VERSION_KINDS, ROUTINE_VERSION_NAME_MAX, type RecentActivityEntry, type RegisterPushSubscriptionRequest, type RelationshipListKind, type RelationshipListQuery, type RelationshipListResponse, type RelationshipMember, type RenaissanceRankDefinition, type RenaissanceRankProgress, type RepType, type ReplaceFeaturedProfileItemsRequest, type ReplaceMeasurableGoalsRequest, type ReplaceTrainingLocationsRequest, type RestAlertPushPayload, type RestAlertRefusal, type RestoreRoutineVersionResponse, type Routine, type RoutineDay, type RoutineDayId, type RoutineExercise, type RoutineId, type RoutineScheduleMode, type RoutineSet, type RoutineVersion, type RoutineVersionDay, type RoutineVersionExercise, type RoutineVersionKind, type RoutineVersionSetup, type RoutineVersionsResponse, SCHEDULE_MOVE_MAX_DAYS, SCHEDULE_OVERRIDES_MAX_RANGE_DAYS, SCHEDULE_OVERRIDE_KINDS, SCHEDULE_SKIP_PAST_DAYS, SESSION_SHARE_DEFAULT_FIELDS, SESSION_SHARE_FIELDS, SESSION_SHARE_MAX_ACTIVE_LINKS, SEXES, STARRED_EXERCISES_MAX, type ScheduleOverride, type ScheduleOverrideKind, type ScheduleOverridesQuery, type ScheduleOverridesResponse, type ScheduleRestAlertRequest, type ScheduleRestAlertResponse, type SessionComparisonExercise, type SessionComparisonQuery, type SessionComparisonResponse, type SessionComparisonRoutineDay, type SessionComparisonSession, type SessionComparisonSet, type SessionExerciseSubstitution, type SessionProgressNotification, type SessionRecapRecord, type SessionShare, type SessionShareField, type SessionShareListResponse, type SetAccountTimeZoneRequest, type SetLog, type Sex, type SharedSessionOwner, type SharedSessionRecap, type SkipOccurrenceRequest, type StarredExercise, type StarredExercisesResponse, type StartWorkoutRequest, type StartWorkoutResponse, type StreakMilestoneEventPayload, type SubstituteSessionExerciseRequest, type SubstituteSessionExerciseResponse, type SupabaseAuthResponse, type SupabaseAuthUser, type SupabaseMigrationResponse, TRAINING_DISCIPLINE_VALUES, TRAINING_EVENT_TYPES, TRAINING_EXPERIENCE_LEVEL_VALUES, TRAINING_GOAL_VALUES, type TrainingDiscipline, type TrainingEventType, type TrainingExperienceLevel, type TrainingGoal, type TrainingIdentity, type TrainingLocationPreference, type TrainingLocationPreferenceInput, type TrainingReminderPreference, type TrainingReminderPushPayload, USERNAME_MAX_LENGTH, USERNAME_MIN_LENGTH, USERNAME_PATTERN_SOURCE, type UpdateNotificationPreferencesRequest, type UpdateProfileDiscoveryRequest, type UpdateProfilePrivacyRequest, type UpdateProfileRequest, type UpdateRoutineRequest, type UpsertSetLogRequest, type UpsertSetLogResponse, type UserId, type UserProfile, type UserSearchResponse, type VolumeTrendPoint, type VolumeTrendQuery, type VolumeTrendResponse, type VolumeTrendSeries, WEIGHT_UNITS, WORKOUT_SESSION_STATUSES, type WeightUnit, type WorkoutAnalyticsStatus, type WorkoutProgressQuery, type WorkoutProgressResponse, type WorkoutSession, type WorkoutSessionId, type WorkoutSessionListResponse, type WorkoutSessionRecap, type WorkoutSessionSnapshotV1, type WorkoutSessionStatus, type WorkoutSessionSummary, type WorkoutStatsQuery, type WorkoutStatsResponse, isWithinQuietHours, routineDayLabel };
package/dist/index.js CHANGED
@@ -367,6 +367,37 @@ var NOTIFICATION_KINDS = [
367
367
  var NOTIFICATIONS_LOOKBACK_DAYS = 30;
368
368
  var NOTIFICATIONS_RETENTION_DAYS = 90;
369
369
  var NOTIFICATIONS_LIST_LIMIT = 50;
370
+
371
+ // src/push.ts
372
+ var PUSH_SUBSCRIPTIONS_MAX = 10;
373
+ var PUSH_PAYLOAD_KINDS = ["REST_ALERT", "TRAINING_REMINDER"];
374
+ var REST_ALERT_MAX_LEAD_SECONDS = 3600;
375
+ var REST_ALERT_MIN_LEAD_SECONDS = 5;
376
+ var REST_ALERT_REFUSALS = [
377
+ /** The account has no subscribed device. */
378
+ "NO_SUBSCRIPTION",
379
+ /** The server holds no VAPID key pair. */
380
+ "PUSH_UNAVAILABLE",
381
+ /** Rest ends too soon for a push to beat it. */
382
+ "TOO_SOON",
383
+ /** NOTIF-05: the owner switched rest alerts off. */
384
+ "CATEGORY_OFF",
385
+ /** NOTIF-05: rest would end inside the owner's quiet hours. */
386
+ "QUIET_HOURS"
387
+ ];
388
+
389
+ // src/notification-preferences.ts
390
+ var NOTIFICATION_CATEGORIES = [
391
+ "REST_ALERT",
392
+ "TRAINING_REMINDER"
393
+ ];
394
+ var MINUTES_IN_DAY = 1440;
395
+ function isWithinQuietHours(minuteOfDay, quietHours) {
396
+ if (!quietHours) return false;
397
+ const { startMinute, endMinute } = quietHours;
398
+ if (startMinute === endMinute) return false;
399
+ return startMinute < endMinute ? minuteOfDay >= startMinute && minuteOfDay < endMinute : minuteOfDay >= startMinute || minuteOfDay < endMinute;
400
+ }
370
401
  export {
371
402
  ACHIEVEMENT_CATEGORIES,
372
403
  ACHIEVEMENT_DEFINITIONS,
@@ -386,11 +417,13 @@ export {
386
417
  MEASURABLE_GOALS_MAX,
387
418
  MEASURABLE_GOAL_DIRECTIONS,
388
419
  MEASURABLE_GOAL_TYPES,
420
+ MINUTES_IN_DAY,
389
421
  MOVEMENT_PATTERNS,
390
422
  MUSCLE_GROUPS,
391
423
  NOTIFICATIONS_LIST_LIMIT,
392
424
  NOTIFICATIONS_LOOKBACK_DAYS,
393
425
  NOTIFICATIONS_RETENTION_DAYS,
426
+ NOTIFICATION_CATEGORIES,
394
427
  NOTIFICATION_KINDS,
395
428
  PLATEAU_MIN_DAYS_SINCE_BEST,
396
429
  PLATEAU_MIN_SESSIONS,
@@ -407,12 +440,17 @@ export {
407
440
  PROFILE_VISIBILITY_VALUES,
408
441
  PROGRESSION_SCHEMES,
409
442
  PROGRESS_TIMELINE_EVENT_TYPES,
443
+ PUSH_PAYLOAD_KINDS,
444
+ PUSH_SUBSCRIPTIONS_MAX,
410
445
  RELATIONSHIP_LIST_DEFAULT_LIMIT,
411
446
  RELATIONSHIP_LIST_KINDS,
412
447
  RELATIONSHIP_LIST_MAX_LIMIT,
413
448
  RENAISSANCE_RANK_DEFINITIONS,
414
449
  REP_TYPES,
415
450
  RESERVED_USERNAMES,
451
+ REST_ALERT_MAX_LEAD_SECONDS,
452
+ REST_ALERT_MIN_LEAD_SECONDS,
453
+ REST_ALERT_REFUSALS,
416
454
  ROUTINE_DAYS_MAX,
417
455
  ROUTINE_DAY_NAME_MAX,
418
456
  ROUTINE_SCHEDULE_MODES,
@@ -437,5 +475,6 @@ export {
437
475
  USERNAME_PATTERN_SOURCE,
438
476
  WEIGHT_UNITS,
439
477
  WORKOUT_SESSION_STATUSES,
478
+ isWithinQuietHours,
440
479
  routineDayLabel
441
480
  };
package/package.json CHANGED
@@ -1,40 +1,40 @@
1
- {
2
- "name": "@sunsteel/contracts",
3
- "version": "0.45.0",
4
- "repository": {
5
- "type": "git",
6
- "url": "git+https://github.com/ezee969/sunsteel-contracts.git"
7
- },
8
- "private": false,
9
- "engines": {
10
- "node": ">=20.11"
11
- },
12
- "type": "module",
13
- "sideEffects": false,
14
- "main": "./dist/index.cjs",
15
- "module": "./dist/index.js",
16
- "types": "./dist/index.d.ts",
17
- "exports": {
18
- ".": {
19
- "types": "./dist/index.d.ts",
20
- "import": "./dist/index.js",
21
- "require": "./dist/index.cjs"
22
- }
23
- },
24
- "files": [
25
- "dist"
26
- ],
27
- "scripts": {
28
- "build": "tsup src/index.ts --format esm,cjs --dts --clean",
29
- "dev": "tsup src/index.ts --format esm,cjs --dts --watch",
30
- "typecheck": "tsc --noEmit",
31
- "lint": "npm run typecheck",
32
- "verify": "npm run typecheck && npm run build",
33
- "verify:security": "npm audit",
34
- "prepublishOnly": "npm run build"
35
- },
36
- "devDependencies": {
37
- "tsup": "^8.3.5",
38
- "typescript": "^5.7.3"
39
- }
40
- }
1
+ {
2
+ "name": "@sunsteel/contracts",
3
+ "version": "0.47.0",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/ezee969/sunsteel-contracts.git"
7
+ },
8
+ "private": false,
9
+ "engines": {
10
+ "node": ">=20.11"
11
+ },
12
+ "type": "module",
13
+ "sideEffects": false,
14
+ "main": "./dist/index.cjs",
15
+ "module": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js",
21
+ "require": "./dist/index.cjs"
22
+ }
23
+ },
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "scripts": {
28
+ "build": "tsup src/index.ts --format esm,cjs --dts --clean",
29
+ "dev": "tsup src/index.ts --format esm,cjs --dts --watch",
30
+ "typecheck": "tsc --noEmit",
31
+ "lint": "npm run typecheck",
32
+ "verify": "npm run typecheck && npm run build",
33
+ "verify:security": "npm audit",
34
+ "prepublishOnly": "npm run build"
35
+ },
36
+ "devDependencies": {
37
+ "tsup": "^8.3.5",
38
+ "typescript": "^5.7.3"
39
+ }
40
+ }