@massalabs/gossip-sdk 0.0.2-dev.20260128094509 → 0.0.2-dev.20260128160824

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.
Files changed (148) hide show
  1. package/dist/api/messageProtocol/index.d.ts +19 -0
  2. package/dist/api/messageProtocol/index.js +26 -0
  3. package/dist/api/messageProtocol/mock.d.ts +12 -0
  4. package/{src/api/messageProtocol/mock.ts → dist/api/messageProtocol/mock.js} +2 -3
  5. package/dist/api/messageProtocol/rest.d.ts +22 -0
  6. package/dist/api/messageProtocol/rest.js +161 -0
  7. package/dist/api/messageProtocol/types.d.ts +61 -0
  8. package/dist/api/messageProtocol/types.js +6 -0
  9. package/dist/assets/generated/wasm/README.md +281 -0
  10. package/dist/assets/generated/wasm/gossip_wasm.d.ts +638 -0
  11. package/dist/assets/generated/wasm/gossip_wasm.js +1557 -0
  12. package/dist/assets/generated/wasm/gossip_wasm_bg.wasm +0 -0
  13. package/dist/assets/generated/wasm/gossip_wasm_bg.wasm.d.ts +164 -0
  14. package/dist/assets/generated/wasm/package.json +15 -0
  15. package/dist/assets/generated/wasm-node/README.md +281 -0
  16. package/dist/assets/generated/wasm-node/gossip_wasm.d.ts +443 -0
  17. package/dist/assets/generated/wasm-node/gossip_wasm.js +1488 -0
  18. package/dist/assets/generated/wasm-node/gossip_wasm_bg.wasm +0 -0
  19. package/dist/assets/generated/wasm-node/gossip_wasm_bg.wasm.d.ts +164 -0
  20. package/dist/assets/generated/wasm-node/package.json +11 -0
  21. package/dist/config/protocol.d.ts +36 -0
  22. package/dist/config/protocol.js +77 -0
  23. package/dist/config/sdk.d.ts +82 -0
  24. package/dist/config/sdk.js +55 -0
  25. package/{src/contacts.ts → dist/contacts.d.ts} +11 -95
  26. package/dist/contacts.js +166 -0
  27. package/dist/core/SdkEventEmitter.d.ts +36 -0
  28. package/dist/core/SdkEventEmitter.js +59 -0
  29. package/dist/core/SdkPolling.d.ts +35 -0
  30. package/dist/core/SdkPolling.js +100 -0
  31. package/{src/core/index.ts → dist/core/index.d.ts} +0 -2
  32. package/dist/core/index.js +5 -0
  33. package/dist/crypto/bip39.d.ts +34 -0
  34. package/dist/crypto/bip39.js +62 -0
  35. package/dist/crypto/encryption.d.ts +37 -0
  36. package/dist/crypto/encryption.js +46 -0
  37. package/dist/db.d.ts +190 -0
  38. package/dist/db.js +311 -0
  39. package/dist/gossipSdk.d.ts +274 -0
  40. package/dist/gossipSdk.js +690 -0
  41. package/dist/index.d.ts +59 -0
  42. package/dist/index.js +61 -0
  43. package/dist/services/announcement.d.ts +43 -0
  44. package/dist/services/announcement.js +491 -0
  45. package/dist/services/auth.d.ts +37 -0
  46. package/dist/services/auth.js +76 -0
  47. package/dist/services/discussion.d.ts +63 -0
  48. package/dist/services/discussion.js +297 -0
  49. package/dist/services/message.d.ts +74 -0
  50. package/dist/services/message.js +826 -0
  51. package/dist/services/refresh.d.ts +41 -0
  52. package/dist/services/refresh.js +205 -0
  53. package/{src/sw.ts → dist/sw.d.ts} +1 -8
  54. package/dist/sw.js +10 -0
  55. package/dist/types/events.d.ts +80 -0
  56. package/dist/types/events.js +7 -0
  57. package/dist/types.d.ts +32 -0
  58. package/dist/types.js +7 -0
  59. package/dist/utils/base64.d.ts +10 -0
  60. package/dist/utils/base64.js +30 -0
  61. package/dist/utils/contacts.d.ts +42 -0
  62. package/dist/utils/contacts.js +113 -0
  63. package/dist/utils/discussions.d.ts +24 -0
  64. package/dist/utils/discussions.js +38 -0
  65. package/dist/utils/logs.d.ts +19 -0
  66. package/dist/utils/logs.js +89 -0
  67. package/dist/utils/messageSerialization.d.ts +64 -0
  68. package/dist/utils/messageSerialization.js +184 -0
  69. package/dist/utils/queue.d.ts +50 -0
  70. package/dist/utils/queue.js +110 -0
  71. package/dist/utils/type.d.ts +10 -0
  72. package/dist/utils/type.js +4 -0
  73. package/dist/utils/userId.d.ts +40 -0
  74. package/dist/utils/userId.js +90 -0
  75. package/dist/utils/validation.d.ts +50 -0
  76. package/dist/utils/validation.js +112 -0
  77. package/dist/utils.d.ts +30 -0
  78. package/{src/utils.ts → dist/utils.js} +9 -19
  79. package/dist/wasm/encryption.d.ts +56 -0
  80. package/{src/wasm/encryption.ts → dist/wasm/encryption.js} +22 -51
  81. package/dist/wasm/index.d.ts +10 -0
  82. package/{src/wasm/index.ts → dist/wasm/index.js} +1 -8
  83. package/dist/wasm/loader.d.ts +22 -0
  84. package/dist/wasm/loader.js +78 -0
  85. package/dist/wasm/session.d.ts +85 -0
  86. package/dist/wasm/session.js +226 -0
  87. package/dist/wasm/userKeys.d.ts +17 -0
  88. package/{src/wasm/userKeys.ts → dist/wasm/userKeys.js} +6 -13
  89. package/package.json +15 -2
  90. package/src/api/messageProtocol/index.ts +0 -53
  91. package/src/api/messageProtocol/rest.ts +0 -209
  92. package/src/api/messageProtocol/types.ts +0 -70
  93. package/src/config/protocol.ts +0 -97
  94. package/src/config/sdk.ts +0 -131
  95. package/src/core/SdkEventEmitter.ts +0 -91
  96. package/src/core/SdkPolling.ts +0 -134
  97. package/src/crypto/bip39.ts +0 -84
  98. package/src/crypto/encryption.ts +0 -77
  99. package/src/db.ts +0 -465
  100. package/src/gossipSdk.ts +0 -994
  101. package/src/index.ts +0 -211
  102. package/src/services/announcement.ts +0 -653
  103. package/src/services/auth.ts +0 -95
  104. package/src/services/discussion.ts +0 -380
  105. package/src/services/message.ts +0 -1055
  106. package/src/services/refresh.ts +0 -234
  107. package/src/types/events.ts +0 -108
  108. package/src/types.ts +0 -70
  109. package/src/utils/base64.ts +0 -39
  110. package/src/utils/contacts.ts +0 -161
  111. package/src/utils/discussions.ts +0 -55
  112. package/src/utils/logs.ts +0 -86
  113. package/src/utils/messageSerialization.ts +0 -257
  114. package/src/utils/queue.ts +0 -106
  115. package/src/utils/type.ts +0 -7
  116. package/src/utils/userId.ts +0 -114
  117. package/src/utils/validation.ts +0 -144
  118. package/src/wasm/loader.ts +0 -123
  119. package/src/wasm/session.ts +0 -276
  120. package/test/config/protocol.spec.ts +0 -31
  121. package/test/config/sdk.spec.ts +0 -163
  122. package/test/db/helpers.spec.ts +0 -142
  123. package/test/db/operations.spec.ts +0 -128
  124. package/test/db/states.spec.ts +0 -535
  125. package/test/integration/discussion-flow.spec.ts +0 -422
  126. package/test/integration/messaging-flow.spec.ts +0 -708
  127. package/test/integration/sdk-lifecycle.spec.ts +0 -325
  128. package/test/mocks/index.ts +0 -9
  129. package/test/mocks/mockMessageProtocol.ts +0 -100
  130. package/test/services/auth.spec.ts +0 -311
  131. package/test/services/discussion.spec.ts +0 -279
  132. package/test/services/message-deduplication.spec.ts +0 -299
  133. package/test/services/message-startup.spec.ts +0 -331
  134. package/test/services/message.spec.ts +0 -817
  135. package/test/services/refresh.spec.ts +0 -199
  136. package/test/services/session-status.spec.ts +0 -349
  137. package/test/session/wasm.spec.ts +0 -227
  138. package/test/setup.ts +0 -52
  139. package/test/utils/contacts.spec.ts +0 -156
  140. package/test/utils/discussions.spec.ts +0 -66
  141. package/test/utils/queue.spec.ts +0 -52
  142. package/test/utils/serialization.spec.ts +0 -120
  143. package/test/utils/userId.spec.ts +0 -120
  144. package/test/utils/validation.spec.ts +0 -223
  145. package/test/utils.ts +0 -212
  146. package/tsconfig.json +0 -26
  147. package/tsconfig.tsbuildinfo +0 -1
  148. package/vitest.config.ts +0 -28
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Logger utility for SDK
3
+ *
4
+ * Provides structured console logging with module and context support.
5
+ * All output goes to the terminal via console methods.
6
+ */
7
+ export declare class Logger {
8
+ private module;
9
+ private context;
10
+ constructor(module: string, context?: string);
11
+ private getSource;
12
+ private formatMainMessage;
13
+ info(message: string, extra?: unknown): void;
14
+ error(messageOrError: string | Error | unknown, extra?: unknown): void;
15
+ debug(message: string, extra?: unknown): void;
16
+ warn(message: string, extra?: unknown): void;
17
+ withContext(newContext: string): Logger;
18
+ forMethod(methodName: string): Logger;
19
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Logger utility for SDK
3
+ *
4
+ * Provides structured console logging with module and context support.
5
+ * All output goes to the terminal via console methods.
6
+ */
7
+ export class Logger {
8
+ constructor(module, context = '') {
9
+ Object.defineProperty(this, "module", {
10
+ enumerable: true,
11
+ configurable: true,
12
+ writable: true,
13
+ value: void 0
14
+ });
15
+ Object.defineProperty(this, "context", {
16
+ enumerable: true,
17
+ configurable: true,
18
+ writable: true,
19
+ value: void 0
20
+ });
21
+ this.module = module;
22
+ this.context = context;
23
+ }
24
+ getSource() {
25
+ return this.context ? `${this.module}:${this.context}` : this.module;
26
+ }
27
+ formatMainMessage(message) {
28
+ const source = this.getSource();
29
+ return `[${source}] ${message}`;
30
+ }
31
+ info(message, extra) {
32
+ const main = this.formatMainMessage(message);
33
+ if (extra !== undefined) {
34
+ console.log(main, extra);
35
+ }
36
+ else {
37
+ console.log(main);
38
+ }
39
+ }
40
+ error(messageOrError, extra) {
41
+ const source = this.getSource();
42
+ if (messageOrError instanceof Error) {
43
+ const main = `[${source}] ${messageOrError.message}`;
44
+ console.error(main, messageOrError, extra);
45
+ }
46
+ else {
47
+ const message = typeof messageOrError === 'string'
48
+ ? messageOrError
49
+ : messageOrError instanceof Error
50
+ ? messageOrError.message
51
+ : JSON.stringify(messageOrError);
52
+ const main = `[${source}] ${message}`;
53
+ if (extra !== undefined) {
54
+ console.error(main, extra);
55
+ }
56
+ else {
57
+ console.error(main);
58
+ }
59
+ }
60
+ }
61
+ debug(message, extra) {
62
+ const main = this.formatMainMessage(message);
63
+ if (extra !== undefined) {
64
+ console.debug(main, extra);
65
+ }
66
+ else {
67
+ console.debug(main);
68
+ }
69
+ }
70
+ warn(message, extra) {
71
+ const main = this.formatMainMessage(message);
72
+ if (extra !== undefined) {
73
+ console.warn(main, extra);
74
+ }
75
+ else {
76
+ console.warn(main);
77
+ }
78
+ }
79
+ // Chainable context builder
80
+ withContext(newContext) {
81
+ const fullContext = this.context
82
+ ? `${this.context}:${newContext}`
83
+ : newContext;
84
+ return new Logger(this.module, fullContext);
85
+ }
86
+ forMethod(methodName) {
87
+ return this.withContext(methodName);
88
+ }
89
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Message Serialization Utilities
3
+ *
4
+ * Functions for serializing and deserializing messages for the protocol.
5
+ * Supports regular text messages, replies, forwards, and keep-alive messages.
6
+ */
7
+ import { MessageType } from '../db';
8
+ export declare const MESSAGE_TYPE_KEEP_ALIVE = 3;
9
+ export interface DeserializedMessage {
10
+ content: string;
11
+ replyTo?: {
12
+ originalContent: string;
13
+ originalSeeker: Uint8Array;
14
+ };
15
+ forwardOf?: {
16
+ originalContent: string;
17
+ originalSeeker: Uint8Array;
18
+ };
19
+ type: MessageType;
20
+ }
21
+ /**
22
+ * Serialize a keep-alive message
23
+ * Keep-alive messages are used to maintain session activity
24
+ */
25
+ export declare function serializeKeepAliveMessage(): Uint8Array;
26
+ /**
27
+ * Serialize a regular text message
28
+ *
29
+ * Format: [type: 1 byte][content: variable]
30
+ *
31
+ * @param content - The message content string
32
+ * @returns Serialized message bytes
33
+ */
34
+ export declare function serializeRegularMessage(content: string): Uint8Array;
35
+ /**
36
+ * Serialize a reply message
37
+ *
38
+ * Format: [type: 1 byte][originalContentLen: 4 bytes][originalContent][seeker: 34 bytes][newContent]
39
+ *
40
+ * @param newContent - The reply content
41
+ * @param originalContent - The content being replied to
42
+ * @param originalSeeker - The seeker of the original message
43
+ * @returns Serialized reply message bytes
44
+ */
45
+ export declare function serializeReplyMessage(newContent: string, originalContent: string, originalSeeker: Uint8Array): Uint8Array;
46
+ /**
47
+ * Serialize a forward message
48
+ *
49
+ * Format: [type: 1 byte][forwardContentLen: 4 bytes][forwardContent][seeker: 34 bytes][newContent]
50
+ *
51
+ * @param forwardContent - The content being forwarded
52
+ * @param newContent - Optional new content to add (empty string if none)
53
+ * @param originalSeeker - The seeker of the original message
54
+ * @returns Serialized forward message bytes
55
+ */
56
+ export declare function serializeForwardMessage(forwardContent: string, newContent: string, originalSeeker: Uint8Array): Uint8Array;
57
+ /**
58
+ * Deserialize a message from bytes
59
+ *
60
+ * @param buffer - The serialized message bytes
61
+ * @returns Deserialized message object
62
+ * @throws Error if message format is invalid
63
+ */
64
+ export declare function deserializeMessage(buffer: Uint8Array): DeserializedMessage;
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Message Serialization Utilities
3
+ *
4
+ * Functions for serializing and deserializing messages for the protocol.
5
+ * Supports regular text messages, replies, forwards, and keep-alive messages.
6
+ */
7
+ import { strToBytes, bytesToStr, U32 } from '@massalabs/massa-web3';
8
+ import { MessageType } from '../db';
9
+ // Message type constants (protocol-level)
10
+ const MESSAGE_TYPE_REGULAR = 0x00;
11
+ const MESSAGE_TYPE_REPLY = 0x01;
12
+ const MESSAGE_TYPE_FORWARD = 0x02;
13
+ export const MESSAGE_TYPE_KEEP_ALIVE = 0x03;
14
+ // Seeker size: 1 byte length prefix + 32 bytes hash + 1 byte key index
15
+ const SEEKER_SIZE = 34;
16
+ /**
17
+ * Serialize a keep-alive message
18
+ * Keep-alive messages are used to maintain session activity
19
+ */
20
+ export function serializeKeepAliveMessage() {
21
+ return new Uint8Array([MESSAGE_TYPE_KEEP_ALIVE]);
22
+ }
23
+ /**
24
+ * Serialize a regular text message
25
+ *
26
+ * Format: [type: 1 byte][content: variable]
27
+ *
28
+ * @param content - The message content string
29
+ * @returns Serialized message bytes
30
+ */
31
+ export function serializeRegularMessage(content) {
32
+ const contentBytes = strToBytes(content);
33
+ const result = new Uint8Array(1 + contentBytes.length);
34
+ result[0] = MESSAGE_TYPE_REGULAR;
35
+ result.set(contentBytes, 1);
36
+ return result;
37
+ }
38
+ /**
39
+ * Serialize a reply message
40
+ *
41
+ * Format: [type: 1 byte][originalContentLen: 4 bytes][originalContent][seeker: 34 bytes][newContent]
42
+ *
43
+ * @param newContent - The reply content
44
+ * @param originalContent - The content being replied to
45
+ * @param originalSeeker - The seeker of the original message
46
+ * @returns Serialized reply message bytes
47
+ */
48
+ export function serializeReplyMessage(newContent, originalContent, originalSeeker) {
49
+ const newContentBytes = strToBytes(newContent);
50
+ const originalContentBytes = strToBytes(originalContent);
51
+ const originalContentLenBytes = U32.toBytes(BigInt(originalContentBytes.length));
52
+ // Calculate total size
53
+ const totalSize = 1 + // type
54
+ originalContentLenBytes.length + // length prefix (4 bytes)
55
+ originalContentBytes.length + // original content
56
+ SEEKER_SIZE + // seeker
57
+ newContentBytes.length; // new content
58
+ const result = new Uint8Array(totalSize);
59
+ let offset = 0;
60
+ // Type byte
61
+ result[offset++] = MESSAGE_TYPE_REPLY;
62
+ // Original content length (4 bytes)
63
+ result.set(originalContentLenBytes, offset);
64
+ offset += originalContentLenBytes.length;
65
+ // Original content
66
+ result.set(originalContentBytes, offset);
67
+ offset += originalContentBytes.length;
68
+ // Seeker (34 bytes)
69
+ result.set(originalSeeker, offset);
70
+ offset += SEEKER_SIZE;
71
+ // New content
72
+ result.set(newContentBytes, offset);
73
+ return result;
74
+ }
75
+ /**
76
+ * Serialize a forward message
77
+ *
78
+ * Format: [type: 1 byte][forwardContentLen: 4 bytes][forwardContent][seeker: 34 bytes][newContent]
79
+ *
80
+ * @param forwardContent - The content being forwarded
81
+ * @param newContent - Optional new content to add (empty string if none)
82
+ * @param originalSeeker - The seeker of the original message
83
+ * @returns Serialized forward message bytes
84
+ */
85
+ export function serializeForwardMessage(forwardContent, newContent, originalSeeker) {
86
+ const newContentBytes = strToBytes(newContent);
87
+ const forwardContentBytes = strToBytes(forwardContent);
88
+ const forwardContentLenBytes = U32.toBytes(BigInt(forwardContentBytes.length));
89
+ // Calculate total size
90
+ const totalSize = 1 + // type
91
+ forwardContentLenBytes.length + // length prefix (4 bytes)
92
+ forwardContentBytes.length + // forward content
93
+ SEEKER_SIZE + // seeker
94
+ newContentBytes.length; // new content
95
+ const result = new Uint8Array(totalSize);
96
+ let offset = 0;
97
+ // Type byte
98
+ result[offset++] = MESSAGE_TYPE_FORWARD;
99
+ // Forward content length (4 bytes)
100
+ result.set(forwardContentLenBytes, offset);
101
+ offset += forwardContentLenBytes.length;
102
+ // Forward content
103
+ result.set(forwardContentBytes, offset);
104
+ offset += forwardContentBytes.length;
105
+ // Seeker (34 bytes)
106
+ result.set(originalSeeker, offset);
107
+ offset += SEEKER_SIZE;
108
+ // New content
109
+ result.set(newContentBytes, offset);
110
+ return result;
111
+ }
112
+ /**
113
+ * Deserialize a message from bytes
114
+ *
115
+ * @param buffer - The serialized message bytes
116
+ * @returns Deserialized message object
117
+ * @throws Error if message format is invalid
118
+ */
119
+ export function deserializeMessage(buffer) {
120
+ if (buffer.length < 1) {
121
+ throw new Error('Empty message buffer');
122
+ }
123
+ const messageType = buffer[0];
124
+ switch (messageType) {
125
+ case MESSAGE_TYPE_KEEP_ALIVE:
126
+ return {
127
+ content: '',
128
+ type: MessageType.KEEP_ALIVE,
129
+ };
130
+ case MESSAGE_TYPE_REGULAR:
131
+ return {
132
+ content: bytesToStr(buffer.slice(1)),
133
+ type: MessageType.TEXT,
134
+ };
135
+ case MESSAGE_TYPE_REPLY: {
136
+ // Format: [type: 1][originalContentLen: 4][originalContent][seeker: 34][newContent]
137
+ let offset = 1;
138
+ // Read original content length (4 bytes)
139
+ const originalContentLen = Number(U32.fromBytes(buffer.slice(offset, offset + 4)));
140
+ offset += 4;
141
+ // Read original content
142
+ const originalContent = bytesToStr(buffer.slice(offset, offset + originalContentLen));
143
+ offset += originalContentLen;
144
+ // Read seeker (34 bytes)
145
+ const originalSeeker = buffer.slice(offset, offset + SEEKER_SIZE);
146
+ offset += SEEKER_SIZE;
147
+ // Read new content (rest of buffer)
148
+ const content = bytesToStr(buffer.slice(offset));
149
+ return {
150
+ content,
151
+ replyTo: {
152
+ originalContent,
153
+ originalSeeker,
154
+ },
155
+ type: MessageType.TEXT,
156
+ };
157
+ }
158
+ case MESSAGE_TYPE_FORWARD: {
159
+ // Format: [type: 1][forwardContentLen: 4][forwardContent][seeker: 34][newContent]
160
+ let offset = 1;
161
+ // Read forward content length (4 bytes)
162
+ const forwardContentLen = Number(U32.fromBytes(buffer.slice(offset, offset + 4)));
163
+ offset += 4;
164
+ // Read forward content
165
+ const originalContent = bytesToStr(buffer.slice(offset, offset + forwardContentLen));
166
+ offset += forwardContentLen;
167
+ // Read seeker (34 bytes)
168
+ const originalSeeker = buffer.slice(offset, offset + SEEKER_SIZE);
169
+ offset += SEEKER_SIZE;
170
+ // Read new content (rest of buffer)
171
+ const content = bytesToStr(buffer.slice(offset));
172
+ return {
173
+ content,
174
+ forwardOf: {
175
+ originalContent,
176
+ originalSeeker,
177
+ },
178
+ type: MessageType.TEXT,
179
+ };
180
+ }
181
+ default:
182
+ throw new Error(`Unknown message type: ${messageType}`);
183
+ }
184
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Promise Queue
3
+ *
4
+ * Ensures async operations are executed sequentially.
5
+ * Used to serialize session manager operations per contact.
6
+ */
7
+ /**
8
+ * A simple promise queue that executes tasks sequentially.
9
+ * Tasks are processed in FIFO order.
10
+ */
11
+ export declare class PromiseQueue {
12
+ private queue;
13
+ private processing;
14
+ /**
15
+ * Add a task to the queue. Returns a promise that resolves
16
+ * when the task completes.
17
+ */
18
+ enqueue<T>(fn: () => Promise<T>): Promise<T>;
19
+ /**
20
+ * Process the next task in the queue.
21
+ */
22
+ private processNext;
23
+ /**
24
+ * Check if the queue is currently processing.
25
+ */
26
+ get isProcessing(): boolean;
27
+ /**
28
+ * Get the number of pending tasks.
29
+ */
30
+ get pendingCount(): number;
31
+ }
32
+ /**
33
+ * Manages multiple queues keyed by string (e.g., contact ID).
34
+ * Creates queues lazily on first use.
35
+ */
36
+ export declare class QueueManager {
37
+ private queues;
38
+ /**
39
+ * Get or create a queue for the given key.
40
+ */
41
+ getQueue(key: string): PromiseQueue;
42
+ /**
43
+ * Enqueue a task for a specific key.
44
+ */
45
+ enqueue<T>(key: string, fn: () => Promise<T>): Promise<T>;
46
+ /**
47
+ * Clear all queues.
48
+ */
49
+ clear(): void;
50
+ }
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Promise Queue
3
+ *
4
+ * Ensures async operations are executed sequentially.
5
+ * Used to serialize session manager operations per contact.
6
+ */
7
+ /**
8
+ * A simple promise queue that executes tasks sequentially.
9
+ * Tasks are processed in FIFO order.
10
+ */
11
+ export class PromiseQueue {
12
+ constructor() {
13
+ Object.defineProperty(this, "queue", {
14
+ enumerable: true,
15
+ configurable: true,
16
+ writable: true,
17
+ value: []
18
+ });
19
+ Object.defineProperty(this, "processing", {
20
+ enumerable: true,
21
+ configurable: true,
22
+ writable: true,
23
+ value: false
24
+ });
25
+ }
26
+ /**
27
+ * Add a task to the queue. Returns a promise that resolves
28
+ * when the task completes.
29
+ */
30
+ enqueue(fn) {
31
+ return new Promise((resolve, reject) => {
32
+ this.queue.push({
33
+ fn: fn,
34
+ resolve: resolve,
35
+ reject,
36
+ });
37
+ this.processNext();
38
+ });
39
+ }
40
+ /**
41
+ * Process the next task in the queue.
42
+ */
43
+ async processNext() {
44
+ if (this.processing || this.queue.length === 0) {
45
+ return;
46
+ }
47
+ this.processing = true;
48
+ const task = this.queue.shift();
49
+ try {
50
+ const result = await task.fn();
51
+ task.resolve(result);
52
+ }
53
+ catch (error) {
54
+ task.reject(error);
55
+ }
56
+ finally {
57
+ this.processing = false;
58
+ this.processNext();
59
+ }
60
+ }
61
+ /**
62
+ * Check if the queue is currently processing.
63
+ */
64
+ get isProcessing() {
65
+ return this.processing;
66
+ }
67
+ /**
68
+ * Get the number of pending tasks.
69
+ */
70
+ get pendingCount() {
71
+ return this.queue.length;
72
+ }
73
+ }
74
+ /**
75
+ * Manages multiple queues keyed by string (e.g., contact ID).
76
+ * Creates queues lazily on first use.
77
+ */
78
+ export class QueueManager {
79
+ constructor() {
80
+ Object.defineProperty(this, "queues", {
81
+ enumerable: true,
82
+ configurable: true,
83
+ writable: true,
84
+ value: new Map()
85
+ });
86
+ }
87
+ /**
88
+ * Get or create a queue for the given key.
89
+ */
90
+ getQueue(key) {
91
+ let queue = this.queues.get(key);
92
+ if (!queue) {
93
+ queue = new PromiseQueue();
94
+ this.queues.set(key, queue);
95
+ }
96
+ return queue;
97
+ }
98
+ /**
99
+ * Enqueue a task for a specific key.
100
+ */
101
+ enqueue(key, fn) {
102
+ return this.getQueue(key).enqueue(fn);
103
+ }
104
+ /**
105
+ * Clear all queues.
106
+ */
107
+ clear() {
108
+ this.queues.clear();
109
+ }
110
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Common type utilities for the SDK
3
+ */
4
+ export type Result<T, E = Error> = {
5
+ success: true;
6
+ data: T;
7
+ } | {
8
+ success: false;
9
+ error: E;
10
+ };
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Common type utilities for the SDK
3
+ */
4
+ export {};
@@ -0,0 +1,40 @@
1
+ /**
2
+ * User ID encoding/decoding utilities using Bech32 format
3
+ * Format: gossip1<encoded-32-bytes>
4
+ *
5
+ * Uses @scure/base for reliable, battle-tested Bech32 encoding
6
+ */
7
+ /**
8
+ * Encode a 32-byte user ID to Bech32 format with "gossip" prefix
9
+ * @param userId - 32-byte user ID as Uint8Array
10
+ * @returns Bech32-encoded string (e.g., "gossip1qpzry9x8gf2tvdw0s3jn54khce6mua7l...")
11
+ * @throws Error if userId is not exactly 32 bytes
12
+ */
13
+ export declare function encodeUserId(userId: Uint8Array): string;
14
+ /**
15
+ * Decode a Bech32-encoded user ID back to 32 bytes
16
+ * @param encoded - Bech32-encoded string (e.g., "gossip1qpzry9x8gf2tvdw0s3jn54khce6mua7l...")
17
+ * @returns 32-byte user ID as Uint8Array
18
+ * @throws Error if the format is invalid, checksum fails, or decoded length is not 32 bytes
19
+ */
20
+ export declare function decodeUserId(encoded: string): Uint8Array;
21
+ /**
22
+ * Validate a Bech32-encoded user ID string
23
+ * @param encoded - Bech32-encoded string to validate
24
+ * @returns true if valid, false otherwise
25
+ */
26
+ export declare function isValidUserId(encoded: string): boolean;
27
+ /**
28
+ * Format a user ID for display (shortened version)
29
+ * @param userId - Bech32-encoded user ID string
30
+ * @param prefixChars - Number of characters to show after prefix (default: 8)
31
+ * @param suffixChars - Number of characters to show at end (default: 6)
32
+ * @returns Formatted string (e.g., "gossip1qpzry9x8...mua7l")
33
+ */
34
+ export declare function formatUserId(userId: string, prefixChars?: number, suffixChars?: number): string;
35
+ /**
36
+ * Generates a random 32-byte user ID
37
+ * @param password - Optional password
38
+ * @returns gossip Bech32 string representing a 32-byte user ID
39
+ */
40
+ export declare function generate(password?: string): Promise<string>;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * User ID encoding/decoding utilities using Bech32 format
3
+ * Format: gossip1<encoded-32-bytes>
4
+ *
5
+ * Uses @scure/base for reliable, battle-tested Bech32 encoding
6
+ */
7
+ import { bech32 } from '@scure/base';
8
+ import { generateUserKeys } from '../wasm';
9
+ const GOSSIP_PREFIX = 'gossip';
10
+ const USER_ID_BYTE_LENGTH = 32;
11
+ /**
12
+ * Encode a 32-byte user ID to Bech32 format with "gossip" prefix
13
+ * @param userId - 32-byte user ID as Uint8Array
14
+ * @returns Bech32-encoded string (e.g., "gossip1qpzry9x8gf2tvdw0s3jn54khce6mua7l...")
15
+ * @throws Error if userId is not exactly 32 bytes
16
+ */
17
+ export function encodeUserId(userId) {
18
+ if (userId.length !== USER_ID_BYTE_LENGTH) {
19
+ throw new Error(`User ID must be exactly ${USER_ID_BYTE_LENGTH} bytes, got ${userId.length}`);
20
+ }
21
+ return bech32.encode(GOSSIP_PREFIX, bech32.toWords(userId));
22
+ }
23
+ /**
24
+ * Decode a Bech32-encoded user ID back to 32 bytes
25
+ * @param encoded - Bech32-encoded string (e.g., "gossip1qpzry9x8gf2tvdw0s3jn54khce6mua7l...")
26
+ * @returns 32-byte user ID as Uint8Array
27
+ * @throws Error if the format is invalid, checksum fails, or decoded length is not 32 bytes
28
+ */
29
+ export function decodeUserId(encoded) {
30
+ // Type assertion needed as bech32.decode expects a template literal type
31
+ const { prefix, words } = bech32.decode(encoded, 90);
32
+ // Verify prefix
33
+ if (prefix !== GOSSIP_PREFIX) {
34
+ throw new Error(`Invalid prefix: expected "${GOSSIP_PREFIX}", got "${prefix}"`);
35
+ }
36
+ // Convert from 5-bit words back to bytes
37
+ const decoded = bech32.fromWords(words);
38
+ // Verify length
39
+ if (decoded.length !== USER_ID_BYTE_LENGTH) {
40
+ throw new Error(`Decoded user ID must be ${USER_ID_BYTE_LENGTH} bytes, got ${decoded.length}`);
41
+ }
42
+ return new Uint8Array(decoded);
43
+ }
44
+ /**
45
+ * Validate a Bech32-encoded user ID string
46
+ * @param encoded - Bech32-encoded string to validate
47
+ * @returns true if valid, false otherwise
48
+ */
49
+ export function isValidUserId(encoded) {
50
+ try {
51
+ decodeUserId(encoded);
52
+ return true;
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ }
58
+ /**
59
+ * Format a user ID for display (shortened version)
60
+ * @param userId - Bech32-encoded user ID string
61
+ * @param prefixChars - Number of characters to show after prefix (default: 8)
62
+ * @param suffixChars - Number of characters to show at end (default: 6)
63
+ * @returns Formatted string (e.g., "gossip1qpzry9x8...mua7l")
64
+ */
65
+ export function formatUserId(userId, prefixChars = 8, suffixChars = 6) {
66
+ if (!userId)
67
+ return '';
68
+ // Find separator position
69
+ const sepPos = userId.indexOf('1');
70
+ if (sepPos === -1)
71
+ return userId;
72
+ const prefix = userId.substring(0, sepPos + 1); // "gossip1"
73
+ const data = userId.substring(sepPos + 1); // rest of the string
74
+ if (data.length <= prefixChars + suffixChars) {
75
+ return userId; // Too short to format
76
+ }
77
+ const start = data.slice(0, prefixChars);
78
+ const end = data.slice(-suffixChars);
79
+ return `${prefix}${start}...${end}`;
80
+ }
81
+ /**
82
+ * Generates a random 32-byte user ID
83
+ * @param password - Optional password
84
+ * @returns gossip Bech32 string representing a 32-byte user ID
85
+ */
86
+ export async function generate(password) {
87
+ const identity = await generateUserKeys(password || '');
88
+ const userId = identity.public_keys().derive_id();
89
+ return encodeUserId(userId);
90
+ }