@quilibrium/quorum-shared 2.1.0-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +2414 -0
- package/dist/index.d.ts +2414 -0
- package/dist/index.js +2788 -0
- package/dist/index.mjs +2678 -0
- package/package.json +49 -0
- package/src/api/client.ts +86 -0
- package/src/api/endpoints.ts +87 -0
- package/src/api/errors.ts +179 -0
- package/src/api/index.ts +35 -0
- package/src/crypto/encryption-state.ts +249 -0
- package/src/crypto/index.ts +55 -0
- package/src/crypto/types.ts +307 -0
- package/src/crypto/wasm-provider.ts +298 -0
- package/src/hooks/index.ts +31 -0
- package/src/hooks/keys.ts +62 -0
- package/src/hooks/mutations/index.ts +15 -0
- package/src/hooks/mutations/useDeleteMessage.ts +67 -0
- package/src/hooks/mutations/useEditMessage.ts +87 -0
- package/src/hooks/mutations/useReaction.ts +163 -0
- package/src/hooks/mutations/useSendMessage.ts +131 -0
- package/src/hooks/useChannels.ts +49 -0
- package/src/hooks/useMessages.ts +77 -0
- package/src/hooks/useSpaces.ts +60 -0
- package/src/index.ts +32 -0
- package/src/signing/index.ts +10 -0
- package/src/signing/types.ts +83 -0
- package/src/signing/wasm-provider.ts +75 -0
- package/src/storage/adapter.ts +118 -0
- package/src/storage/index.ts +9 -0
- package/src/sync/index.ts +83 -0
- package/src/sync/service.test.ts +822 -0
- package/src/sync/service.ts +947 -0
- package/src/sync/types.ts +267 -0
- package/src/sync/utils.ts +588 -0
- package/src/transport/browser-websocket.ts +299 -0
- package/src/transport/index.ts +34 -0
- package/src/transport/rn-websocket.ts +321 -0
- package/src/transport/types.ts +56 -0
- package/src/transport/websocket.ts +212 -0
- package/src/types/bookmark.ts +29 -0
- package/src/types/conversation.ts +25 -0
- package/src/types/index.ts +57 -0
- package/src/types/message.ts +178 -0
- package/src/types/space.ts +75 -0
- package/src/types/user.ts +72 -0
- package/src/utils/encoding.ts +106 -0
- package/src/utils/formatting.ts +139 -0
- package/src/utils/index.ts +9 -0
- package/src/utils/logger.ts +141 -0
- package/src/utils/mentions.ts +135 -0
- package/src/utils/validation.ts +84 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useSpaces hook
|
|
3
|
+
*
|
|
4
|
+
* Fetches and caches space data with offline support
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
|
8
|
+
import type { Space } from '../types';
|
|
9
|
+
import type { StorageAdapter } from '../storage';
|
|
10
|
+
import { queryKeys } from './keys';
|
|
11
|
+
|
|
12
|
+
export interface UseSpacesOptions {
|
|
13
|
+
storage: StorageAdapter;
|
|
14
|
+
enabled?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function useSpaces({ storage, enabled = true }: UseSpacesOptions) {
|
|
18
|
+
return useQuery({
|
|
19
|
+
queryKey: queryKeys.spaces.all,
|
|
20
|
+
queryFn: async (): Promise<Space[]> => {
|
|
21
|
+
return storage.getSpaces();
|
|
22
|
+
},
|
|
23
|
+
enabled,
|
|
24
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface UseSpaceOptions {
|
|
29
|
+
storage: StorageAdapter;
|
|
30
|
+
spaceId: string | undefined;
|
|
31
|
+
enabled?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function useSpace({ storage, spaceId, enabled = true }: UseSpaceOptions) {
|
|
35
|
+
return useQuery({
|
|
36
|
+
queryKey: queryKeys.spaces.detail(spaceId ?? ''),
|
|
37
|
+
queryFn: async (): Promise<Space | null> => {
|
|
38
|
+
if (!spaceId) return null;
|
|
39
|
+
return storage.getSpace(spaceId);
|
|
40
|
+
},
|
|
41
|
+
enabled: enabled && !!spaceId,
|
|
42
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function useSpaceMembers({
|
|
47
|
+
storage,
|
|
48
|
+
spaceId,
|
|
49
|
+
enabled = true,
|
|
50
|
+
}: UseSpaceOptions) {
|
|
51
|
+
return useQuery({
|
|
52
|
+
queryKey: queryKeys.spaces.members(spaceId ?? ''),
|
|
53
|
+
queryFn: async () => {
|
|
54
|
+
if (!spaceId) return [];
|
|
55
|
+
return storage.getSpaceMembers(spaceId);
|
|
56
|
+
},
|
|
57
|
+
enabled: enabled && !!spaceId,
|
|
58
|
+
staleTime: 1000 * 60 * 2, // 2 minutes
|
|
59
|
+
});
|
|
60
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @quorum/shared
|
|
3
|
+
*
|
|
4
|
+
* Shared types, hooks, and utilities for Quorum mobile and desktop apps
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Types
|
|
8
|
+
export * from './types';
|
|
9
|
+
|
|
10
|
+
// Storage
|
|
11
|
+
export * from './storage';
|
|
12
|
+
|
|
13
|
+
// API
|
|
14
|
+
export * from './api';
|
|
15
|
+
|
|
16
|
+
// Hooks
|
|
17
|
+
export * from './hooks';
|
|
18
|
+
|
|
19
|
+
// Utils
|
|
20
|
+
export * from './utils';
|
|
21
|
+
|
|
22
|
+
// Crypto (E2E encryption)
|
|
23
|
+
export * from './crypto';
|
|
24
|
+
|
|
25
|
+
// Signing (Ed448)
|
|
26
|
+
export * from './signing';
|
|
27
|
+
|
|
28
|
+
// Transport (HTTP, WebSocket)
|
|
29
|
+
export * from './transport';
|
|
30
|
+
|
|
31
|
+
// Sync (hash-based delta synchronization)
|
|
32
|
+
export * from './sync';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signing module exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type { SigningProvider, SignedMessage } from './types';
|
|
6
|
+
|
|
7
|
+
export { verifySignedMessage, createSignedMessage } from './types';
|
|
8
|
+
|
|
9
|
+
// WASM implementation (for desktop/web)
|
|
10
|
+
export { WasmSigningProvider } from './wasm-provider';
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signing types and SigningProvider interface
|
|
3
|
+
*
|
|
4
|
+
* Platform-agnostic message signing and verification.
|
|
5
|
+
* Uses Ed448 for all signing operations.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* SigningProvider - Platform-agnostic interface for cryptographic signing
|
|
10
|
+
*
|
|
11
|
+
* Implementations:
|
|
12
|
+
* - WASM (desktop/web): Uses channel-wasm js_sign_ed448/js_verify_ed448
|
|
13
|
+
* - Native (iOS/Android): Uses uniffi-generated bindings
|
|
14
|
+
*/
|
|
15
|
+
export interface SigningProvider {
|
|
16
|
+
/**
|
|
17
|
+
* Sign a message using Ed448
|
|
18
|
+
* @param privateKey Base64-encoded Ed448 private key (56 bytes)
|
|
19
|
+
* @param message Base64-encoded message to sign
|
|
20
|
+
* @returns Base64-encoded signature (114 bytes)
|
|
21
|
+
*/
|
|
22
|
+
signEd448(privateKey: string, message: string): Promise<string>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Verify an Ed448 signature
|
|
26
|
+
* @param publicKey Base64-encoded Ed448 public key (57 bytes)
|
|
27
|
+
* @param message Base64-encoded original message
|
|
28
|
+
* @param signature Base64-encoded signature to verify
|
|
29
|
+
* @returns true if signature is valid, false otherwise
|
|
30
|
+
*/
|
|
31
|
+
verifyEd448(publicKey: string, message: string, signature: string): Promise<boolean>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Signed message structure
|
|
36
|
+
*/
|
|
37
|
+
export interface SignedMessage {
|
|
38
|
+
/** The message content (may be encrypted) */
|
|
39
|
+
content: string;
|
|
40
|
+
/** Base64-encoded Ed448 signature */
|
|
41
|
+
signature: string;
|
|
42
|
+
/** Base64-encoded Ed448 public key of signer */
|
|
43
|
+
publicKey: string;
|
|
44
|
+
/** Timestamp when signed */
|
|
45
|
+
timestamp: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Verify a signed message structure
|
|
50
|
+
*/
|
|
51
|
+
export async function verifySignedMessage(
|
|
52
|
+
provider: SigningProvider,
|
|
53
|
+
message: SignedMessage
|
|
54
|
+
): Promise<boolean> {
|
|
55
|
+
// Reconstruct the signed payload (content + timestamp)
|
|
56
|
+
const payload = `${message.content}:${message.timestamp}`;
|
|
57
|
+
const payloadBase64 = btoa(payload);
|
|
58
|
+
|
|
59
|
+
return provider.verifyEd448(message.publicKey, payloadBase64, message.signature);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Create a signed message
|
|
64
|
+
*/
|
|
65
|
+
export async function createSignedMessage(
|
|
66
|
+
provider: SigningProvider,
|
|
67
|
+
privateKey: string,
|
|
68
|
+
publicKey: string,
|
|
69
|
+
content: string
|
|
70
|
+
): Promise<SignedMessage> {
|
|
71
|
+
const timestamp = Date.now();
|
|
72
|
+
const payload = `${content}:${timestamp}`;
|
|
73
|
+
const payloadBase64 = btoa(payload);
|
|
74
|
+
|
|
75
|
+
const signature = await provider.signEd448(privateKey, payloadBase64);
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
content,
|
|
79
|
+
signature,
|
|
80
|
+
publicKey,
|
|
81
|
+
timestamp,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WASM SigningProvider implementation
|
|
3
|
+
*
|
|
4
|
+
* Wraps the channel-wasm WASM module to implement the SigningProvider interface.
|
|
5
|
+
* Used by desktop/web applications.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { SigningProvider } from './types';
|
|
9
|
+
import type { ChannelWasmModule } from '../crypto/wasm-provider';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Parse WASM verification result
|
|
13
|
+
* Returns true for "true"/"valid", false for "false"/"invalid"
|
|
14
|
+
*/
|
|
15
|
+
function parseVerifyResult(result: string): boolean {
|
|
16
|
+
const normalized = result.toLowerCase().trim();
|
|
17
|
+
if (normalized === 'true' || normalized === 'valid') {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
if (normalized === 'false' || normalized === 'invalid') {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
// Check for error patterns
|
|
24
|
+
if (
|
|
25
|
+
result.startsWith('invalid') ||
|
|
26
|
+
result.startsWith('error') ||
|
|
27
|
+
result.includes('failed') ||
|
|
28
|
+
result.includes('Error')
|
|
29
|
+
) {
|
|
30
|
+
throw new Error(result);
|
|
31
|
+
}
|
|
32
|
+
// Try to parse as JSON boolean
|
|
33
|
+
try {
|
|
34
|
+
return JSON.parse(result) as boolean;
|
|
35
|
+
} catch {
|
|
36
|
+
throw new Error(`Unexpected verification result: ${result}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* WasmSigningProvider - Implements SigningProvider using channel-wasm
|
|
42
|
+
*/
|
|
43
|
+
export class WasmSigningProvider implements SigningProvider {
|
|
44
|
+
private wasm: ChannelWasmModule;
|
|
45
|
+
|
|
46
|
+
constructor(wasmModule: ChannelWasmModule) {
|
|
47
|
+
this.wasm = wasmModule;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async signEd448(privateKey: string, message: string): Promise<string> {
|
|
51
|
+
const result = this.wasm.js_sign_ed448(privateKey, message);
|
|
52
|
+
|
|
53
|
+
// Check for error patterns
|
|
54
|
+
if (
|
|
55
|
+
result.startsWith('invalid') ||
|
|
56
|
+
result.startsWith('error') ||
|
|
57
|
+
result.includes('failed') ||
|
|
58
|
+
result.includes('Error')
|
|
59
|
+
) {
|
|
60
|
+
throw new Error(result);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Remove quotes if present (WASM returns quoted string)
|
|
64
|
+
if (result.startsWith('"') && result.endsWith('"')) {
|
|
65
|
+
return result.slice(1, -1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async verifyEd448(publicKey: string, message: string, signature: string): Promise<boolean> {
|
|
72
|
+
const result = this.wasm.js_verify_ed448(publicKey, message, signature);
|
|
73
|
+
return parseVerifyResult(result);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StorageAdapter interface
|
|
3
|
+
*
|
|
4
|
+
* Platform-agnostic storage interface that can be implemented by:
|
|
5
|
+
* - IndexedDB (desktop/web)
|
|
6
|
+
* - MMKV (React Native mobile)
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Space, Channel, Message, Conversation, UserConfig, SpaceMember } from '../types';
|
|
10
|
+
import type { MessageDigest, MemberDigest, DeletedMessageTombstone } from '../sync/types';
|
|
11
|
+
|
|
12
|
+
export interface GetMessagesParams {
|
|
13
|
+
spaceId: string;
|
|
14
|
+
channelId: string;
|
|
15
|
+
cursor?: number;
|
|
16
|
+
direction?: 'forward' | 'backward';
|
|
17
|
+
limit?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface GetMessagesResult {
|
|
21
|
+
messages: Message[];
|
|
22
|
+
nextCursor: number | null;
|
|
23
|
+
prevCursor: number | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface StorageAdapter {
|
|
27
|
+
// Initialization
|
|
28
|
+
init(): Promise<void>;
|
|
29
|
+
|
|
30
|
+
// Spaces
|
|
31
|
+
getSpaces(): Promise<Space[]>;
|
|
32
|
+
getSpace(spaceId: string): Promise<Space | null>;
|
|
33
|
+
saveSpace(space: Space): Promise<void>;
|
|
34
|
+
deleteSpace(spaceId: string): Promise<void>;
|
|
35
|
+
|
|
36
|
+
// Channels (embedded in Space, but may need separate access)
|
|
37
|
+
getChannels(spaceId: string): Promise<Channel[]>;
|
|
38
|
+
|
|
39
|
+
// Messages
|
|
40
|
+
getMessages(params: GetMessagesParams): Promise<GetMessagesResult>;
|
|
41
|
+
getMessage(params: {
|
|
42
|
+
spaceId: string;
|
|
43
|
+
channelId: string;
|
|
44
|
+
messageId: string;
|
|
45
|
+
}): Promise<Message | undefined>;
|
|
46
|
+
saveMessage(
|
|
47
|
+
message: Message,
|
|
48
|
+
lastMessageTimestamp: number,
|
|
49
|
+
address: string,
|
|
50
|
+
conversationType: string,
|
|
51
|
+
icon: string,
|
|
52
|
+
displayName: string
|
|
53
|
+
): Promise<void>;
|
|
54
|
+
deleteMessage(messageId: string): Promise<void>;
|
|
55
|
+
|
|
56
|
+
// Conversations (DMs)
|
|
57
|
+
getConversations(params: {
|
|
58
|
+
type: 'direct' | 'group';
|
|
59
|
+
cursor?: number;
|
|
60
|
+
limit?: number;
|
|
61
|
+
}): Promise<{ conversations: Conversation[]; nextCursor: number | null }>;
|
|
62
|
+
getConversation(conversationId: string): Promise<Conversation | undefined>;
|
|
63
|
+
saveConversation(conversation: Conversation): Promise<void>;
|
|
64
|
+
deleteConversation(conversationId: string): Promise<void>;
|
|
65
|
+
|
|
66
|
+
// User Config
|
|
67
|
+
getUserConfig(address: string): Promise<UserConfig | undefined>;
|
|
68
|
+
saveUserConfig(userConfig: UserConfig): Promise<void>;
|
|
69
|
+
|
|
70
|
+
// Space Members
|
|
71
|
+
getSpaceMembers(spaceId: string): Promise<SpaceMember[]>;
|
|
72
|
+
getSpaceMember(spaceId: string, address: string): Promise<SpaceMember | undefined>;
|
|
73
|
+
saveSpaceMember(spaceId: string, member: SpaceMember): Promise<void>;
|
|
74
|
+
|
|
75
|
+
// Sync metadata
|
|
76
|
+
getLastSyncTime(key: string): Promise<number | undefined>;
|
|
77
|
+
setLastSyncTime(key: string, time: number): Promise<void>;
|
|
78
|
+
|
|
79
|
+
// Sync-specific queries (optional - for optimized sync)
|
|
80
|
+
// If not implemented, SyncService will compute these from full data
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get message digests for efficient sync comparison.
|
|
84
|
+
* If not implemented, returns undefined and SyncService computes from messages.
|
|
85
|
+
*/
|
|
86
|
+
getMessageDigests?(spaceId: string, channelId: string): Promise<MessageDigest[] | undefined>;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Get messages by IDs for delta sync.
|
|
90
|
+
* If not implemented, returns undefined and caller fetches individually.
|
|
91
|
+
*/
|
|
92
|
+
getMessagesByIds?(
|
|
93
|
+
spaceId: string,
|
|
94
|
+
channelId: string,
|
|
95
|
+
ids: string[]
|
|
96
|
+
): Promise<Message[] | undefined>;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Get member digests for efficient sync comparison.
|
|
100
|
+
* If not implemented, returns undefined and SyncService computes from members.
|
|
101
|
+
*/
|
|
102
|
+
getMemberDigests?(spaceId: string): Promise<MemberDigest[] | undefined>;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get deleted message tombstones for sync.
|
|
106
|
+
*/
|
|
107
|
+
getTombstones?(spaceId: string, channelId: string): Promise<DeletedMessageTombstone[]>;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Save deleted message tombstone.
|
|
111
|
+
*/
|
|
112
|
+
saveTombstone?(tombstone: DeletedMessageTombstone): Promise<void>;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Clean up old tombstones.
|
|
116
|
+
*/
|
|
117
|
+
cleanupTombstones?(maxAgeMs: number): Promise<void>;
|
|
118
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync Module
|
|
3
|
+
*
|
|
4
|
+
* Hash-based delta synchronization for efficient data transfer.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Types
|
|
8
|
+
export type {
|
|
9
|
+
// Message sync
|
|
10
|
+
MessageDigest,
|
|
11
|
+
ReactionDigest,
|
|
12
|
+
SyncManifest,
|
|
13
|
+
MessageDelta,
|
|
14
|
+
ReactionDelta,
|
|
15
|
+
// Member sync
|
|
16
|
+
MemberDigest,
|
|
17
|
+
MemberDelta,
|
|
18
|
+
// Peer map sync
|
|
19
|
+
PeerEntry,
|
|
20
|
+
PeerMapDelta,
|
|
21
|
+
// Tombstones
|
|
22
|
+
DeletedMessageTombstone,
|
|
23
|
+
// Control messages
|
|
24
|
+
SyncSummary,
|
|
25
|
+
SyncRequestPayload,
|
|
26
|
+
SyncInfoPayload,
|
|
27
|
+
SyncInitiatePayload,
|
|
28
|
+
SyncManifestPayload,
|
|
29
|
+
SyncDeltaPayload,
|
|
30
|
+
// State
|
|
31
|
+
SyncCandidate,
|
|
32
|
+
SyncSession,
|
|
33
|
+
// Union
|
|
34
|
+
SyncControlPayload,
|
|
35
|
+
} from './types';
|
|
36
|
+
|
|
37
|
+
// Type guards
|
|
38
|
+
export {
|
|
39
|
+
isSyncRequest,
|
|
40
|
+
isSyncInfo,
|
|
41
|
+
isSyncInitiate,
|
|
42
|
+
isSyncManifest,
|
|
43
|
+
isSyncDelta,
|
|
44
|
+
} from './types';
|
|
45
|
+
|
|
46
|
+
// Utils
|
|
47
|
+
export {
|
|
48
|
+
// Constants
|
|
49
|
+
MAX_CHUNK_SIZE,
|
|
50
|
+
DEFAULT_SYNC_EXPIRY_MS,
|
|
51
|
+
AGGRESSIVE_SYNC_TIMEOUT_MS,
|
|
52
|
+
// Hash functions
|
|
53
|
+
computeHash,
|
|
54
|
+
computeContentHash,
|
|
55
|
+
computeReactionHash,
|
|
56
|
+
computeMemberHash,
|
|
57
|
+
computeManifestHash,
|
|
58
|
+
// Digest creation
|
|
59
|
+
createMessageDigest,
|
|
60
|
+
createReactionDigest,
|
|
61
|
+
createManifest,
|
|
62
|
+
createMemberDigest,
|
|
63
|
+
// Delta calculation
|
|
64
|
+
computeMessageDiff,
|
|
65
|
+
computeReactionDiff,
|
|
66
|
+
computeMemberDiff,
|
|
67
|
+
computePeerDiff,
|
|
68
|
+
// Delta building
|
|
69
|
+
buildMessageDelta,
|
|
70
|
+
buildReactionDelta,
|
|
71
|
+
buildMemberDelta,
|
|
72
|
+
// Chunking
|
|
73
|
+
chunkMessages,
|
|
74
|
+
chunkMembers,
|
|
75
|
+
// Summary
|
|
76
|
+
createSyncSummary,
|
|
77
|
+
} from './utils';
|
|
78
|
+
|
|
79
|
+
export type { MessageDiffResult, ReactionDiffResult, MemberDiffResult, PeerDiffResult } from './utils';
|
|
80
|
+
|
|
81
|
+
// Service
|
|
82
|
+
export { SyncService } from './service';
|
|
83
|
+
export type { SyncServiceConfig } from './service';
|