@sunsteel/contracts 0.46.0 → 0.48.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,
@@ -85,6 +87,7 @@ __export(index_exports, {
85
87
  SESSION_SHARE_MAX_ACTIVE_LINKS: () => SESSION_SHARE_MAX_ACTIVE_LINKS,
86
88
  SEXES: () => SEXES,
87
89
  STARRED_EXERCISES_MAX: () => STARRED_EXERCISES_MAX,
90
+ STREAK_MAX_GAP_DAYS: () => STREAK_MAX_GAP_DAYS,
88
91
  TRAINING_DISCIPLINE_VALUES: () => TRAINING_DISCIPLINE_VALUES,
89
92
  TRAINING_EVENT_TYPES: () => TRAINING_EVENT_TYPES,
90
93
  TRAINING_EXPERIENCE_LEVEL_VALUES: () => TRAINING_EXPERIENCE_LEVEL_VALUES,
@@ -94,6 +97,7 @@ __export(index_exports, {
94
97
  USERNAME_PATTERN_SOURCE: () => USERNAME_PATTERN_SOURCE,
95
98
  WEIGHT_UNITS: () => WEIGHT_UNITS,
96
99
  WORKOUT_SESSION_STATUSES: () => WORKOUT_SESSION_STATUSES,
100
+ isWithinQuietHours: () => isWithinQuietHours,
97
101
  routineDayLabel: () => routineDayLabel
98
102
  });
99
103
  module.exports = __toCommonJS(index_exports);
@@ -470,7 +474,11 @@ var NOTIFICATIONS_LIST_LIMIT = 50;
470
474
 
471
475
  // src/push.ts
472
476
  var PUSH_SUBSCRIPTIONS_MAX = 10;
473
- var PUSH_PAYLOAD_KINDS = ["REST_ALERT"];
477
+ var PUSH_PAYLOAD_KINDS = [
478
+ "REST_ALERT",
479
+ "TRAINING_REMINDER",
480
+ "STREAK_AT_RISK"
481
+ ];
474
482
  var REST_ALERT_MAX_LEAD_SECONDS = 3600;
475
483
  var REST_ALERT_MIN_LEAD_SECONDS = 5;
476
484
  var REST_ALERT_REFUSALS = [
@@ -479,8 +487,27 @@ var REST_ALERT_REFUSALS = [
479
487
  /** The server holds no VAPID key pair. */
480
488
  "PUSH_UNAVAILABLE",
481
489
  /** Rest ends too soon for a push to beat it. */
482
- "TOO_SOON"
490
+ "TOO_SOON",
491
+ /** NOTIF-05: the owner switched rest alerts off. */
492
+ "CATEGORY_OFF",
493
+ /** NOTIF-05: rest would end inside the owner's quiet hours. */
494
+ "QUIET_HOURS"
495
+ ];
496
+
497
+ // src/notification-preferences.ts
498
+ var NOTIFICATION_CATEGORIES = [
499
+ "REST_ALERT",
500
+ "TRAINING_REMINDER",
501
+ "STREAK_AT_RISK"
483
502
  ];
503
+ var MINUTES_IN_DAY = 1440;
504
+ function isWithinQuietHours(minuteOfDay, quietHours) {
505
+ if (!quietHours) return false;
506
+ const { startMinute, endMinute } = quietHours;
507
+ if (startMinute === endMinute) return false;
508
+ return startMinute < endMinute ? minuteOfDay >= startMinute && minuteOfDay < endMinute : minuteOfDay >= startMinute || minuteOfDay < endMinute;
509
+ }
510
+ var STREAK_MAX_GAP_DAYS = 3;
484
511
  // Annotate the CommonJS export names for ESM import in node:
485
512
  0 && (module.exports = {
486
513
  ACHIEVEMENT_CATEGORIES,
@@ -501,11 +528,13 @@ var REST_ALERT_REFUSALS = [
501
528
  MEASURABLE_GOALS_MAX,
502
529
  MEASURABLE_GOAL_DIRECTIONS,
503
530
  MEASURABLE_GOAL_TYPES,
531
+ MINUTES_IN_DAY,
504
532
  MOVEMENT_PATTERNS,
505
533
  MUSCLE_GROUPS,
506
534
  NOTIFICATIONS_LIST_LIMIT,
507
535
  NOTIFICATIONS_LOOKBACK_DAYS,
508
536
  NOTIFICATIONS_RETENTION_DAYS,
537
+ NOTIFICATION_CATEGORIES,
509
538
  NOTIFICATION_KINDS,
510
539
  PLATEAU_MIN_DAYS_SINCE_BEST,
511
540
  PLATEAU_MIN_SESSIONS,
@@ -548,6 +577,7 @@ var REST_ALERT_REFUSALS = [
548
577
  SESSION_SHARE_MAX_ACTIVE_LINKS,
549
578
  SEXES,
550
579
  STARRED_EXERCISES_MAX,
580
+ STREAK_MAX_GAP_DAYS,
551
581
  TRAINING_DISCIPLINE_VALUES,
552
582
  TRAINING_EVENT_TYPES,
553
583
  TRAINING_EXPERIENCE_LEVEL_VALUES,
@@ -557,5 +587,6 @@ var REST_ALERT_REFUSALS = [
557
587
  USERNAME_PATTERN_SOURCE,
558
588
  WEIGHT_UNITS,
559
589
  WORKOUT_SESSION_STATUSES,
590
+ isWithinQuietHours,
560
591
  routineDayLabel
561
592
  });
package/dist/index.d.cts CHANGED
@@ -1539,7 +1539,7 @@ interface DeletePushSubscriptionRequest {
1539
1539
  * What a delivered push asks the service worker to show. `kind` exists so the
1540
1540
  * worker can branch without guessing from the copy.
1541
1541
  */
1542
- declare const PUSH_PAYLOAD_KINDS: readonly ["REST_ALERT"];
1542
+ declare const PUSH_PAYLOAD_KINDS: readonly ["REST_ALERT", "TRAINING_REMINDER", "STREAK_AT_RISK"];
1543
1543
  type PushPayloadKind = (typeof PUSH_PAYLOAD_KINDS)[number];
1544
1544
  interface RestAlertPushPayload {
1545
1545
  kind: 'REST_ALERT';
@@ -1555,7 +1555,27 @@ interface RestAlertPushPayload {
1555
1555
  /** Collapses an older alert for the same session instead of stacking. */
1556
1556
  tag: string;
1557
1557
  }
1558
- type PushPayload = RestAlertPushPayload;
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
+ /**
1567
+ * NOTIF-06. Sent on the last day a run can still be saved, in place of that
1568
+ * day's reminder rather than beside it. It states the evidence and never
1569
+ * instructs anyone to train: a rest day ending a streak is the plan working.
1570
+ */
1571
+ interface StreakAtRiskPushPayload {
1572
+ kind: 'STREAK_AT_RISK';
1573
+ title: string;
1574
+ body: string;
1575
+ url: string;
1576
+ tag: string;
1577
+ }
1578
+ type PushPayload = RestAlertPushPayload | TrainingReminderPushPayload | StreakAtRiskPushPayload;
1559
1579
  /** A rest alert is refused beyond this far ahead. */
1560
1580
  declare const REST_ALERT_MAX_LEAD_SECONDS = 3600;
1561
1581
  /**
@@ -1580,7 +1600,91 @@ interface ScheduleRestAlertResponse {
1580
1600
  scheduledFor: IsoDateString | null;
1581
1601
  reason: RestAlertRefusal | null;
1582
1602
  }
1583
- declare const REST_ALERT_REFUSALS: readonly ["NO_SUBSCRIPTION", "PUSH_UNAVAILABLE", "TOO_SOON"];
1603
+ declare const REST_ALERT_REFUSALS: readonly ["NO_SUBSCRIPTION", "PUSH_UNAVAILABLE", "TOO_SOON", "CATEGORY_OFF", "QUIET_HOURS"];
1584
1604
  type RestAlertRefusal = (typeof REST_ALERT_REFUSALS)[number];
1585
1605
 
1586
- 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, 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, PUSH_PAYLOAD_KINDS, PUSH_SUBSCRIPTIONS_MAX, 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, type PushPayload, type PushPayloadKind, type PushSubscriptionKeys, type PushSubscriptionSummary, type PushSubscriptionsResponse, 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, 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 };
1606
+ /**
1607
+ * What a notification can be about. Every delivered payload names one, and an
1608
+ * owner can switch each off independently.
1609
+ *
1610
+ * There is deliberately no "channel" axis beside this. Web Push is the only
1611
+ * delivery channel that exists, so a channel switch would be the same switch
1612
+ * twice; the NOTIF-01 centre is gathered on read rather than delivered, and is
1613
+ * not something to turn off.
1614
+ */
1615
+ declare const NOTIFICATION_CATEGORIES: readonly ["REST_ALERT", "TRAINING_REMINDER", "STREAK_AT_RISK"];
1616
+ type NotificationCategory = (typeof NOTIFICATION_CATEGORIES)[number];
1617
+ /**
1618
+ * A local-clock window in which nothing is delivered, as minutes from
1619
+ * midnight. It may wrap past midnight (22:00 to 07:00 is `1320` to `420`),
1620
+ * which is the normal case, so a plain `start <= x < end` test is wrong.
1621
+ */
1622
+ interface QuietHours {
1623
+ startMinute: number;
1624
+ endMinute: number;
1625
+ }
1626
+ declare const MINUTES_IN_DAY = 1440;
1627
+ /** True when a local minute-of-day falls inside the window, wrap included. */
1628
+ declare function isWithinQuietHours(minuteOfDay: number, quietHours: QuietHours | null): boolean;
1629
+ /**
1630
+ * NOTIF-04's reminder time, as minutes from local midnight.
1631
+ *
1632
+ * It is a time of day, not a lead time before a session, because the product
1633
+ * does not know what hour anyone trains: a routine day carries a weekday and
1634
+ * nothing stores an intended start. Counting back from a session would mean
1635
+ * inventing the session's hour.
1636
+ */
1637
+ interface TrainingReminderPreference {
1638
+ /** Null switches reminders off without discarding the chosen time. */
1639
+ minuteOfDay: number | null;
1640
+ }
1641
+ /**
1642
+ * NOTIF-06. A streak survives a gap of `STREAK_MAX_GAP_DAYS` and dies on the
1643
+ * next day, so "at risk" is not a judgement: it is the last local date that
1644
+ * can still save the run. The rule lives here because both halves of the
1645
+ * product state it.
1646
+ */
1647
+ declare const STREAK_MAX_GAP_DAYS = 3;
1648
+ interface NotificationPreferences {
1649
+ /** Every category, so a client never has to assume a default. */
1650
+ categories: Record<NotificationCategory, boolean>;
1651
+ quietHours: QuietHours | null;
1652
+ reminder: TrainingReminderPreference;
1653
+ /**
1654
+ * The zone every local rule above is evaluated in. Read-only here; it is
1655
+ * owned by `PUT /users/time-zone` and registered by the device.
1656
+ */
1657
+ timeZone: string | null;
1658
+ }
1659
+ /** PUT /notifications/preferences. Every field is optional and partial. */
1660
+ interface UpdateNotificationPreferencesRequest {
1661
+ categories?: Partial<Record<NotificationCategory, boolean>>;
1662
+ /** Null clears the window; omitting it leaves the stored one alone. */
1663
+ quietHours?: QuietHours | null;
1664
+ reminder?: TrainingReminderPreference;
1665
+ }
1666
+ /**
1667
+ * GET /notifications/preferences
1668
+ *
1669
+ * Carries the delivery state beside the preferences so one read answers both
1670
+ * "what did I choose" and "can any of it actually reach me" — a category left
1671
+ * on while no device is subscribed would otherwise read as working.
1672
+ */
1673
+ interface NotificationPreferencesResponse {
1674
+ preferences: NotificationPreferences;
1675
+ /** False when the account has no subscribed device. */
1676
+ hasSubscribedDevice: boolean;
1677
+ /** False when the server holds no VAPID key pair. */
1678
+ pushAvailable: boolean;
1679
+ }
1680
+ /**
1681
+ * A reminder is planned for a whole local date, not a session: the schedule
1682
+ * knows which days an account trains, never at what hour.
1683
+ */
1684
+ interface PlannedReminder {
1685
+ date: CalendarDate;
1686
+ /** The routines planned that day, named in the notification. */
1687
+ routineNames: string[];
1688
+ }
1689
+
1690
+ 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, STREAK_MAX_GAP_DAYS, 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 StreakAtRiskPushPayload, 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
@@ -1539,7 +1539,7 @@ interface DeletePushSubscriptionRequest {
1539
1539
  * What a delivered push asks the service worker to show. `kind` exists so the
1540
1540
  * worker can branch without guessing from the copy.
1541
1541
  */
1542
- declare const PUSH_PAYLOAD_KINDS: readonly ["REST_ALERT"];
1542
+ declare const PUSH_PAYLOAD_KINDS: readonly ["REST_ALERT", "TRAINING_REMINDER", "STREAK_AT_RISK"];
1543
1543
  type PushPayloadKind = (typeof PUSH_PAYLOAD_KINDS)[number];
1544
1544
  interface RestAlertPushPayload {
1545
1545
  kind: 'REST_ALERT';
@@ -1555,7 +1555,27 @@ interface RestAlertPushPayload {
1555
1555
  /** Collapses an older alert for the same session instead of stacking. */
1556
1556
  tag: string;
1557
1557
  }
1558
- type PushPayload = RestAlertPushPayload;
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
+ /**
1567
+ * NOTIF-06. Sent on the last day a run can still be saved, in place of that
1568
+ * day's reminder rather than beside it. It states the evidence and never
1569
+ * instructs anyone to train: a rest day ending a streak is the plan working.
1570
+ */
1571
+ interface StreakAtRiskPushPayload {
1572
+ kind: 'STREAK_AT_RISK';
1573
+ title: string;
1574
+ body: string;
1575
+ url: string;
1576
+ tag: string;
1577
+ }
1578
+ type PushPayload = RestAlertPushPayload | TrainingReminderPushPayload | StreakAtRiskPushPayload;
1559
1579
  /** A rest alert is refused beyond this far ahead. */
1560
1580
  declare const REST_ALERT_MAX_LEAD_SECONDS = 3600;
1561
1581
  /**
@@ -1580,7 +1600,91 @@ interface ScheduleRestAlertResponse {
1580
1600
  scheduledFor: IsoDateString | null;
1581
1601
  reason: RestAlertRefusal | null;
1582
1602
  }
1583
- declare const REST_ALERT_REFUSALS: readonly ["NO_SUBSCRIPTION", "PUSH_UNAVAILABLE", "TOO_SOON"];
1603
+ declare const REST_ALERT_REFUSALS: readonly ["NO_SUBSCRIPTION", "PUSH_UNAVAILABLE", "TOO_SOON", "CATEGORY_OFF", "QUIET_HOURS"];
1584
1604
  type RestAlertRefusal = (typeof REST_ALERT_REFUSALS)[number];
1585
1605
 
1586
- 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, 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, PUSH_PAYLOAD_KINDS, PUSH_SUBSCRIPTIONS_MAX, 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, type PushPayload, type PushPayloadKind, type PushSubscriptionKeys, type PushSubscriptionSummary, type PushSubscriptionsResponse, 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, 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 };
1606
+ /**
1607
+ * What a notification can be about. Every delivered payload names one, and an
1608
+ * owner can switch each off independently.
1609
+ *
1610
+ * There is deliberately no "channel" axis beside this. Web Push is the only
1611
+ * delivery channel that exists, so a channel switch would be the same switch
1612
+ * twice; the NOTIF-01 centre is gathered on read rather than delivered, and is
1613
+ * not something to turn off.
1614
+ */
1615
+ declare const NOTIFICATION_CATEGORIES: readonly ["REST_ALERT", "TRAINING_REMINDER", "STREAK_AT_RISK"];
1616
+ type NotificationCategory = (typeof NOTIFICATION_CATEGORIES)[number];
1617
+ /**
1618
+ * A local-clock window in which nothing is delivered, as minutes from
1619
+ * midnight. It may wrap past midnight (22:00 to 07:00 is `1320` to `420`),
1620
+ * which is the normal case, so a plain `start <= x < end` test is wrong.
1621
+ */
1622
+ interface QuietHours {
1623
+ startMinute: number;
1624
+ endMinute: number;
1625
+ }
1626
+ declare const MINUTES_IN_DAY = 1440;
1627
+ /** True when a local minute-of-day falls inside the window, wrap included. */
1628
+ declare function isWithinQuietHours(minuteOfDay: number, quietHours: QuietHours | null): boolean;
1629
+ /**
1630
+ * NOTIF-04's reminder time, as minutes from local midnight.
1631
+ *
1632
+ * It is a time of day, not a lead time before a session, because the product
1633
+ * does not know what hour anyone trains: a routine day carries a weekday and
1634
+ * nothing stores an intended start. Counting back from a session would mean
1635
+ * inventing the session's hour.
1636
+ */
1637
+ interface TrainingReminderPreference {
1638
+ /** Null switches reminders off without discarding the chosen time. */
1639
+ minuteOfDay: number | null;
1640
+ }
1641
+ /**
1642
+ * NOTIF-06. A streak survives a gap of `STREAK_MAX_GAP_DAYS` and dies on the
1643
+ * next day, so "at risk" is not a judgement: it is the last local date that
1644
+ * can still save the run. The rule lives here because both halves of the
1645
+ * product state it.
1646
+ */
1647
+ declare const STREAK_MAX_GAP_DAYS = 3;
1648
+ interface NotificationPreferences {
1649
+ /** Every category, so a client never has to assume a default. */
1650
+ categories: Record<NotificationCategory, boolean>;
1651
+ quietHours: QuietHours | null;
1652
+ reminder: TrainingReminderPreference;
1653
+ /**
1654
+ * The zone every local rule above is evaluated in. Read-only here; it is
1655
+ * owned by `PUT /users/time-zone` and registered by the device.
1656
+ */
1657
+ timeZone: string | null;
1658
+ }
1659
+ /** PUT /notifications/preferences. Every field is optional and partial. */
1660
+ interface UpdateNotificationPreferencesRequest {
1661
+ categories?: Partial<Record<NotificationCategory, boolean>>;
1662
+ /** Null clears the window; omitting it leaves the stored one alone. */
1663
+ quietHours?: QuietHours | null;
1664
+ reminder?: TrainingReminderPreference;
1665
+ }
1666
+ /**
1667
+ * GET /notifications/preferences
1668
+ *
1669
+ * Carries the delivery state beside the preferences so one read answers both
1670
+ * "what did I choose" and "can any of it actually reach me" — a category left
1671
+ * on while no device is subscribed would otherwise read as working.
1672
+ */
1673
+ interface NotificationPreferencesResponse {
1674
+ preferences: NotificationPreferences;
1675
+ /** False when the account has no subscribed device. */
1676
+ hasSubscribedDevice: boolean;
1677
+ /** False when the server holds no VAPID key pair. */
1678
+ pushAvailable: boolean;
1679
+ }
1680
+ /**
1681
+ * A reminder is planned for a whole local date, not a session: the schedule
1682
+ * knows which days an account trains, never at what hour.
1683
+ */
1684
+ interface PlannedReminder {
1685
+ date: CalendarDate;
1686
+ /** The routines planned that day, named in the notification. */
1687
+ routineNames: string[];
1688
+ }
1689
+
1690
+ 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, STREAK_MAX_GAP_DAYS, 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 StreakAtRiskPushPayload, 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
@@ -370,7 +370,11 @@ var NOTIFICATIONS_LIST_LIMIT = 50;
370
370
 
371
371
  // src/push.ts
372
372
  var PUSH_SUBSCRIPTIONS_MAX = 10;
373
- var PUSH_PAYLOAD_KINDS = ["REST_ALERT"];
373
+ var PUSH_PAYLOAD_KINDS = [
374
+ "REST_ALERT",
375
+ "TRAINING_REMINDER",
376
+ "STREAK_AT_RISK"
377
+ ];
374
378
  var REST_ALERT_MAX_LEAD_SECONDS = 3600;
375
379
  var REST_ALERT_MIN_LEAD_SECONDS = 5;
376
380
  var REST_ALERT_REFUSALS = [
@@ -379,8 +383,27 @@ var REST_ALERT_REFUSALS = [
379
383
  /** The server holds no VAPID key pair. */
380
384
  "PUSH_UNAVAILABLE",
381
385
  /** Rest ends too soon for a push to beat it. */
382
- "TOO_SOON"
386
+ "TOO_SOON",
387
+ /** NOTIF-05: the owner switched rest alerts off. */
388
+ "CATEGORY_OFF",
389
+ /** NOTIF-05: rest would end inside the owner's quiet hours. */
390
+ "QUIET_HOURS"
391
+ ];
392
+
393
+ // src/notification-preferences.ts
394
+ var NOTIFICATION_CATEGORIES = [
395
+ "REST_ALERT",
396
+ "TRAINING_REMINDER",
397
+ "STREAK_AT_RISK"
383
398
  ];
399
+ var MINUTES_IN_DAY = 1440;
400
+ function isWithinQuietHours(minuteOfDay, quietHours) {
401
+ if (!quietHours) return false;
402
+ const { startMinute, endMinute } = quietHours;
403
+ if (startMinute === endMinute) return false;
404
+ return startMinute < endMinute ? minuteOfDay >= startMinute && minuteOfDay < endMinute : minuteOfDay >= startMinute || minuteOfDay < endMinute;
405
+ }
406
+ var STREAK_MAX_GAP_DAYS = 3;
384
407
  export {
385
408
  ACHIEVEMENT_CATEGORIES,
386
409
  ACHIEVEMENT_DEFINITIONS,
@@ -400,11 +423,13 @@ export {
400
423
  MEASURABLE_GOALS_MAX,
401
424
  MEASURABLE_GOAL_DIRECTIONS,
402
425
  MEASURABLE_GOAL_TYPES,
426
+ MINUTES_IN_DAY,
403
427
  MOVEMENT_PATTERNS,
404
428
  MUSCLE_GROUPS,
405
429
  NOTIFICATIONS_LIST_LIMIT,
406
430
  NOTIFICATIONS_LOOKBACK_DAYS,
407
431
  NOTIFICATIONS_RETENTION_DAYS,
432
+ NOTIFICATION_CATEGORIES,
408
433
  NOTIFICATION_KINDS,
409
434
  PLATEAU_MIN_DAYS_SINCE_BEST,
410
435
  PLATEAU_MIN_SESSIONS,
@@ -447,6 +472,7 @@ export {
447
472
  SESSION_SHARE_MAX_ACTIVE_LINKS,
448
473
  SEXES,
449
474
  STARRED_EXERCISES_MAX,
475
+ STREAK_MAX_GAP_DAYS,
450
476
  TRAINING_DISCIPLINE_VALUES,
451
477
  TRAINING_EVENT_TYPES,
452
478
  TRAINING_EXPERIENCE_LEVEL_VALUES,
@@ -456,5 +482,6 @@ export {
456
482
  USERNAME_PATTERN_SOURCE,
457
483
  WEIGHT_UNITS,
458
484
  WORKOUT_SESSION_STATUSES,
485
+ isWithinQuietHours,
459
486
  routineDayLabel
460
487
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sunsteel/contracts",
3
- "version": "0.46.0",
3
+ "version": "0.48.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/ezee969/sunsteel-contracts.git"