@peers-app/peers-sdk 0.7.17 → 0.7.19

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.
@@ -0,0 +1,267 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tx_encoding_1 = require("./tx-encoding");
4
+ describe('tx-encode-decode', () => {
5
+ describe('txEncode and txDecode', () => {
6
+ it('should encode and decode simple objects', () => {
7
+ const testObj = {
8
+ name: 'test',
9
+ number: 42,
10
+ bool: true,
11
+ str: 'hello world'
12
+ };
13
+ const encoded = (0, tx_encoding_1.txEncode)(testObj);
14
+ expect(encoded).toBeInstanceOf(Uint8Array);
15
+ expect(encoded.length).toBeGreaterThan(0);
16
+ const decoded = (0, tx_encoding_1.txDecode)(encoded);
17
+ expect(decoded).toEqual(testObj);
18
+ });
19
+ it('should encode and decode arrays', () => {
20
+ const testArray = [1, 2, 3, 'four', { five: 5 }];
21
+ const encoded = (0, tx_encoding_1.txEncode)(testArray);
22
+ const decoded = (0, tx_encoding_1.txDecode)(encoded);
23
+ expect(decoded).toEqual(testArray);
24
+ });
25
+ it('should encode and decode nested objects', () => {
26
+ const testObj = {
27
+ level1: {
28
+ level2: {
29
+ level3: {
30
+ value: 'deep nested value',
31
+ number: 123
32
+ },
33
+ array: [1, 2, 3]
34
+ }
35
+ }
36
+ };
37
+ const encoded = (0, tx_encoding_1.txEncode)(testObj);
38
+ const decoded = (0, tx_encoding_1.txDecode)(encoded);
39
+ expect(decoded).toEqual(testObj);
40
+ });
41
+ it('should encode and decode special types (dates, etc.)', () => {
42
+ const testObj = {
43
+ date: new Date('2023-01-01T00:00:00.000Z'),
44
+ nan: NaN,
45
+ infinity: Infinity,
46
+ negInfinity: -Infinity,
47
+ undef: undefined,
48
+ nullVal: null
49
+ };
50
+ const encoded = (0, tx_encoding_1.txEncode)(testObj);
51
+ const decoded = (0, tx_encoding_1.txDecode)(encoded);
52
+ expect(decoded.date).toBeInstanceOf(Date);
53
+ expect(decoded.date.toISOString()).toBe('2023-01-01T00:00:00.000Z');
54
+ expect(Number.isNaN(decoded.nan)).toBe(true);
55
+ expect(decoded.infinity).toBe(Infinity);
56
+ expect(decoded.negInfinity).toBe(-Infinity);
57
+ expect(decoded.undef).toBeUndefined();
58
+ expect(decoded.nullVal).toBeNull();
59
+ });
60
+ it('should encode and decode Uint8Array', () => {
61
+ const testObj = {
62
+ data: new Uint8Array([72, 101, 108, 108, 111]),
63
+ metadata: { size: 5 }
64
+ };
65
+ const encoded = (0, tx_encoding_1.txEncode)(testObj);
66
+ const decoded = (0, tx_encoding_1.txDecode)(encoded);
67
+ expect(decoded.data).toBeInstanceOf(Uint8Array);
68
+ expect(decoded.data).toEqual(testObj.data);
69
+ expect(decoded.metadata).toEqual(testObj.metadata);
70
+ });
71
+ it('should encode and decode Buffer', () => {
72
+ const testObj = {
73
+ buffer: Buffer.from('Hello Buffer'),
74
+ name: 'test'
75
+ };
76
+ const encoded = (0, tx_encoding_1.txEncode)(testObj);
77
+ const decoded = (0, tx_encoding_1.txDecode)(encoded);
78
+ expect(Buffer.isBuffer(decoded.buffer)).toBe(true);
79
+ expect(decoded.buffer).toEqual(testObj.buffer);
80
+ expect(decoded.name).toBe('test');
81
+ });
82
+ });
83
+ describe('compression threshold', () => {
84
+ it('should not compress small payloads (< 1024 bytes)', () => {
85
+ const smallObj = { message: 'small' };
86
+ const encoded = (0, tx_encoding_1.txEncode)(smallObj);
87
+ // First byte is the flag
88
+ expect(encoded[0]).toBe(0); // flag = 0 means not compressed
89
+ });
90
+ it('should compress large payloads (> 1024 bytes)', () => {
91
+ // Create an object that will exceed 1024 bytes when encoded
92
+ const largeObj = {
93
+ data: 'x'.repeat(2000),
94
+ array: Array.from({ length: 100 }, (_, i) => ({ id: i, value: `item ${i}` }))
95
+ };
96
+ const jsonStr = JSON.stringify(largeObj);
97
+ expect(jsonStr.length).toBeGreaterThan(1024);
98
+ const encoded = (0, tx_encoding_1.txEncode)(largeObj);
99
+ // First byte is the flag
100
+ expect(encoded[0]).toBe(1); // flag = 1 means compressed
101
+ // Verify it can still be decoded correctly
102
+ const decoded = (0, tx_encoding_1.txDecode)(encoded);
103
+ expect(decoded).toEqual(largeObj);
104
+ });
105
+ it('should have smaller encoded size for large compressible data', () => {
106
+ const largeRepetitiveObj = {
107
+ data: 'repeat '.repeat(500),
108
+ values: Array.from({ length: 200 }, () => 'same string')
109
+ };
110
+ const encoded = (0, tx_encoding_1.txEncode)(largeRepetitiveObj);
111
+ // Compressed size should be significantly smaller than the raw data
112
+ const rawDataSize = JSON.stringify(largeRepetitiveObj).length;
113
+ expect(encoded.length).toBeLessThan(rawDataSize / 2);
114
+ // Verify correctness
115
+ const decoded = (0, tx_encoding_1.txDecode)(encoded);
116
+ expect(decoded).toEqual(largeRepetitiveObj);
117
+ });
118
+ });
119
+ describe('error handling', () => {
120
+ it('should throw error on empty payload', () => {
121
+ const emptyPayload = new Uint8Array(0);
122
+ expect(() => (0, tx_encoding_1.txDecode)(emptyPayload)).toThrow('Empty payload');
123
+ });
124
+ it('should throw error on unknown flag', () => {
125
+ // Create a payload with an invalid flag (2)
126
+ const invalidPayload = new Uint8Array([2, 0, 0, 0]);
127
+ expect(() => (0, tx_encoding_1.txDecode)(invalidPayload)).toThrow('Unknown tx flag: 2');
128
+ });
129
+ it('should throw error on unknown flag (255)', () => {
130
+ const invalidPayload = new Uint8Array([255, 0, 0, 0]);
131
+ expect(() => (0, tx_encoding_1.txDecode)(invalidPayload)).toThrow('Unknown tx flag: 255');
132
+ });
133
+ });
134
+ describe('round-trip consistency', () => {
135
+ it('should handle empty objects', () => {
136
+ const emptyObj = {};
137
+ const encoded = (0, tx_encoding_1.txEncode)(emptyObj);
138
+ const decoded = (0, tx_encoding_1.txDecode)(encoded);
139
+ expect(decoded).toEqual(emptyObj);
140
+ });
141
+ it('should handle empty arrays', () => {
142
+ const emptyArray = [];
143
+ const encoded = (0, tx_encoding_1.txEncode)(emptyArray);
144
+ const decoded = (0, tx_encoding_1.txDecode)(encoded);
145
+ expect(decoded).toEqual(emptyArray);
146
+ });
147
+ it('should handle strings with special characters', () => {
148
+ const testObj = {
149
+ emoji: '🚀🎉',
150
+ unicode: 'Hello 世界',
151
+ special: 'line1\nline2\ttab',
152
+ quotes: 'He said "hello"'
153
+ };
154
+ const encoded = (0, tx_encoding_1.txEncode)(testObj);
155
+ const decoded = (0, tx_encoding_1.txDecode)(encoded);
156
+ expect(decoded).toEqual(testObj);
157
+ });
158
+ it('should handle very large numbers', () => {
159
+ const testObj = {
160
+ maxSafeInt: Number.MAX_SAFE_INTEGER,
161
+ minSafeInt: Number.MIN_SAFE_INTEGER,
162
+ large: 9007199254740991,
163
+ small: -9007199254740991
164
+ };
165
+ const encoded = (0, tx_encoding_1.txEncode)(testObj);
166
+ const decoded = (0, tx_encoding_1.txDecode)(encoded);
167
+ expect(decoded).toEqual(testObj);
168
+ });
169
+ it('should handle mixed type arrays', () => {
170
+ const testArray = [
171
+ 1,
172
+ 'string',
173
+ true,
174
+ null,
175
+ undefined,
176
+ { obj: 'value' },
177
+ [1, 2, 3],
178
+ new Date('2023-01-01'),
179
+ new Uint8Array([1, 2, 3])
180
+ ];
181
+ const encoded = (0, tx_encoding_1.txEncode)(testArray);
182
+ const decoded = (0, tx_encoding_1.txDecode)(encoded);
183
+ expect(decoded[0]).toBe(1);
184
+ expect(decoded[1]).toBe('string');
185
+ expect(decoded[2]).toBe(true);
186
+ expect(decoded[3]).toBeNull();
187
+ expect(decoded[4]).toBeUndefined();
188
+ expect(decoded[5]).toEqual({ obj: 'value' });
189
+ expect(decoded[6]).toEqual([1, 2, 3]);
190
+ expect(decoded[7]).toBeInstanceOf(Date);
191
+ expect(decoded[8]).toBeInstanceOf(Uint8Array);
192
+ expect(decoded[8]).toEqual(new Uint8Array([1, 2, 3]));
193
+ });
194
+ it('should handle objects with circular references removed by toJSON', () => {
195
+ // toJSON handles circular references, so this should work
196
+ const obj = { name: 'test' };
197
+ obj.self = obj; // circular reference
198
+ const encoded = (0, tx_encoding_1.txEncode)(obj);
199
+ const decoded = (0, tx_encoding_1.txDecode)(encoded);
200
+ // The circular reference should be handled by toJSON/fromJSON
201
+ expect(decoded).toHaveProperty('name', 'test');
202
+ expect(decoded).toHaveProperty('self');
203
+ expect(decoded.self).toBe(decoded); // self-reference restored
204
+ });
205
+ it('should preserve data integrity across multiple encode/decode cycles', () => {
206
+ const original = {
207
+ id: 123,
208
+ name: 'multi-cycle test',
209
+ data: new Uint8Array([1, 2, 3, 4, 5]),
210
+ timestamp: new Date('2023-06-15T12:00:00.000Z')
211
+ };
212
+ // Encode and decode multiple times
213
+ let current = original;
214
+ for (let i = 0; i < 5; i++) {
215
+ const encoded = (0, tx_encoding_1.txEncode)(current);
216
+ current = (0, tx_encoding_1.txDecode)(encoded);
217
+ }
218
+ expect(current.id).toBe(original.id);
219
+ expect(current.name).toBe(original.name);
220
+ expect(current.data).toEqual(original.data);
221
+ expect(current.timestamp).toEqual(original.timestamp);
222
+ });
223
+ });
224
+ describe('payload structure', () => {
225
+ it('should have flag byte as first byte', () => {
226
+ const testObj = { test: 'value' };
227
+ const encoded = (0, tx_encoding_1.txEncode)(testObj);
228
+ // First byte should be 0 or 1
229
+ expect(encoded[0]).toBeGreaterThanOrEqual(0);
230
+ expect(encoded[0]).toBeLessThanOrEqual(1);
231
+ });
232
+ it('should have body after flag byte', () => {
233
+ const testObj = { test: 'value' };
234
+ const encoded = (0, tx_encoding_1.txEncode)(testObj);
235
+ // Should have at least 2 bytes (flag + body)
236
+ expect(encoded.length).toBeGreaterThan(1);
237
+ });
238
+ });
239
+ describe('edge cases', () => {
240
+ it('should handle objects at exactly 1024 bytes threshold', () => {
241
+ // Create an object that when msgpack-encoded is very close to 1024 bytes
242
+ // This is tricky to get exact, so we just verify it works
243
+ const testObj = {
244
+ data: 'x'.repeat(1000)
245
+ };
246
+ const encoded = (0, tx_encoding_1.txEncode)(testObj);
247
+ const decoded = (0, tx_encoding_1.txDecode)(encoded);
248
+ expect(decoded).toEqual(testObj);
249
+ });
250
+ it('should handle primitive values', () => {
251
+ expect((0, tx_encoding_1.txDecode)((0, tx_encoding_1.txEncode)(42))).toBe(42);
252
+ expect((0, tx_encoding_1.txDecode)((0, tx_encoding_1.txEncode)('string'))).toBe('string');
253
+ expect((0, tx_encoding_1.txDecode)((0, tx_encoding_1.txEncode)(true))).toBe(true);
254
+ expect((0, tx_encoding_1.txDecode)((0, tx_encoding_1.txEncode)(false))).toBe(false);
255
+ expect((0, tx_encoding_1.txDecode)((0, tx_encoding_1.txEncode)(null))).toBe(null);
256
+ });
257
+ it('should handle objects with only undefined values', () => {
258
+ const testObj = {
259
+ a: undefined,
260
+ b: undefined
261
+ };
262
+ const encoded = (0, tx_encoding_1.txEncode)(testObj);
263
+ const decoded = (0, tx_encoding_1.txDecode)(encoded);
264
+ expect(decoded).toEqual(testObj);
265
+ });
266
+ });
267
+ });
package/dist/index.d.ts CHANGED
@@ -17,6 +17,7 @@ export * from "./device/device";
17
17
  export * from "./device/device-election";
18
18
  export * from "./device/get-trust-level";
19
19
  export * from "./device/socket.type";
20
+ export * from "./device/tx-encoding";
20
21
  export * from "./package-loader";
21
22
  export * from "./events";
22
23
  export * from "./data";
package/dist/index.js CHANGED
@@ -34,6 +34,7 @@ __exportStar(require("./device/device"), exports);
34
34
  __exportStar(require("./device/device-election"), exports);
35
35
  __exportStar(require("./device/get-trust-level"), exports);
36
36
  __exportStar(require("./device/socket.type"), exports);
37
+ __exportStar(require("./device/tx-encoding"), exports);
37
38
  __exportStar(require("./package-loader"), exports);
38
39
  __exportStar(require("./events"), exports);
39
40
  __exportStar(require("./data"), exports);
package/dist/keys.js CHANGED
@@ -22,12 +22,13 @@ exports.addSignatureToObject = addSignatureToObject;
22
22
  exports.verifyObjectSignature = verifyObjectSignature;
23
23
  exports.isObjectSignatureValid = isObjectSignatureValid;
24
24
  exports.getPublicKeyFromObjectSignature = getPublicKeyFromObjectSignature;
25
+ const sha2_1 = require("@noble/hashes/sha2");
26
+ const buffer_1 = require("buffer");
25
27
  const nacl = require("tweetnacl");
26
28
  const utils = require("tweetnacl-util");
27
29
  const tweetnacl_util_1 = require("tweetnacl-util");
30
+ const tx_encoding_1 = require("./device/tx-encoding");
28
31
  const serial_json_1 = require("./serial-json");
29
- const sha2_1 = require("@noble/hashes/sha2");
30
- const buffer_1 = require("buffer");
31
32
  globalThis.Buffer = buffer_1.Buffer; // shim for browsers/RN
32
33
  const _stableStringify = require('fast-json-stable-stringify');
33
34
  function setPRNG(fn) {
@@ -114,10 +115,10 @@ function signObjectWithSecretKey(obj, secretKey) {
114
115
  }
115
116
  const objStr = (0, serial_json_1.toJSONString)(obj);
116
117
  const objDecoded = (0, tweetnacl_util_1.decodeUTF8)(objStr);
117
- const objSigned = nacl.sign.detached(objDecoded, _secretKey);
118
+ const signatureByteArray = nacl.sign.detached(objDecoded, _secretKey);
118
119
  return {
119
120
  contents: obj,
120
- signature: encodeBase64(objSigned),
121
+ signature: encodeBase64(signatureByteArray),
121
122
  publicKey: encodeBase64(_secretKey.slice(32)),
122
123
  };
123
124
  }
@@ -146,9 +147,8 @@ function boxDataWithKeys(data, toPublicBoxKey, mySecretKey) {
146
147
  const boxKeyPair = nacl.box.keyPair.fromSecretKey(_secretKey.slice(0, 32));
147
148
  const _toPublicBoxKey = decodeBase64(toPublicBoxKey);
148
149
  const nonce = nacl.randomBytes(24);
149
- data = (0, serial_json_1.toJSONString)(data);
150
- const dataDecoded = (0, tweetnacl_util_1.decodeUTF8)(data);
151
- const dataBoxed = nacl.box(dataDecoded, nonce, _toPublicBoxKey, boxKeyPair.secretKey);
150
+ const dataByteArray = (0, tx_encoding_1.txEncode)(data);
151
+ const dataBoxed = nacl.box(dataByteArray, nonce, _toPublicBoxKey, boxKeyPair.secretKey);
152
152
  return {
153
153
  contents: encodeBase64(dataBoxed),
154
154
  nonce: encodeBase64(nonce),
@@ -161,12 +161,11 @@ function openBoxWithSecretKey(box, mySecretKey) {
161
161
  const boxedData = decodeBase64(box.contents);
162
162
  const nonce = decodeBase64(box.nonce);
163
163
  const _fromPublicBoxKey = decodeBase64(box.fromPublicKey);
164
- const dataAry = nacl.box.open(boxedData, nonce, _fromPublicBoxKey, boxKeyPair.secretKey);
165
- if (dataAry === null) {
164
+ const dataByteArray = nacl.box.open(boxedData, nonce, _fromPublicBoxKey, boxKeyPair.secretKey);
165
+ if (dataByteArray === null) {
166
166
  throw new Error('Message was null or verification failed');
167
167
  }
168
- const dataStr = (0, tweetnacl_util_1.encodeUTF8)(dataAry);
169
- return (0, serial_json_1.fromJSONString)(dataStr);
168
+ return (0, tx_encoding_1.txDecode)(dataByteArray);
170
169
  }
171
170
  function encryptString(data, secretKey) {
172
171
  let _secretKey = decodeBase64(secretKey);
@@ -8,3 +8,56 @@ export declare function setupConsoleProxy(processName: string): Promise<void>;
8
8
  * Restore original console methods
9
9
  */
10
10
  export declare function restoreConsole(): void;
11
+ /**
12
+ * Extract core message by removing common prefixes that might be added by different processes
13
+ * This helps detect cross-process loops where each process adds its own prefix
14
+ * @internal Exported for testing
15
+ */
16
+ export declare function extractCoreMessage(message: string): string;
17
+ /**
18
+ * Mark the logging system as initialized and flush any pending logs
19
+ */
20
+ export declare function markLoggingInitialized(): void;
21
+ /**
22
+ * Reset logging initialization state (primarily for testing)
23
+ * @internal
24
+ */
25
+ export declare function resetLoggingState(): void;
26
+ /**
27
+ * Logger class for creating source-specific loggers
28
+ *
29
+ * Usage:
30
+ * ```typescript
31
+ * const logger = new Logger('MyModule');
32
+ * logger.log('Something happened');
33
+ * logger.error('An error occurred');
34
+ * ```
35
+ */
36
+ export declare class Logger {
37
+ private source;
38
+ constructor(source?: string);
39
+ /**
40
+ * Log a debug message
41
+ */
42
+ debug(...args: any[]): void;
43
+ /**
44
+ * Log an info message
45
+ */
46
+ info(...args: any[]): void;
47
+ /**
48
+ * Log a general message
49
+ */
50
+ log(...args: any[]): void;
51
+ /**
52
+ * Log a warning message
53
+ */
54
+ warn(...args: any[]): void;
55
+ /**
56
+ * Log an error message
57
+ */
58
+ error(...args: any[]): void;
59
+ /**
60
+ * Internal method to write log to database
61
+ */
62
+ private writeLog;
63
+ }