Repository navigation
Expand file tree
/
Copy pathworker.js
More file actions
63 lines (58 loc) · 2.2 KB
/
Copy pathworker.js
File metadata and controls
63 lines (58 loc) · 2.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/**
* forceCalendar core as a server-side scheduling engine on Cloudflare Workers.
*
* Workers ban eval and dynamic code generation — @forcecalendar/core is
* pure ES modules with zero dependencies, so it deploys unmodified.
*
* Endpoints:
* GET /occurrences?rrule=FREQ=WEEKLY;BYDAY=MO,WE;COUNT=10&start=2026-01-05T09:00:00Z
* -> JSON array of expanded occurrences
* GET /ics?rrule=...&start=...&title=Standup
* -> downloadable iCalendar file
*/
import { Calendar, RecurrenceEngine, ICSHandler } from '@forcecalendar/core';
function eventFromQuery(params) {
const start = new Date(params.get('start') || Date.now());
const durationMin = Number(params.get('duration') || 60);
return {
id: 'evt-1',
title: params.get('title') || 'Recurring event',
start,
end: new Date(start.getTime() + durationMin * 60000),
recurring: true,
recurrenceRule: params.get('rrule') || 'FREQ=DAILY;COUNT=7',
timeZone: params.get('tz') || 'UTC'
};
}
export default {
async fetch(request) {
const url = new URL(request.url);
const event = eventFromQuery(url.searchParams);
const rangeStart = new Date(url.searchParams.get('from') || event.start);
const rangeEnd = new Date(
url.searchParams.get('to') || rangeStart.getTime() + 366 * 86400000
);
if (url.pathname === '/occurrences') {
const occurrences = RecurrenceEngine.expandEvent(event, rangeStart, rangeEnd, 500);
return Response.json({
rule: event.recurrenceRule,
count: occurrences.length,
occurrences: occurrences.map(o => ({ start: o.start, end: o.end }))
});
}
if (url.pathname === '/ics') {
const calendar = new Calendar({ timeZone: event.timeZone });
calendar.addEvent(event);
const ics = new ICSHandler(calendar).export({ calendarName: event.title });
return new Response(ics, {
headers: {
'Content-Type': 'text/calendar; charset=utf-8',
'Content-Disposition': 'attachment; filename="event.ics"'
}
});
}
return Response.json({
usage: ['/occurrences?rrule=FREQ=WEEKLY;BYDAY=MO,WE;COUNT=10&start=2026-01-05T09:00:00Z', '/ics?rrule=FREQ=DAILY;COUNT=5&title=Standup']
});
}
};