@shaxpir/duiduidui-models 1.37.0 → 1.37.3

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.
@@ -68,6 +68,18 @@ export declare class Billing extends Content {
68
68
  isActive(): boolean;
69
69
  isTrialing(): boolean;
70
70
  isLifetimeFree(): boolean;
71
+ /**
72
+ * Client-side belt-and-suspenders check: returns true if the billing doc
73
+ * has an expires_at in the past, regardless of what subscription_status says.
74
+ * This catches the window between actual expiry and the server sweep updating the status.
75
+ */
76
+ isExpiredLocally(): boolean;
77
+ /**
78
+ * Returns the number of days remaining until expiry as a float, or null if no expiry is set.
79
+ * Returns 0 if already expired. The float value allows granular display
80
+ * (e.g., hours/minutes remaining on the last day).
81
+ */
82
+ daysRemaining(): number | null;
71
83
  /**
72
84
  * Check whether the user has an active (non-expired) grant for the given feature flag.
73
85
  */
@@ -86,6 +86,29 @@ class Billing extends Content_1.Content {
86
86
  isLifetimeFree() {
87
87
  return this.subscriptionSource === 'lifetime_free';
88
88
  }
89
+ /**
90
+ * Client-side belt-and-suspenders check: returns true if the billing doc
91
+ * has an expires_at in the past, regardless of what subscription_status says.
92
+ * This catches the window between actual expiry and the server sweep updating the status.
93
+ */
94
+ isExpiredLocally() {
95
+ const expiresAt = this.expiresAt;
96
+ if (!expiresAt)
97
+ return false;
98
+ const now = shaxpir_common_1.ClockService.getClock().utc();
99
+ return shaxpir_common_1.Time.isDateTimeBefore(expiresAt, now);
100
+ }
101
+ /**
102
+ * Returns the number of days remaining until expiry as a float, or null if no expiry is set.
103
+ * Returns 0 if already expired. The float value allows granular display
104
+ * (e.g., hours/minutes remaining on the last day).
105
+ */
106
+ daysRemaining() {
107
+ const expiresAt = this.expiresAt;
108
+ if (!expiresAt)
109
+ return null;
110
+ return Math.max(0, shaxpir_common_1.Time.timeUntil(expiresAt, 'day'));
111
+ }
89
112
  /**
90
113
  * Check whether the user has an active (non-expired) grant for the given feature flag.
91
114
  */
@@ -14,7 +14,14 @@ exports.Condition = {
14
14
  gradeD: () => ({ type: 'grade', grade: 'D' }),
15
15
  gradeF: () => ({ type: 'grade', grade: 'F' }),
16
16
  // Theta conditions
17
- theta: (min, max) => ({ type: 'theta', min, max }),
17
+ theta: (min, max) => {
18
+ const c = { type: 'theta' };
19
+ if (min !== undefined)
20
+ c.min = min;
21
+ if (max !== undefined)
22
+ c.max = max;
23
+ return c;
24
+ },
18
25
  learningZone: () => ({ type: 'theta', min: 0.4, max: 0.6 }),
19
26
  struggling: () => ({ type: 'theta', max: 0.3 }),
20
27
  nearMastery: () => ({ type: 'theta', min: 0.7, max: 0.8 }),
@@ -33,7 +40,14 @@ exports.Condition = {
33
40
  starred: () => ({ type: 'starred', value: true }),
34
41
  notStarred: () => ({ type: 'starred', value: false }),
35
42
  // Difficulty conditions
36
- difficulty: (min, max) => ({ type: 'difficulty', min, max }),
43
+ difficulty: (min, max) => {
44
+ const c = { type: 'difficulty' };
45
+ if (min !== undefined)
46
+ c.min = min;
47
+ if (max !== undefined)
48
+ c.max = max;
49
+ return c;
50
+ },
37
51
  beginner: () => ({ type: 'difficulty', max: 100 }), // Very easy content
38
52
  elementary: () => ({ type: 'difficulty', min: 100, max: 500 }), // Easy
39
53
  intermediate: () => ({ type: 'difficulty', min: 500, max: 1500 }), // Medium
@@ -63,7 +63,7 @@ export declare class Device extends Content {
63
63
  setReviewAutoPlaySpeech(value: boolean): void;
64
64
  setReviewCardLimit(value: number | null): void;
65
65
  setReviewChallenge(value: ChallengeLevel): void;
66
- setReviewCollection(value: string | undefined): void;
66
+ setReviewCollection(value: string | null): void;
67
67
  get reviewCustomConditions(): Conditions;
68
68
  setReviewCustomConditions(value: Conditions): void;
69
69
  getBuiltInDbState(): BuiltInDbState | undefined;
@@ -114,7 +114,12 @@ class Device extends Content_1.Content {
114
114
  setReviewCollection(value) {
115
115
  this.checkDisposed("Device.setReviewCollection");
116
116
  const batch = new Operation_1.BatchOperation(this);
117
- batch.setPathValue(['payload', 'review_config', 'selection', 'collection'], value);
117
+ if (value) {
118
+ batch.setPathValue(['payload', 'review_config', 'selection', 'collection'], value);
119
+ }
120
+ else {
121
+ batch.removeValueAtPath(['payload', 'review_config', 'selection', 'collection']);
122
+ }
118
123
  batch.commit();
119
124
  }
120
125
  // Review Custom Conditions (for Custom mode)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shaxpir/duiduidui-models",
3
- "version": "1.37.0",
3
+ "version": "1.37.3",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/shaxpir/duiduidui-models"