diff --git a/keyserver/src/shared/state-sync/current-user-state-sync-spec.js b/keyserver/src/shared/state-sync/current-user-state-sync-spec.js
--- a/keyserver/src/shared/state-sync/current-user-state-sync-spec.js
+++ b/keyserver/src/shared/state-sync/current-user-state-sync-spec.js
@@ -1,19 +1,20 @@
 // @flow
 
+import { currentUserStateSyncSpec as libSpec } from 'lib/shared/state-sync/current-user-state-sync-spec.js';
 import type {
   CurrentUserInfo,
   OldCurrentUserInfo,
 } from 'lib/types/user-types.js';
 
-import type { StateSyncSpec } from './state-sync-spec.js';
+import type { ServerStateSyncSpec } from './state-sync-spec.js';
 import { fetchCurrentUserInfo } from '../../fetchers/user-fetchers.js';
 import type { Viewer } from '../../session/viewer.js';
 
-export const currentUserStateSyncSpec: StateSyncSpec<
+export const currentUserStateSyncSpec: ServerStateSyncSpec<
   OldCurrentUserInfo | CurrentUserInfo,
 > = Object.freeze({
   fetch(viewer: Viewer) {
     return fetchCurrentUserInfo(viewer);
   },
-  hashKey: 'currentUserInfo',
+  ...libSpec,
 });
diff --git a/keyserver/src/shared/state-sync/entries-state-sync-spec.js b/keyserver/src/shared/state-sync/entries-state-sync-spec.js
--- a/keyserver/src/shared/state-sync/entries-state-sync-spec.js
+++ b/keyserver/src/shared/state-sync/entries-state-sync-spec.js
@@ -1,17 +1,18 @@
 // @flow
 
 import { serverEntryInfosObject } from 'lib/shared/entry-utils.js';
+import { entriesStateSyncSpec as libSpec } from 'lib/shared/state-sync/entries-state-sync-spec.js';
 import type { CalendarQuery, RawEntryInfos } from 'lib/types/entry-types.js';
 
-import type { StateSyncSpec } from './state-sync-spec.js';
+import type { ServerStateSyncSpec } from './state-sync-spec.js';
 import {
   fetchEntryInfos,
   fetchEntryInfosByID,
 } from '../../fetchers/entry-fetchers.js';
 import type { Viewer } from '../../session/viewer.js';
 
-export const entriesStateSyncSpec: StateSyncSpec<RawEntryInfos> = Object.freeze(
-  {
+export const entriesStateSyncSpec: ServerStateSyncSpec<RawEntryInfos> =
+  Object.freeze({
     async fetch(
       viewer: Viewer,
       query: $ReadOnlyArray<CalendarQuery>,
@@ -23,11 +24,5 @@
       const entriesResult = await fetchEntryInfos(viewer, query);
       return serverEntryInfosObject(entriesResult.rawEntryInfos);
     },
-    hashKey: 'entryInfos',
-    innerHashSpec: {
-      hashKey: 'entryInfo',
-      deleteKey: 'deleteEntryIDs',
-      rawInfosKey: 'rawEntryInfos',
-    },
-  },
-);
+    ...libSpec,
+  });
diff --git a/keyserver/src/shared/state-sync/state-sync-spec.js b/keyserver/src/shared/state-sync/state-sync-spec.js
--- a/keyserver/src/shared/state-sync/state-sync-spec.js
+++ b/keyserver/src/shared/state-sync/state-sync-spec.js
@@ -1,20 +1,15 @@
 // @flow
 
+import type { StateSyncSpec } from 'lib/shared/state-sync/state-sync-spec.js';
 import type { CalendarQuery } from 'lib/types/entry-types.js';
 
 import type { Viewer } from '../../session/viewer.js';
 
-export type StateSyncSpec<Infos, Info = empty> = {
+export type ServerStateSyncSpec<Infos, Info = empty> = {
   +fetch: (
     viewer: Viewer,
     calendarQuery: $ReadOnlyArray<CalendarQuery>,
     ids?: $ReadOnlySet<string>,
   ) => Promise<Infos>,
-  +hashKey: string,
-  +innerHashSpec?: {
-    +hashKey: string,
-    +deleteKey: string,
-    +rawInfosKey: string,
-    +additionalDeleteCondition?: Info => boolean,
-  },
+  ...StateSyncSpec<Info>,
 };
diff --git a/keyserver/src/shared/state-sync/state-sync-specs.js b/keyserver/src/shared/state-sync/state-sync-specs.js
--- a/keyserver/src/shared/state-sync/state-sync-specs.js
+++ b/keyserver/src/shared/state-sync/state-sync-specs.js
@@ -2,12 +2,12 @@
 
 import { currentUserStateSyncSpec } from './current-user-state-sync-spec.js';
 import { entriesStateSyncSpec } from './entries-state-sync-spec.js';
-import type { StateSyncSpec } from './state-sync-spec.js';
+import type { ServerStateSyncSpec } from './state-sync-spec.js';
 import { threadsStateSyncSpec } from './threads-state-sync-spec.js';
 import { usersStateSyncSpec } from './users-state-sync-spec.js';
 
 export const serverStateSyncSpecs: {
-  +[string]: StateSyncSpec<*>,
+  +[string]: ServerStateSyncSpec<*, *>,
 } = Object.freeze({
   threads: threadsStateSyncSpec,
   entries: entriesStateSyncSpec,
diff --git a/keyserver/src/shared/state-sync/threads-state-sync-spec.js b/keyserver/src/shared/state-sync/threads-state-sync-spec.js
--- a/keyserver/src/shared/state-sync/threads-state-sync-spec.js
+++ b/keyserver/src/shared/state-sync/threads-state-sync-spec.js
@@ -1,15 +1,16 @@
 // @flow
 
+import { threadsStateSyncSpec as libSpec } from 'lib/shared/state-sync/threads-state-sync-spec.js';
 import type { CalendarQuery } from 'lib/types/entry-types.js';
 
-import type { StateSyncSpec } from './state-sync-spec.js';
+import type { ServerStateSyncSpec } from './state-sync-spec.js';
 import {
   fetchThreadInfos,
   type RawThreadInfos,
 } from '../../fetchers/thread-fetchers.js';
 import type { Viewer } from '../../session/viewer.js';
 
-export const threadsStateSyncSpec: StateSyncSpec<RawThreadInfos> =
+export const threadsStateSyncSpec: ServerStateSyncSpec<RawThreadInfos> =
   Object.freeze({
     async fetch(
       viewer: Viewer,
@@ -20,10 +21,5 @@
       const result = await fetchThreadInfos(viewer, filter);
       return result.threadInfos;
     },
-    hashKey: 'threadInfos',
-    innerHashSpec: {
-      hashKey: 'threadInfo',
-      deleteKey: 'deleteThreadIDs',
-      rawInfosKey: 'rawThreadInfos',
-    },
+    ...libSpec,
   });
diff --git a/keyserver/src/shared/state-sync/users-state-sync-spec.js b/keyserver/src/shared/state-sync/users-state-sync-spec.js
--- a/keyserver/src/shared/state-sync/users-state-sync-spec.js
+++ b/keyserver/src/shared/state-sync/users-state-sync-spec.js
@@ -1,13 +1,14 @@
 // @flow
 
+import { usersStateSyncSpec as libSpec } from 'lib/shared/state-sync/users-state-sync-spec.js';
 import type { CalendarQuery } from 'lib/types/entry-types.js';
 import type { UserInfos, UserInfo } from 'lib/types/user-types.js';
 
-import type { StateSyncSpec } from './state-sync-spec.js';
+import type { ServerStateSyncSpec } from './state-sync-spec.js';
 import { fetchKnownUserInfos } from '../../fetchers/user-fetchers.js';
 import type { Viewer } from '../../session/viewer.js';
 
-export const usersStateSyncSpec: StateSyncSpec<UserInfos, UserInfo> =
+export const usersStateSyncSpec: ServerStateSyncSpec<UserInfos, UserInfo> =
   Object.freeze({
     fetch(
       viewer: Viewer,
@@ -20,13 +21,5 @@
 
       return fetchKnownUserInfos(viewer);
     },
-    hashKey: 'userInfos',
-    innerHashSpec: {
-      hashKey: 'userInfo',
-      deleteKey: 'deleteUserInfoIDs',
-      rawInfosKey: 'userInfos',
-      additionalDeleteCondition(user: UserInfo) {
-        return !user.username;
-      },
-    },
+    ...libSpec,
   });
diff --git a/lib/shared/state-sync/current-user-state-sync-spec.js b/lib/shared/state-sync/current-user-state-sync-spec.js
new file mode 100644
--- /dev/null
+++ b/lib/shared/state-sync/current-user-state-sync-spec.js
@@ -0,0 +1,7 @@
+// @flow
+
+import type { StateSyncSpec } from './state-sync-spec.js';
+
+export const currentUserStateSyncSpec: StateSyncSpec<> = Object.freeze({
+  hashKey: 'currentUserInfo',
+});
diff --git a/lib/shared/state-sync/entries-state-sync-spec.js b/lib/shared/state-sync/entries-state-sync-spec.js
new file mode 100644
--- /dev/null
+++ b/lib/shared/state-sync/entries-state-sync-spec.js
@@ -0,0 +1,12 @@
+// @flow
+
+import type { StateSyncSpec } from './state-sync-spec.js';
+
+export const entriesStateSyncSpec: StateSyncSpec<> = Object.freeze({
+  hashKey: 'entryInfos',
+  innerHashSpec: {
+    hashKey: 'entryInfo',
+    deleteKey: 'deleteEntryIDs',
+    rawInfosKey: 'rawEntryInfos',
+  },
+});
diff --git a/lib/shared/state-sync/state-sync-spec.js b/lib/shared/state-sync/state-sync-spec.js
new file mode 100644
--- /dev/null
+++ b/lib/shared/state-sync/state-sync-spec.js
@@ -0,0 +1,11 @@
+// @flow
+
+export type StateSyncSpec<Info = empty> = {
+  +hashKey: string,
+  +innerHashSpec?: {
+    +hashKey: string,
+    +deleteKey: string,
+    +rawInfosKey: string,
+    +additionalDeleteCondition?: Info => boolean,
+  },
+};
diff --git a/keyserver/src/shared/state-sync/state-sync-specs.js b/lib/shared/state-sync/state-sync-specs.js
copy from keyserver/src/shared/state-sync/state-sync-specs.js
copy to lib/shared/state-sync/state-sync-specs.js
--- a/keyserver/src/shared/state-sync/state-sync-specs.js
+++ b/lib/shared/state-sync/state-sync-specs.js
@@ -6,7 +6,7 @@
 import { threadsStateSyncSpec } from './threads-state-sync-spec.js';
 import { usersStateSyncSpec } from './users-state-sync-spec.js';
 
-export const serverStateSyncSpecs: {
+export const stateSyncSpecs: {
   +[string]: StateSyncSpec<*>,
 } = Object.freeze({
   threads: threadsStateSyncSpec,
diff --git a/lib/shared/state-sync/threads-state-sync-spec.js b/lib/shared/state-sync/threads-state-sync-spec.js
new file mode 100644
--- /dev/null
+++ b/lib/shared/state-sync/threads-state-sync-spec.js
@@ -0,0 +1,12 @@
+// @flow
+
+import type { StateSyncSpec } from './state-sync-spec.js';
+
+export const threadsStateSyncSpec: StateSyncSpec<> = Object.freeze({
+  hashKey: 'threadInfos',
+  innerHashSpec: {
+    hashKey: 'threadInfo',
+    deleteKey: 'deleteThreadIDs',
+    rawInfosKey: 'rawThreadInfos',
+  },
+});
diff --git a/lib/shared/state-sync/users-state-sync-spec.js b/lib/shared/state-sync/users-state-sync-spec.js
new file mode 100644
--- /dev/null
+++ b/lib/shared/state-sync/users-state-sync-spec.js
@@ -0,0 +1,16 @@
+// @flow
+
+import type { StateSyncSpec } from './state-sync-spec.js';
+import type { UserInfo } from '../../types/user-types.js';
+
+export const usersStateSyncSpec: StateSyncSpec<UserInfo> = Object.freeze({
+  hashKey: 'userInfos',
+  innerHashSpec: {
+    hashKey: 'userInfo',
+    deleteKey: 'deleteUserInfoIDs',
+    rawInfosKey: 'userInfos',
+    additionalDeleteCondition(user: UserInfo) {
+      return !user.username;
+    },
+  },
+});