46 lines
1.5 KiB
TypeScript
46 lines
1.5 KiB
TypeScript
/**
|
|
* SyncServer singleton — shared across server/index.ts and modules.
|
|
*
|
|
* Participant mode: server maintains its own Automerge docs.
|
|
* On any doc change, debounced-save to disk via doc-persistence.
|
|
*
|
|
* When a doc belongs to an encrypted space (meta.encrypted === true),
|
|
* the save is encrypted at rest using the space's encryptionKeyId.
|
|
*
|
|
* Relay mode: for encrypted spaces, the server stores opaque blobs
|
|
* it cannot decrypt, enabling cross-device restore.
|
|
*/
|
|
|
|
import { SyncServer } from "./local-first/sync-server";
|
|
import { saveDoc, saveEncryptedBlob, loadEncryptedBlob } from "./local-first/doc-persistence";
|
|
import { getDocumentData } from "./community-store";
|
|
|
|
/**
|
|
* Look up the encryption key ID for a doc's space.
|
|
* DocIds are formatted as "spaceSlug:module:collection[:itemId]".
|
|
* Returns the encryptionKeyId if the space has encryption enabled, else undefined.
|
|
*/
|
|
function getEncryptionKeyId(docId: string): string | undefined {
|
|
const spaceSlug = docId.split(":")[0];
|
|
if (!spaceSlug || spaceSlug === "global") return undefined;
|
|
const data = getDocumentData(spaceSlug);
|
|
if (data?.meta?.encrypted && data.meta.encryptionKeyId) {
|
|
return data.meta.encryptionKeyId;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
export const syncServer = new SyncServer({
|
|
participantMode: true,
|
|
onDocChange: (docId, doc) => {
|
|
const encryptionKeyId = getEncryptionKeyId(docId);
|
|
saveDoc(docId, doc, encryptionKeyId);
|
|
},
|
|
onRelayBackup: (docId, blob) => {
|
|
saveEncryptedBlob(docId, blob);
|
|
},
|
|
onRelayLoad: (docId) => {
|
|
return loadEncryptedBlob(docId);
|
|
},
|
|
});
|