Skip to content

API Architecture

Purpose

The Full Calendar API exposes safe, permissioned entry points for other plugins and external systems while keeping EventCache as the single source of truth.

Components and Ownership

Component Responsibility Must Not Own
PublicAPI Bouncer surface on app.plugins.plugins['full-calendar'].api. Handles token verification, Personal Access Tokens (PATs), and plugin access request modals. Direct event state or provider I/O.
LocalServer Localhost HTTP server (127.0.0.1) running in Node.js. Translates incoming REST API requests (Bearer Token) into programmatically executed operations. UI presentation or file writing policies.
InternalAPI Executes raw actions (querying, opening views, modifying events) using PluginState. Third-party validation logic or CLI exposure.
PluginState Runtime singleton holding references to settings, cache, registry, and system capabilities. Alternative sources of state.
EventCache Canonical cached event state and database mutations. UI decisions or CLI protocol formatting.
ProviderRegistry Network/Local calendar source route management and synchronization. Client filtering engines.

Authorization & Token Storage

The API uses standard scope-gated capability tokens stored under FullCalendarSettings.apiTokens. * Plugin Tokens: Acquired via PublicAPI.requestAccess(pluginId, reason, requestedScopes) showing an authorization modal. Stored with the calling plugin's identifier. * Personal Access Tokens (PATs): Generated manually by the user in settings. Stored with a fixed pluginId: 'personal'. Prefixed with ofc_pat_ to prevent collisions. * Tracking: On access via PublicAPI.withToken(token), lastUsedAt is updated and persisted asynchronously to disk.

Scope Model

Methods require a specific scope (e.g. events:read, events:write, ui:open-calendar, providers:read). system:full-access provides raw access to singletons via AuthorizedAPI.getInternalState().

Local REST Server

When enableLocalServer is toggled in settings: 1. LocalServer opens an HTTP listener on the configured localServerPort (default 8540) bound to 127.0.0.1 (localhost). 2. It intercept requests, validates Authorization: Bearer <token> against PublicAPI.withToken(), and checks scopes. 3. Requests map to the AuthorizedAPI surface.

Supported REST Routes

  • Events:
  • GET /api/v1/events -> Returns JSON array of events matching criteria (events:read). Query parameters: start (ISO/ms), end (ISO/ms), calendar (IDs), query (text search), isTask (bool), isCompleted (bool).
  • GET /api/v1/events/:id -> Detailed event object & source file path (events:read).
  • POST /api/v1/events -> Create event in source (events:write).
  • PUT /api/v1/events/:id -> Update event details (events:write).
  • DELETE /api/v1/events/:id -> Remove or suppress event (events:write).
  • UI Controls:
  • POST /api/v1/ui/open-calendar -> Open main calendar leaf (ui:open-calendar).
  • POST /api/v1/ui/open-sidebar -> Focus right sidebar (ui:open-sidebar).
  • POST /api/v1/ui/change-view -> Switch view (e.g., timeGridWeek) (ui:change-view).
  • System/Sync:
  • GET /api/v1/calendars -> List configured calendars and sources (providers:read).
  • POST /api/v1/providers/revalidate -> Trigger background sync/reload (providers:write).
  • GET / PUT /api/v1/settings -> Read/update plugin settings (settings:read/settings:write).

Data Flow

sequenceDiagram
    participant CLI as External Script / CLI
    participant Server as LocalServer
    participant API as PublicAPI / AuthorizedAPI
    participant Cache as EventCache
    participant Registry as ProviderRegistry

    CLI->>Server: HTTP GET /api/v1/events (Bearer Token)
    Server->>API: withToken(token)
    API-->>Server: return AuthorizedAPI
    Server->>API: getEvents(criteria)
    API->>Cache: getEvents() / query()
    Cache-->>API: return raw queryables
    API-->>Server: return filtered JSON
    Server-->>CLI: HTTP 200 OK + JSON events

Constraints and Invariants

  • Process Boundary Security: The server binds strictly to 127.0.0.1 preventing network exposure.
  • State Isolation: Writes always flow through the EventCache mutating the source file or network provider, rather than modifying memory representations.
  • Platform Exclusions: The LocalServer checks PluginState.isMobile() and disables itself on mobile platforms to prevent Capacitor runtime errors.