@massalabs/gossip-sdk 0.0.1 → 0.0.2-dev.20260128111120
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/api/messageProtocol/index.d.ts +19 -0
- package/dist/api/messageProtocol/index.js +26 -0
- package/dist/api/messageProtocol/mock.d.ts +12 -0
- package/{src/api/messageProtocol/mock.ts → dist/api/messageProtocol/mock.js} +2 -3
- package/dist/api/messageProtocol/rest.d.ts +22 -0
- package/dist/api/messageProtocol/rest.js +161 -0
- package/dist/api/messageProtocol/types.d.ts +61 -0
- package/dist/api/messageProtocol/types.js +6 -0
- package/dist/assets/generated/wasm/README.md +281 -0
- package/dist/assets/generated/wasm/gossip_wasm.d.ts +498 -0
- package/dist/assets/generated/wasm/gossip_wasm.js +1399 -0
- package/dist/assets/generated/wasm/gossip_wasm_bg.wasm +0 -0
- package/dist/assets/generated/wasm/gossip_wasm_bg.wasm.d.ts +68 -0
- package/dist/assets/generated/wasm/package.json +15 -0
- package/dist/config/protocol.d.ts +36 -0
- package/dist/config/protocol.js +77 -0
- package/dist/config/sdk.d.ts +82 -0
- package/dist/config/sdk.js +55 -0
- package/{src/contacts.ts → dist/contacts.d.ts} +10 -94
- package/dist/contacts.js +166 -0
- package/dist/core/SdkEventEmitter.d.ts +36 -0
- package/dist/core/SdkEventEmitter.js +59 -0
- package/dist/core/SdkPolling.d.ts +35 -0
- package/dist/core/SdkPolling.js +100 -0
- package/{src/core/index.ts → dist/core/index.d.ts} +0 -2
- package/dist/core/index.js +5 -0
- package/dist/crypto/bip39.d.ts +34 -0
- package/dist/crypto/bip39.js +62 -0
- package/dist/crypto/encryption.d.ts +37 -0
- package/dist/crypto/encryption.js +46 -0
- package/dist/db.d.ts +190 -0
- package/dist/db.js +311 -0
- package/dist/gossipSdk.d.ts +274 -0
- package/dist/gossipSdk.js +690 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +77 -0
- package/dist/services/announcement.d.ts +43 -0
- package/dist/services/announcement.js +491 -0
- package/dist/services/auth.d.ts +37 -0
- package/dist/services/auth.js +76 -0
- package/dist/services/discussion.d.ts +63 -0
- package/dist/services/discussion.js +297 -0
- package/dist/services/message.d.ts +74 -0
- package/dist/services/message.js +826 -0
- package/dist/services/refresh.d.ts +41 -0
- package/dist/services/refresh.js +205 -0
- package/{src/sw.ts → dist/sw.d.ts} +1 -8
- package/dist/sw.js +10 -0
- package/dist/types/events.d.ts +80 -0
- package/dist/types/events.js +7 -0
- package/dist/types.d.ts +32 -0
- package/dist/types.js +7 -0
- package/dist/utils/base64.d.ts +10 -0
- package/dist/utils/base64.js +30 -0
- package/dist/utils/contacts.d.ts +42 -0
- package/dist/utils/contacts.js +113 -0
- package/dist/utils/discussions.d.ts +24 -0
- package/dist/utils/discussions.js +38 -0
- package/dist/utils/logs.d.ts +19 -0
- package/dist/utils/logs.js +89 -0
- package/dist/utils/messageSerialization.d.ts +64 -0
- package/dist/utils/messageSerialization.js +184 -0
- package/dist/utils/queue.d.ts +50 -0
- package/dist/utils/queue.js +110 -0
- package/dist/utils/type.d.ts +10 -0
- package/dist/utils/type.js +4 -0
- package/dist/utils/userId.d.ts +40 -0
- package/dist/utils/userId.js +90 -0
- package/dist/utils/validation.d.ts +50 -0
- package/dist/utils/validation.js +112 -0
- package/dist/utils.d.ts +30 -0
- package/{src/utils.ts → dist/utils.js} +9 -19
- package/dist/wasm/encryption.d.ts +56 -0
- package/{src/wasm/encryption.ts → dist/wasm/encryption.js} +22 -51
- package/dist/wasm/index.d.ts +10 -0
- package/{src/wasm/index.ts → dist/wasm/index.js} +1 -8
- package/dist/wasm/loader.d.ts +21 -0
- package/dist/wasm/loader.js +103 -0
- package/dist/wasm/session.d.ts +85 -0
- package/dist/wasm/session.js +226 -0
- package/dist/wasm/userKeys.d.ts +17 -0
- package/{src/wasm/userKeys.ts → dist/wasm/userKeys.js} +6 -13
- package/package.json +5 -1
- package/src/api/messageProtocol/index.ts +0 -53
- package/src/api/messageProtocol/rest.ts +0 -209
- package/src/api/messageProtocol/types.ts +0 -70
- package/src/config/protocol.ts +0 -97
- package/src/config/sdk.ts +0 -131
- package/src/core/SdkEventEmitter.ts +0 -91
- package/src/core/SdkPolling.ts +0 -134
- package/src/crypto/bip39.ts +0 -84
- package/src/crypto/encryption.ts +0 -77
- package/src/db.ts +0 -465
- package/src/gossipSdk.ts +0 -994
- package/src/index.ts +0 -211
- package/src/services/announcement.ts +0 -653
- package/src/services/auth.ts +0 -95
- package/src/services/discussion.ts +0 -380
- package/src/services/message.ts +0 -1055
- package/src/services/refresh.ts +0 -234
- package/src/types/events.ts +0 -108
- package/src/types.ts +0 -70
- package/src/utils/base64.ts +0 -39
- package/src/utils/contacts.ts +0 -161
- package/src/utils/discussions.ts +0 -55
- package/src/utils/logs.ts +0 -86
- package/src/utils/messageSerialization.ts +0 -257
- package/src/utils/queue.ts +0 -106
- package/src/utils/type.ts +0 -7
- package/src/utils/userId.ts +0 -114
- package/src/utils/validation.ts +0 -144
- package/src/wasm/loader.ts +0 -123
- package/src/wasm/session.ts +0 -276
- package/test/config/protocol.spec.ts +0 -31
- package/test/config/sdk.spec.ts +0 -163
- package/test/db/helpers.spec.ts +0 -142
- package/test/db/operations.spec.ts +0 -128
- package/test/db/states.spec.ts +0 -535
- package/test/integration/discussion-flow.spec.ts +0 -422
- package/test/integration/messaging-flow.spec.ts +0 -708
- package/test/integration/sdk-lifecycle.spec.ts +0 -325
- package/test/mocks/index.ts +0 -9
- package/test/mocks/mockMessageProtocol.ts +0 -100
- package/test/services/auth.spec.ts +0 -311
- package/test/services/discussion.spec.ts +0 -279
- package/test/services/message-deduplication.spec.ts +0 -299
- package/test/services/message-startup.spec.ts +0 -331
- package/test/services/message.spec.ts +0 -817
- package/test/services/refresh.spec.ts +0 -199
- package/test/services/session-status.spec.ts +0 -349
- package/test/session/wasm.spec.ts +0 -227
- package/test/setup.ts +0 -52
- package/test/utils/contacts.spec.ts +0 -156
- package/test/utils/discussions.spec.ts +0 -66
- package/test/utils/queue.spec.ts +0 -52
- package/test/utils/serialization.spec.ts +0 -120
- package/test/utils/userId.spec.ts +0 -120
- package/test/utils/validation.spec.ts +0 -223
- package/test/utils.ts +0 -212
- package/tsconfig.json +0 -26
- package/tsconfig.tsbuildinfo +0 -1
- package/vitest.config.ts +0 -28
package/src/wasm/loader.ts
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WASM Module Loader and Initialization Service
|
|
3
|
-
*
|
|
4
|
-
* This file handles both WASM core initialization and module loading.
|
|
5
|
-
* It ensures WASM modules are initialized once and properly throughout
|
|
6
|
-
* the application lifecycle.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import init from '../assets/generated/wasm/gossip_wasm';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Check if we're running in Node.js environment
|
|
13
|
-
*/
|
|
14
|
-
function isNodeEnvironment(): boolean {
|
|
15
|
-
return (
|
|
16
|
-
typeof process !== 'undefined' &&
|
|
17
|
-
process.versions != null &&
|
|
18
|
-
process.versions.node != null
|
|
19
|
-
);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Load WASM module for Node.js environment using fs.readFileSync
|
|
24
|
-
*/
|
|
25
|
-
async function loadWasmForNode(): Promise<WebAssembly.Module> {
|
|
26
|
-
// Dynamic import to avoid bundling Node.js modules in browser builds
|
|
27
|
-
const fs = await import('node:fs');
|
|
28
|
-
const path = await import('node:path');
|
|
29
|
-
const { fileURLToPath } = await import('node:url');
|
|
30
|
-
|
|
31
|
-
// Get the directory of the current module
|
|
32
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
33
|
-
const __dirname = path.dirname(__filename);
|
|
34
|
-
|
|
35
|
-
// Resolve path to WASM file - WASM is in the SDK's generated folder
|
|
36
|
-
const wasmPath = path.resolve(
|
|
37
|
-
__dirname,
|
|
38
|
-
'../assets/generated/wasm/gossip_wasm_bg.wasm'
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
// Read WASM file as binary
|
|
42
|
-
const wasmBuffer = fs.readFileSync(wasmPath);
|
|
43
|
-
|
|
44
|
-
// Instantiate WASM module
|
|
45
|
-
const wasmModule = await WebAssembly.compile(wasmBuffer);
|
|
46
|
-
return wasmModule;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* WASM Initialization State
|
|
51
|
-
*/
|
|
52
|
-
let isInitializing = false;
|
|
53
|
-
let isInitialized = false;
|
|
54
|
-
let initializationPromise: Promise<void> | null = null;
|
|
55
|
-
let initError: Error | null = null;
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Initialize WASM modules if not already initialized
|
|
59
|
-
* This function is idempotent - safe to call multiple times
|
|
60
|
-
*/
|
|
61
|
-
export async function initializeWasm(): Promise<void> {
|
|
62
|
-
// If already initialized, return immediately
|
|
63
|
-
if (isInitialized) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// If initialization is in progress, wait for it to complete
|
|
68
|
-
if (isInitializing && initializationPromise) {
|
|
69
|
-
return initializationPromise;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Start initialization
|
|
73
|
-
isInitializing = true;
|
|
74
|
-
initError = null;
|
|
75
|
-
|
|
76
|
-
initializationPromise = (async () => {
|
|
77
|
-
try {
|
|
78
|
-
// In Node.js environment, load WASM using fs.readFileSync
|
|
79
|
-
if (isNodeEnvironment()) {
|
|
80
|
-
const wasmModule = await loadWasmForNode();
|
|
81
|
-
await init(wasmModule);
|
|
82
|
-
} else {
|
|
83
|
-
// In browser/jsdom, use default init (which uses fetch)
|
|
84
|
-
await init();
|
|
85
|
-
}
|
|
86
|
-
isInitialized = true;
|
|
87
|
-
isInitializing = false;
|
|
88
|
-
} catch (error) {
|
|
89
|
-
initError = error as Error;
|
|
90
|
-
isInitializing = false;
|
|
91
|
-
console.error('[WASM] Failed to initialize WASM modules:', error);
|
|
92
|
-
throw error;
|
|
93
|
-
}
|
|
94
|
-
})();
|
|
95
|
-
|
|
96
|
-
return initializationPromise;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Ensure WASM is initialized, throwing an error if initialization failed
|
|
101
|
-
*/
|
|
102
|
-
export async function ensureWasmInitialized(): Promise<void> {
|
|
103
|
-
await initializeWasm();
|
|
104
|
-
|
|
105
|
-
if (initError) {
|
|
106
|
-
throw new Error(`WASM initialization failed: ${initError.message}`);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (!isInitialized) {
|
|
110
|
-
throw new Error('WASM not initialized');
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Start WASM initialization in the background.
|
|
116
|
-
* Call this early in the app lifecycle (for example in main.tsx).
|
|
117
|
-
*/
|
|
118
|
-
export function startWasmInitialization(): void {
|
|
119
|
-
// Fire and forget - start initialization in background
|
|
120
|
-
initializeWasm().catch(error => {
|
|
121
|
-
console.error('[WASM] Background initialization error:', error);
|
|
122
|
-
});
|
|
123
|
-
}
|
package/src/wasm/session.ts
DELETED
|
@@ -1,276 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session Module Implementation
|
|
3
|
-
*
|
|
4
|
-
* This file contains the real WASM implementation of the SessionModule
|
|
5
|
-
* using SessionManagerWrapper and related WASM classes.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
SessionManagerWrapper,
|
|
10
|
-
UserPublicKeys,
|
|
11
|
-
UserSecretKeys,
|
|
12
|
-
ReceiveMessageOutput,
|
|
13
|
-
SendMessageOutput,
|
|
14
|
-
SessionStatus,
|
|
15
|
-
EncryptionKey,
|
|
16
|
-
SessionConfig,
|
|
17
|
-
AnnouncementResult,
|
|
18
|
-
UserKeys,
|
|
19
|
-
} from '../assets/generated/wasm/gossip_wasm';
|
|
20
|
-
import { UserProfile } from '../db';
|
|
21
|
-
import { encodeUserId } from '../utils/userId';
|
|
22
|
-
|
|
23
|
-
export class SessionModule {
|
|
24
|
-
private sessionManager: SessionManagerWrapper | null = null;
|
|
25
|
-
private onPersist?: () => Promise<void>; // Async callback for persistence
|
|
26
|
-
public ourPk: UserPublicKeys;
|
|
27
|
-
public ourSk: UserSecretKeys;
|
|
28
|
-
public userId: Uint8Array;
|
|
29
|
-
public userIdEncoded: string;
|
|
30
|
-
|
|
31
|
-
constructor(
|
|
32
|
-
userKeys: UserKeys,
|
|
33
|
-
onPersist?: () => Promise<void>,
|
|
34
|
-
config?: SessionConfig
|
|
35
|
-
) {
|
|
36
|
-
this.ourPk = userKeys.public_keys();
|
|
37
|
-
this.ourSk = userKeys.secret_keys();
|
|
38
|
-
this.userId = this.ourPk.derive_id();
|
|
39
|
-
this.userIdEncoded = encodeUserId(this.userId);
|
|
40
|
-
|
|
41
|
-
const sessionConfig = config ?? SessionConfig.new_default();
|
|
42
|
-
this.sessionManager = new SessionManagerWrapper(sessionConfig);
|
|
43
|
-
this.onPersist = onPersist;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Set the persistence callback
|
|
48
|
-
*/
|
|
49
|
-
setOnPersist(callback: () => Promise<void>): void {
|
|
50
|
-
this.onPersist = callback;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Helper to trigger persistence after state changes.
|
|
55
|
-
* Returns a promise that resolves when persistence is complete.
|
|
56
|
-
* IMPORTANT: Callers should await this before sending data to network
|
|
57
|
-
* to prevent state loss on app crash.
|
|
58
|
-
*/
|
|
59
|
-
private async persistIfNeeded(): Promise<void> {
|
|
60
|
-
if (this.onPersist) {
|
|
61
|
-
await this.onPersist();
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Trigger persistence explicitly and wait for completion.
|
|
67
|
-
* Use this when you need to ensure state is saved before proceeding.
|
|
68
|
-
*/
|
|
69
|
-
async persist(): Promise<void> {
|
|
70
|
-
await this.persistIfNeeded();
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Initialize session from an encrypted blob
|
|
75
|
-
*/
|
|
76
|
-
load(profile: UserProfile, encryptionKey: EncryptionKey): void {
|
|
77
|
-
// Clean up existing session if any
|
|
78
|
-
this.cleanup();
|
|
79
|
-
|
|
80
|
-
this.sessionManager = SessionManagerWrapper.from_encrypted_blob(
|
|
81
|
-
profile.session,
|
|
82
|
-
encryptionKey
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Serialize session to an encrypted blob
|
|
88
|
-
*/
|
|
89
|
-
toEncryptedBlob(key: EncryptionKey): Uint8Array {
|
|
90
|
-
if (!this.sessionManager) {
|
|
91
|
-
throw new Error('Session manager is not initialized');
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return this.sessionManager.to_encrypted_blob(key);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
cleanup(): void {
|
|
98
|
-
this.sessionManager?.free();
|
|
99
|
-
this.sessionManager = null;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Establish an outgoing session with a peer via the underlying WASM wrapper
|
|
104
|
-
* @param peerPk - The peer's public keys
|
|
105
|
-
* @param userData - Optional user data to include in the announcement (defaults to empty array)
|
|
106
|
-
* @returns The announcement bytes to publish
|
|
107
|
-
*/
|
|
108
|
-
async establishOutgoingSession(
|
|
109
|
-
peerPk: UserPublicKeys,
|
|
110
|
-
userData?: Uint8Array
|
|
111
|
-
): Promise<Uint8Array> {
|
|
112
|
-
if (!this.sessionManager) {
|
|
113
|
-
throw new Error('Session manager is not initialized');
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const userDataBytes = userData ?? new Uint8Array(0);
|
|
117
|
-
const result = this.sessionManager.establish_outgoing_session(
|
|
118
|
-
peerPk,
|
|
119
|
-
this.ourPk,
|
|
120
|
-
this.ourSk,
|
|
121
|
-
userDataBytes
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
if (result.length === 0) {
|
|
125
|
-
throw new Error(
|
|
126
|
-
'Failed to establish outgoing session. Session manager returned empty announcement bytes.'
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
await this.persistIfNeeded();
|
|
131
|
-
return result;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Feed an incoming announcement into the session manager
|
|
136
|
-
* @returns AnnouncementResult containing the announcer's public keys, timestamp, and user data, or undefined if invalid
|
|
137
|
-
*/
|
|
138
|
-
async feedIncomingAnnouncement(
|
|
139
|
-
announcementBytes: Uint8Array
|
|
140
|
-
): Promise<AnnouncementResult | undefined> {
|
|
141
|
-
if (!this.sessionManager) {
|
|
142
|
-
throw new Error('Session manager is not initialized');
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const result = this.sessionManager.feed_incoming_announcement(
|
|
146
|
-
announcementBytes,
|
|
147
|
-
this.ourPk,
|
|
148
|
-
this.ourSk
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
if (result) {
|
|
152
|
-
await this.persistIfNeeded();
|
|
153
|
-
}
|
|
154
|
-
return result;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Get the list of message board read keys (seekers) to monitor
|
|
159
|
-
*/
|
|
160
|
-
getMessageBoardReadKeys(): Array<Uint8Array> {
|
|
161
|
-
if (!this.sessionManager) {
|
|
162
|
-
throw new Error('Session manager is not initialized');
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return this.sessionManager.get_message_board_read_keys();
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Process an incoming ciphertext from the message board
|
|
170
|
-
*/
|
|
171
|
-
async feedIncomingMessageBoardRead(
|
|
172
|
-
seeker: Uint8Array,
|
|
173
|
-
ciphertext: Uint8Array
|
|
174
|
-
): Promise<ReceiveMessageOutput | undefined> {
|
|
175
|
-
if (!this.sessionManager) {
|
|
176
|
-
throw new Error('Session manager is not initialized');
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const result = this.sessionManager.feed_incoming_message_board_read(
|
|
180
|
-
seeker,
|
|
181
|
-
ciphertext,
|
|
182
|
-
this.ourSk
|
|
183
|
-
);
|
|
184
|
-
|
|
185
|
-
await this.persistIfNeeded();
|
|
186
|
-
return result;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Send a message to a peer.
|
|
191
|
-
* IMPORTANT: This persists session state before returning.
|
|
192
|
-
* The returned output should only be sent to network AFTER this resolves.
|
|
193
|
-
*/
|
|
194
|
-
async sendMessage(
|
|
195
|
-
peerId: Uint8Array,
|
|
196
|
-
message: Uint8Array
|
|
197
|
-
): Promise<SendMessageOutput | undefined> {
|
|
198
|
-
if (!this.sessionManager) {
|
|
199
|
-
throw new Error('Session manager is not initialized');
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const result = this.sessionManager.send_message(peerId, message);
|
|
203
|
-
// CRITICAL: Persist session state BEFORE returning
|
|
204
|
-
// This ensures state is saved before the encrypted message goes on the network
|
|
205
|
-
await this.persistIfNeeded();
|
|
206
|
-
return result;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* List all known peer IDs
|
|
211
|
-
*/
|
|
212
|
-
peerList(): Array<Uint8Array> {
|
|
213
|
-
if (!this.sessionManager) {
|
|
214
|
-
throw new Error('Session manager is not initialized');
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return this.sessionManager.peer_list();
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Get the session status for a peer
|
|
222
|
-
*/
|
|
223
|
-
peerSessionStatus(peerId: Uint8Array): SessionStatus {
|
|
224
|
-
if (!this.sessionManager) {
|
|
225
|
-
throw new Error('Session manager is not initialized');
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return this.sessionManager.peer_session_status(peerId);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Discard a peer and all associated session state
|
|
233
|
-
*/
|
|
234
|
-
async peerDiscard(peerId: Uint8Array): Promise<void> {
|
|
235
|
-
if (!this.sessionManager) {
|
|
236
|
-
throw new Error('Session manager is not initialized');
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
this.sessionManager.peer_discard(peerId);
|
|
240
|
-
await this.persistIfNeeded();
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Refresh sessions, returning peer IDs that need keep-alive messages
|
|
245
|
-
*/
|
|
246
|
-
async refresh(): Promise<Array<Uint8Array>> {
|
|
247
|
-
if (!this.sessionManager) {
|
|
248
|
-
throw new Error('Session manager is not initialized');
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const result = this.sessionManager.refresh();
|
|
252
|
-
await this.persistIfNeeded();
|
|
253
|
-
return result;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
export function sessionStatusToString(status: SessionStatus): string {
|
|
258
|
-
switch (status) {
|
|
259
|
-
case SessionStatus.Active:
|
|
260
|
-
return 'Active';
|
|
261
|
-
case SessionStatus.UnknownPeer:
|
|
262
|
-
return 'UnknownPeer';
|
|
263
|
-
case SessionStatus.NoSession:
|
|
264
|
-
return 'NoSession';
|
|
265
|
-
case SessionStatus.PeerRequested:
|
|
266
|
-
return 'PeerRequested';
|
|
267
|
-
case SessionStatus.SelfRequested:
|
|
268
|
-
return 'SelfRequested';
|
|
269
|
-
case SessionStatus.Killed:
|
|
270
|
-
return 'Killed';
|
|
271
|
-
case SessionStatus.Saturated:
|
|
272
|
-
return 'Saturated';
|
|
273
|
-
default:
|
|
274
|
-
throw new Error(`Unknown session status: ${status}`);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Protocol config tests
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
6
|
-
import {
|
|
7
|
-
protocolConfig,
|
|
8
|
-
setProtocolBaseUrl,
|
|
9
|
-
resetProtocolBaseUrl,
|
|
10
|
-
} from '../../src/config/protocol';
|
|
11
|
-
|
|
12
|
-
describe('protocol config', () => {
|
|
13
|
-
beforeEach(() => {
|
|
14
|
-
resetProtocolBaseUrl();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
afterEach(() => {
|
|
18
|
-
resetProtocolBaseUrl();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('uses runtime override when provided', () => {
|
|
22
|
-
setProtocolBaseUrl('https://custom.example.com/api');
|
|
23
|
-
expect(protocolConfig.baseUrl).toBe('https://custom.example.com/api');
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('resets to default after override', () => {
|
|
27
|
-
setProtocolBaseUrl('https://custom.example.com/api');
|
|
28
|
-
resetProtocolBaseUrl();
|
|
29
|
-
expect(protocolConfig.baseUrl).toBe('https://api.usegossip.com/api');
|
|
30
|
-
});
|
|
31
|
-
});
|
package/test/config/sdk.spec.ts
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SDK Config tests
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect } from 'vitest';
|
|
6
|
-
import {
|
|
7
|
-
defaultSdkConfig,
|
|
8
|
-
mergeConfig,
|
|
9
|
-
type SdkConfig,
|
|
10
|
-
type DeepPartial,
|
|
11
|
-
} from '../../src/config/sdk';
|
|
12
|
-
|
|
13
|
-
describe('SDK Config', () => {
|
|
14
|
-
describe('defaultSdkConfig', () => {
|
|
15
|
-
it('should have correct default protocol values', () => {
|
|
16
|
-
expect(defaultSdkConfig.protocol.timeout).toBe(10000);
|
|
17
|
-
expect(defaultSdkConfig.protocol.retryAttempts).toBe(3);
|
|
18
|
-
expect(defaultSdkConfig.protocol.baseUrl).toBeUndefined();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('should have correct default polling values', () => {
|
|
22
|
-
expect(defaultSdkConfig.polling.enabled).toBe(false);
|
|
23
|
-
expect(defaultSdkConfig.polling.messagesIntervalMs).toBe(5000);
|
|
24
|
-
expect(defaultSdkConfig.polling.announcementsIntervalMs).toBe(10000);
|
|
25
|
-
expect(defaultSdkConfig.polling.sessionRefreshIntervalMs).toBe(30000);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('should have correct default messages values', () => {
|
|
29
|
-
expect(defaultSdkConfig.messages.fetchDelayMs).toBe(100);
|
|
30
|
-
expect(defaultSdkConfig.messages.maxFetchIterations).toBe(30);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('should have correct default announcements values', () => {
|
|
34
|
-
expect(defaultSdkConfig.announcements.fetchLimit).toBe(500);
|
|
35
|
-
expect(defaultSdkConfig.announcements.brokenThresholdMs).toBe(
|
|
36
|
-
60 * 60 * 1000
|
|
37
|
-
);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
describe('mergeConfig', () => {
|
|
42
|
-
it('should return defaults when no partial provided', () => {
|
|
43
|
-
const config = mergeConfig();
|
|
44
|
-
expect(config).toEqual(defaultSdkConfig);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('should return defaults when undefined provided', () => {
|
|
48
|
-
const config = mergeConfig(undefined);
|
|
49
|
-
expect(config).toEqual(defaultSdkConfig);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('should merge partial protocol config', () => {
|
|
53
|
-
const partial: DeepPartial<SdkConfig> = {
|
|
54
|
-
protocol: {
|
|
55
|
-
timeout: 5000,
|
|
56
|
-
},
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const config = mergeConfig(partial);
|
|
60
|
-
|
|
61
|
-
expect(config.protocol.timeout).toBe(5000);
|
|
62
|
-
expect(config.protocol.retryAttempts).toBe(3);
|
|
63
|
-
expect(config.polling.enabled).toBe(false);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should merge partial polling config', () => {
|
|
67
|
-
const partial: DeepPartial<SdkConfig> = {
|
|
68
|
-
polling: {
|
|
69
|
-
enabled: true,
|
|
70
|
-
messagesIntervalMs: 2000,
|
|
71
|
-
},
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
const config = mergeConfig(partial);
|
|
75
|
-
|
|
76
|
-
expect(config.polling.enabled).toBe(true);
|
|
77
|
-
expect(config.polling.messagesIntervalMs).toBe(2000);
|
|
78
|
-
expect(config.polling.announcementsIntervalMs).toBe(10000);
|
|
79
|
-
expect(config.polling.sessionRefreshIntervalMs).toBe(30000);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('should merge partial messages config', () => {
|
|
83
|
-
const partial: DeepPartial<SdkConfig> = {
|
|
84
|
-
messages: {
|
|
85
|
-
maxFetchIterations: 50,
|
|
86
|
-
},
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const config = mergeConfig(partial);
|
|
90
|
-
|
|
91
|
-
expect(config.messages.maxFetchIterations).toBe(50);
|
|
92
|
-
expect(config.messages.fetchDelayMs).toBe(100);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('should merge partial announcements config', () => {
|
|
96
|
-
const partial: DeepPartial<SdkConfig> = {
|
|
97
|
-
announcements: {
|
|
98
|
-
brokenThresholdMs: 30 * 60 * 1000,
|
|
99
|
-
},
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const config = mergeConfig(partial);
|
|
103
|
-
|
|
104
|
-
expect(config.announcements.brokenThresholdMs).toBe(30 * 60 * 1000);
|
|
105
|
-
expect(config.announcements.fetchLimit).toBe(500);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('should merge multiple sections at once', () => {
|
|
109
|
-
const partial: DeepPartial<SdkConfig> = {
|
|
110
|
-
protocol: {
|
|
111
|
-
baseUrl: 'https://custom.api.com',
|
|
112
|
-
},
|
|
113
|
-
polling: {
|
|
114
|
-
enabled: true,
|
|
115
|
-
},
|
|
116
|
-
messages: {
|
|
117
|
-
fetchDelayMs: 50,
|
|
118
|
-
},
|
|
119
|
-
announcements: {
|
|
120
|
-
fetchLimit: 1000,
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const config = mergeConfig(partial);
|
|
125
|
-
|
|
126
|
-
expect(config.protocol.baseUrl).toBe('https://custom.api.com');
|
|
127
|
-
expect(config.polling.enabled).toBe(true);
|
|
128
|
-
expect(config.messages.fetchDelayMs).toBe(50);
|
|
129
|
-
expect(config.announcements.fetchLimit).toBe(1000);
|
|
130
|
-
expect(config.protocol.timeout).toBe(10000);
|
|
131
|
-
expect(config.polling.messagesIntervalMs).toBe(5000);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it('should not mutate the original defaults', () => {
|
|
135
|
-
const originalTimeout = defaultSdkConfig.protocol.timeout;
|
|
136
|
-
|
|
137
|
-
mergeConfig({
|
|
138
|
-
protocol: { timeout: 1234 },
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
expect(defaultSdkConfig.protocol.timeout).toBe(originalTimeout);
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
describe('Max Fetch Iterations Limit', () => {
|
|
147
|
-
it('should respect maxFetchIterations config', async () => {
|
|
148
|
-
const config: SdkConfig = {
|
|
149
|
-
...defaultSdkConfig,
|
|
150
|
-
messages: {
|
|
151
|
-
...defaultSdkConfig.messages,
|
|
152
|
-
maxFetchIterations: 5,
|
|
153
|
-
fetchDelayMs: 0,
|
|
154
|
-
},
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
expect(config.messages.maxFetchIterations).toBe(5);
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
it('should have default maxFetchIterations of 30', () => {
|
|
161
|
-
expect(defaultSdkConfig.messages.maxFetchIterations).toBe(30);
|
|
162
|
-
});
|
|
163
|
-
});
|