@forcecalendar/core 2.1.13 → 2.1.15

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.
@@ -154,12 +154,20 @@ export class Event {
154
154
  // Validate timezone if provided
155
155
  if (data.timeZone) {
156
156
  try {
157
- // Test if timezone is valid by trying to use it
158
157
  new Intl.DateTimeFormat('en-US', { timeZone: data.timeZone });
159
158
  } catch (e) {
160
159
  throw new Error(`Invalid timezone: ${data.timeZone}`);
161
160
  }
162
161
  }
162
+
163
+ // Validate end timezone if provided
164
+ if (data.endTimeZone) {
165
+ try {
166
+ new Intl.DateTimeFormat('en-US', { timeZone: data.endTimeZone });
167
+ } catch (e) {
168
+ throw new Error(`Invalid end timezone: ${data.endTimeZone}`);
169
+ }
170
+ }
163
171
  }
164
172
 
165
173
  /**
@@ -503,15 +503,24 @@ export class EventStore {
503
503
  * Get events for a date range
504
504
  * @param {Date} start - Start date
505
505
  * @param {Date} end - End date
506
- * @param {boolean|string} expandRecurring - Whether to expand recurring events, or timezone string
507
- * @param {string} [timezone] - Timezone for the query (if expandRecurring is boolean)
506
+ * @param {boolean|Object} [expandRecurringOrOptions=true] - Boolean to expand recurring events,
507
+ * or options object: { expandRecurring?: boolean, timezone?: string }
508
+ * @param {string} [timezone] - Timezone for the query
508
509
  * @returns {Event[]}
509
510
  */
510
- getEventsInRange(start, end, expandRecurring = true, timezone = null) {
511
- // Handle overloaded parameters
512
- if (typeof expandRecurring === 'string') {
513
- timezone = expandRecurring;
511
+ getEventsInRange(start, end, expandRecurringOrOptions = true, timezone = null) {
512
+ let expandRecurring = true;
513
+
514
+ if (typeof expandRecurringOrOptions === 'object' && expandRecurringOrOptions !== null) {
515
+ // Options object form: getEventsInRange(start, end, { expandRecurring, timezone })
516
+ expandRecurring = expandRecurringOrOptions.expandRecurring !== false;
517
+ timezone = expandRecurringOrOptions.timezone || timezone;
518
+ } else if (typeof expandRecurringOrOptions === 'string') {
519
+ // Legacy overloaded form: string was treated as timezone (deprecated)
520
+ timezone = expandRecurringOrOptions;
514
521
  expandRecurring = true;
522
+ } else {
523
+ expandRecurring = expandRecurringOrOptions;
515
524
  }
516
525
 
517
526
  timezone = timezone || this.defaultTimezone;
@@ -10,9 +10,37 @@ export class EventSearch {
10
10
  // Search index for performance
11
11
  this.searchIndex = new Map();
12
12
  this.indexFields = ['title', 'description', 'location', 'category'];
13
+ this._indexDirty = false;
13
14
 
14
15
  // Build initial index
15
16
  this.rebuildIndex();
17
+
18
+ // Subscribe to EventStore changes to keep index in sync
19
+ if (this.eventStore && typeof this.eventStore.subscribe === 'function') {
20
+ this._unsubscribe = this.eventStore.subscribe(change => {
21
+ if (change.type === 'batch') {
22
+ this._indexDirty = true;
23
+ } else if (
24
+ change.type === 'add' ||
25
+ change.type === 'update' ||
26
+ change.type === 'remove' ||
27
+ change.type === 'clear'
28
+ ) {
29
+ this._indexDirty = true;
30
+ }
31
+ });
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Destroy the search engine and unsubscribe from store changes
37
+ */
38
+ destroy() {
39
+ if (this._unsubscribe) {
40
+ this._unsubscribe();
41
+ this._unsubscribe = null;
42
+ }
43
+ this.searchIndex.clear();
16
44
  }
17
45
 
18
46
  /**
@@ -34,6 +62,9 @@ export class EventSearch {
34
62
  return [];
35
63
  }
36
64
 
65
+ // Rebuild index if stale
66
+ this._ensureIndex();
67
+
37
68
  // Normalize query
38
69
  const normalizedQuery = caseSensitive ? query : query.toLowerCase();
39
70
  const queryTerms = this.tokenize(normalizedQuery);
@@ -443,11 +474,22 @@ export class EventSearch {
443
474
  }
444
475
  }
445
476
 
477
+ /**
478
+ * Ensure the search index is up to date
479
+ * @private
480
+ */
481
+ _ensureIndex() {
482
+ if (this._indexDirty) {
483
+ this.rebuildIndex();
484
+ }
485
+ }
486
+
446
487
  /**
447
488
  * Rebuild search index
448
489
  */
449
490
  rebuildIndex() {
450
491
  this.searchIndex.clear();
492
+ this._indexDirty = false;
451
493
  const events = this.eventStore.getAllEvents();
452
494
 
453
495
  for (const event of events) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forcecalendar/core",
3
- "version": "2.1.13",
3
+ "version": "2.1.15",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "A modern, lightweight, framework-agnostic calendar engine optimized for Salesforce",