Milestones
Milestones are document snapshots that represent the document state at a specific point in time. They provide version history and can be used to restore documents to previous states.
Overview
Section titled “Overview”A Milestone is a document snapshot as the client saw the document at a point in time. Milestones are:
- Stored separately from the document as a sort of version history
- Can be pulled back over the network again
- An example of the RPC system, which adds custom messages & handlers for custom operations over the transport layer in-protocol
Creating Milestones
Section titled “Creating Milestones”Manual Creation
Section titled “Manual Creation”Create a milestone from the current document state:
import { Provider } from "teleportal/providers";
const provider = await Provider.create({ url: "wss://example.com", document: "my-document",});
// Create a milestone with a nameconst milestone = await provider.createMilestone("v1.0");
// Or let the server auto-generate a nameconst milestone2 = await provider.createMilestone();Automatic Creation
Section titled “Automatic Creation”Milestones can be created automatically based on triggers:
import { Server } from "teleportal/server";
const server = new Server({ // ... other options milestoneTriggerConfig: { defaultTriggers: [ { type: "time-based", interval: 3600000, // 1 hour }, { type: "update-count", threshold: 1000, // After 1000 updates }, ], },});Listing Milestones
Section titled “Listing Milestones”List all milestones for a document:
// List all milestonesconst milestones = await provider.listMilestones();
// List with incremental updates (only new milestones)const newMilestones = await provider.listMilestones( existingMilestoneIds);Retrieving Milestones
Section titled “Retrieving Milestones”Get the snapshot content for a specific milestone:
// Get milestone snapshotconst snapshot = await provider.getMilestoneSnapshot(milestoneId);
// The snapshot is a Uint8Array containing the Y.js document state// You can apply it to a new document:import * as Y from "yjs";
const newDoc = new Y.Doc();Y.applyUpdate(newDoc, snapshot);Updating Milestones
Section titled “Updating Milestones”Update a milestone’s name:
await provider.updateMilestoneName(milestoneId, "v1.0.1");Soft Delete and Restore
Section titled “Soft Delete and Restore”Milestones support soft delete and restore:
// Soft delete a milestoneawait provider.deleteMilestone(milestoneId);
// Restore a deleted milestoneawait provider.restoreMilestone(milestoneId);Milestone Metadata
Section titled “Milestone Metadata”Each milestone includes metadata:
interface Milestone { id: string; name: string; documentId: string; createdAt: number; deletedAt?: number; lifecycleState?: "active" | "deleted" | "archived" | "expired"; expiresAt?: number; createdBy: { type: "user" | "system"; id: string; };}The createdBy field indicates who or what created the milestone:
{ type: "user", id: userId }- Created by a user viamilestone-create-request{ type: "system", id: nodeId }- Created automatically by the system (triggers, API)
Server Configuration
Section titled “Server Configuration”To enable milestone operations on the server:
import { Server } from "teleportal/server";import { getMilestoneRpcHandlers } from "teleportal/protocols/milestone";import { createUnstorage } from "teleportal/storage";
const { documentStorage, milestoneStorage } = createUnstorage(storage, { // ... options});
const server = new Server({ getStorage: async (ctx) => documentStorage, rpcHandlers: { ...getMilestoneRpcHandlers(milestoneStorage), },});Storage
Section titled “Storage”Milestones are stored separately from documents using MilestoneStorage:
import { MilestoneStorage } from "teleportal/storage";
// MilestoneStorage interfaceinterface MilestoneStorage { listMilestones( documentId: string, options?: { snapshotIds?: string[]; includeDeleted?: boolean } ): Promise<Milestone[]>;
getMilestoneSnapshot( documentId: string, milestoneId: string ): Promise<Uint8Array | null>;
createMilestone( documentId: string, snapshot: Uint8Array, name?: string, userId?: string ): Promise<Milestone>;
// ... other methods}Use Cases
Section titled “Use Cases”Version History
Section titled “Version History”Create milestones at important points in the document lifecycle:
// Create milestone when user clicks "Save"await provider.createMilestone("Save point 1");
// Create milestone when document is publishedawait provider.createMilestone("Published v1.0");Document Restoration
Section titled “Document Restoration”Restore a document to a previous milestone:
// Get milestone snapshotconst snapshot = await provider.getMilestoneSnapshot(milestoneId);
// Apply to current documentimport * as Y from "yjs";Y.applyUpdate(provider.doc, snapshot);Automatic Backups
Section titled “Automatic Backups”Use automatic triggers to create regular backups:
const server = new Server({ milestoneTriggerConfig: { defaultTriggers: [ { type: "time-based", interval: 3600000, // Every hour }, ], },});Best Practices
Section titled “Best Practices”- Name milestones meaningfully: Use descriptive names like “v1.0”, “Published”, “Before refactor”
- Create milestones at important points: Save milestones at key moments in the document lifecycle
- Use automatic triggers: Set up automatic milestone creation for regular backups
- Clean up old milestones: Periodically delete or archive old milestones to save storage
- Track createdBy: Use the
createdByfield to distinguish user vs system milestones