Sync your Obsidian vault to an atproto PDS community.obsidian.md/plugins/pds-sync
0

Configure Feed

Select the types of activity you want to include in your feed.

obsidian-pds-sync / src / sync / target.ts
2.5 kB 74 lines
1import type { AtpClient } from "../atproto/client"; 2 3/** 4 * A SyncTarget is one backend a note can be pushed to. The engine is backend- 5 * agnostic: it diffs notes and calls push/delete. This is the seam that lets us 6 * ship public + private today and slot in native atproto private-namespaces or 7 * `ats://` spaces later without touching the engine. 8 */ 9 10/** Stable id for a target. Persisted in note frontmatter as `pds_target`. */ 11export type TargetId = "standard-site" | "e2ee-pds" | "ats-space"; 12 13/** Normalised note ready to push (frontmatter already stripped from body). */ 14export interface NoteInput { 15 /** Vault-relative path, e.g. "notes/idea.md". */ 16 path: string; 17 title: string; 18 /** Note body, no frontmatter. */ 19 markdown: string; 20 /** Optional URL slug for public publishing. */ 21 slug?: string; 22 /** ISO timestamp. */ 23 publishedAt: string; 24 /** ISO timestamp, if known. */ 25 updatedAt?: string; 26 /** The note's user frontmatter (minus our index keys) - preserved for private notes. */ 27 frontmatter?: Record<string, unknown>; 28} 29 30/** Pointer to a pushed record. Persisted back into the note's frontmatter. */ 31export interface RemoteRef { 32 rkey: string; 33 cid: string; 34 uri: string; 35} 36 37/** A record fetched from the PDS, decoded back into a note (decrypted if private). */ 38export interface PulledNote { 39 ref: RemoteRef; 40 note: NoteInput; 41} 42 43/** 44 * Outcome of a push. "written" = the record was created/updated/recreated. 45 * "conflict" = the remote record changed under us; the caller resolves it 46 * (write `remote` as a conflict copy) rather than clobbering. 47 */ 48export type PushResult = 49 | { status: "written"; ref: RemoteRef } 50 | { status: "conflict"; remote: PulledNote; current: RemoteRef }; 51 52export interface SyncTarget { 53 readonly id: TargetId; 54 /** Collection NSID this target writes to. */ 55 readonly collection: string; 56 /** Human label for notices/logs. */ 57 readonly label: string; 58 59 /** True if this target is configured well enough to run. */ 60 isReady(): boolean; 61 /** Reason it is not ready, for surfacing to the user. */ 62 readyError(): string; 63 64 /** Create or update the record for a note (compare-and-swap). `existing` is its prior ref. */ 65 push( 66 client: AtpClient, 67 note: NoteInput, 68 existing?: RemoteRef, 69 ): Promise<PushResult>; 70 /** Delete the record for an orphaned note. */ 71 delete(client: AtpClient, ref: RemoteRef): Promise<void>; 72 /** Fetch every record in this collection, decoded into notes (for pull/restore). */ 73 list(client: AtpClient): Promise<PulledNote[]>; 74}