@remit/calendar-service 0.0.18 → 0.0.20

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.
Files changed (73) hide show
  1. package/dist/accept.d.ts +71 -0
  2. package/dist/accept.js +159 -0
  3. package/dist/build.d.ts +79 -0
  4. package/dist/build.js +196 -0
  5. package/dist/correct.d.ts +4 -0
  6. package/dist/correct.js +22 -0
  7. package/dist/errors.d.ts +56 -0
  8. package/dist/errors.js +1 -0
  9. package/dist/etag.d.ts +9 -0
  10. package/{src/etag.ts → dist/etag.js} +1 -3
  11. package/dist/expand.d.ts +73 -0
  12. package/dist/expand.js +188 -0
  13. package/dist/feed.d.ts +81 -0
  14. package/dist/feed.js +157 -0
  15. package/dist/fixtures.d.ts +19 -0
  16. package/dist/fixtures.js +37 -0
  17. package/dist/index.d.ts +16 -0
  18. package/dist/index.js +15 -0
  19. package/dist/memory-store.d.ts +105 -0
  20. package/dist/memory-store.js +319 -0
  21. package/dist/parse.d.ts +39 -0
  22. package/dist/parse.js +87 -0
  23. package/dist/project.d.ts +30 -0
  24. package/dist/project.js +57 -0
  25. package/dist/put.d.ts +52 -0
  26. package/dist/put.js +78 -0
  27. package/dist/reopen.d.ts +14 -0
  28. package/dist/reopen.js +92 -0
  29. package/dist/scope.d.ts +70 -0
  30. package/dist/scope.js +687 -0
  31. package/dist/subscribe.d.ts +96 -0
  32. package/dist/subscribe.js +298 -0
  33. package/dist/suggest.d.ts +74 -0
  34. package/dist/suggest.js +138 -0
  35. package/dist/time.d.ts +76 -0
  36. package/dist/time.js +164 -0
  37. package/dist/window.d.ts +85 -0
  38. package/dist/window.js +161 -0
  39. package/package.json +40 -35
  40. package/src/accept.test.ts +0 -403
  41. package/src/accept.ts +0 -250
  42. package/src/build.test.ts +0 -113
  43. package/src/build.ts +0 -311
  44. package/src/correct.test.ts +0 -173
  45. package/src/correct.ts +0 -40
  46. package/src/errors.ts +0 -62
  47. package/src/etag.test.ts +0 -54
  48. package/src/expand.test.ts +0 -361
  49. package/src/expand.ts +0 -303
  50. package/src/feed.test.ts +0 -334
  51. package/src/feed.ts +0 -203
  52. package/src/feeds/google-secret-address.ics +0 -99
  53. package/src/fixtures.ts +0 -52
  54. package/src/index.ts +0 -128
  55. package/src/memory-store.ts +0 -485
  56. package/src/parse.test.ts +0 -264
  57. package/src/parse.ts +0 -138
  58. package/src/project.test.ts +0 -247
  59. package/src/project.ts +0 -122
  60. package/src/put.test.ts +0 -318
  61. package/src/put.ts +0 -133
  62. package/src/reopen.test.ts +0 -529
  63. package/src/reopen.ts +0 -199
  64. package/src/scope.test.ts +0 -1421
  65. package/src/scope.ts +0 -1003
  66. package/src/subscribe.test.ts +0 -582
  67. package/src/subscribe.ts +0 -433
  68. package/src/suggest.test.ts +0 -376
  69. package/src/suggest.ts +0 -244
  70. package/src/time.ts +0 -260
  71. package/src/window.test.ts +0 -648
  72. package/src/window.ts +0 -281
  73. package/tsconfig.json +0 -8
package/src/project.ts DELETED
@@ -1,122 +0,0 @@
1
- import type { CalendarObjectItem } from "@remit/data-ports";
2
- import { CalendarEventStatus, CalendarTransparency } from "@remit/domain-enums";
3
- import ICAL from "ical.js";
4
- import { type CalendarResult, calendarFailure } from "./errors.js";
5
- import type { ParsedCalendar } from "./parse.js";
6
- import { resolveTime, tzidOf } from "./time.js";
7
-
8
- /**
9
- * The columns `CalendarObject` carries beside its bytes. Every one of them is
10
- * read out of the VEVENT here and nowhere else, so the row can only ever
11
- * describe the `icalData` it was written with.
12
- */
13
- export type CalendarObjectProjection = Pick<
14
- CalendarObjectItem,
15
- | "icalUid"
16
- | "summary"
17
- | "dtStart"
18
- | "dtEnd"
19
- | "allDay"
20
- | "zoneCertainty"
21
- | "status"
22
- | "transparency"
23
- | "hasRecurrence"
24
- | "sequence"
25
- >;
26
-
27
- const STATUS_BY_ICAL: Record<string, CalendarObjectItem["status"]> = {
28
- CONFIRMED: CalendarEventStatus.Confirmed,
29
- TENTATIVE: CalendarEventStatus.Tentative,
30
- CANCELLED: CalendarEventStatus.Cancelled,
31
- };
32
-
33
- const TRANSPARENCY_BY_ICAL: Record<string, CalendarObjectItem["transparency"]> =
34
- {
35
- OPAQUE: CalendarTransparency.Opaque,
36
- TRANSPARENT: CalendarTransparency.Transparent,
37
- };
38
-
39
- export const readString = (component: ICAL.Component, name: string): string => {
40
- const value = component.getFirstPropertyValue(name);
41
- return typeof value === "string" ? value : "";
42
- };
43
-
44
- /**
45
- * The fields that describe one VEVENT rather than the series it belongs to.
46
- *
47
- * Read per occurrence as well as per resource: an override VEVENT carries its
48
- * own summary, status and transparency, and a range read that took them from
49
- * the master would draw the old title over an edited instance and count a
50
- * cancelled one as busy time.
51
- */
52
- export type CalendarEventDisplay = Pick<
53
- CalendarObjectItem,
54
- "summary" | "status" | "transparency"
55
- >;
56
-
57
- export const projectEventDisplay = (
58
- component: ICAL.Component,
59
- ): CalendarEventDisplay => ({
60
- summary: readString(component, "summary"),
61
- status:
62
- STATUS_BY_ICAL[readString(component, "status").toUpperCase()] ??
63
- CalendarEventStatus.Confirmed,
64
- transparency:
65
- TRANSPARENCY_BY_ICAL[readString(component, "transp").toUpperCase()] ??
66
- CalendarTransparency.Opaque,
67
- });
68
-
69
- /**
70
- * Whether the resource expands to more than its master instance — an RRULE, an
71
- * RDATE, or an override VEVENT. The overrides count: a client that edits one
72
- * instance of a series and then deletes the rule leaves a resource with nothing
73
- * but a master and its exceptions, and every one of those is still an
74
- * occurrence somebody has to see.
75
- */
76
- export const hasRecurrence = (calendar: ParsedCalendar): boolean =>
77
- calendar.master.hasProperty("rrule") ||
78
- calendar.master.hasProperty("rdate") ||
79
- calendar.overrides.length > 0;
80
-
81
- export const projectCalendar = (
82
- calendar: ParsedCalendar,
83
- collectionTimezone: string,
84
- ): CalendarResult<CalendarObjectProjection> => {
85
- const event = new ICAL.Event(calendar.master);
86
- const start = resolveTime(
87
- event.startDate,
88
- tzidOf(calendar.master.getFirstProperty("dtstart")),
89
- collectionTimezone,
90
- );
91
- const end = resolveTime(
92
- event.endDate,
93
- tzidOf(
94
- calendar.master.getFirstProperty("dtend") ??
95
- calendar.master.getFirstProperty("dtstart"),
96
- ),
97
- collectionTimezone,
98
- );
99
-
100
- if (end.instantMs < start.instantMs) {
101
- return calendarFailure(
102
- "BackwardsEnd",
103
- `the event ends at ${end.isoUtc}, before it starts at ${start.isoUtc}`,
104
- );
105
- }
106
-
107
- const sequence = calendar.master.getFirstPropertyValue("sequence");
108
-
109
- return {
110
- ok: true,
111
- value: {
112
- icalUid: calendar.uid,
113
- dtStart: start.isoOffset,
114
- dtEnd: end.isoOffset,
115
- allDay: start.isDate,
116
- zoneCertainty: start.certainty,
117
- ...projectEventDisplay(calendar.master),
118
- hasRecurrence: hasRecurrence(calendar),
119
- sequence: typeof sequence === "number" ? sequence : 0,
120
- },
121
- };
122
- };
package/src/put.test.ts DELETED
@@ -1,318 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import { describe, it } from "node:test";
3
- import { computeEtag } from "./etag.js";
4
- import { asLf, singleEvent } from "./fixtures.js";
5
- import { MemoryCalendarStore, MissingRow } from "./memory-store.js";
6
- import { parseCalendar, serializeCalendar } from "./parse.js";
7
- import {
8
- DEFAULT_CALENDAR_URL_SEGMENT,
9
- deleteCalendarObject,
10
- provisionDefaultCalendar,
11
- putCalendarObject,
12
- } from "./put.js";
13
-
14
- const ACCOUNT_CONFIG_ID = "account-config-1";
15
-
16
- const provisioned = async (): Promise<{
17
- store: MemoryCalendarStore;
18
- calendarId: string;
19
- }> => {
20
- const store = new MemoryCalendarStore();
21
- const collection = await provisionDefaultCalendar(store, ACCOUNT_CONFIG_ID);
22
- return { store, calendarId: collection.calendarId };
23
- };
24
-
25
- const RESOURCE = singleEvent(
26
- "DTSTART:20260826T090000Z",
27
- "DTEND:20260826T100000Z",
28
- "SUMMARY:Quarterly review",
29
- );
30
-
31
- describe("provisionDefaultCalendar", () => {
32
- it("gives an account config a default collection at the default segment", async () => {
33
- const store = new MemoryCalendarStore();
34
-
35
- const collection = await provisionDefaultCalendar(store, ACCOUNT_CONFIG_ID);
36
-
37
- assert.equal(collection.urlSegment, DEFAULT_CALENDAR_URL_SEGMENT);
38
- assert.equal(collection.source, "Default");
39
- assert.equal(collection.displayName, "Calendar");
40
- });
41
-
42
- it("returns the same collection on a second first use", async () => {
43
- const store = new MemoryCalendarStore();
44
-
45
- const first = await provisionDefaultCalendar(store, ACCOUNT_CONFIG_ID);
46
- const second = await provisionDefaultCalendar(store, ACCOUNT_CONFIG_ID);
47
-
48
- assert.equal(second.calendarId, first.calendarId);
49
- assert.equal(store.collections.size, 1);
50
- });
51
- });
52
-
53
- describe("putCalendarObject", () => {
54
- it("stores the bytes it was given, untouched", async () => {
55
- const { store, calendarId } = await provisioned();
56
-
57
- const result = await putCalendarObject(store, {
58
- accountConfigId: ACCOUNT_CONFIG_ID,
59
- calendarId,
60
- resourceName: "review.ics",
61
- icalData: RESOURCE,
62
- });
63
-
64
- assert.ok(result.ok);
65
- assert.equal(result.value.icalData, RESOURCE);
66
- assert.equal(result.value.summary, "Quarterly review");
67
- assert.equal(result.value.icalUid, "fixture@example.com");
68
- });
69
-
70
- it("stores the input bytes rather than a reserialization of them", async () => {
71
- // The etag is a digest of what the writer sent. ical.js refolds and
72
- // reorders on serialize, so a write path that stored its own
73
- // reserialization would hand back a tag for bytes nobody wrote, and every
74
- // client's cached copy would miss on the next read.
75
- const { store, calendarId } = await provisioned();
76
- const source = singleEvent(
77
- "DTSTART:20260826T090000Z",
78
- "DTEND:20260826T100000Z",
79
- "SUMMARY:A summary long enough that RFC 5545 line folding rewrites it when ical.js serializes the event again",
80
- "X-MICROSOFT-CDO-BUSYSTATUS:BUSY",
81
- );
82
- const parsed = await parseCalendar(source);
83
- assert.ok(parsed.ok);
84
- const reserialized = serializeCalendar(parsed.value.component);
85
- assert.notEqual(
86
- reserialized,
87
- source,
88
- "the fixture survives reserialization unchanged, so it proves nothing",
89
- );
90
-
91
- const result = await putCalendarObject(store, {
92
- accountConfigId: ACCOUNT_CONFIG_ID,
93
- calendarId,
94
- resourceName: "folded.ics",
95
- icalData: source,
96
- });
97
-
98
- assert.ok(result.ok);
99
- assert.equal(result.value.icalData, source);
100
- assert.equal(result.value.etag, computeEtag(source));
101
- assert.notEqual(result.value.etag, computeEtag(reserialized));
102
- });
103
-
104
- it("stores an LF-only resource as it arrived, without normalizing it", async () => {
105
- // The store keeps what the writer sent. Rewriting line endings on the way
106
- // in would give the resource an etag for bytes nobody wrote, and the
107
- // writer's own If-Match would miss on its very next request.
108
- const { store, calendarId } = await provisioned();
109
- const source = asLf(RESOURCE);
110
-
111
- const result = await putCalendarObject(store, {
112
- accountConfigId: ACCOUNT_CONFIG_ID,
113
- calendarId,
114
- resourceName: "lf.ics",
115
- icalData: source,
116
- });
117
-
118
- assert.ok(result.ok);
119
- assert.equal(result.value.icalData, source);
120
- assert.ok(!result.value.icalData.includes("\r"));
121
- assert.equal(result.value.etag, computeEtag(source));
122
- assert.equal(result.value.summary, "Quarterly review");
123
- assert.equal(result.value.dtStart, "2026-08-26T09:00:00+00:00");
124
- });
125
-
126
- it("writes the occurrence rows the resource expands to", async () => {
127
- const { store, calendarId } = await provisioned();
128
-
129
- const result = await putCalendarObject(store, {
130
- accountConfigId: ACCOUNT_CONFIG_ID,
131
- calendarId,
132
- resourceName: "series.ics",
133
- icalData: singleEvent(
134
- "DTSTART:20260826T090000Z",
135
- "DTEND:20260826T100000Z",
136
- "RRULE:FREQ=WEEKLY;COUNT=3",
137
- ),
138
- });
139
-
140
- assert.ok(result.ok);
141
- assert.equal(
142
- store.occurrences.get(result.value.calendarObjectId)?.length,
143
- 3,
144
- );
145
- });
146
-
147
- it("replaces the occurrences of a resource it rewrites", async () => {
148
- const { store, calendarId } = await provisioned();
149
- const input = {
150
- accountConfigId: ACCOUNT_CONFIG_ID,
151
- calendarId,
152
- resourceName: "series.ics",
153
- };
154
-
155
- await putCalendarObject(store, {
156
- ...input,
157
- icalData: singleEvent(
158
- "DTSTART:20260826T090000Z",
159
- "DTEND:20260826T100000Z",
160
- "RRULE:FREQ=WEEKLY;COUNT=5",
161
- ),
162
- });
163
- const result = await putCalendarObject(store, {
164
- ...input,
165
- icalData: singleEvent(
166
- "DTSTART:20260826T090000Z",
167
- "DTEND:20260826T100000Z",
168
- "RRULE:FREQ=WEEKLY;COUNT=2",
169
- ),
170
- });
171
-
172
- assert.ok(result.ok);
173
- assert.equal(store.objects.size, 1);
174
- assert.equal(
175
- store.occurrences.get(result.value.calendarObjectId)?.length,
176
- 2,
177
- );
178
- });
179
-
180
- it("stamps the collection's new sequence on the resource it wrote", async () => {
181
- const { store, calendarId } = await provisioned();
182
-
183
- const first = await putCalendarObject(store, {
184
- accountConfigId: ACCOUNT_CONFIG_ID,
185
- calendarId,
186
- resourceName: "one.ics",
187
- icalData: RESOURCE,
188
- });
189
- const second = await putCalendarObject(store, {
190
- accountConfigId: ACCOUNT_CONFIG_ID,
191
- calendarId,
192
- resourceName: "two.ics",
193
- icalData: singleEvent(
194
- "DTSTART:20260827T090000Z",
195
- "DTEND:20260827T100000Z",
196
- ),
197
- });
198
-
199
- assert.ok(first.ok);
200
- assert.ok(second.ok);
201
- assert.equal(first.value.syncSequence, 1);
202
- assert.equal(second.value.syncSequence, 2);
203
- assert.equal(store.collections.get(calendarId)?.syncSequence, 2);
204
- });
205
-
206
- it("computes the etag over the stored bytes", async () => {
207
- const { store, calendarId } = await provisioned();
208
-
209
- const result = await putCalendarObject(store, {
210
- accountConfigId: ACCOUNT_CONFIG_ID,
211
- calendarId,
212
- resourceName: "review.ics",
213
- icalData: RESOURCE,
214
- });
215
-
216
- assert.ok(result.ok);
217
- assert.match(result.value.etag, /^[0-9a-f]{64}$/);
218
- });
219
-
220
- it("refuses a resource the collection does not store, and writes nothing", async () => {
221
- const { store, calendarId } = await provisioned();
222
-
223
- const result = await putCalendarObject(store, {
224
- accountConfigId: ACCOUNT_CONFIG_ID,
225
- calendarId,
226
- resourceName: "todo.ics",
227
- icalData: [
228
- "BEGIN:VCALENDAR",
229
- "VERSION:2.0",
230
- "BEGIN:VTODO",
231
- "UID:todo@example.com",
232
- "END:VTODO",
233
- "END:VCALENDAR",
234
- "",
235
- ].join("\r\n"),
236
- });
237
-
238
- assert.ok(!result.ok);
239
- assert.equal(result.error.code, "UnsupportedComponent");
240
- assert.equal(store.objects.size, 0);
241
- assert.equal(store.collections.get(calendarId)?.syncSequence, 0);
242
- });
243
-
244
- it("refuses an event that ends before it starts", async () => {
245
- const { store, calendarId } = await provisioned();
246
-
247
- const result = await putCalendarObject(store, {
248
- accountConfigId: ACCOUNT_CONFIG_ID,
249
- calendarId,
250
- resourceName: "backwards.ics",
251
- icalData: singleEvent(
252
- "DTSTART:20260826T100000Z",
253
- "DTEND:20260826T090000Z",
254
- ),
255
- });
256
-
257
- assert.ok(!result.ok);
258
- assert.equal(result.error.code, "BackwardsEnd");
259
- assert.equal(store.objects.size, 0);
260
- });
261
-
262
- it("fails loudly when the collection does not exist", async () => {
263
- const store = new MemoryCalendarStore();
264
-
265
- await assert.rejects(
266
- putCalendarObject(store, {
267
- accountConfigId: ACCOUNT_CONFIG_ID,
268
- calendarId: "no-such-calendar",
269
- resourceName: "review.ics",
270
- icalData: RESOURCE,
271
- }),
272
- MissingRow,
273
- );
274
- });
275
-
276
- it("projects the event in the collection's timezone", async () => {
277
- const store = new MemoryCalendarStore();
278
- const collection = await store.repos.calendarCollection.create({
279
- accountConfigId: ACCOUNT_CONFIG_ID,
280
- urlSegment: "berlin",
281
- displayName: "Berlin",
282
- timezone: "Europe/Berlin",
283
- });
284
-
285
- const result = await putCalendarObject(store, {
286
- accountConfigId: ACCOUNT_CONFIG_ID,
287
- calendarId: collection.calendarId,
288
- resourceName: "floating.ics",
289
- icalData: singleEvent("DTSTART:20260826T090000", "DTEND:20260826T100000"),
290
- });
291
-
292
- assert.ok(result.ok);
293
- assert.equal(result.value.dtStart, "2026-08-26T09:00:00+02:00");
294
- });
295
- });
296
-
297
- describe("deleteCalendarObject", () => {
298
- it("takes the occurrences with the resource and bumps the collection", async () => {
299
- const { store, calendarId } = await provisioned();
300
- const written = await putCalendarObject(store, {
301
- accountConfigId: ACCOUNT_CONFIG_ID,
302
- calendarId,
303
- resourceName: "review.ics",
304
- icalData: RESOURCE,
305
- });
306
- assert.ok(written.ok);
307
-
308
- await deleteCalendarObject(store, {
309
- accountConfigId: ACCOUNT_CONFIG_ID,
310
- calendarId,
311
- calendarObjectId: written.value.calendarObjectId,
312
- });
313
-
314
- assert.equal(store.objects.size, 0);
315
- assert.equal(store.occurrences.size, 0);
316
- assert.equal(store.collections.get(calendarId)?.syncSequence, 2);
317
- });
318
- });
package/src/put.ts DELETED
@@ -1,133 +0,0 @@
1
- import type {
2
- CalendarCollectionItem,
3
- CalendarObjectItem,
4
- DeleteCalendarObjectWrite,
5
- ICalendarStore,
6
- PutCalendarObjectWrite,
7
- } from "@remit/data-ports";
8
- import { deriveCalendarObjectId } from "@remit/data-ports/id";
9
- import { CalendarSource } from "@remit/domain-enums";
10
- import type { CalendarResult } from "./errors.js";
11
- import { computeEtag } from "./etag.js";
12
- import { expandCalendar } from "./expand.js";
13
- import { parseCalendar } from "./parse.js";
14
- import { projectCalendar } from "./project.js";
15
-
16
- /** URL segment of the collection every account config is provisioned with. */
17
- export const DEFAULT_CALENDAR_URL_SEGMENT = "default";
18
-
19
- export interface PutCalendarObjectInput {
20
- accountConfigId: string;
21
- calendarId: string;
22
- /** Last path segment of the resource's URL, e.g. `"a1b2c3.ics"`. */
23
- resourceName: string;
24
- /** The VCALENDAR text as it arrived, stored byte-for-byte. */
25
- icalData: string;
26
- }
27
-
28
- /**
29
- * Turns one calendar resource into the write that stores it, read in the
30
- * collection's timezone. Every caller that stores an event goes through here —
31
- * a REST handler, a DAV PUT, an accepted suggestion, a feed refresh — because
32
- * the object row, its occurrence rows and the collection's sequence bump are
33
- * one fact, and a caller that writes any of them alone leaves the store
34
- * describing a calendar that does not exist.
35
- *
36
- * The bytes are stored exactly as given: parsing is for validating and
37
- * projecting them, never for rewriting them. Refusing the resource is a
38
- * returned value — the input is client-supplied, so malformed iCalendar is an
39
- * outcome the caller renders, not a fault.
40
- */
41
- export const prepareCalendarObject = async (
42
- collection: Pick<CalendarCollectionItem, "timezone">,
43
- input: PutCalendarObjectInput,
44
- ): Promise<CalendarResult<PutCalendarObjectWrite>> => {
45
- const parsed = await parseCalendar(input.icalData);
46
- if (!parsed.ok) return parsed;
47
-
48
- const projection = projectCalendar(parsed.value, collection.timezone);
49
- if (!projection.ok) return projection;
50
-
51
- const expansion = expandCalendar(parsed.value, collection.timezone);
52
- return {
53
- ok: true,
54
- value: {
55
- kind: "PutObject",
56
- accountConfigId: input.accountConfigId,
57
- object: {
58
- ...projection.value,
59
- calendarId: input.calendarId,
60
- resourceName: input.resourceName,
61
- icalData: input.icalData,
62
- etag: computeEtag(input.icalData),
63
- expandedThrough: expansion.expandedThrough,
64
- },
65
- occurrences: expansion.occurrences,
66
- },
67
- };
68
- };
69
-
70
- /** The resource a committed put wrote, under the id its name derives to. */
71
- export const readWrittenObject = (
72
- store: ICalendarStore,
73
- write: PutCalendarObjectWrite,
74
- ): Promise<CalendarObjectItem> =>
75
- store.repos.calendarObject.get(
76
- write.object.calendarId,
77
- deriveCalendarObjectId(write.object.calendarId, write.object.resourceName),
78
- );
79
-
80
- /** Writes one calendar resource into its collection. */
81
- export const putCalendarObject = async (
82
- store: ICalendarStore,
83
- input: PutCalendarObjectInput,
84
- ): Promise<CalendarResult<CalendarObjectItem>> => {
85
- const collection = await store.repos.calendarCollection.get(
86
- input.accountConfigId,
87
- input.calendarId,
88
- );
89
- const write = await prepareCalendarObject(collection, input);
90
- if (!write.ok) return write;
91
- await store.commit([write.value]);
92
- return { ok: true, value: await readWrittenObject(store, write.value) };
93
- };
94
-
95
- /**
96
- * Removes a resource and the occurrences it produced — an object dropped
97
- * without its occurrence rows leaves a calendar showing events no resource
98
- * backs, which nothing later can attribute or clean up.
99
- */
100
- export const deleteCalendarObjectWrite = (input: {
101
- accountConfigId: string;
102
- calendarId: string;
103
- calendarObjectId: string;
104
- }): DeleteCalendarObjectWrite => ({ kind: "DeleteObject", ...input });
105
-
106
- export const deleteCalendarObject = async (
107
- store: ICalendarStore,
108
- input: {
109
- accountConfigId: string;
110
- calendarId: string;
111
- calendarObjectId: string;
112
- },
113
- ): Promise<void> => {
114
- await store.commit([deleteCalendarObjectWrite(input)]);
115
- };
116
-
117
- /**
118
- * The collection an account config stores events in until someone makes
119
- * another. Safe to call on every request that needs a calendar: `calendarId` is
120
- * derived from the account config and the URL segment, so a second call returns
121
- * the collection the first one made rather than a rival copy of it.
122
- */
123
- export const provisionDefaultCalendar = (
124
- store: ICalendarStore,
125
- accountConfigId: string,
126
- displayName = "Calendar",
127
- ): Promise<CalendarCollectionItem> =>
128
- store.repos.calendarCollection.create({
129
- accountConfigId,
130
- urlSegment: DEFAULT_CALENDAR_URL_SEGMENT,
131
- displayName,
132
- source: CalendarSource.Default,
133
- });