0.10.0: Archify Sync, optional live collaboration on a model
Several people edit one model at once through a server you run yourself (archify-vscode-ext-sync); the files stay ordinary files on each disk. Sign-in through the browser, offline-first with later merge, teammates' cursors in the Source view and text editors, and a Shared section on the model page with people, versions, Compare and Restore. Without a server nothing changes: the sync code is a separate bundle that loads only when a model is shared, after a sign-in, or when a sync command or invite link is used.
This commit is contained in:
1 parent
a9021312b0
commit
c99f3e5fe8
27 files changed
+2899
-14
No files matched your search
@@ -0,0 +1,60 @@
|
||||
// What the extension and the Archify Sync server agree on. Mirrors
|
||||
// `packages/protocol` (generated from Rust) in archify-vscode-ext-sync; keep
|
||||
// both in step when the protocol changes.
|
||||
|
||||
export const PROTOCOL_VERSION = 1;
|
||||
/** Root map of a space's Yjs document: model-root-relative POSIX path → Y.Text. */
|
||||
export const FILES_MAP = 'files';
|
||||
/** The link file in a model root: names server and space, holds no secrets. */
|
||||
export const LINK_FILE = '.archify-sync';
|
||||
|
||||
export type OrgRole = 'admin' | 'member';
|
||||
export type SpaceRole = 'owner' | 'editor';
|
||||
export type VersionKind = 'snapshot' | 'publish' | 'restore';
|
||||
|
||||
export interface ApiError { error: string; message: string }
|
||||
export interface Account { id: string; organisation_id: string; name: string; display_name: string; role: OrgRole }
|
||||
export interface TokenResponse { access_token: string; expires_in: number; refresh_token: string; account: Account }
|
||||
export interface ServerInfo { name: string; version: string; protocol: number; set_up: boolean }
|
||||
export interface Space { id: string; name: string; role: SpaceRole; created_at: string }
|
||||
export interface Member { account_id: string; name: string; display_name: string; role: SpaceRole }
|
||||
export interface Invite { token: string; url: string; expires_at: string }
|
||||
export interface JoinResponse { space: Space }
|
||||
export interface Version {
|
||||
id: number;
|
||||
major: number;
|
||||
minor: number;
|
||||
kind: VersionKind;
|
||||
name: string | null;
|
||||
created_by: string | null;
|
||||
created_at: string;
|
||||
restored_from: number | null;
|
||||
}
|
||||
export interface VersionFiles { version: Version; files: { path: string; text: string }[] }
|
||||
|
||||
/** The contents of `.archify-sync`. */
|
||||
export interface Link {
|
||||
server: string;
|
||||
space: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export function parseLink(text: string): Link | undefined {
|
||||
try {
|
||||
const value = JSON.parse(text) as Partial<Link>;
|
||||
if (typeof value.server === 'string' && typeof value.space === 'string' && /^[0-9a-f-]{36}$/i.test(value.space)) {
|
||||
return { server: value.server.replace(/\/+$/, ''), space: value.space, name: typeof value.name === 'string' ? value.name : undefined };
|
||||
}
|
||||
} catch {
|
||||
// not a link
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function formatLink(link: Link): string {
|
||||
return `${JSON.stringify({ server: link.server, space: link.space, name: link.name }, null, 2)}\n`;
|
||||
}
|
||||
|
||||
export function versionLabel(v: Version): string {
|
||||
return `${v.major}.${v.minor}`;
|
||||
}
|
||||
Reference in new issue
Block a user