rspace-online/modules/rcal/schemas.ts

143 lines
3.6 KiB
TypeScript

/**
* 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<string, CalendarSource>;
events: Record<string, CalendarEvent>;
}
// ── Schema registration ──
export const calendarSchema: DocSchema<CalendarDoc> = {
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<string, unknown>;
}
/** 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;
}