/** * rCal Automerge document schemas. * * Granularity: one Automerge document per space (all events + sources). * DocId format: {space}:cal:events */ import type { DocSchema } from '../../shared/local-first/document'; // ── Document types ── export interface CalendarSource { id: string; name: string; sourceType: string; url: string | null; color: string | null; isActive: boolean; isVisible: boolean; syncIntervalMinutes: number | null; lastSyncedAt: number; ownerId: string | null; createdAt: number; } export interface CalendarEvent { id: string; title: string; description: string; startTime: number; endTime: number; allDay: boolean; timezone: string | null; rrule: string | null; status: string | null; visibility: string | null; sourceId: string | null; sourceName: string | null; sourceType: string | null; sourceColor: string | null; locationId: string | null; locationName: string | null; coordinates: { x: number; y: number } | null; locationGranularity: string | null; locationLat: number | null; locationLng: number | null; isVirtual: boolean; virtualUrl: string | null; virtualPlatform: string | null; rToolSource: string | null; rToolEntityId: string | null; attendees: unknown[]; attendeeCount: number; metadata: unknown | null; createdAt: number; updatedAt: number; } export interface CalendarDoc { meta: { module: string; collection: string; version: number; spaceSlug: string; createdAt: number; }; sources: Record; events: Record; } // ── Schema registration ── export const calendarSchema: DocSchema = { module: 'cal', collection: 'events', version: 1, init: (): CalendarDoc => ({ meta: { module: 'cal', collection: 'events', version: 1, spaceSlug: '', createdAt: Date.now(), }, sources: {}, events: {}, }), }; // ── KOI-Inspired Provenance (stored in CalendarEvent.metadata) ── /** Lifecycle events following BlockScience KOI's RID pattern */ export type ProvenanceLifecycle = 'NEW' | 'UPDATE' | 'FORGET'; /** KOI-inspired provenance — stored in CalendarEvent.metadata.provenance */ export interface KnowledgeProvenance { /** Reference identifier in "type:uuid" format, e.g. "folk-note:abc-123" */ rid: string; /** SHA-256 hex digest of content at scheduling time */ contentHash: string | null; /** Shape type that originated this item (e.g. "folk-note", "folk-photo") */ sourceType: string; /** Space slug where the item lives */ sourceSpace: string; /** KOI lifecycle event */ lifecycleEvent: ProvenanceLifecycle; /** Original creation timestamp of the source item (epoch ms) */ originalCreatedAt: number; /** DID or user identifier who scheduled this */ scheduledBy: string | null; /** When the scheduling action occurred (epoch ms) */ scheduledAt: number; } /** Preview snapshot for email rendering — stored in metadata.itemPreview */ export interface ItemPreview { /** First ~200 chars of content */ textPreview: string; /** MIME type: text/markdown, image/jpeg, etc. */ mimeType: string; /** Thumbnail URL for photos/media */ thumbnailUrl?: string; /** Deep link back to canvas shape */ canvasUrl?: string; /** Full serialized shape data for reconstruction */ shapeSnapshot?: Record; } /** Typed metadata shape when CalendarEvent represents a scheduled knowledge item */ export interface ScheduledItemMetadata { isScheduledItem: true; provenance: KnowledgeProvenance; itemPreview: ItemPreview; reminderSent: boolean; reminderSentAt: number | null; } // ── Helpers ── export function calendarDocId(space: string) { return `${space}:cal:events` as const; }