@forcecalendar/core 1.0.4 → 1.0.6

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.
@@ -15,8 +15,8 @@ export class Calendar {
15
15
  * @param {import('../../types.js').CalendarConfig} [config={}] - Configuration options
16
16
  */
17
17
  constructor(config = {}) {
18
- // Initialize timezone manager first
19
- this.timezoneManager = new TimezoneManager();
18
+ // Initialize timezone manager first (use singleton to share cache)
19
+ this.timezoneManager = TimezoneManager.getInstance();
20
20
 
21
21
  // Initialize configuration
22
22
  this.config = {
@@ -37,8 +37,9 @@ export class DateUtils {
37
37
  const day = result.getDay();
38
38
  const diff = (day < weekStartsOn ? 7 : 0) + day - weekStartsOn;
39
39
 
40
- // Use setTime to handle month/year boundaries correctly
41
- result.setTime(result.getTime() - (diff * 24 * 60 * 60 * 1000));
40
+ // Use setDate() to handle DST transitions correctly
41
+ // (millisecond arithmetic fails when days are 23 or 25 hours)
42
+ result.setDate(result.getDate() - diff);
42
43
  result.setHours(0, 0, 0, 0);
43
44
  return result;
44
45
  }
@@ -51,8 +52,9 @@ export class DateUtils {
51
52
  */
52
53
  static endOfWeek(date, weekStartsOn = 0) {
53
54
  const result = DateUtils.startOfWeek(date, weekStartsOn);
54
- // Use setTime to handle month/year boundaries correctly
55
- result.setTime(result.getTime() + (6 * 24 * 60 * 60 * 1000));
55
+ // Use setDate() to handle DST transitions correctly
56
+ // (millisecond arithmetic fails when days are 23 or 25 hours)
57
+ result.setDate(result.getDate() + 6);
56
58
  result.setHours(23, 59, 59, 999);
57
59
  return result;
58
60
  }
@@ -101,8 +103,9 @@ export class DateUtils {
101
103
  */
102
104
  static addDays(date, days) {
103
105
  const result = new Date(date);
104
- // Use setTime to handle month/year boundaries correctly
105
- result.setTime(result.getTime() + (days * 24 * 60 * 60 * 1000));
106
+ // Use setDate() to handle DST transitions correctly
107
+ // (millisecond arithmetic fails when days are 23 or 25 hours)
108
+ result.setDate(result.getDate() + days);
106
109
  return result;
107
110
  }
108
111
 
@@ -402,8 +405,9 @@ export class DateUtils {
402
405
 
403
406
  while (current.getTime() <= endTime) {
404
407
  dates.push(new Date(current));
405
- // Use setTime to handle month/year boundaries correctly
406
- current.setTime(current.getTime() + (24 * 60 * 60 * 1000));
408
+ // Use setDate() to handle DST transitions correctly
409
+ // (millisecond arithmetic fails when days are 23 or 25 hours)
410
+ current.setDate(current.getDate() + 1);
407
411
  }
408
412
 
409
413
  return dates;
@@ -221,8 +221,9 @@ export class Event {
221
221
  this.id = normalized.id;
222
222
  this.title = normalized.title;
223
223
 
224
- // Initialize timezone manager
225
- this._timezoneManager = new TimezoneManager();
224
+ // Use shared timezone manager singleton to avoid memory bloat
225
+ // (previously each Event created its own TimezoneManager instance)
226
+ this._timezoneManager = TimezoneManager.getInstance();
226
227
 
227
228
  // Timezone handling
228
229
  // Store the timezone the event was created in (wall-clock time)
@@ -30,8 +30,8 @@ export class EventStore {
30
30
  byStatus: new Map()
31
31
  };
32
32
 
33
- // Timezone manager for conversions
34
- this.timezoneManager = new TimezoneManager();
33
+ // Timezone manager for conversions (use singleton to share cache)
34
+ this.timezoneManager = TimezoneManager.getInstance();
35
35
 
36
36
  // Default timezone for the store (can be overridden)
37
37
  this.defaultTimezone = config.timezone || this.timezoneManager.getSystemTimezone();
@@ -367,7 +367,8 @@ export class EventStore {
367
367
  // Collect all events from those dates
368
368
  const checkedIds = new Set();
369
369
  dates.forEach(date => {
370
- const dateStr = date.toDateString();
370
+ // Use getLocalDateString to match the index key format (YYYY-MM-DD)
371
+ const dateStr = DateUtils.getLocalDateString(date);
371
372
  const eventIds = this.indices.byDate.get(dateStr) || new Set();
372
373
 
373
374
  eventIds.forEach(id => {
@@ -25,7 +25,7 @@ export class RecurrenceEngine {
25
25
  const occurrences = [];
26
26
  const duration = event.end - event.start;
27
27
  const eventTimezone = timezone || event.timeZone || 'UTC';
28
- const tzManager = new TimezoneManager();
28
+ const tzManager = TimezoneManager.getInstance();
29
29
 
30
30
  // Work in event's timezone for accurate recurrence calculation
31
31
  let currentDate = new Date(event.start);
@@ -8,7 +8,8 @@ import { RRuleParser } from './RRuleParser.js';
8
8
 
9
9
  export class RecurrenceEngineV2 {
10
10
  constructor() {
11
- this.tzManager = new TimezoneManager();
11
+ // Use singleton to share cache across all components
12
+ this.tzManager = TimezoneManager.getInstance();
12
13
 
13
14
  // Cache for expanded occurrences
14
15
  this.occurrenceCache = new Map();
@@ -7,7 +7,33 @@
7
7
 
8
8
  import { TimezoneDatabase } from './TimezoneDatabase.js';
9
9
 
10
+ // Singleton instance for shared use across the application
11
+ let sharedInstance = null;
12
+
10
13
  export class TimezoneManager {
14
+ /**
15
+ * Get the shared singleton instance of TimezoneManager
16
+ * This should be used instead of creating new instances to avoid memory bloat
17
+ * @returns {TimezoneManager} The shared instance
18
+ */
19
+ static getInstance() {
20
+ if (!sharedInstance) {
21
+ sharedInstance = new TimezoneManager();
22
+ }
23
+ return sharedInstance;
24
+ }
25
+
26
+ /**
27
+ * Reset the singleton instance (useful for testing)
28
+ * @private
29
+ */
30
+ static _resetInstance() {
31
+ if (sharedInstance) {
32
+ sharedInstance.clearCache();
33
+ }
34
+ sharedInstance = null;
35
+ }
36
+
11
37
  constructor() {
12
38
  // Initialize comprehensive timezone database
13
39
  this.database = new TimezoneDatabase();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forcecalendar/core",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "A modern, lightweight, framework-agnostic calendar engine optimized for Salesforce",