@mcpher/gas-fakes 1.2.28 → 1.2.30
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/package.json +2 -2
- package/src/services/calendarapp/fakecalendar.js +81 -11
- package/src/services/calendarapp/fakecalendarapp.js +133 -1
- package/src/services/calendarapp/fakecalendarevent.js +507 -1
- package/src/services/calendarapp/fakecalendareventseries.js +412 -0
- package/src/services/calendarapp/fakeeventguest.js +44 -0
- package/src/services/calendarapp/fakeeventrecurrence.js +38 -1
- package/src/services/calendarapp/fakerecurrencerule.js +48 -0
- package/src/services/enums/calendarenums.js +42 -37
- package/src/services/gmailapp/fakegmailapp.js +6 -10
- package/src/services/scriptapp/behavior.js +19 -25
- package/src/support/backoff.js +7 -1
- package/src/support/helpers.js +1 -1
- package/src/support/sxcalendar.js +15 -3
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"node": ">=20.11.0"
|
|
4
4
|
},
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@mcpher/fake-gasenum": "^1.0.
|
|
6
|
+
"@mcpher/fake-gasenum": "^1.0.6",
|
|
7
7
|
"@mcpher/gas-flex-cache": "^1.1.3",
|
|
8
8
|
"@modelcontextprotocol/sdk": "^1.20.2",
|
|
9
9
|
"@sindresorhus/is": "^7.0.1",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"name": "@mcpher/gas-fakes",
|
|
36
36
|
"author": "bruce mcpherson",
|
|
37
|
-
"version": "1.2.
|
|
37
|
+
"version": "1.2.30",
|
|
38
38
|
"license": "MIT",
|
|
39
39
|
"main": "main.js",
|
|
40
40
|
"description": "A proof of concept implementation of Apps Script Environment on Node",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Proxies } from '../../support/proxies.js';
|
|
2
2
|
import { newFakeCalendarEvent } from './fakecalendarevent.js';
|
|
3
3
|
import { newFakeCalendarEventSeries } from './fakecalendareventseries.js';
|
|
4
|
-
|
|
4
|
+
import { Utils } from '../../support/utils.js';
|
|
5
5
|
export const newFakeCalendar = (...args) => {
|
|
6
6
|
return Proxies.guard(new FakeCalendar(...args));
|
|
7
7
|
};
|
|
@@ -16,7 +16,9 @@ export class FakeCalendar {
|
|
|
16
16
|
* @param {object} resource The underlying Calendar resource (Advanced).
|
|
17
17
|
*/
|
|
18
18
|
constructor(id, resource) {
|
|
19
|
-
|
|
19
|
+
// If a resource is provided, use its canonical ID (e.g. email) instead of the lookup ID (e.g. 'primary')
|
|
20
|
+
// This matches GAS behavior where getId() returns the email even if retrieved via 'primary'
|
|
21
|
+
this.__id = (resource && resource.id) ? resource.id : id;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
/**
|
|
@@ -81,10 +83,13 @@ export class FakeCalendar {
|
|
|
81
83
|
const entry = this.__listEntry;
|
|
82
84
|
return entry ? entry.backgroundColor : '';
|
|
83
85
|
}
|
|
84
|
-
|
|
86
|
+
// this can be an enum, or a hex code
|
|
85
87
|
setColor(color) {
|
|
86
88
|
this.__checkWriteAccess();
|
|
87
|
-
|
|
89
|
+
if (Utils.isEnum(color)) {
|
|
90
|
+
color = color.toString();
|
|
91
|
+
}
|
|
92
|
+
Calendar.CalendarList.patch({ backgroundColor: color }, this.getId(), {colorRgbFormat: true});
|
|
88
93
|
return this;
|
|
89
94
|
}
|
|
90
95
|
|
|
@@ -123,11 +128,13 @@ export class FakeCalendar {
|
|
|
123
128
|
* Permanently deletes a calendar.
|
|
124
129
|
*/
|
|
125
130
|
deleteCalendar() {
|
|
131
|
+
this.__checkUsage('write');
|
|
126
132
|
this.__checkDeleteAccess();
|
|
127
|
-
Calendar.Calendars.
|
|
133
|
+
Calendar.Calendars.delete(this.getId());
|
|
128
134
|
}
|
|
129
135
|
|
|
130
136
|
unsubscribeFromCalendar() {
|
|
137
|
+
this.__checkUsage('write');
|
|
131
138
|
// Unsubscribes the user from a calendar (removes from list).
|
|
132
139
|
Calendar.CalendarList.remove(this.getId());
|
|
133
140
|
}
|
|
@@ -138,6 +145,7 @@ export class FakeCalendar {
|
|
|
138
145
|
if (startTime.getTime() >= endTime.getTime()) {
|
|
139
146
|
throw new Error('Event start date must be before event end date.');
|
|
140
147
|
}
|
|
148
|
+
this.__checkUsage('write');
|
|
141
149
|
this.__checkWriteAccess();
|
|
142
150
|
const resource = {
|
|
143
151
|
summary: title,
|
|
@@ -156,6 +164,7 @@ export class FakeCalendar {
|
|
|
156
164
|
}
|
|
157
165
|
|
|
158
166
|
createAllDayEvent(title, startDate, endDateOrOptions, options) {
|
|
167
|
+
this.__checkUsage('write');
|
|
159
168
|
this.__checkWriteAccess();
|
|
160
169
|
|
|
161
170
|
let endDate = startDate;
|
|
@@ -199,12 +208,14 @@ export class FakeCalendar {
|
|
|
199
208
|
}
|
|
200
209
|
|
|
201
210
|
createEventFromDescription(description) {
|
|
211
|
+
this.__checkUsage('write');
|
|
202
212
|
this.__checkWriteAccess();
|
|
203
213
|
const event = Calendar.Events.quickAdd(this.getId(), description);
|
|
204
214
|
return newFakeCalendarEvent(this.getId(), event);
|
|
205
215
|
}
|
|
206
216
|
|
|
207
217
|
getEvents(startTime, endTime, options) {
|
|
218
|
+
this.__checkUsage('read');
|
|
208
219
|
this.__checkReadAccess();
|
|
209
220
|
const args = {
|
|
210
221
|
timeMin: startTime.toISOString(),
|
|
@@ -232,6 +243,7 @@ export class FakeCalendar {
|
|
|
232
243
|
}
|
|
233
244
|
|
|
234
245
|
getEventById(iCalId) {
|
|
246
|
+
this.__checkUsage('read');
|
|
235
247
|
this.__checkReadAccess();
|
|
236
248
|
// Apps Script expects iCalUID. Try finding by iCalUID first using list.
|
|
237
249
|
// This avoids "Not Found" errors in the worker when passing iCalUID to events.get (which expects eventId)
|
|
@@ -252,18 +264,48 @@ export class FakeCalendar {
|
|
|
252
264
|
// --- Series ---
|
|
253
265
|
|
|
254
266
|
createEventSeries(title, startTime, endTime, recurrence, options) {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
267
|
+
this.__checkUsage('write');
|
|
268
|
+
this.__checkWriteAccess();
|
|
269
|
+
const resource = {
|
|
270
|
+
summary: title,
|
|
271
|
+
start: { dateTime: startTime.toISOString() },
|
|
272
|
+
end: { dateTime: endTime.toISOString() },
|
|
273
|
+
recurrence: [ recurrence.toString() ] // Assuming recurrence has proper RRULE string representation or handled
|
|
274
|
+
};
|
|
275
|
+
this.__applyEventOptions(resource, options);
|
|
276
|
+
const event = Calendar.Events.insert(resource, this.getId());
|
|
277
|
+
return newFakeCalendarEventSeries(this.getId(), event);
|
|
258
278
|
}
|
|
259
279
|
|
|
260
280
|
createAllDayEventSeries(title, startDate, recurrence, options) {
|
|
261
|
-
|
|
262
|
-
|
|
281
|
+
this.__checkUsage('write');
|
|
282
|
+
this.__checkWriteAccess();
|
|
283
|
+
const toDateString = (date) => date.toISOString().split('T')[0];
|
|
284
|
+
// For all day series, end date is usually next day for the first instance
|
|
285
|
+
const endDate = new Date(startDate);
|
|
286
|
+
endDate.setDate(endDate.getDate() + 1);
|
|
287
|
+
|
|
288
|
+
const resource = {
|
|
289
|
+
summary: title,
|
|
290
|
+
start: { date: toDateString(startDate) },
|
|
291
|
+
end: { date: toDateString(endDate) },
|
|
292
|
+
recurrence: [ recurrence.toString() ]
|
|
293
|
+
};
|
|
294
|
+
this.__applyEventOptions(resource, options);
|
|
295
|
+
const event = Calendar.Events.insert(resource, this.getId());
|
|
296
|
+
return newFakeCalendarEventSeries(this.getId(), event);
|
|
263
297
|
}
|
|
264
298
|
|
|
265
299
|
getEventSeriesById(iCalId) {
|
|
266
|
-
|
|
300
|
+
this.__checkUsage('read');
|
|
301
|
+
this.__checkReadAccess();
|
|
302
|
+
try {
|
|
303
|
+
const event = Calendar.Events.get(this.getId(), iCalId);
|
|
304
|
+
// Check if it's actually a recurring event (has recurrence or is instance)
|
|
305
|
+
if (event.recurrence || event.recurringEventId) {
|
|
306
|
+
return newFakeCalendarEventSeries(this.getId(), event);
|
|
307
|
+
}
|
|
308
|
+
} catch (e) {}
|
|
267
309
|
return null;
|
|
268
310
|
}
|
|
269
311
|
|
|
@@ -277,6 +319,34 @@ export class FakeCalendar {
|
|
|
277
319
|
}
|
|
278
320
|
}
|
|
279
321
|
|
|
322
|
+
__checkUsage(type) {
|
|
323
|
+
const serviceName = 'CalendarApp';
|
|
324
|
+
const behavior = ScriptApp.__behavior;
|
|
325
|
+
if (behavior.sandboxMode) {
|
|
326
|
+
const settings = behavior.sandboxService[serviceName];
|
|
327
|
+
let limit = settings && settings.usageLimit;
|
|
328
|
+
if (limit) {
|
|
329
|
+
if (typeof limit === 'number') {
|
|
330
|
+
const total = (settings.usageCount.read || 0) + (settings.usageCount.write || 0) + (settings.usageCount.trash || 0);
|
|
331
|
+
if (total >= limit) {
|
|
332
|
+
throw new Error(`Calendar total usage limit of ${limit} exceeded`);
|
|
333
|
+
}
|
|
334
|
+
settings.incrementUsage(type);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
let specificLimit = limit[type];
|
|
339
|
+
if (specificLimit !== undefined) {
|
|
340
|
+
const current = settings.usageCount[type] || 0;
|
|
341
|
+
if (current >= specificLimit) {
|
|
342
|
+
throw new Error(`Calendar ${type} usage limit of ${specificLimit} exceeded`);
|
|
343
|
+
}
|
|
344
|
+
settings.incrementUsage(type);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
280
350
|
__checkAccess(accessType) {
|
|
281
351
|
const behavior = ScriptApp.__behavior;
|
|
282
352
|
if (!behavior.sandboxMode) return true;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Proxies } from '../../support/proxies.js';
|
|
2
2
|
import * as CalendarEnums from '../enums/calendarenums.js';
|
|
3
3
|
import { newFakeCalendar } from './fakecalendar.js';
|
|
4
|
+
import { newFakeEventRecurrence } from './fakeeventrecurrence.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Creates a new FakeCalendarApp instance.
|
|
@@ -20,16 +21,31 @@ export class FakeCalendarApp {
|
|
|
20
21
|
Object.assign(this, CalendarEnums);
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
// --- Service Methods ---
|
|
25
|
+
|
|
26
|
+
newRecurrence() {
|
|
27
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'newRecurrence');
|
|
28
|
+
return newFakeEventRecurrence();
|
|
29
|
+
}
|
|
30
|
+
|
|
23
31
|
createCalendar(name, options = {}) {
|
|
24
32
|
ScriptApp.__behavior.checkMethod('CalendarApp', 'createCalendar');
|
|
25
33
|
this.__checkUsage('write');
|
|
26
34
|
const resource = Calendar.Calendars.insert({ summary: name, ...options });
|
|
27
|
-
if (
|
|
35
|
+
if (resource.id) {
|
|
28
36
|
ScriptApp.__behavior.addCalendarId(resource.id);
|
|
29
37
|
}
|
|
30
38
|
return newFakeCalendar(resource.id, resource);
|
|
31
39
|
}
|
|
32
40
|
|
|
41
|
+
subscribeToCalendar(id) {
|
|
42
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'subscribeToCalendar');
|
|
43
|
+
this.__checkUsage('write');
|
|
44
|
+
const resource = { id };
|
|
45
|
+
Calendar.CalendarList.insert(resource);
|
|
46
|
+
return newFakeCalendar(id);
|
|
47
|
+
}
|
|
48
|
+
|
|
33
49
|
getCalendarById(id) {
|
|
34
50
|
ScriptApp.__behavior.checkMethod('CalendarApp', 'getCalendarById');
|
|
35
51
|
this.__checkUsage('read');
|
|
@@ -53,6 +69,19 @@ export class FakeCalendarApp {
|
|
|
53
69
|
.map(item => newFakeCalendar(item.id, item));
|
|
54
70
|
}
|
|
55
71
|
|
|
72
|
+
getOwnedCalendarsByName(name) {
|
|
73
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'getOwnedCalendarsByName');
|
|
74
|
+
this.__checkUsage('read');
|
|
75
|
+
return this.getCalendarsByName(name).filter(c => c.isOwnedByMe());
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
getOwnedCalendarById(id) {
|
|
79
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'getOwnedCalendarById');
|
|
80
|
+
this.__checkUsage('read');
|
|
81
|
+
const cal = this.getCalendarById(id);
|
|
82
|
+
return cal && cal.isOwnedByMe() ? cal : null;
|
|
83
|
+
}
|
|
84
|
+
|
|
56
85
|
getAllCalendars() {
|
|
57
86
|
ScriptApp.__behavior.checkMethod('CalendarApp', 'getAllCalendars');
|
|
58
87
|
this.__checkUsage('read');
|
|
@@ -72,6 +101,109 @@ export class FakeCalendarApp {
|
|
|
72
101
|
.map(item => newFakeCalendar(item.id, item));
|
|
73
102
|
}
|
|
74
103
|
|
|
104
|
+
// --- Default Calendar Delegates ---
|
|
105
|
+
|
|
106
|
+
createAllDayEvent(...args) {
|
|
107
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'createAllDayEvent');
|
|
108
|
+
return this.getDefaultCalendar().createAllDayEvent(...args);
|
|
109
|
+
}
|
|
110
|
+
createAllDayEventSeries(...args) {
|
|
111
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'createAllDayEventSeries');
|
|
112
|
+
return this.getDefaultCalendar().createAllDayEventSeries(...args);
|
|
113
|
+
}
|
|
114
|
+
createEvent(...args) {
|
|
115
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'createEvent');
|
|
116
|
+
return this.getDefaultCalendar().createEvent(...args);
|
|
117
|
+
}
|
|
118
|
+
createEventFromDescription(...args) {
|
|
119
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'createEventFromDescription');
|
|
120
|
+
return this.getDefaultCalendar().createEventFromDescription(...args);
|
|
121
|
+
}
|
|
122
|
+
createEventSeries(...args) {
|
|
123
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'createEventSeries');
|
|
124
|
+
return this.getDefaultCalendar().createEventSeries(...args);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
getEventById(id) {
|
|
128
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'getEventById');
|
|
129
|
+
return this.getDefaultCalendar().getEventById(id);
|
|
130
|
+
}
|
|
131
|
+
getEvents(...args) {
|
|
132
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'getEvents');
|
|
133
|
+
return this.getDefaultCalendar().getEvents(...args);
|
|
134
|
+
}
|
|
135
|
+
getEventsForDay(...args) {
|
|
136
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'getEventsForDay');
|
|
137
|
+
return this.getDefaultCalendar().getEventsForDay(...args);
|
|
138
|
+
}
|
|
139
|
+
getEventSeriesById(id) {
|
|
140
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'getEventSeriesById');
|
|
141
|
+
return this.getDefaultCalendar().getEventSeriesById(id);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
getColor() {
|
|
145
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'getColor');
|
|
146
|
+
return this.getDefaultCalendar().getColor();
|
|
147
|
+
}
|
|
148
|
+
setColor(color) {
|
|
149
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'setColor');
|
|
150
|
+
return this.getDefaultCalendar().setColor(color);
|
|
151
|
+
}
|
|
152
|
+
getDescription() {
|
|
153
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'getDescription');
|
|
154
|
+
return this.getDefaultCalendar().getDescription();
|
|
155
|
+
}
|
|
156
|
+
setDescription(description) {
|
|
157
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'setDescription');
|
|
158
|
+
return this.getDefaultCalendar().setDescription(description);
|
|
159
|
+
}
|
|
160
|
+
getId() {
|
|
161
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'getId');
|
|
162
|
+
return this.getDefaultCalendar().getId();
|
|
163
|
+
}
|
|
164
|
+
getName() {
|
|
165
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'getName');
|
|
166
|
+
return this.getDefaultCalendar().getName();
|
|
167
|
+
}
|
|
168
|
+
setName(name) {
|
|
169
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'setName');
|
|
170
|
+
return this.getDefaultCalendar().setName(name);
|
|
171
|
+
}
|
|
172
|
+
getTimeZone() {
|
|
173
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'getTimeZone');
|
|
174
|
+
return this.getDefaultCalendar().getTimeZone();
|
|
175
|
+
}
|
|
176
|
+
setTimeZone(timeZone) {
|
|
177
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'setTimeZone');
|
|
178
|
+
return this.getDefaultCalendar().setTimeZone(timeZone);
|
|
179
|
+
}
|
|
180
|
+
isHidden() {
|
|
181
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'isHidden');
|
|
182
|
+
return this.getDefaultCalendar().isHidden();
|
|
183
|
+
}
|
|
184
|
+
setHidden(hidden) {
|
|
185
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'setHidden');
|
|
186
|
+
return this.getDefaultCalendar().setHidden(hidden);
|
|
187
|
+
}
|
|
188
|
+
isSelected() {
|
|
189
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'isSelected');
|
|
190
|
+
return this.getDefaultCalendar().isSelected();
|
|
191
|
+
}
|
|
192
|
+
setSelected(selected) {
|
|
193
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'setSelected');
|
|
194
|
+
return this.getDefaultCalendar().setSelected(selected);
|
|
195
|
+
}
|
|
196
|
+
isMyPrimaryCalendar() {
|
|
197
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'isMyPrimaryCalendar');
|
|
198
|
+
return this.getDefaultCalendar().isMyPrimaryCalendar();
|
|
199
|
+
}
|
|
200
|
+
isOwnedByMe() {
|
|
201
|
+
ScriptApp.__behavior.checkMethod('CalendarApp', 'isOwnedByMe');
|
|
202
|
+
return this.getDefaultCalendar().isOwnedByMe();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// --- Internals ---
|
|
206
|
+
|
|
75
207
|
__isCalendarAccessible(calendarId) {
|
|
76
208
|
try {
|
|
77
209
|
this.__checkCalendarAccess(calendarId);
|