Skip to content

API Architecture Overview

Core Concept

Full Calendar Remastered exposes a unified, scope-gated API layer that powers both in-vault JavaScript integrations (third-party plugins, DataviewJS, Templater) and external REST client scripts (cURL, Python, CLI tools). All requests funnel through capability checks into InternalAPI and EventCache.


High-Level System Architecture

The API architecture employs a strict Bouncer Design Pattern. Third-party callers never hold direct references to plugin singletons or internal memory stores. Instead, they receive a scoped AuthorizedAPI instance generated by PublicAPI.withToken().

flowchart TD
    subgraph Clients["Integration Clients"]
        TP["Third-Party Obsidian Plugin"]
        DV["DataviewJS / Templater Script"]
        EXT["External CLI / Python / cURL"]
    end

    subgraph Security["Security & Access Gate"]
        PAPI["PublicAPI (app.plugins.plugins['full-calendar'].api)"]
        LSRV["LocalServer Daemon (127.0.0.1:8540)"]
        AMOD["AuthorizationModal (Consent Prompt)"]
        TSTORE["Settings Storage (apiTokens)"]
    end

    subgraph AuthLayer["Scoped Capability API"]
        AAPI["AuthorizedAPI Instance"]
        SCHK["assertScope(grantedScopes, required)"]
    end

    subgraph InternalCore["Core Plugin State Authority"]
        IAPI["InternalAPI Dispatcher"]
        ECACHE["EventCache (Canonical State)"]
        PREG["ProviderRegistry (Remote & File I/O)"]
        PSTATE["PluginState Singletons"]
    end

    TP -->|"requestAccess()"| PAPI
    PAPI -->|"Prompt User"| AMOD
    AMOD -->|"Grant Token"| TSTORE

    TP -->|"withToken(token)"| PAPI
    DV -->|"withToken(PAT)"| PAPI
    PAPI -->|"Validate Token"| TSTORE
    PAPI -->|"Instantiate"| AAPI

    EXT -->|"HTTP + Bearer Token"| LSRV
    LSRV -->|"withToken(token)"| PAPI

    AAPI -->|"Method Call"| SCHK
    SCHK -->|"Pass"| IAPI
    IAPI --> ECACHE
    IAPI --> PREG
    IAPI --> PSTATE

Component Ownership Matrix

Layer Responsibility Must Own Must NOT Own
PublicAPI Entry point attached to app.plugins.plugins['full-calendar'].api. Manages access token lookup, modal prompts, and legacy token migration. Token validation, modal dispatching, PAT resolution. Direct event data, file operations, HTTP server logic.
LocalServer Embedded Node.js HTTP listener (127.0.0.1:${port}). Parses HTTP requests, CORS headers, and Bearer tokens. Port binding, HTTP routing, JSON body parsing. Business logic, cache filtering engines, UI state.
AuthorizedAPI Ephemeral closure wrapper implementing authorized API calls. Enforces assertScope() per method call. Scope verification, forwarding calls to InternalAPI or EventCache. Persistent token storage, raw internal singletons.
InternalAPI Execution engine bridging API requests to workspace leaves and cache engine. Active view tracking, calendar tab opening, view changing. Client permission checking, HTTP response formatting.
EventCache Single source of truth for cached events and event index operations. In-memory event index, mutation dispatching, file sync. API token validation, UI view state management.

Request Execution Lifecycle

sequenceDiagram
    autonumber
    participant Client as External REST Client / JS Script
    participant Bouncer as LocalServer / PublicAPI
    participant Authorized as AuthorizedAPI Closure
    participant Internal as InternalAPI Engine
    participant Cache as EventCache

    Client->>Bouncer: Call Endpoint / Method with Token
    Bouncer->>Bouncer: Lookup Token in Settings (apiTokens)
    alt Token Missing or Invalid
        Bouncer-->>Client: Return 401 Unauthorized / null
    else Token Valid
        Bouncer->>Bouncer: Update lastUsedAt timestamp (async save)
        Bouncer->>Authorized: Return / Instantiate AuthorizedAPI
        Authorized->>Authorized: assertScope(grantedScopes, requiredScope)
        alt Scope Missing
            Authorized-->>Client: Throw Error / Return 403 Forbidden
        else Scope Granted
            Authorized->>Internal: Forward Operation (e.g. getEvents)
            Internal->>Cache: Query Event Store / Filter Engine
            Cache-->>Internal: Return Matching Queryables
            Internal-->>Authorized: Return Normalized Event Objects
            Authorized-->>Client: Return JSON Result / Typed Objects
        end
    end

Security Model & Sandbox Guarantees

  1. Process Boundary Isolation: Third-party plugins cannot access internal data structures (EventCache, ProviderRegistry) directly without possessing a token with system:full-access scope.
  2. Localhost Restriction: The REST server (LocalServer) forces network interface binding to 127.0.0.1. Requests originating outside local loopback are rejected by the operating system kernel network stack.
  3. Mobile Platform Exclusions: Obsidian runs on desktop (Electron/Node.js) and mobile (Capacitor/WebView). The LocalServer detects mobile platforms via PluginState.isMobile() and disables the HTTP listener, avoiding mobile runtime crashes while keeping the JS PublicAPI available.
  4. Token Persistence: Personal Access Tokens (PATs) and plugin authorization records are persisted securely in Obsidian's plugin configuration (data.json under apiTokens).

Reading Order & Detailed References

  1. Public JS API: JS entry points, requestAccess(), and complete AuthorizedAPI method contracts.
  2. REST Server Specification: HTTP REST routes, schemas, headers, status codes, and cURL examples.
  3. Scopes & Authorization: Detailed breakdown of permissions, risks, and token storage format.
  4. Internal API Engine: View tracking, workspace leaf resolution, and cache querying mechanics.
  5. Recipes & Blueprints: Complete recipes for plugins, DataviewJS, Templater, Python, and shell scripts.

Back to API Index · Public JS API · REST Server · Scopes & Permissions