@forcecalendar/core 2.3.0 → 2.5.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/core/calendar/Calendar.js +198 -14
- package/core/events/Event.js +173 -0
- package/core/events/EventStore.js +484 -92
- package/core/events/RecurrenceEngine.js +586 -20
- package/core/events/RecurrenceEngineV2.js +384 -51
- package/core/index.js +1 -1
- package/core/integration/EnhancedCalendar.js +88 -14
- package/core/types.js +95 -1
- package/package.json +1 -1
- package/types/calendar/Calendar.d.ts +137 -10
- package/types/events/Event.d.ts +75 -0
- package/types/events/EventStore.d.ts +213 -6
- package/types/events/RecurrenceEngine.d.ts +216 -1
- package/types/events/RecurrenceEngineV2.d.ts +156 -9
- package/types/index.d.ts +1 -1
- package/types/integration/EnhancedCalendar.d.ts +66 -1
- package/types/types.d.ts +296 -2
|
@@ -10,16 +10,151 @@ export declare class RecurrenceEngineV2 {
|
|
|
10
10
|
modifiedInstances: Map<any, any>;
|
|
11
11
|
exceptionStore: Map<any, any>;
|
|
12
12
|
static MAX_OCCURRENCES_HARD_LIMIT: number;
|
|
13
|
+
static MAX_ITERATIONS_HARD_LIMIT: number;
|
|
13
14
|
constructor();
|
|
14
15
|
/**
|
|
15
16
|
* Expand recurring event with advanced handling
|
|
16
|
-
*
|
|
17
|
+
*
|
|
18
|
+
* Occurrences before rangeStart are skipped without being generated:
|
|
19
|
+
* daily, weekly, hourly and minutely rules seek straight to the range, so
|
|
20
|
+
* a series that started years before the queried window is expanded at
|
|
21
|
+
* the same cost as one that started yesterday.
|
|
22
|
+
*
|
|
23
|
+
* @param {import('./Event.js').Event} event - Recurring event
|
|
17
24
|
* @param {Date} rangeStart - Start of expansion range
|
|
18
25
|
* @param {Date} rangeEnd - End of expansion range
|
|
19
26
|
* @param {Object} options - Expansion options
|
|
20
|
-
* @
|
|
27
|
+
* @param {number} [options.maxOccurrences=365] - Maximum number of occurrences to
|
|
28
|
+
* return. Only occurrences inside the range count towards this limit.
|
|
29
|
+
* @param {boolean} [options.includeModified=true] - Apply stored instance modifications
|
|
30
|
+
* @param {boolean} [options.includeCancelled=false] - Return exception dates as cancelled occurrences
|
|
31
|
+
* @param {string} [options.timezone] - Timezone for expansion (defaults to the event's)
|
|
32
|
+
* @param {boolean} [options.handleDST=true] - Adjust occurrences across DST transitions
|
|
33
|
+
* @returns {import('../types.js').ExpandedOccurrence[]} Expanded occurrences
|
|
21
34
|
*/
|
|
22
|
-
expandEvent(event: Event, rangeStart: Date, rangeEnd: Date, options?:
|
|
35
|
+
expandEvent(event: import('./Event.js').Event, rangeStart: Date, rangeEnd: Date, options?: {
|
|
36
|
+
maxOccurrences?: number;
|
|
37
|
+
includeModified?: boolean;
|
|
38
|
+
includeCancelled?: boolean;
|
|
39
|
+
timezone?: string;
|
|
40
|
+
handleDST?: boolean;
|
|
41
|
+
}): import('../types.js').ExpandedOccurrence[];
|
|
42
|
+
/**
|
|
43
|
+
* Lazily iterate the occurrences of an event in chronological order.
|
|
44
|
+
*
|
|
45
|
+
* Yields what expandEvent returns for the window, one occurrence at a
|
|
46
|
+
* time and without the expansion cache: stored instance modifications
|
|
47
|
+
* and exceptions are applied as each occurrence is produced, so changes
|
|
48
|
+
* made through addModifiedInstance or addException are visible on the
|
|
49
|
+
* next pull. Rules seekToRange can seek (plain daily and weekly, hourly,
|
|
50
|
+
* minutely) jump straight to `after`, and DST transitions are scanned
|
|
51
|
+
* lazily ahead of the cursor instead of for the whole window up front.
|
|
52
|
+
*
|
|
53
|
+
* Both bounds are exclusive unless `inclusive` is set: an occurrence that
|
|
54
|
+
* starts exactly at `after` or `before` is skipped by default, so
|
|
55
|
+
* iterating from a known occurrence's start continues the series without
|
|
56
|
+
* repeating it; with `inclusive: true` the window is closed on both ends
|
|
57
|
+
* like expandEvent's range. A non-recurring event yields its single
|
|
58
|
+
* occurrence when it falls inside the window. Iteration ends at COUNT or
|
|
59
|
+
* UNTIL, at `before`, or — as a guard for rules that produce no
|
|
60
|
+
* occurrences — after MAX_ITERATIONS_HARD_LIMIT consecutive steps
|
|
61
|
+
* without one. The generator is single-use; call again for a fresh one.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* const engine = new RecurrenceEngineV2();
|
|
65
|
+
* for (const occurrence of engine.iterateOccurrences(event, { after: new Date() })) {
|
|
66
|
+
* if (occurrence.start > deadline) break;
|
|
67
|
+
* schedule(occurrence);
|
|
68
|
+
* }
|
|
69
|
+
*
|
|
70
|
+
* @param {import('./Event.js').Event} event - The event to iterate
|
|
71
|
+
* @param {import('../types.js').ExpandedOccurrenceIteratorOptions} [options={}] - Window and expansion options
|
|
72
|
+
* @returns {Generator<import('../types.js').ExpandedOccurrence, void, undefined>} Occurrences in chronological order
|
|
73
|
+
* @throws {TypeError} If `after` or `before` is not a valid Date or timestamp
|
|
74
|
+
*/
|
|
75
|
+
iterateOccurrences(event: import('./Event.js').Event, options?: import('../types.js').ExpandedOccurrenceIteratorOptions): Generator<import('../types.js').ExpandedOccurrence, void, undefined>;
|
|
76
|
+
/**
|
|
77
|
+
* First occurrence of an event after an instant, or null when the series
|
|
78
|
+
* has no occurrence after it. `after` is exclusive unless
|
|
79
|
+
* `options.inclusive` is set, so passing the start of a known occurrence
|
|
80
|
+
* returns the one that follows it.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* const upcoming = engine.nextOccurrence(event, new Date());
|
|
84
|
+
*
|
|
85
|
+
* @param {import('./Event.js').Event} event - The event to query
|
|
86
|
+
* @param {Date|number} [after=null] - Instant to search from (defaults to the series start)
|
|
87
|
+
* @param {import('../types.js').ExpandedOccurrenceIteratorOptions} [options={}] - Further options
|
|
88
|
+
* @returns {import('../types.js').ExpandedOccurrence|null} The next occurrence, or null
|
|
89
|
+
*/
|
|
90
|
+
nextOccurrence(event: import('./Event.js').Event, after?: Date | number, options?: import('../types.js').ExpandedOccurrenceIteratorOptions): import('../types.js').ExpandedOccurrence | null;
|
|
91
|
+
/**
|
|
92
|
+
* The first `count` occurrences of an event inside a window, generated
|
|
93
|
+
* lazily so an open-ended series costs only the occurrences taken.
|
|
94
|
+
* `count` is capped at MAX_OCCURRENCES_HARD_LIMIT; fewer are returned
|
|
95
|
+
* when the series or the window ends first.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* const nextFive = engine.takeOccurrences(event, 5, { after: new Date() });
|
|
99
|
+
*
|
|
100
|
+
* @param {import('./Event.js').Event} event - The event to query
|
|
101
|
+
* @param {number} count - Maximum number of occurrences to return
|
|
102
|
+
* @param {import('../types.js').ExpandedOccurrenceIteratorOptions} [options={}] - Window and expansion options
|
|
103
|
+
* @returns {import('../types.js').ExpandedOccurrence[]} Up to `count` occurrences in chronological order
|
|
104
|
+
*/
|
|
105
|
+
takeOccurrences(event: import('./Event.js').Event, count: number, options?: import('../types.js').ExpandedOccurrenceIteratorOptions): import('../types.js').ExpandedOccurrence[];
|
|
106
|
+
/**
|
|
107
|
+
* Yield a non-recurring event's single occurrence if it starts inside
|
|
108
|
+
* the window
|
|
109
|
+
* @param {import('./Event.js').Event} event - The event
|
|
110
|
+
* @param {{ startMs: number, endMs: number }} window - Inclusive bounds
|
|
111
|
+
* @returns {Generator<import('../types.js').ExpandedOccurrence, void, undefined>}
|
|
112
|
+
* @private
|
|
113
|
+
*/
|
|
114
|
+
private _iterateSingle;
|
|
115
|
+
/**
|
|
116
|
+
* Lazy counterpart of the expandEvent loop: seeks to the window, then
|
|
117
|
+
* steps the cursor and yields each in-window occurrence with the same
|
|
118
|
+
* DST adjustment, exception handling and instance modifications.
|
|
119
|
+
* @private
|
|
120
|
+
*/
|
|
121
|
+
private _iterateRule;
|
|
122
|
+
/**
|
|
123
|
+
* Apply exceptions and stored instance modifications to a generated
|
|
124
|
+
* occurrence
|
|
125
|
+
* @param {import('./Event.js').Event} event - The recurring event
|
|
126
|
+
* @param {Object} occurrence - Occurrence from generateOccurrence
|
|
127
|
+
* @param {Object} rule - Parsed recurrence rule
|
|
128
|
+
* @param {boolean} includeCancelled - Return exception dates as cancelled occurrences
|
|
129
|
+
* @param {boolean} includeModified - Apply stored instance modifications
|
|
130
|
+
* @returns {Object|null} The occurrence, or null when it is excluded
|
|
131
|
+
* @private
|
|
132
|
+
*/
|
|
133
|
+
private _applyOverrides;
|
|
134
|
+
/**
|
|
135
|
+
* Move the expansion cursor to the last occurrence before the range
|
|
136
|
+
* without stepping through every occurrence in between.
|
|
137
|
+
*
|
|
138
|
+
* Applies to rules whose step is a fixed duration between system-timezone
|
|
139
|
+
* transitions (plain DAILY and WEEKLY, HOURLY, MINUTELY); the step that
|
|
140
|
+
* crosses a transition is taken with getNextDate so the result is exactly
|
|
141
|
+
* what stepping from DTSTART would produce. Never seeks past UNTIL, and
|
|
142
|
+
* counts skipped steps against COUNT.
|
|
143
|
+
*
|
|
144
|
+
* @param {Object} state - Expansion state (currentDate and count are updated)
|
|
145
|
+
* @param {Object} rule - Parsed recurrence rule
|
|
146
|
+
* @param {Date} rangeStart - Start of expansion range
|
|
147
|
+
* @param {Date} rangeEnd - End of expansion range
|
|
148
|
+
* @param {string} timezone - Expansion timezone
|
|
149
|
+
*/
|
|
150
|
+
seekToRange(state: Object, rule: Object, rangeStart: Date, rangeEnd: Date, timezone: string): void;
|
|
151
|
+
/**
|
|
152
|
+
* Milliseconds per step for rules getNextDate advances by a fixed
|
|
153
|
+
* duration while the system UTC offset is constant
|
|
154
|
+
* @param {Object} rule - Parsed recurrence rule
|
|
155
|
+
* @returns {number} Step length in milliseconds, or 0 when not fixed
|
|
156
|
+
*/
|
|
157
|
+
getFixedStepMs(rule: Object): number;
|
|
23
158
|
/**
|
|
24
159
|
* Generate a single occurrence with timezone handling
|
|
25
160
|
*/
|
|
@@ -68,12 +203,18 @@ export declare class RecurrenceEngineV2 {
|
|
|
68
203
|
/**
|
|
69
204
|
* Find DST transitions in date range
|
|
70
205
|
*/
|
|
71
|
-
findDSTTransitions(start: any, end: any, timezone: any):
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
206
|
+
findDSTTransitions(start: any, end: any, timezone: any): any[];
|
|
207
|
+
/**
|
|
208
|
+
* Walk the scan cursor one day at a time up to untilMs, appending each
|
|
209
|
+
* offset change. The cursor and last offset persist in `scan`, so the
|
|
210
|
+
* walk can be resumed later on the same day grid.
|
|
211
|
+
* @param {{ cursor: Date, lastOffset: number }} scan - Resumable scan position (mutated)
|
|
212
|
+
* @param {Array} transitions - Transition list to append to
|
|
213
|
+
* @param {number} untilMs - Scan through this timestamp (inclusive)
|
|
214
|
+
* @param {string} timezone - Timezone to probe
|
|
215
|
+
* @private
|
|
216
|
+
*/
|
|
217
|
+
private _scanDSTTransitions;
|
|
77
218
|
/**
|
|
78
219
|
* Adjust occurrence for DST transitions
|
|
79
220
|
*/
|
|
@@ -117,6 +258,12 @@ export declare class RecurrenceEngineV2 {
|
|
|
117
258
|
* Clone occurrence results before returning or caching.
|
|
118
259
|
*/
|
|
119
260
|
cloneOccurrences(occurrences: any): any;
|
|
261
|
+
/**
|
|
262
|
+
* Clone a single occurrence, copying its Date and array fields.
|
|
263
|
+
* @param {import('../types.js').ExpandedOccurrence} occurrence - Occurrence to clone
|
|
264
|
+
* @returns {import('../types.js').ExpandedOccurrence} Independent copy
|
|
265
|
+
*/
|
|
266
|
+
cloneOccurrence(occurrence: import('../types.js').ExpandedOccurrence): import('../types.js').ExpandedOccurrence;
|
|
120
267
|
/**
|
|
121
268
|
* Clear cache for specific event
|
|
122
269
|
*/
|
package/types/index.d.ts
CHANGED
|
@@ -18,5 +18,5 @@ export { RRuleParser } from './events/RRuleParser.js';
|
|
|
18
18
|
export { TimezoneManager } from './timezone/TimezoneManager.js';
|
|
19
19
|
export { ConflictDetector } from './conflicts/ConflictDetector.js';
|
|
20
20
|
export { EnhancedCalendar } from './integration/EnhancedCalendar.js';
|
|
21
|
-
export declare const VERSION = "2.
|
|
21
|
+
export declare const VERSION = "2.5.0";
|
|
22
22
|
export { Calendar as default } from './calendar/Calendar.js';
|
|
@@ -21,8 +21,36 @@ export declare class EnhancedCalendar extends Calendar {
|
|
|
21
21
|
search(query: any, options?: {}): Promise<any>;
|
|
22
22
|
/**
|
|
23
23
|
* Get events with enhanced recurrence expansion
|
|
24
|
+
*
|
|
25
|
+
* Regular events overlapping the range are returned as stored. Every
|
|
26
|
+
* recurring series in the store is expanded with this calendar's
|
|
27
|
+
* RecurrenceEngineV2 (so instance modifications and cancellations apply),
|
|
28
|
+
* including series that started before the range. Occurrences are the
|
|
29
|
+
* engine's plain occurrence objects, with the id `<masterId>_<startMs>`
|
|
30
|
+
* (see `Event.occurrenceId`), `recurringEventId`, `isOccurrence: true` and
|
|
31
|
+
* `occurrenceStart`.
|
|
24
32
|
*/
|
|
25
|
-
getEventsInRange(startDate: any, endDate: any, options?: {}):
|
|
33
|
+
getEventsInRange(startDate: any, endDate: any, options?: {}): (import("../index.js").Event | {
|
|
34
|
+
id: string;
|
|
35
|
+
recurringEventId?: string;
|
|
36
|
+
title: string;
|
|
37
|
+
start: Date;
|
|
38
|
+
end: Date;
|
|
39
|
+
startUTC?: Date;
|
|
40
|
+
endUTC?: Date;
|
|
41
|
+
timezone: string;
|
|
42
|
+
originalStart?: Date;
|
|
43
|
+
allDay: boolean;
|
|
44
|
+
description?: string;
|
|
45
|
+
location?: string;
|
|
46
|
+
categories?: string[];
|
|
47
|
+
status?: import("../types.js").EventStatus;
|
|
48
|
+
cancellationReason?: string;
|
|
49
|
+
isRecurring: boolean;
|
|
50
|
+
isModified?: boolean;
|
|
51
|
+
isOccurrence: boolean;
|
|
52
|
+
occurrenceStart: Date;
|
|
53
|
+
})[];
|
|
26
54
|
/**
|
|
27
55
|
* Modify a single occurrence of a recurring event
|
|
28
56
|
*/
|
|
@@ -31,6 +59,43 @@ export declare class EnhancedCalendar extends Calendar {
|
|
|
31
59
|
* Cancel a single occurrence of a recurring event
|
|
32
60
|
*/
|
|
33
61
|
cancelOccurrence(eventId: any, occurrenceDate: any, reason?: string): void;
|
|
62
|
+
/**
|
|
63
|
+
* Lazily iterate the occurrences of an event through the enhanced
|
|
64
|
+
* engine, so occurrences changed with modifyOccurrence or cancelled with
|
|
65
|
+
* cancelOccurrence are reflected. Same semantics as
|
|
66
|
+
* Calendar#iterateOccurrences.
|
|
67
|
+
* @param {string} eventId - The event ID
|
|
68
|
+
* @param {import('../types.js').ExpandedOccurrenceIteratorOptions} [options={}] - Window and expansion options
|
|
69
|
+
* @returns {Generator<import('../types.js').ExpandedOccurrence, void, undefined>} Occurrences in chronological order
|
|
70
|
+
* @throws {Error} If no event with the ID exists
|
|
71
|
+
*/
|
|
72
|
+
iterateOccurrences(eventId: string, options?: import('../types.js').ExpandedOccurrenceIteratorOptions): Generator<import('../types.js').ExpandedOccurrence, void, undefined>;
|
|
73
|
+
/**
|
|
74
|
+
* First occurrence of an event after an instant through the enhanced
|
|
75
|
+
* engine, or null. Same semantics as Calendar#getNextOccurrence.
|
|
76
|
+
* @param {string} eventId - The event ID
|
|
77
|
+
* @param {Date|number} [after=null] - Instant to search from (defaults to the series start)
|
|
78
|
+
* @param {import('../types.js').ExpandedOccurrenceIteratorOptions} [options={}] - Further options
|
|
79
|
+
* @returns {import('../types.js').ExpandedOccurrence|null} The next occurrence, or null
|
|
80
|
+
* @throws {Error} If no event with the ID exists
|
|
81
|
+
*/
|
|
82
|
+
getNextOccurrence(eventId: string, after?: Date | number, options?: import('../types.js').ExpandedOccurrenceIteratorOptions): import('../types.js').ExpandedOccurrence | null;
|
|
83
|
+
/**
|
|
84
|
+
* The first `count` occurrences of an event through the enhanced
|
|
85
|
+
* engine. Same semantics as Calendar#takeOccurrences.
|
|
86
|
+
* @param {string} eventId - The event ID
|
|
87
|
+
* @param {number} count - Maximum number of occurrences to return
|
|
88
|
+
* @param {import('../types.js').ExpandedOccurrenceIteratorOptions} [options={}] - Window and expansion options
|
|
89
|
+
* @returns {import('../types.js').ExpandedOccurrence[]} Up to `count` occurrences in chronological order
|
|
90
|
+
* @throws {Error} If no event with the ID exists
|
|
91
|
+
*/
|
|
92
|
+
takeOccurrences(eventId: string, count: number, options?: import('../types.js').ExpandedOccurrenceIteratorOptions): import('../types.js').ExpandedOccurrence[];
|
|
93
|
+
/**
|
|
94
|
+
* Resolve an occurrence query to the stored event and its options, with
|
|
95
|
+
* the timezone defaulted as getEventsInRange does
|
|
96
|
+
* @private
|
|
97
|
+
*/
|
|
98
|
+
private _occurrenceQuery;
|
|
34
99
|
/**
|
|
35
100
|
* Bulk operations for recurring events
|
|
36
101
|
*/
|
package/types/types.d.ts
CHANGED
|
@@ -688,7 +688,7 @@ export type EventStoreChange = {
|
|
|
688
688
|
/**
|
|
689
689
|
* - Type of change
|
|
690
690
|
*/
|
|
691
|
-
type: ('add' | 'update' | 'remove' | 'clear');
|
|
691
|
+
type: ('add' | 'update' | 'remove' | 'clear' | 'batch');
|
|
692
692
|
/**
|
|
693
693
|
* - Affected event
|
|
694
694
|
*/
|
|
@@ -701,11 +701,94 @@ export type EventStoreChange = {
|
|
|
701
701
|
* - Previous events (for clear)
|
|
702
702
|
*/
|
|
703
703
|
oldEvents?: import('./events/Event.js').Event[];
|
|
704
|
+
/**
|
|
705
|
+
* - Individual changes (for batch)
|
|
706
|
+
*/
|
|
707
|
+
changes?: EventStoreChange[];
|
|
708
|
+
/**
|
|
709
|
+
* - Number of individual changes (for batch)
|
|
710
|
+
*/
|
|
711
|
+
count?: number;
|
|
704
712
|
/**
|
|
705
713
|
* - Store version number
|
|
706
714
|
*/
|
|
707
715
|
version: number;
|
|
708
716
|
};
|
|
717
|
+
export type EventEquivalenceFn = (a: import('./events/Event.js').Event, b: import('./events/Event.js').Event) => boolean;
|
|
718
|
+
export type ReconcileOptions = {
|
|
719
|
+
/**
|
|
720
|
+
* - Remove stored events that are absent from the snapshot
|
|
721
|
+
*/
|
|
722
|
+
removeMissing?: boolean;
|
|
723
|
+
/**
|
|
724
|
+
* - Comparator deciding whether a stored event is unchanged (defaults to Event.isEquivalent)
|
|
725
|
+
*/
|
|
726
|
+
isEquivalent?: EventEquivalenceFn;
|
|
727
|
+
};
|
|
728
|
+
export type ReconciledUpdate = {
|
|
729
|
+
/**
|
|
730
|
+
* - Event now in the store
|
|
731
|
+
*/
|
|
732
|
+
event: import('./events/Event.js').Event;
|
|
733
|
+
/**
|
|
734
|
+
* - Event it replaced
|
|
735
|
+
*/
|
|
736
|
+
oldEvent: import('./events/Event.js').Event;
|
|
737
|
+
};
|
|
738
|
+
export type ReconcileResult = {
|
|
739
|
+
/**
|
|
740
|
+
* - Events that were not in the store before
|
|
741
|
+
*/
|
|
742
|
+
added: import('./events/Event.js').Event[];
|
|
743
|
+
/**
|
|
744
|
+
* - Events whose data changed
|
|
745
|
+
*/
|
|
746
|
+
updated: ReconciledUpdate[];
|
|
747
|
+
/**
|
|
748
|
+
* - Events removed from the store
|
|
749
|
+
*/
|
|
750
|
+
removed: import('./events/Event.js').Event[];
|
|
751
|
+
/**
|
|
752
|
+
* - Stored events left untouched (same instances)
|
|
753
|
+
*/
|
|
754
|
+
unchanged: import('./events/Event.js').Event[];
|
|
755
|
+
};
|
|
756
|
+
export type SetEventsOptions = {
|
|
757
|
+
/**
|
|
758
|
+
* - Apply only the differences instead of clearing and re-adding
|
|
759
|
+
*/
|
|
760
|
+
reconcile?: boolean;
|
|
761
|
+
/**
|
|
762
|
+
* - Reconcile only: remove stored events absent from the snapshot
|
|
763
|
+
*/
|
|
764
|
+
removeMissing?: boolean;
|
|
765
|
+
/**
|
|
766
|
+
* - Reconcile only: custom equivalence comparator
|
|
767
|
+
*/
|
|
768
|
+
isEquivalent?: EventEquivalenceFn;
|
|
769
|
+
};
|
|
770
|
+
export type EventsSetPayload = {
|
|
771
|
+
/**
|
|
772
|
+
* - All events after the operation
|
|
773
|
+
*/
|
|
774
|
+
events: import('./events/Event.js').Event[];
|
|
775
|
+
/**
|
|
776
|
+
* - Events added by the operation
|
|
777
|
+
*/
|
|
778
|
+
added: import('./events/Event.js').Event[];
|
|
779
|
+
/**
|
|
780
|
+
* - Events replaced by the operation
|
|
781
|
+
*/
|
|
782
|
+
updated: ReconciledUpdate[];
|
|
783
|
+
/**
|
|
784
|
+
* - Events removed by the operation
|
|
785
|
+
*/
|
|
786
|
+
removed: import('./events/Event.js').Event[];
|
|
787
|
+
/**
|
|
788
|
+
* - Events left untouched
|
|
789
|
+
*/
|
|
790
|
+
unchanged: import('./events/Event.js').Event[];
|
|
791
|
+
};
|
|
709
792
|
export type QueryFilters = {
|
|
710
793
|
/**
|
|
711
794
|
* - Start date for range query
|
|
@@ -773,6 +856,132 @@ export type EventOccurrence = {
|
|
|
773
856
|
* - ID of the parent recurring event
|
|
774
857
|
*/
|
|
775
858
|
recurringEventId: string;
|
|
859
|
+
/**
|
|
860
|
+
* - Timezone the occurrence was expanded in
|
|
861
|
+
*/
|
|
862
|
+
timezone?: string;
|
|
863
|
+
/**
|
|
864
|
+
* - Start of the series (DTSTART)
|
|
865
|
+
*/
|
|
866
|
+
originalStart?: Date;
|
|
867
|
+
};
|
|
868
|
+
export type OccurrenceIteratorOptions = {
|
|
869
|
+
/**
|
|
870
|
+
* - Only occurrences starting after this instant (Date or timestamp)
|
|
871
|
+
*/
|
|
872
|
+
after?: Date | number;
|
|
873
|
+
/**
|
|
874
|
+
* - Only occurrences starting before this instant (Date or timestamp)
|
|
875
|
+
*/
|
|
876
|
+
before?: Date | number;
|
|
877
|
+
/**
|
|
878
|
+
* - Treat `after` and `before` as closed bounds
|
|
879
|
+
*/
|
|
880
|
+
inclusive?: boolean;
|
|
881
|
+
/**
|
|
882
|
+
* - Timezone for expansion (defaults to the event's)
|
|
883
|
+
*/
|
|
884
|
+
timezone?: string;
|
|
885
|
+
};
|
|
886
|
+
export type ExpandedOccurrenceIteratorOptions = {
|
|
887
|
+
/**
|
|
888
|
+
* - Only occurrences starting after this instant (Date or timestamp)
|
|
889
|
+
*/
|
|
890
|
+
after?: Date | number;
|
|
891
|
+
/**
|
|
892
|
+
* - Only occurrences starting before this instant (Date or timestamp)
|
|
893
|
+
*/
|
|
894
|
+
before?: Date | number;
|
|
895
|
+
/**
|
|
896
|
+
* - Treat `after` and `before` as closed bounds
|
|
897
|
+
*/
|
|
898
|
+
inclusive?: boolean;
|
|
899
|
+
/**
|
|
900
|
+
* - Timezone for expansion (defaults to the event's)
|
|
901
|
+
*/
|
|
902
|
+
timezone?: string;
|
|
903
|
+
/**
|
|
904
|
+
* - Apply stored instance modifications
|
|
905
|
+
*/
|
|
906
|
+
includeModified?: boolean;
|
|
907
|
+
/**
|
|
908
|
+
* - Yield exception dates as cancelled occurrences
|
|
909
|
+
*/
|
|
910
|
+
includeCancelled?: boolean;
|
|
911
|
+
/**
|
|
912
|
+
* - Adjust occurrences across DST transitions
|
|
913
|
+
*/
|
|
914
|
+
handleDST?: boolean;
|
|
915
|
+
};
|
|
916
|
+
export type ExpandedOccurrence = {
|
|
917
|
+
/**
|
|
918
|
+
* - Occurrence ID (`<eventId>_<startTimestamp>` for recurring events)
|
|
919
|
+
*/
|
|
920
|
+
id: string;
|
|
921
|
+
/**
|
|
922
|
+
* - ID of the parent recurring event
|
|
923
|
+
*/
|
|
924
|
+
recurringEventId?: string;
|
|
925
|
+
/**
|
|
926
|
+
* - Event title
|
|
927
|
+
*/
|
|
928
|
+
title: string;
|
|
929
|
+
/**
|
|
930
|
+
* - Occurrence start date
|
|
931
|
+
*/
|
|
932
|
+
start: Date;
|
|
933
|
+
/**
|
|
934
|
+
* - Occurrence end date
|
|
935
|
+
*/
|
|
936
|
+
end: Date;
|
|
937
|
+
/**
|
|
938
|
+
* - Occurrence start in UTC
|
|
939
|
+
*/
|
|
940
|
+
startUTC?: Date;
|
|
941
|
+
/**
|
|
942
|
+
* - Occurrence end in UTC
|
|
943
|
+
*/
|
|
944
|
+
endUTC?: Date;
|
|
945
|
+
/**
|
|
946
|
+
* - Timezone the occurrence was expanded in
|
|
947
|
+
*/
|
|
948
|
+
timezone: string;
|
|
949
|
+
/**
|
|
950
|
+
* - Start of the series (DTSTART)
|
|
951
|
+
*/
|
|
952
|
+
originalStart?: Date;
|
|
953
|
+
/**
|
|
954
|
+
* - Whether the event is all-day
|
|
955
|
+
*/
|
|
956
|
+
allDay: boolean;
|
|
957
|
+
/**
|
|
958
|
+
* - Event description
|
|
959
|
+
*/
|
|
960
|
+
description?: string;
|
|
961
|
+
/**
|
|
962
|
+
* - Event location
|
|
963
|
+
*/
|
|
964
|
+
location?: string;
|
|
965
|
+
/**
|
|
966
|
+
* - Event categories
|
|
967
|
+
*/
|
|
968
|
+
categories?: string[];
|
|
969
|
+
/**
|
|
970
|
+
* - 'confirmed', or 'cancelled' for exception dates yielded with includeCancelled
|
|
971
|
+
*/
|
|
972
|
+
status?: EventStatus;
|
|
973
|
+
/**
|
|
974
|
+
* - Reason recorded for a cancelled occurrence
|
|
975
|
+
*/
|
|
976
|
+
cancellationReason?: string;
|
|
977
|
+
/**
|
|
978
|
+
* - Whether the occurrence belongs to a recurring series
|
|
979
|
+
*/
|
|
980
|
+
isRecurring: boolean;
|
|
981
|
+
/**
|
|
982
|
+
* - Whether a stored instance modification was applied
|
|
983
|
+
*/
|
|
984
|
+
isModified?: boolean;
|
|
776
985
|
};
|
|
777
986
|
export type CalendarPlugin = {
|
|
778
987
|
/**
|
|
@@ -1142,12 +1351,48 @@ export type ConflictSummary = {
|
|
|
1142
1351
|
*/
|
|
1143
1352
|
/**
|
|
1144
1353
|
* @typedef {Object} EventStoreChange
|
|
1145
|
-
* @property {('add'|'update'|'remove'|'clear')} type - Type of change
|
|
1354
|
+
* @property {('add'|'update'|'remove'|'clear'|'batch')} type - Type of change
|
|
1146
1355
|
* @property {import('./events/Event.js').Event} [event] - Affected event
|
|
1147
1356
|
* @property {import('./events/Event.js').Event} [oldEvent] - Previous event state (for updates)
|
|
1148
1357
|
* @property {import('./events/Event.js').Event[]} [oldEvents] - Previous events (for clear)
|
|
1358
|
+
* @property {EventStoreChange[]} [changes] - Individual changes (for batch)
|
|
1359
|
+
* @property {number} [count] - Number of individual changes (for batch)
|
|
1149
1360
|
* @property {number} version - Store version number
|
|
1150
1361
|
*/
|
|
1362
|
+
/**
|
|
1363
|
+
* @typedef {(a: import('./events/Event.js').Event, b: import('./events/Event.js').Event) => boolean} EventEquivalenceFn
|
|
1364
|
+
*/
|
|
1365
|
+
/**
|
|
1366
|
+
* @typedef {Object} ReconcileOptions
|
|
1367
|
+
* @property {boolean} [removeMissing=true] - Remove stored events that are absent from the snapshot
|
|
1368
|
+
* @property {EventEquivalenceFn} [isEquivalent] - Comparator deciding whether a stored event is unchanged (defaults to Event.isEquivalent)
|
|
1369
|
+
*/
|
|
1370
|
+
/**
|
|
1371
|
+
* @typedef {Object} ReconciledUpdate
|
|
1372
|
+
* @property {import('./events/Event.js').Event} event - Event now in the store
|
|
1373
|
+
* @property {import('./events/Event.js').Event} oldEvent - Event it replaced
|
|
1374
|
+
*/
|
|
1375
|
+
/**
|
|
1376
|
+
* @typedef {Object} ReconcileResult
|
|
1377
|
+
* @property {import('./events/Event.js').Event[]} added - Events that were not in the store before
|
|
1378
|
+
* @property {ReconciledUpdate[]} updated - Events whose data changed
|
|
1379
|
+
* @property {import('./events/Event.js').Event[]} removed - Events removed from the store
|
|
1380
|
+
* @property {import('./events/Event.js').Event[]} unchanged - Stored events left untouched (same instances)
|
|
1381
|
+
*/
|
|
1382
|
+
/**
|
|
1383
|
+
* @typedef {Object} SetEventsOptions
|
|
1384
|
+
* @property {boolean} [reconcile=false] - Apply only the differences instead of clearing and re-adding
|
|
1385
|
+
* @property {boolean} [removeMissing=true] - Reconcile only: remove stored events absent from the snapshot
|
|
1386
|
+
* @property {EventEquivalenceFn} [isEquivalent] - Reconcile only: custom equivalence comparator
|
|
1387
|
+
*/
|
|
1388
|
+
/**
|
|
1389
|
+
* @typedef {Object} EventsSetPayload
|
|
1390
|
+
* @property {import('./events/Event.js').Event[]} events - All events after the operation
|
|
1391
|
+
* @property {import('./events/Event.js').Event[]} added - Events added by the operation
|
|
1392
|
+
* @property {ReconciledUpdate[]} updated - Events replaced by the operation
|
|
1393
|
+
* @property {import('./events/Event.js').Event[]} removed - Events removed by the operation
|
|
1394
|
+
* @property {import('./events/Event.js').Event[]} unchanged - Events left untouched
|
|
1395
|
+
*/
|
|
1151
1396
|
/**
|
|
1152
1397
|
* @typedef {Object} QueryFilters
|
|
1153
1398
|
* @property {Date} [start] - Start date for range query
|
|
@@ -1169,6 +1414,55 @@ export type ConflictSummary = {
|
|
|
1169
1414
|
* @property {Date} start - Occurrence start date
|
|
1170
1415
|
* @property {Date} end - Occurrence end date
|
|
1171
1416
|
* @property {string} recurringEventId - ID of the parent recurring event
|
|
1417
|
+
* @property {string} [timezone] - Timezone the occurrence was expanded in
|
|
1418
|
+
* @property {Date} [originalStart] - Start of the series (DTSTART)
|
|
1419
|
+
*/
|
|
1420
|
+
/**
|
|
1421
|
+
* Window for lazy occurrence iteration. Both bounds are exclusive unless
|
|
1422
|
+
* `inclusive` is set: an occurrence starting exactly at `after` or `before`
|
|
1423
|
+
* is skipped by default, so iterating from a known occurrence's start
|
|
1424
|
+
* continues the series without repeating it. Omit a bound to leave that
|
|
1425
|
+
* end of the window open.
|
|
1426
|
+
* @typedef {Object} OccurrenceIteratorOptions
|
|
1427
|
+
* @property {Date|number} [after] - Only occurrences starting after this instant (Date or timestamp)
|
|
1428
|
+
* @property {Date|number} [before] - Only occurrences starting before this instant (Date or timestamp)
|
|
1429
|
+
* @property {boolean} [inclusive=false] - Treat `after` and `before` as closed bounds
|
|
1430
|
+
* @property {string} [timezone] - Timezone for expansion (defaults to the event's)
|
|
1431
|
+
*/
|
|
1432
|
+
/**
|
|
1433
|
+
* Options for lazy occurrence iteration through RecurrenceEngineV2,
|
|
1434
|
+
* EventStore and Calendar: the OccurrenceIteratorOptions window plus the
|
|
1435
|
+
* expansion switches RecurrenceEngineV2.expandEvent accepts.
|
|
1436
|
+
* @typedef {Object} ExpandedOccurrenceIteratorOptions
|
|
1437
|
+
* @property {Date|number} [after] - Only occurrences starting after this instant (Date or timestamp)
|
|
1438
|
+
* @property {Date|number} [before] - Only occurrences starting before this instant (Date or timestamp)
|
|
1439
|
+
* @property {boolean} [inclusive=false] - Treat `after` and `before` as closed bounds
|
|
1440
|
+
* @property {string} [timezone] - Timezone for expansion (defaults to the event's)
|
|
1441
|
+
* @property {boolean} [includeModified=true] - Apply stored instance modifications
|
|
1442
|
+
* @property {boolean} [includeCancelled=false] - Yield exception dates as cancelled occurrences
|
|
1443
|
+
* @property {boolean} [handleDST=true] - Adjust occurrences across DST transitions
|
|
1444
|
+
*/
|
|
1445
|
+
/**
|
|
1446
|
+
* Occurrence produced by RecurrenceEngineV2 (and therefore by EventStore
|
|
1447
|
+
* and Calendar occurrence queries)
|
|
1448
|
+
* @typedef {Object} ExpandedOccurrence
|
|
1449
|
+
* @property {string} id - Occurrence ID (`<eventId>_<startTimestamp>` for recurring events)
|
|
1450
|
+
* @property {string} [recurringEventId] - ID of the parent recurring event
|
|
1451
|
+
* @property {string} title - Event title
|
|
1452
|
+
* @property {Date} start - Occurrence start date
|
|
1453
|
+
* @property {Date} end - Occurrence end date
|
|
1454
|
+
* @property {Date} [startUTC] - Occurrence start in UTC
|
|
1455
|
+
* @property {Date} [endUTC] - Occurrence end in UTC
|
|
1456
|
+
* @property {string} timezone - Timezone the occurrence was expanded in
|
|
1457
|
+
* @property {Date} [originalStart] - Start of the series (DTSTART)
|
|
1458
|
+
* @property {boolean} allDay - Whether the event is all-day
|
|
1459
|
+
* @property {string} [description] - Event description
|
|
1460
|
+
* @property {string} [location] - Event location
|
|
1461
|
+
* @property {string[]} [categories] - Event categories
|
|
1462
|
+
* @property {EventStatus} [status] - 'confirmed', or 'cancelled' for exception dates yielded with includeCancelled
|
|
1463
|
+
* @property {string} [cancellationReason] - Reason recorded for a cancelled occurrence
|
|
1464
|
+
* @property {boolean} isRecurring - Whether the occurrence belongs to a recurring series
|
|
1465
|
+
* @property {boolean} [isModified] - Whether a stored instance modification was applied
|
|
1172
1466
|
*/
|
|
1173
1467
|
/**
|
|
1174
1468
|
* @typedef {Object} CalendarPlugin
|