@elizaos/capacitor-calendar 2.0.3-beta.2

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.
@@ -0,0 +1,18 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'ElizaosCapacitorCalendar'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.license = package['license'] || { :type => 'MIT' }
10
+ s.homepage = 'https://elizaos.ai'
11
+ s.authors = { 'elizaOS' => 'dev@elizaos.ai' }
12
+ s.source = { :git => 'https://github.com/elizaOS/eliza.git', :tag => s.version.to_s }
13
+ s.source_files = 'ios/Sources/**/*.{swift,h,m}'
14
+ s.ios.deployment_target = '15.0'
15
+ s.dependency 'Capacitor'
16
+ s.swift_version = '5.9'
17
+ s.frameworks = 'EventKit', 'UIKit'
18
+ end
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shaw Walters and elizaOS Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # @elizaos/capacitor-calendar
2
+
3
+ Reads and writes Apple Calendar events through EventKit, for elizaOS iOS apps and macOS desktop runtimes.
4
+
5
+ ## What it does
6
+
7
+ This package provides a Capacitor native-bridge plugin (`AppleCalendar`) that gives elizaOS apps running on iOS (or macOS via the Electrobun desktop shell with the EventKit dylib) full read/write access to the device's calendar store. On web/browser targets every method returns a graceful `not_supported` error.
8
+
9
+ ## Capabilities
10
+
11
+ | Operation | Method |
12
+ |-----------|--------|
13
+ | Check EventKit permission state | `AppleCalendar.checkPermissions()` |
14
+ | Request calendar access from the user | `AppleCalendar.requestPermissions()` |
15
+ | List all calendars | `AppleCalendar.listCalendars()` |
16
+ | Fetch events in a time window | `AppleCalendar.listEvents({ timeMin, timeMax, calendarId? })` |
17
+ | Create a new event | `AppleCalendar.createEvent(input)` |
18
+ | Update an existing event | `AppleCalendar.updateEvent({ eventId, ...input })` |
19
+ | Delete an event | `AppleCalendar.deleteEvent({ eventId })` |
20
+
21
+ All methods return a Promise. Results include an `ok: boolean` field; failures include `error` and `message` string fields.
22
+
23
+ ## Limitations
24
+
25
+ - **Attendees are not supported.** EventKit does not permit third-party apps to set event invitees. Passing `attendees` to `createEvent` or `updateEvent` returns `error: "unsupported_feature"`.
26
+ - **macOS desktop** uses the Electrobun EventKit dylib, not this Capacitor plugin.
27
+ - **Browser/web** targets receive `{ ok: false, error: "not_supported" }` from every method.
28
+ - iOS 17+ requires full-access authorization (`requestFullAccessToEvents`). `writeOnly` authorization is treated as `restricted`.
29
+
30
+ ## Required platform setup
31
+
32
+ ### iOS
33
+
34
+ Add the plugin to your Capacitor iOS project:
35
+
36
+ ```bash
37
+ npm install @elizaos/capacitor-calendar
38
+ npx cap sync ios
39
+ ```
40
+
41
+ Add the `NSCalendarsFullAccessUsageDescription` key to `Info.plist` explaining why calendar access is needed. Without this key the system will deny access.
42
+
43
+ The native pod (`ElizaosCapacitorCalendar`) requires iOS 15.0+ and Swift 5.9+.
44
+
45
+ ## Usage
46
+
47
+ ```typescript
48
+ import { AppleCalendar } from "@elizaos/capacitor-calendar";
49
+
50
+ // Check and request permission
51
+ const status = await AppleCalendar.checkPermissions();
52
+ if (status.calendar !== "granted") {
53
+ await AppleCalendar.requestPermissions();
54
+ }
55
+
56
+ // List events for the next 7 days
57
+ const now = new Date();
58
+ const nextWeek = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);
59
+ const result = await AppleCalendar.listEvents({
60
+ timeMin: now.toISOString(),
61
+ timeMax: nextWeek.toISOString(),
62
+ });
63
+ if (result.ok) {
64
+ console.log(result.events);
65
+ }
66
+
67
+ // Create an event
68
+ const created = await AppleCalendar.createEvent({
69
+ title: "Team sync",
70
+ startAt: "2026-06-01T10:00:00.000Z",
71
+ endAt: "2026-06-01T11:00:00.000Z",
72
+ });
73
+ ```
74
+
75
+ ## Config / Env Vars
76
+
77
+ None. This package reads no environment variables. Authorization is granted at the OS level by the user.
@@ -0,0 +1,93 @@
1
+ export type AppleCalendarPermissionState = "granted" | "denied" | "prompt" | "restricted";
2
+ export interface AppleCalendarPermissionStatus {
3
+ calendar: AppleCalendarPermissionState;
4
+ canRequest: boolean;
5
+ reason?: string | null;
6
+ }
7
+ export interface AppleCalendarSummary {
8
+ calendarId: string;
9
+ summary: string;
10
+ description: string | null;
11
+ primary: boolean;
12
+ accessRole: string;
13
+ backgroundColor: string | null;
14
+ foregroundColor: string | null;
15
+ timeZone: string | null;
16
+ selected: boolean;
17
+ }
18
+ export interface AppleCalendarAttendee {
19
+ email: string | null;
20
+ displayName: string | null;
21
+ responseStatus: string | null;
22
+ self: boolean;
23
+ organizer: boolean;
24
+ optional: boolean;
25
+ }
26
+ export interface AppleCalendarEvent {
27
+ id: string;
28
+ externalId: string;
29
+ calendarId: string;
30
+ calendarSummary: string;
31
+ title: string;
32
+ description: string;
33
+ location: string;
34
+ status: string;
35
+ startAt: string;
36
+ endAt: string;
37
+ isAllDay: boolean;
38
+ timezone: string | null;
39
+ htmlLink: string | null;
40
+ conferenceLink: string | null;
41
+ organizer: Record<string, unknown> | null;
42
+ attendees: AppleCalendarAttendee[];
43
+ }
44
+ export interface AppleCalendarBaseResult {
45
+ ok: boolean;
46
+ error?: string;
47
+ message?: string;
48
+ }
49
+ export interface AppleCalendarListResult extends AppleCalendarBaseResult {
50
+ calendars?: AppleCalendarSummary[];
51
+ }
52
+ export interface AppleCalendarEventsResult extends AppleCalendarBaseResult {
53
+ events?: AppleCalendarEvent[];
54
+ }
55
+ export interface AppleCalendarEventResult extends AppleCalendarBaseResult {
56
+ event?: AppleCalendarEvent;
57
+ }
58
+ export interface AppleCalendarListEventsOptions {
59
+ calendarId?: string | null;
60
+ timeMin: string;
61
+ timeMax: string;
62
+ }
63
+ export interface AppleCalendarEventInput {
64
+ calendarId?: string;
65
+ title?: string;
66
+ description?: string;
67
+ location?: string;
68
+ startAt?: string;
69
+ endAt?: string;
70
+ timeZone?: string;
71
+ isAllDay?: boolean;
72
+ attendees?: Array<{
73
+ email: string;
74
+ displayName?: string;
75
+ optional?: boolean;
76
+ }>;
77
+ }
78
+ export interface AppleCalendarUpdateEventInput extends AppleCalendarEventInput {
79
+ eventId: string;
80
+ }
81
+ export interface AppleCalendarDeleteEventInput {
82
+ eventId: string;
83
+ }
84
+ export interface AppleCalendarPlugin {
85
+ checkPermissions(): Promise<AppleCalendarPermissionStatus>;
86
+ requestPermissions(): Promise<AppleCalendarPermissionStatus>;
87
+ listCalendars(): Promise<AppleCalendarListResult>;
88
+ listEvents(options: AppleCalendarListEventsOptions): Promise<AppleCalendarEventsResult>;
89
+ createEvent(input: AppleCalendarEventInput): Promise<AppleCalendarEventResult>;
90
+ updateEvent(input: AppleCalendarUpdateEventInput): Promise<AppleCalendarEventResult>;
91
+ deleteEvent(input: AppleCalendarDeleteEventInput): Promise<AppleCalendarBaseResult>;
92
+ }
93
+ //# sourceMappingURL=definitions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=definitions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ import type { AppleCalendarPlugin } from "./definitions";
2
+ export * from "./definitions";
3
+ export * from "./macos-bridge-policy";
4
+ export declare const AppleCalendar: AppleCalendarPlugin;
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEzD,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AAItC,eAAO,MAAM,aAAa,qBAKzB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { registerPlugin } from "@capacitor/core";
2
+ export * from "./definitions";
3
+ export * from "./macos-bridge-policy";
4
+ const loadWeb = () => import("./web").then((m) => new m.AppleCalendarWeb());
5
+ export const AppleCalendar = registerPlugin("AppleCalendar", {
6
+ web: loadWeb,
7
+ });
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjD,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AAEtC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC;AAE5E,MAAM,CAAC,MAAM,aAAa,GAAG,cAAc,CACzC,eAAe,EACf;IACE,GAAG,EAAE,OAAO;CACb,CACF,CAAC"}
@@ -0,0 +1,9 @@
1
+ export interface AppleCalendarMacosBridgeCandidate {
2
+ label: string;
3
+ path: string;
4
+ }
5
+ export declare const APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME = "libMacWindowEffects.dylib";
6
+ export declare function appleCalendarMacosBridgeCandidates(args?: {
7
+ envDylibPath?: string | null;
8
+ }): AppleCalendarMacosBridgeCandidate[];
9
+ //# sourceMappingURL=macos-bridge-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"macos-bridge-policy.d.ts","sourceRoot":"","sources":["../../src/macos-bridge-policy.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iCAAiC;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,0CAA0C,8BAC1B,CAAC;AAE9B,wBAAgB,kCAAkC,CAAC,IAAI,CAAC,EAAE;IACxD,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,GAAG,iCAAiC,EAAE,CAmBtC"}
@@ -0,0 +1,22 @@
1
+ export const APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME = "libMacWindowEffects.dylib";
2
+ export function appleCalendarMacosBridgeCandidates(args) {
3
+ return [
4
+ {
5
+ label: "ELIZA_NATIVE_PERMISSIONS_DYLIB",
6
+ path: args?.envDylibPath ?? "",
7
+ },
8
+ {
9
+ label: "packaged Apple permissions bridge",
10
+ path: `../../../../../../../${APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME}`,
11
+ },
12
+ {
13
+ label: "packaged Apple permissions bridge",
14
+ path: `../../../../../../${APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME}`,
15
+ },
16
+ {
17
+ label: "local Apple permissions bridge",
18
+ path: `../../../../packages/app-core/platforms/electrobun/src/${APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME}`,
19
+ },
20
+ ].filter((candidate) => candidate.path.trim().length > 0);
21
+ }
22
+ //# sourceMappingURL=macos-bridge-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"macos-bridge-policy.js","sourceRoot":"","sources":["../../src/macos-bridge-policy.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,MAAM,0CAA0C,GACrD,2BAA2B,CAAC;AAE9B,MAAM,UAAU,kCAAkC,CAAC,IAElD;IACC,OAAO;QACL;YACE,KAAK,EAAE,gCAAgC;YACvC,IAAI,EAAE,IAAI,EAAE,YAAY,IAAI,EAAE;SAC/B;QACD;YACE,KAAK,EAAE,mCAAmC;YAC1C,IAAI,EAAE,wBAAwB,0CAA0C,EAAE;SAC3E;QACD;YACE,KAAK,EAAE,mCAAmC;YAC1C,IAAI,EAAE,qBAAqB,0CAA0C,EAAE;SACxE;QACD;YACE,KAAK,EAAE,gCAAgC;YACvC,IAAI,EAAE,0DAA0D,0CAA0C,EAAE;SAC7G;KACF,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { WebPlugin } from "@capacitor/core";
2
+ import type { AppleCalendarBaseResult, AppleCalendarEventInput, AppleCalendarEventResult, AppleCalendarEventsResult, AppleCalendarListEventsOptions, AppleCalendarListResult, AppleCalendarPermissionStatus, AppleCalendarPlugin, AppleCalendarUpdateEventInput } from "./definitions";
3
+ export declare class AppleCalendarWeb extends WebPlugin implements AppleCalendarPlugin {
4
+ checkPermissions(): Promise<AppleCalendarPermissionStatus>;
5
+ requestPermissions(): Promise<AppleCalendarPermissionStatus>;
6
+ listCalendars(): Promise<AppleCalendarListResult>;
7
+ listEvents(_options: AppleCalendarListEventsOptions): Promise<AppleCalendarEventsResult>;
8
+ createEvent(_input: AppleCalendarEventInput): Promise<AppleCalendarEventResult>;
9
+ updateEvent(_input: AppleCalendarUpdateEventInput): Promise<AppleCalendarEventResult>;
10
+ deleteEvent(_input: Parameters<AppleCalendarPlugin["deleteEvent"]>[0]): Promise<AppleCalendarBaseResult>;
11
+ }
12
+ //# sourceMappingURL=web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EACV,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,yBAAyB,EACzB,8BAA8B,EAC9B,uBAAuB,EACvB,6BAA6B,EAC7B,mBAAmB,EACnB,6BAA6B,EAC9B,MAAM,eAAe,CAAC;AASvB,qBAAa,gBAAiB,SAAQ,SAAU,YAAW,mBAAmB;IACtE,gBAAgB,IAAI,OAAO,CAAC,6BAA6B,CAAC;IAQ1D,kBAAkB,IAAI,OAAO,CAAC,6BAA6B,CAAC;IAI5D,aAAa,IAAI,OAAO,CAAC,uBAAuB,CAAC;IAIjD,UAAU,CACd,QAAQ,EAAE,8BAA8B,GACvC,OAAO,CAAC,yBAAyB,CAAC;IAI/B,WAAW,CACf,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,wBAAwB,CAAC;IAI9B,WAAW,CACf,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,wBAAwB,CAAC;IAI9B,WAAW,CACf,MAAM,EAAE,UAAU,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,GACxD,OAAO,CAAC,uBAAuB,CAAC;CAGpC"}
@@ -0,0 +1,34 @@
1
+ import { WebPlugin } from "@capacitor/core";
2
+ const unsupported = {
3
+ ok: false,
4
+ error: "not_supported",
5
+ message: "Apple Calendar is only available through the native iOS app or macOS desktop runtime.",
6
+ };
7
+ export class AppleCalendarWeb extends WebPlugin {
8
+ async checkPermissions() {
9
+ return {
10
+ calendar: "restricted",
11
+ canRequest: false,
12
+ reason: unsupported.message,
13
+ };
14
+ }
15
+ async requestPermissions() {
16
+ return this.checkPermissions();
17
+ }
18
+ async listCalendars() {
19
+ return { ...unsupported };
20
+ }
21
+ async listEvents(_options) {
22
+ return { ...unsupported };
23
+ }
24
+ async createEvent(_input) {
25
+ return { ...unsupported };
26
+ }
27
+ async updateEvent(_input) {
28
+ return { ...unsupported };
29
+ }
30
+ async deleteEvent(_input) {
31
+ return { ...unsupported };
32
+ }
33
+ }
34
+ //# sourceMappingURL=web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAa5C,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE,KAAK;IACT,KAAK,EAAE,eAAe;IACtB,OAAO,EACL,uFAAuF;CACjF,CAAC;AAEX,MAAM,OAAO,gBAAiB,SAAQ,SAAS;IAC7C,KAAK,CAAC,gBAAgB;QACpB,OAAO;YACL,QAAQ,EAAE,YAAY;YACtB,UAAU,EAAE,KAAK;YACjB,MAAM,EAAE,WAAW,CAAC,OAAO;SAC5B,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,kBAAkB;QACtB,OAAO,IAAI,CAAC,gBAAgB,EAAE,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,OAAO,EAAE,GAAG,WAAW,EAAE,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,UAAU,CACd,QAAwC;QAExC,OAAO,EAAE,GAAG,WAAW,EAAE,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,WAAW,CACf,MAA+B;QAE/B,OAAO,EAAE,GAAG,WAAW,EAAE,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,WAAW,CACf,MAAqC;QAErC,OAAO,EAAE,GAAG,WAAW,EAAE,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,WAAW,CACf,MAAyD;QAEzD,OAAO,EAAE,GAAG,WAAW,EAAE,CAAC;IAC5B,CAAC;CACF"}
@@ -0,0 +1,73 @@
1
+ 'use strict';
2
+
3
+ var core = require('@capacitor/core');
4
+
5
+ const APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME = "libMacWindowEffects.dylib";
6
+ function appleCalendarMacosBridgeCandidates(args) {
7
+ return [
8
+ {
9
+ label: "ELIZA_NATIVE_PERMISSIONS_DYLIB",
10
+ path: args?.envDylibPath ?? "",
11
+ },
12
+ {
13
+ label: "packaged Apple permissions bridge",
14
+ path: `../../../../../../../${APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME}`,
15
+ },
16
+ {
17
+ label: "packaged Apple permissions bridge",
18
+ path: `../../../../../../${APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME}`,
19
+ },
20
+ {
21
+ label: "local Apple permissions bridge",
22
+ path: `../../../../packages/app-core/platforms/electrobun/src/${APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME}`,
23
+ },
24
+ ].filter((candidate) => candidate.path.trim().length > 0);
25
+ }
26
+
27
+ const loadWeb = () => Promise.resolve().then(function () { return web; }).then((m) => new m.AppleCalendarWeb());
28
+ const AppleCalendar = core.registerPlugin("AppleCalendar", {
29
+ web: loadWeb,
30
+ });
31
+
32
+ const unsupported = {
33
+ ok: false,
34
+ error: "not_supported",
35
+ message: "Apple Calendar is only available through the native iOS app or macOS desktop runtime.",
36
+ };
37
+ class AppleCalendarWeb extends core.WebPlugin {
38
+ async checkPermissions() {
39
+ return {
40
+ calendar: "restricted",
41
+ canRequest: false,
42
+ reason: unsupported.message,
43
+ };
44
+ }
45
+ async requestPermissions() {
46
+ return this.checkPermissions();
47
+ }
48
+ async listCalendars() {
49
+ return { ...unsupported };
50
+ }
51
+ async listEvents(_options) {
52
+ return { ...unsupported };
53
+ }
54
+ async createEvent(_input) {
55
+ return { ...unsupported };
56
+ }
57
+ async updateEvent(_input) {
58
+ return { ...unsupported };
59
+ }
60
+ async deleteEvent(_input) {
61
+ return { ...unsupported };
62
+ }
63
+ }
64
+
65
+ var web = /*#__PURE__*/Object.freeze({
66
+ __proto__: null,
67
+ AppleCalendarWeb: AppleCalendarWeb
68
+ });
69
+
70
+ exports.APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME = APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME;
71
+ exports.AppleCalendar = AppleCalendar;
72
+ exports.appleCalendarMacosBridgeCandidates = appleCalendarMacosBridgeCandidates;
73
+ //# sourceMappingURL=plugin.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/macos-bridge-policy.js","esm/index.js","esm/web.js"],"sourcesContent":["export const APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME = \"libMacWindowEffects.dylib\";\nexport function appleCalendarMacosBridgeCandidates(args) {\n return [\n {\n label: \"ELIZA_NATIVE_PERMISSIONS_DYLIB\",\n path: args?.envDylibPath ?? \"\",\n },\n {\n label: \"packaged Apple permissions bridge\",\n path: `../../../../../../../${APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME}`,\n },\n {\n label: \"packaged Apple permissions bridge\",\n path: `../../../../../../${APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME}`,\n },\n {\n label: \"local Apple permissions bridge\",\n path: `../../../../packages/app-core/platforms/electrobun/src/${APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME}`,\n },\n ].filter((candidate) => candidate.path.trim().length > 0);\n}\n//# sourceMappingURL=macos-bridge-policy.js.map","import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nexport * from \"./macos-bridge-policy\";\nconst loadWeb = () => import(\"./web\").then((m) => new m.AppleCalendarWeb());\nexport const AppleCalendar = registerPlugin(\"AppleCalendar\", {\n web: loadWeb,\n});\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\nconst unsupported = {\n ok: false,\n error: \"not_supported\",\n message: \"Apple Calendar is only available through the native iOS app or macOS desktop runtime.\",\n};\nexport class AppleCalendarWeb extends WebPlugin {\n async checkPermissions() {\n return {\n calendar: \"restricted\",\n canRequest: false,\n reason: unsupported.message,\n };\n }\n async requestPermissions() {\n return this.checkPermissions();\n }\n async listCalendars() {\n return { ...unsupported };\n }\n async listEvents(_options) {\n return { ...unsupported };\n }\n async createEvent(_input) {\n return { ...unsupported };\n }\n async updateEvent(_input) {\n return { ...unsupported };\n }\n async deleteEvent(_input) {\n return { ...unsupported };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AAAY,MAAC,0CAA0C,GAAG;AACnD,SAAS,kCAAkC,CAAC,IAAI,EAAE;AACzD,IAAI,OAAO;AACX,QAAQ;AACR,YAAY,KAAK,EAAE,gCAAgC;AACnD,YAAY,IAAI,EAAE,IAAI,EAAE,YAAY,IAAI,EAAE;AAC1C,SAAS;AACT,QAAQ;AACR,YAAY,KAAK,EAAE,mCAAmC;AACtD,YAAY,IAAI,EAAE,CAAC,qBAAqB,EAAE,0CAA0C,CAAC,CAAC;AACtF,SAAS;AACT,QAAQ;AACR,YAAY,KAAK,EAAE,mCAAmC;AACtD,YAAY,IAAI,EAAE,CAAC,kBAAkB,EAAE,0CAA0C,CAAC,CAAC;AACnF,SAAS;AACT,QAAQ;AACR,YAAY,KAAK,EAAE,gCAAgC;AACnD,YAAY,IAAI,EAAE,CAAC,uDAAuD,EAAE,0CAA0C,CAAC,CAAC;AACxH,SAAS;AACT,KAAK,CAAC,MAAM,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;AAC7D;;ACjBA,MAAM,OAAO,GAAG,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,gBAAgB,EAAE,CAAC;AAC/D,MAAC,aAAa,GAAGA,mBAAc,CAAC,eAAe,EAAE;AAC7D,IAAI,GAAG,EAAE,OAAO;AAChB,CAAC;;ACLD,MAAM,WAAW,GAAG;AACpB,IAAI,EAAE,EAAE,KAAK;AACb,IAAI,KAAK,EAAE,eAAe;AAC1B,IAAI,OAAO,EAAE,uFAAuF;AACpG,CAAC;AACM,MAAM,gBAAgB,SAASC,cAAS,CAAC;AAChD,IAAI,MAAM,gBAAgB,GAAG;AAC7B,QAAQ,OAAO;AACf,YAAY,QAAQ,EAAE,YAAY;AAClC,YAAY,UAAU,EAAE,KAAK;AAC7B,YAAY,MAAM,EAAE,WAAW,CAAC,OAAO;AACvC,SAAS;AACT,IAAI;AACJ,IAAI,MAAM,kBAAkB,GAAG;AAC/B,QAAQ,OAAO,IAAI,CAAC,gBAAgB,EAAE;AACtC,IAAI;AACJ,IAAI,MAAM,aAAa,GAAG;AAC1B,QAAQ,OAAO,EAAE,GAAG,WAAW,EAAE;AACjC,IAAI;AACJ,IAAI,MAAM,UAAU,CAAC,QAAQ,EAAE;AAC/B,QAAQ,OAAO,EAAE,GAAG,WAAW,EAAE;AACjC,IAAI;AACJ,IAAI,MAAM,WAAW,CAAC,MAAM,EAAE;AAC9B,QAAQ,OAAO,EAAE,GAAG,WAAW,EAAE;AACjC,IAAI;AACJ,IAAI,MAAM,WAAW,CAAC,MAAM,EAAE;AAC9B,QAAQ,OAAO,EAAE,GAAG,WAAW,EAAE;AACjC,IAAI;AACJ,IAAI,MAAM,WAAW,CAAC,MAAM,EAAE;AAC9B,QAAQ,OAAO,EAAE,GAAG,WAAW,EAAE;AACjC,IAAI;AACJ;;;;;;;;;;;"}
package/dist/plugin.js ADDED
@@ -0,0 +1,76 @@
1
+ var capacitorAppleCalendar = (function (exports, core) {
2
+ 'use strict';
3
+
4
+ const APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME = "libMacWindowEffects.dylib";
5
+ function appleCalendarMacosBridgeCandidates(args) {
6
+ return [
7
+ {
8
+ label: "ELIZA_NATIVE_PERMISSIONS_DYLIB",
9
+ path: args?.envDylibPath ?? "",
10
+ },
11
+ {
12
+ label: "packaged Apple permissions bridge",
13
+ path: `../../../../../../../${APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME}`,
14
+ },
15
+ {
16
+ label: "packaged Apple permissions bridge",
17
+ path: `../../../../../../${APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME}`,
18
+ },
19
+ {
20
+ label: "local Apple permissions bridge",
21
+ path: `../../../../packages/app-core/platforms/electrobun/src/${APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME}`,
22
+ },
23
+ ].filter((candidate) => candidate.path.trim().length > 0);
24
+ }
25
+
26
+ const loadWeb = () => Promise.resolve().then(function () { return web; }).then((m) => new m.AppleCalendarWeb());
27
+ const AppleCalendar = core.registerPlugin("AppleCalendar", {
28
+ web: loadWeb,
29
+ });
30
+
31
+ const unsupported = {
32
+ ok: false,
33
+ error: "not_supported",
34
+ message: "Apple Calendar is only available through the native iOS app or macOS desktop runtime.",
35
+ };
36
+ class AppleCalendarWeb extends core.WebPlugin {
37
+ async checkPermissions() {
38
+ return {
39
+ calendar: "restricted",
40
+ canRequest: false,
41
+ reason: unsupported.message,
42
+ };
43
+ }
44
+ async requestPermissions() {
45
+ return this.checkPermissions();
46
+ }
47
+ async listCalendars() {
48
+ return { ...unsupported };
49
+ }
50
+ async listEvents(_options) {
51
+ return { ...unsupported };
52
+ }
53
+ async createEvent(_input) {
54
+ return { ...unsupported };
55
+ }
56
+ async updateEvent(_input) {
57
+ return { ...unsupported };
58
+ }
59
+ async deleteEvent(_input) {
60
+ return { ...unsupported };
61
+ }
62
+ }
63
+
64
+ var web = /*#__PURE__*/Object.freeze({
65
+ __proto__: null,
66
+ AppleCalendarWeb: AppleCalendarWeb
67
+ });
68
+
69
+ exports.APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME = APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME;
70
+ exports.AppleCalendar = AppleCalendar;
71
+ exports.appleCalendarMacosBridgeCandidates = appleCalendarMacosBridgeCandidates;
72
+
73
+ return exports;
74
+
75
+ })({}, capacitorExports);
76
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sources":["esm/macos-bridge-policy.js","esm/index.js","esm/web.js"],"sourcesContent":["export const APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME = \"libMacWindowEffects.dylib\";\nexport function appleCalendarMacosBridgeCandidates(args) {\n return [\n {\n label: \"ELIZA_NATIVE_PERMISSIONS_DYLIB\",\n path: args?.envDylibPath ?? \"\",\n },\n {\n label: \"packaged Apple permissions bridge\",\n path: `../../../../../../../${APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME}`,\n },\n {\n label: \"packaged Apple permissions bridge\",\n path: `../../../../../../${APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME}`,\n },\n {\n label: \"local Apple permissions bridge\",\n path: `../../../../packages/app-core/platforms/electrobun/src/${APPLE_CALENDAR_MACOS_BRIDGE_DYLIB_BASENAME}`,\n },\n ].filter((candidate) => candidate.path.trim().length > 0);\n}\n//# sourceMappingURL=macos-bridge-policy.js.map","import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nexport * from \"./macos-bridge-policy\";\nconst loadWeb = () => import(\"./web\").then((m) => new m.AppleCalendarWeb());\nexport const AppleCalendar = registerPlugin(\"AppleCalendar\", {\n web: loadWeb,\n});\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\nconst unsupported = {\n ok: false,\n error: \"not_supported\",\n message: \"Apple Calendar is only available through the native iOS app or macOS desktop runtime.\",\n};\nexport class AppleCalendarWeb extends WebPlugin {\n async checkPermissions() {\n return {\n calendar: \"restricted\",\n canRequest: false,\n reason: unsupported.message,\n };\n }\n async requestPermissions() {\n return this.checkPermissions();\n }\n async listCalendars() {\n return { ...unsupported };\n }\n async listEvents(_options) {\n return { ...unsupported };\n }\n async createEvent(_input) {\n return { ...unsupported };\n }\n async updateEvent(_input) {\n return { ...unsupported };\n }\n async deleteEvent(_input) {\n return { ...unsupported };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AAAY,UAAC,0CAA0C,GAAG;IACnD,SAAS,kCAAkC,CAAC,IAAI,EAAE;IACzD,IAAI,OAAO;IACX,QAAQ;IACR,YAAY,KAAK,EAAE,gCAAgC;IACnD,YAAY,IAAI,EAAE,IAAI,EAAE,YAAY,IAAI,EAAE;IAC1C,SAAS;IACT,QAAQ;IACR,YAAY,KAAK,EAAE,mCAAmC;IACtD,YAAY,IAAI,EAAE,CAAC,qBAAqB,EAAE,0CAA0C,CAAC,CAAC;IACtF,SAAS;IACT,QAAQ;IACR,YAAY,KAAK,EAAE,mCAAmC;IACtD,YAAY,IAAI,EAAE,CAAC,kBAAkB,EAAE,0CAA0C,CAAC,CAAC;IACnF,SAAS;IACT,QAAQ;IACR,YAAY,KAAK,EAAE,gCAAgC;IACnD,YAAY,IAAI,EAAE,CAAC,uDAAuD,EAAE,0CAA0C,CAAC,CAAC;IACxH,SAAS;IACT,KAAK,CAAC,MAAM,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7D;;ICjBA,MAAM,OAAO,GAAG,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,gBAAgB,EAAE,CAAC;AAC/D,UAAC,aAAa,GAAGA,mBAAc,CAAC,eAAe,EAAE;IAC7D,IAAI,GAAG,EAAE,OAAO;IAChB,CAAC;;ICLD,MAAM,WAAW,GAAG;IACpB,IAAI,EAAE,EAAE,KAAK;IACb,IAAI,KAAK,EAAE,eAAe;IAC1B,IAAI,OAAO,EAAE,uFAAuF;IACpG,CAAC;IACM,MAAM,gBAAgB,SAASC,cAAS,CAAC;IAChD,IAAI,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,OAAO;IACf,YAAY,QAAQ,EAAE,YAAY;IAClC,YAAY,UAAU,EAAE,KAAK;IAC7B,YAAY,MAAM,EAAE,WAAW,CAAC,OAAO;IACvC,SAAS;IACT,IAAI;IACJ,IAAI,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,OAAO,IAAI,CAAC,gBAAgB,EAAE;IACtC,IAAI;IACJ,IAAI,MAAM,aAAa,GAAG;IAC1B,QAAQ,OAAO,EAAE,GAAG,WAAW,EAAE;IACjC,IAAI;IACJ,IAAI,MAAM,UAAU,CAAC,QAAQ,EAAE;IAC/B,QAAQ,OAAO,EAAE,GAAG,WAAW,EAAE;IACjC,IAAI;IACJ,IAAI,MAAM,WAAW,CAAC,MAAM,EAAE;IAC9B,QAAQ,OAAO,EAAE,GAAG,WAAW,EAAE;IACjC,IAAI;IACJ,IAAI,MAAM,WAAW,CAAC,MAAM,EAAE;IAC9B,QAAQ,OAAO,EAAE,GAAG,WAAW,EAAE;IACjC,IAAI;IACJ,IAAI,MAAM,WAAW,CAAC,MAAM,EAAE;IAC9B,QAAQ,OAAO,EAAE,GAAG,WAAW,EAAE;IACjC,IAAI;IACJ;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,560 @@
1
+ import Foundation
2
+ import Capacitor
3
+ import EventKit
4
+ import UIKit
5
+
6
+ @objc(AppleCalendarPlugin)
7
+ public class AppleCalendarPlugin: CAPPlugin, CAPBridgedPlugin {
8
+ public let identifier = "AppleCalendarPlugin"
9
+ public let jsName = "AppleCalendar"
10
+ public let pluginMethods: [CAPPluginMethod] = [
11
+ CAPPluginMethod(name: "checkPermissions", returnType: CAPPluginReturnPromise),
12
+ CAPPluginMethod(name: "requestPermissions", returnType: CAPPluginReturnPromise),
13
+ CAPPluginMethod(name: "listCalendars", returnType: CAPPluginReturnPromise),
14
+ CAPPluginMethod(name: "listEvents", returnType: CAPPluginReturnPromise),
15
+ CAPPluginMethod(name: "createEvent", returnType: CAPPluginReturnPromise),
16
+ CAPPluginMethod(name: "updateEvent", returnType: CAPPluginReturnPromise),
17
+ CAPPluginMethod(name: "deleteEvent", returnType: CAPPluginReturnPromise),
18
+ ]
19
+
20
+ private let eventStore = EKEventStore()
21
+ private let maxTitleLength = 512
22
+ private let maxDescriptionLength = 20000
23
+ private let maxLocationLength = 1024
24
+ private let unsupportedRecurrenceFields = [
25
+ "recurrence",
26
+ "recurrenceRule",
27
+ "recurrenceRules",
28
+ "rrule",
29
+ ]
30
+ private lazy var isoWithFractionalSeconds: ISO8601DateFormatter = {
31
+ let formatter = ISO8601DateFormatter()
32
+ formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
33
+ return formatter
34
+ }()
35
+ private lazy var isoWithoutFractionalSeconds: ISO8601DateFormatter = {
36
+ let formatter = ISO8601DateFormatter()
37
+ formatter.formatOptions = [.withInternetDateTime]
38
+ return formatter
39
+ }()
40
+
41
+ @objc public override func checkPermissions(_ call: CAPPluginCall) {
42
+ call.resolve(permissionResult())
43
+ }
44
+
45
+ @objc public override func requestPermissions(_ call: CAPPluginCall) {
46
+ let status = EKEventStore.authorizationStatus(for: .event)
47
+ if isGranted(status) || isDeniedOrRestricted(status) {
48
+ call.resolve(permissionResult())
49
+ return
50
+ }
51
+
52
+ if #available(iOS 17.0, *) {
53
+ eventStore.requestFullAccessToEvents { [weak self] _, error in
54
+ DispatchQueue.main.async {
55
+ var result = self?.permissionResult() ?? [
56
+ "calendar": "restricted",
57
+ "canRequest": false,
58
+ ]
59
+ if let error {
60
+ result["reason"] = error.localizedDescription
61
+ }
62
+ call.resolve(result)
63
+ }
64
+ }
65
+ } else {
66
+ eventStore.requestAccess(to: .event) { [weak self] _, error in
67
+ DispatchQueue.main.async {
68
+ var result = self?.permissionResult() ?? [
69
+ "calendar": "restricted",
70
+ "canRequest": false,
71
+ ]
72
+ if let error {
73
+ result["reason"] = error.localizedDescription
74
+ }
75
+ call.resolve(result)
76
+ }
77
+ }
78
+ }
79
+ }
80
+
81
+ @objc func listCalendars(_ call: CAPPluginCall) {
82
+ guard hasFullAccess() else {
83
+ call.resolve(permissionError())
84
+ return
85
+ }
86
+ let defaultCalendar = eventStore.defaultCalendarForNewEvents
87
+ let calendars = eventStore.calendars(for: .event).map {
88
+ calendarJson($0, defaultCalendar: defaultCalendar)
89
+ }
90
+ call.resolve(["ok": true, "calendars": calendars])
91
+ }
92
+
93
+ @objc func listEvents(_ call: CAPPluginCall) {
94
+ guard hasFullAccess() else {
95
+ call.resolve(permissionError())
96
+ return
97
+ }
98
+ guard let timeMin = parseDate(call.getString("timeMin") ?? ""),
99
+ let timeMax = parseDate(call.getString("timeMax") ?? ""),
100
+ timeMax > timeMin
101
+ else {
102
+ call.resolve(nativeError("Calendar event window is invalid."))
103
+ return
104
+ }
105
+
106
+ let requestedCalendarId = (call.getString("calendarId") ?? "")
107
+ .trimmingCharacters(in: .whitespacesAndNewlines)
108
+ var calendars: [EKCalendar]? = nil
109
+ if !requestedCalendarId.isEmpty && requestedCalendarId != "all" {
110
+ guard let calendar = calendar(withIdentifier: requestedCalendarId, requireWritable: false) else {
111
+ call.resolve([
112
+ "ok": false,
113
+ "error": "not_found",
114
+ "message": "Apple Calendar was not found.",
115
+ ])
116
+ return
117
+ }
118
+ calendars = [calendar]
119
+ }
120
+
121
+ let predicate = eventStore.predicateForEvents(
122
+ withStart: timeMin,
123
+ end: timeMax,
124
+ calendars: calendars
125
+ )
126
+ let events = eventStore.events(matching: predicate)
127
+ .sorted { $0.startDate < $1.startDate }
128
+ .map(eventJson)
129
+ call.resolve(["ok": true, "events": events])
130
+ }
131
+
132
+ @objc func createEvent(_ call: CAPPluginCall) {
133
+ guard hasFullAccess() else {
134
+ call.resolve(permissionError())
135
+ return
136
+ }
137
+ let event = EKEvent(eventStore: eventStore)
138
+ if let error = applyEventPayload(call, to: event, requireTitle: true) {
139
+ call.resolve(error)
140
+ return
141
+ }
142
+ do {
143
+ try eventStore.save(event, span: .thisEvent, commit: true)
144
+ call.resolve(["ok": true, "event": eventJson(event)])
145
+ } catch {
146
+ call.resolve(nativeError("Failed to create Apple Calendar event: \(error.localizedDescription)"))
147
+ }
148
+ }
149
+
150
+ @objc func updateEvent(_ call: CAPPluginCall) {
151
+ guard hasFullAccess() else {
152
+ call.resolve(permissionError())
153
+ return
154
+ }
155
+ guard let eventId = nonEmptyString(call.getString("eventId")) else {
156
+ call.resolve(nativeError("Calendar event id is required."))
157
+ return
158
+ }
159
+ guard let item = eventStore.calendarItem(withIdentifier: eventId) as? EKEvent else {
160
+ call.resolve([
161
+ "ok": false,
162
+ "error": "not_found",
163
+ "message": "Apple Calendar event was not found.",
164
+ ])
165
+ return
166
+ }
167
+ guard item.calendar.allowsContentModifications else {
168
+ call.resolve(nativeError("Apple Calendar event is not writable."))
169
+ return
170
+ }
171
+ if let error = applyEventPayload(call, to: item, requireTitle: false) {
172
+ call.resolve(error)
173
+ return
174
+ }
175
+ do {
176
+ try eventStore.save(item, span: .thisEvent, commit: true)
177
+ call.resolve(["ok": true, "event": eventJson(item)])
178
+ } catch {
179
+ call.resolve(nativeError("Failed to update Apple Calendar event: \(error.localizedDescription)"))
180
+ }
181
+ }
182
+
183
+ @objc func deleteEvent(_ call: CAPPluginCall) {
184
+ guard hasFullAccess() else {
185
+ call.resolve(permissionError())
186
+ return
187
+ }
188
+ guard let eventId = nonEmptyString(call.getString("eventId")) else {
189
+ call.resolve(nativeError("Calendar event id is required."))
190
+ return
191
+ }
192
+ guard let event = eventStore.calendarItem(withIdentifier: eventId) as? EKEvent else {
193
+ call.resolve([
194
+ "ok": false,
195
+ "error": "not_found",
196
+ "message": "Apple Calendar event was not found.",
197
+ ])
198
+ return
199
+ }
200
+ do {
201
+ try eventStore.remove(event, span: .thisEvent, commit: true)
202
+ call.resolve(["ok": true])
203
+ } catch {
204
+ call.resolve(nativeError("Failed to delete Apple Calendar event: \(error.localizedDescription)"))
205
+ }
206
+ }
207
+
208
+ private func permissionResult() -> [String: Any] {
209
+ let status = EKEventStore.authorizationStatus(for: .event)
210
+ return [
211
+ "calendar": permissionString(status),
212
+ "canRequest": permissionString(status) == "prompt",
213
+ "reason": NSNull(),
214
+ ]
215
+ }
216
+
217
+ private func permissionString(_ status: EKAuthorizationStatus) -> String {
218
+ if isGranted(status) {
219
+ return "granted"
220
+ }
221
+ if isDenied(status) {
222
+ return "denied"
223
+ }
224
+ if isRestricted(status) {
225
+ return "restricted"
226
+ }
227
+ return "prompt"
228
+ }
229
+
230
+ private func hasFullAccess() -> Bool {
231
+ isGranted(EKEventStore.authorizationStatus(for: .event))
232
+ }
233
+
234
+ private func isGranted(_ status: EKAuthorizationStatus) -> Bool {
235
+ if #available(iOS 17.0, *) {
236
+ if status == .fullAccess {
237
+ return true
238
+ }
239
+ if status == .writeOnly {
240
+ return false
241
+ }
242
+ }
243
+ return status == .authorized
244
+ }
245
+
246
+ private func isDenied(_ status: EKAuthorizationStatus) -> Bool {
247
+ status == .denied
248
+ }
249
+
250
+ private func isRestricted(_ status: EKAuthorizationStatus) -> Bool {
251
+ if #available(iOS 17.0, *), status == .writeOnly {
252
+ return true
253
+ }
254
+ return status == .restricted
255
+ }
256
+
257
+ private func isDeniedOrRestricted(_ status: EKAuthorizationStatus) -> Bool {
258
+ isDenied(status) || isRestricted(status)
259
+ }
260
+
261
+ private func permissionError() -> [String: Any] {
262
+ [
263
+ "ok": false,
264
+ "error": "permission",
265
+ "message": "Apple Calendar access has not been granted.",
266
+ ]
267
+ }
268
+
269
+ private func nativeError(_ message: String) -> [String: Any] {
270
+ [
271
+ "ok": false,
272
+ "error": "native_error",
273
+ "message": message,
274
+ ]
275
+ }
276
+
277
+ private func nonEmptyString(_ value: String?) -> String? {
278
+ guard let trimmed = value?.trimmingCharacters(in: .whitespacesAndNewlines),
279
+ !trimmed.isEmpty
280
+ else {
281
+ return nil
282
+ }
283
+ return trimmed
284
+ }
285
+
286
+ private func parseDate(_ value: String) -> Date? {
287
+ guard !value.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
288
+ return nil
289
+ }
290
+ if let date = isoWithFractionalSeconds.date(from: value) {
291
+ return date
292
+ }
293
+ return isoWithoutFractionalSeconds.date(from: value)
294
+ }
295
+
296
+ private func textValue(
297
+ _ call: CAPPluginCall,
298
+ key: String,
299
+ maxLength: Int,
300
+ required: Bool
301
+ ) -> (value: String?, error: [String: Any]?) {
302
+ let rawValue = call.options[key]
303
+ if rawValue == nil || rawValue is NSNull {
304
+ if required {
305
+ return (nil, nativeError("Calendar event \(key) is required."))
306
+ }
307
+ return (nil, nil)
308
+ }
309
+ guard rawValue is String else {
310
+ return (nil, nativeError("Calendar event \(key) must be a string."))
311
+ }
312
+ guard let value = call.getString(key) else {
313
+ if required {
314
+ return (nil, nativeError("Calendar event \(key) is required."))
315
+ }
316
+ return (nil, nil)
317
+ }
318
+ guard value.count <= maxLength else {
319
+ return (nil, nativeError("Calendar event \(key) is too long."))
320
+ }
321
+ return (value, nil)
322
+ }
323
+
324
+ private func isoString(_ date: Date?) -> String {
325
+ guard let date else { return "" }
326
+ return isoWithFractionalSeconds.string(from: date)
327
+ }
328
+
329
+ private func calendar(withIdentifier identifier: String, requireWritable: Bool) -> EKCalendar? {
330
+ if identifier.isEmpty || identifier == "primary" {
331
+ if let calendar = eventStore.defaultCalendarForNewEvents,
332
+ !requireWritable || calendar.allowsContentModifications
333
+ {
334
+ return calendar
335
+ }
336
+ if requireWritable {
337
+ return eventStore.calendars(for: .event)
338
+ .first(where: { $0.allowsContentModifications })
339
+ }
340
+ return eventStore.defaultCalendarForNewEvents
341
+ }
342
+ guard let calendar = eventStore.calendars(for: .event)
343
+ .first(where: { $0.calendarIdentifier == identifier })
344
+ else {
345
+ return nil
346
+ }
347
+ if requireWritable && !calendar.allowsContentModifications {
348
+ return nil
349
+ }
350
+ return calendar
351
+ }
352
+
353
+ private func calendarJson(_ calendar: EKCalendar, defaultCalendar: EKCalendar?) -> [String: Any] {
354
+ let color = UIColor(cgColor: calendar.cgColor)
355
+ let components = color.resolvedColor(with: UITraitCollection.current).cgColor.components ?? []
356
+ let red = components.indices.contains(0) ? components[0] : 0
357
+ let green = components.indices.contains(1) ? components[1] : red
358
+ let blue = components.indices.contains(2) ? components[2] : red
359
+ let hex = String(
360
+ format: "#%02X%02X%02X",
361
+ Int(max(0, min(1, red)) * 255),
362
+ Int(max(0, min(1, green)) * 255),
363
+ Int(max(0, min(1, blue)) * 255)
364
+ )
365
+ return [
366
+ "calendarId": calendar.calendarIdentifier,
367
+ "summary": calendar.title,
368
+ "description": calendar.source.title,
369
+ "primary": calendar.calendarIdentifier == defaultCalendar?.calendarIdentifier,
370
+ "accessRole": calendar.allowsContentModifications ? "writer" : "reader",
371
+ "backgroundColor": hex,
372
+ "foregroundColor": NSNull(),
373
+ "timeZone": TimeZone.current.identifier,
374
+ "selected": true,
375
+ ]
376
+ }
377
+
378
+ private func participantEmail(_ participant: EKParticipant) -> String? {
379
+ guard participant.url.scheme?.lowercased() == "mailto" else {
380
+ return nil
381
+ }
382
+ let raw = participant.url.absoluteString
383
+ let prefix = "mailto:"
384
+ guard raw.lowercased().hasPrefix(prefix) else {
385
+ return nil
386
+ }
387
+ let address = String(raw.dropFirst(prefix.count))
388
+ return address.removingPercentEncoding ?? address
389
+ }
390
+
391
+ private func participantStatus(_ status: EKParticipantStatus) -> String {
392
+ switch status {
393
+ case .unknown: return "unknown"
394
+ case .pending: return "pending"
395
+ case .accepted: return "accepted"
396
+ case .declined: return "declined"
397
+ case .tentative: return "tentative"
398
+ case .delegated: return "delegated"
399
+ case .completed: return "completed"
400
+ case .inProcess: return "in_process"
401
+ @unknown default: return "unknown"
402
+ }
403
+ }
404
+
405
+ private func participantJson(_ participant: EKParticipant) -> [String: Any] {
406
+ [
407
+ "email": participantEmail(participant) ?? NSNull(),
408
+ "displayName": participant.name ?? NSNull(),
409
+ "responseStatus": participantStatus(participant.participantStatus),
410
+ "self": participant.isCurrentUser,
411
+ "organizer": participant.participantRole == .chair,
412
+ "optional": participant.participantRole == .optional,
413
+ ]
414
+ }
415
+
416
+ private func eventStatus(_ status: EKEventStatus) -> String {
417
+ switch status {
418
+ case .none: return "none"
419
+ case .confirmed: return "confirmed"
420
+ case .tentative: return "tentative"
421
+ case .canceled: return "cancelled"
422
+ @unknown default: return "unknown"
423
+ }
424
+ }
425
+
426
+ private func eventJson(_ event: EKEvent) -> [String: Any] {
427
+ let identifier = event.calendarItemIdentifier
428
+ return [
429
+ "id": identifier,
430
+ "externalId": identifier,
431
+ "calendarId": event.calendar.calendarIdentifier,
432
+ "calendarSummary": event.calendar.title,
433
+ "title": event.title?.isEmpty == false ? event.title as Any : "(untitled)",
434
+ "description": event.notes ?? "",
435
+ "location": event.location ?? "",
436
+ "status": eventStatus(event.status),
437
+ "startAt": isoString(event.startDate),
438
+ "endAt": isoString(event.endDate),
439
+ "isAllDay": event.isAllDay,
440
+ "timezone": event.timeZone?.identifier ?? NSNull(),
441
+ "htmlLink": NSNull(),
442
+ "conferenceLink": NSNull(),
443
+ "organizer": event.organizer.map(participantJson) ?? NSNull(),
444
+ "attendees": event.attendees?.map(participantJson) ?? [],
445
+ ]
446
+ }
447
+
448
+ private func applyEventPayload(
449
+ _ call: CAPPluginCall,
450
+ to event: EKEvent,
451
+ requireTitle: Bool
452
+ ) -> [String: Any]? {
453
+ for key in unsupportedRecurrenceFields where call.options.keys.contains(key) {
454
+ return [
455
+ "ok": false,
456
+ "error": "unsupported_feature",
457
+ "message": "Apple Calendar recurrence editing is not supported by this bridge.",
458
+ ]
459
+ }
460
+
461
+ if call.options.keys.contains("attendees") {
462
+ guard let attendees = call.options["attendees"] as? [Any] else {
463
+ return nativeError("Calendar event attendees must be an array.")
464
+ }
465
+ if !attendees.isEmpty {
466
+ return [
467
+ "ok": false,
468
+ "error": "unsupported_feature",
469
+ "message": "Apple Calendar does not allow this app to create or edit event invitees through EventKit. Remove attendees or use Google Calendar for invited meetings.",
470
+ ]
471
+ }
472
+ }
473
+
474
+ if call.options.keys.contains("title") || requireTitle {
475
+ let titleResult = textValue(
476
+ call,
477
+ key: "title",
478
+ maxLength: maxTitleLength,
479
+ required: true
480
+ )
481
+ if let error = titleResult.error {
482
+ return error
483
+ }
484
+ guard let title = nonEmptyString(titleResult.value) else {
485
+ return nativeError("Calendar event title is required.")
486
+ }
487
+ event.title = title
488
+ }
489
+ if call.options.keys.contains("description") {
490
+ let descriptionResult = textValue(
491
+ call,
492
+ key: "description",
493
+ maxLength: maxDescriptionLength,
494
+ required: false
495
+ )
496
+ if let error = descriptionResult.error {
497
+ return error
498
+ }
499
+ event.notes = descriptionResult.value
500
+ }
501
+ if call.options.keys.contains("location") {
502
+ let locationResult = textValue(
503
+ call,
504
+ key: "location",
505
+ maxLength: maxLocationLength,
506
+ required: false
507
+ )
508
+ if let error = locationResult.error {
509
+ return error
510
+ }
511
+ event.location = locationResult.value
512
+ }
513
+ if call.options.keys.contains("timeZone") {
514
+ guard let timeZoneName = nonEmptyString(call.getString("timeZone")) else {
515
+ return nativeError("Calendar event timeZone is invalid.")
516
+ }
517
+ guard let timeZone = TimeZone(identifier: timeZoneName) else {
518
+ return nativeError("Calendar event timeZone is invalid.")
519
+ }
520
+ event.timeZone = timeZone
521
+ }
522
+ if call.options.keys.contains("calendarId") {
523
+ guard let calendar = calendar(
524
+ withIdentifier: call.getString("calendarId") ?? "",
525
+ requireWritable: true
526
+ ) else {
527
+ return nativeError("The selected Apple Calendar is not writable or was not found.")
528
+ }
529
+ event.calendar = calendar
530
+ }
531
+ if call.options.keys.contains("isAllDay") {
532
+ event.isAllDay = call.getBool("isAllDay") ?? false
533
+ }
534
+ if call.options.keys.contains("startAt") {
535
+ guard let start = parseDate(call.getString("startAt") ?? "") else {
536
+ return nativeError("Calendar event startAt is invalid.")
537
+ }
538
+ event.startDate = start
539
+ }
540
+ if call.options.keys.contains("endAt") {
541
+ guard let end = parseDate(call.getString("endAt") ?? "") else {
542
+ return nativeError("Calendar event endAt is invalid.")
543
+ }
544
+ event.endDate = end
545
+ }
546
+ guard event.startDate != nil, event.endDate != nil else {
547
+ return nativeError("Calendar event startAt and endAt are required.")
548
+ }
549
+ guard event.endDate > event.startDate else {
550
+ return nativeError("Calendar event endAt must be later than startAt.")
551
+ }
552
+ if event.calendar == nil {
553
+ guard let calendar = calendar(withIdentifier: "primary", requireWritable: true) else {
554
+ return nativeError("No writable Apple Calendar is available.")
555
+ }
556
+ event.calendar = calendar
557
+ }
558
+ return nil
559
+ }
560
+ }
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@elizaos/capacitor-calendar",
3
+ "version": "2.0.3-beta.2",
4
+ "description": "Reads and writes Apple Calendar events through EventKit.",
5
+ "keywords": [
6
+ "calendar",
7
+ "eventkit",
8
+ "ios",
9
+ "permissions"
10
+ ],
11
+ "main": "./dist/plugin.cjs.js",
12
+ "module": "./dist/esm/index.js",
13
+ "types": "./dist/esm/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/esm/index.d.ts",
17
+ "bun": "./src/index.ts",
18
+ "development": "./src/index.ts",
19
+ "import": "./dist/esm/index.js",
20
+ "require": "./dist/plugin.cjs.js"
21
+ },
22
+ "./package.json": "./package.json"
23
+ },
24
+ "unpkg": "dist/plugin.js",
25
+ "files": [
26
+ "dist/",
27
+ "ios/Sources/",
28
+ "*.podspec",
29
+ "dist"
30
+ ],
31
+ "author": "elizaOS",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/elizaOS/eliza.git"
36
+ },
37
+ "scripts": {
38
+ "build": "node ../../packages/scripts/with-package-build-lock.mjs plugins/plugin-native-calendar -- bun run build:unlocked",
39
+ "clean": "node ../../packages/scripts/rm-path-recursive.mjs dist",
40
+ "test": "vitest run",
41
+ "prepublishOnly": "bun run build",
42
+ "build:unlocked": "bun run clean && tsc && bunx rollup -c rollup.config.mjs"
43
+ },
44
+ "capacitor": {
45
+ "ios": {
46
+ "src": "ios",
47
+ "podName": "ElizaosCapacitorCalendar"
48
+ }
49
+ },
50
+ "devDependencies": {
51
+ "@capacitor/core": "^8.3.1",
52
+ "rollup": "^4.60.2",
53
+ "typescript": "^6.0.3"
54
+ },
55
+ "peerDependencies": {
56
+ "@capacitor/core": "^8.3.1"
57
+ },
58
+ "publishConfig": {
59
+ "access": "public"
60
+ },
61
+ "elizaos": {
62
+ "platforms": [
63
+ "browser",
64
+ "node"
65
+ ],
66
+ "runtime": "both",
67
+ "platformDetails": {
68
+ "browser": "Graceful unsupported fallback.",
69
+ "ios": true,
70
+ "node": "macOS uses the Electrobun EventKit dylib instead."
71
+ }
72
+ },
73
+ "gitHead": "82fe0f44215954c2417328203f5bd6510985c1fc"
74
+ }