@cofhe/sdk 0.1.1 → 0.2.0

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 (96) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/adapters/ethers6.ts +28 -28
  3. package/adapters/hardhat.ts +0 -1
  4. package/adapters/index.test.ts +14 -19
  5. package/adapters/smartWallet.ts +81 -73
  6. package/adapters/test-utils.ts +45 -45
  7. package/adapters/types.ts +3 -3
  8. package/chains/chains/localcofhe.ts +14 -0
  9. package/chains/chains.test.ts +2 -1
  10. package/chains/index.ts +3 -1
  11. package/core/baseBuilder.ts +30 -49
  12. package/core/client.test.ts +94 -77
  13. package/core/client.ts +133 -149
  14. package/core/clientTypes.ts +108 -0
  15. package/core/config.test.ts +22 -11
  16. package/core/config.ts +16 -9
  17. package/core/decrypt/decryptHandleBuilder.ts +51 -45
  18. package/core/decrypt/{tnSealOutput.ts → tnSealOutputV1.ts} +1 -1
  19. package/core/decrypt/tnSealOutputV2.ts +298 -0
  20. package/core/encrypt/cofheMocksZkVerifySign.ts +16 -10
  21. package/core/encrypt/encryptInputsBuilder.test.ts +132 -116
  22. package/core/encrypt/encryptInputsBuilder.ts +159 -111
  23. package/core/encrypt/encryptUtils.ts +6 -3
  24. package/core/encrypt/zkPackProveVerify.ts +70 -8
  25. package/core/error.ts +0 -2
  26. package/core/fetchKeys.test.ts +1 -18
  27. package/core/fetchKeys.ts +0 -26
  28. package/core/index.ts +29 -17
  29. package/core/keyStore.ts +65 -38
  30. package/core/permits.test.ts +253 -1
  31. package/core/permits.ts +80 -16
  32. package/core/types.ts +198 -152
  33. package/core/utils.ts +43 -1
  34. package/dist/adapters.d.cts +38 -20
  35. package/dist/adapters.d.ts +38 -20
  36. package/dist/chains.cjs +14 -1
  37. package/dist/chains.d.cts +23 -1
  38. package/dist/chains.d.ts +23 -1
  39. package/dist/chains.js +1 -1
  40. package/dist/{chunk-LU7BMUUT.js → chunk-UGBVZNRT.js} +39 -25
  41. package/dist/{chunk-GZCQQYVI.js → chunk-WEAZ25JO.js} +14 -2
  42. package/dist/{chunk-KFGPTJ6X.js → chunk-WGCRJCBR.js} +1920 -1692
  43. package/dist/{types-bB7wLj0q.d.cts → clientTypes-5_1nwtUe.d.cts} +308 -347
  44. package/dist/{types-PhwGgQvs.d.ts → clientTypes-Es7fyi65.d.ts} +308 -347
  45. package/dist/core.cjs +2872 -2632
  46. package/dist/core.d.cts +101 -6
  47. package/dist/core.d.ts +101 -6
  48. package/dist/core.js +3 -3
  49. package/dist/node.cjs +2716 -2520
  50. package/dist/node.d.cts +3 -3
  51. package/dist/node.d.ts +3 -3
  52. package/dist/node.js +4 -3
  53. package/dist/{permit-S9CnI6MF.d.cts → permit-fUSe6KKq.d.cts} +31 -15
  54. package/dist/{permit-S9CnI6MF.d.ts → permit-fUSe6KKq.d.ts} +31 -15
  55. package/dist/permits.cjs +39 -24
  56. package/dist/permits.d.cts +137 -148
  57. package/dist/permits.d.ts +137 -148
  58. package/dist/permits.js +1 -1
  59. package/dist/web.cjs +2929 -2518
  60. package/dist/web.d.cts +21 -5
  61. package/dist/web.d.ts +21 -5
  62. package/dist/web.js +185 -9
  63. package/dist/zkProve.worker.cjs +93 -0
  64. package/dist/zkProve.worker.d.cts +2 -0
  65. package/dist/zkProve.worker.d.ts +2 -0
  66. package/dist/zkProve.worker.js +91 -0
  67. package/node/client.test.ts +20 -25
  68. package/node/encryptInputs.test.ts +18 -38
  69. package/node/index.ts +1 -0
  70. package/package.json +14 -14
  71. package/permits/index.ts +1 -0
  72. package/permits/localstorage.test.ts +0 -1
  73. package/permits/permit.test.ts +25 -22
  74. package/permits/permit.ts +30 -21
  75. package/permits/sealing.test.ts +3 -3
  76. package/permits/sealing.ts +2 -2
  77. package/permits/store.ts +5 -7
  78. package/permits/test-utils.ts +1 -1
  79. package/permits/types.ts +17 -0
  80. package/permits/utils.ts +0 -1
  81. package/permits/validation.ts +24 -4
  82. package/web/client.web.test.ts +20 -25
  83. package/web/config.web.test.ts +0 -2
  84. package/web/encryptInputs.web.test.ts +31 -54
  85. package/web/index.ts +65 -1
  86. package/web/storage.ts +19 -5
  87. package/web/worker.builder.web.test.ts +148 -0
  88. package/web/worker.config.web.test.ts +329 -0
  89. package/web/worker.output.web.test.ts +84 -0
  90. package/web/workerManager.test.ts +80 -0
  91. package/web/workerManager.ts +214 -0
  92. package/web/workerManager.web.test.ts +114 -0
  93. package/web/zkProve.worker.ts +133 -0
  94. package/core/result.test.ts +0 -180
  95. package/core/result.ts +0 -67
  96. package/core/test-utils.ts +0 -45
@@ -0,0 +1,114 @@
1
+ import { describe, it, expect, afterEach } from 'vitest';
2
+ import { getWorkerManager, terminateWorker, areWorkersAvailable } from './workerManager.js';
3
+
4
+ describe('WorkerManager (Browser)', () => {
5
+ afterEach(() => {
6
+ // Clean up worker after each test
7
+ terminateWorker();
8
+ });
9
+
10
+ describe('areWorkersAvailable', () => {
11
+ it('should return true in browser environment', () => {
12
+ // In real browser with Playwright, workers should be available
13
+ expect(areWorkersAvailable()).toBe(true);
14
+ });
15
+ });
16
+
17
+ describe('Worker lifecycle', () => {
18
+ it('should initialize worker successfully', async () => {
19
+ const manager = getWorkerManager();
20
+ expect(manager).toBeDefined();
21
+
22
+ // Worker should be available
23
+ expect(areWorkersAvailable()).toBe(true);
24
+ });
25
+
26
+ it('should handle worker termination', () => {
27
+ const manager = getWorkerManager();
28
+ expect(manager).toBeDefined();
29
+
30
+ terminateWorker();
31
+
32
+ // Should be able to get a new instance
33
+ const newManager = getWorkerManager();
34
+ expect(newManager).toBeDefined();
35
+ });
36
+ });
37
+
38
+ describe('submitProof', () => {
39
+ it('should reject invalid data with error message', async () => {
40
+ const manager = getWorkerManager();
41
+
42
+ // Submit with invalid data - should fail quickly
43
+ await expect(manager.submitProof('invalid', 'invalid', [], new Uint8Array())).rejects.toThrow();
44
+ }, 35000);
45
+
46
+ it('should reject invalid message type', async () => {
47
+ const manager = getWorkerManager();
48
+
49
+ // Submit with invalid data that will cause worker error
50
+ await expect(
51
+ manager.submitProof(
52
+ '', // empty key
53
+ '', // empty crs
54
+ [{ utype: 'invalid', data: 'test' }],
55
+ new Uint8Array([1, 2, 3])
56
+ )
57
+ ).rejects.toThrow();
58
+ }, 35000);
59
+ });
60
+
61
+ describe('Concurrent requests', () => {
62
+ it('should handle multiple concurrent proof requests', async () => {
63
+ const manager = getWorkerManager();
64
+
65
+ // Submit multiple requests concurrently
66
+ const requests = [
67
+ manager.submitProof('key1', 'crs1', [], new Uint8Array([1])),
68
+ manager.submitProof('key2', 'crs2', [], new Uint8Array([2])),
69
+ manager.submitProof('key3', 'crs3', [], new Uint8Array([3])),
70
+ ];
71
+
72
+ // All should reject (invalid data), but shouldn't crash
73
+ const results = await Promise.allSettled(requests);
74
+
75
+ expect(results).toHaveLength(3);
76
+ results.forEach((result) => {
77
+ expect(result.status).toBe('rejected');
78
+ });
79
+ }, 35000);
80
+ });
81
+
82
+ describe('Worker error handling', () => {
83
+ it('should handle worker errors gracefully', async () => {
84
+ const manager = getWorkerManager();
85
+
86
+ // This should cause an error in the worker
87
+ await expect(
88
+ manager.submitProof(
89
+ 'malformed-hex',
90
+ 'malformed-crs',
91
+ [{ utype: 'uint128', data: 'not-a-number' }],
92
+ new Uint8Array([])
93
+ )
94
+ ).rejects.toThrow();
95
+ }, 35000);
96
+ });
97
+
98
+ describe('Termination during processing', () => {
99
+ it('should reject pending requests on termination', async () => {
100
+ const manager = getWorkerManager();
101
+
102
+ // Start a request (will timeout)
103
+ const proofPromise = manager.submitProof('test', 'test', [], new Uint8Array());
104
+
105
+ // Terminate immediately
106
+ setTimeout(() => {
107
+ terminateWorker();
108
+ }, 100);
109
+
110
+ // Request should be rejected
111
+ await expect(proofPromise).rejects.toThrow();
112
+ }, 5000);
113
+ });
114
+ });
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Web Worker for ZK Proof Generation
3
+ * Performs heavy WASM computation off the main thread
4
+ */
5
+
6
+ /// <reference lib="webworker" />
7
+ /* eslint-disable no-undef */
8
+
9
+ import type { ZkProveWorkerRequest, ZkProveWorkerResponse } from '../core/encrypt/zkPackProveVerify.js';
10
+
11
+ // TFHE module (will be initialized on first use)
12
+ let tfheModule: any = null;
13
+ let initialized = false;
14
+
15
+ /**
16
+ * Initialize TFHE in worker context
17
+ */
18
+ async function initTfhe() {
19
+ if (initialized) return;
20
+
21
+ try {
22
+ // Dynamic import of tfhe module
23
+ tfheModule = await import('tfhe');
24
+ await tfheModule.default();
25
+ await tfheModule.init_panic_hook();
26
+ initialized = true;
27
+ console.log('[Worker] TFHE initialized');
28
+ } catch (error) {
29
+ console.error('[Worker] Failed to initialize TFHE:', error);
30
+ throw error;
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Convert hex string to Uint8Array
36
+ */
37
+ function fromHexString(hexString: string): Uint8Array {
38
+ const cleanString = hexString.length % 2 === 1 ? `0${hexString}` : hexString;
39
+ const arr = cleanString.replace(/^0x/, '').match(/.{1,2}/g);
40
+ if (!arr) return new Uint8Array();
41
+ return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
42
+ }
43
+
44
+ /**
45
+ * Main message handler
46
+ */
47
+ self.onmessage = async (event: MessageEvent) => {
48
+ const { id, type, fheKeyHex, crsHex, items, metadata } = event.data as ZkProveWorkerRequest;
49
+
50
+ if (type !== 'zkProve') {
51
+ self.postMessage({
52
+ id,
53
+ type: 'error',
54
+ error: 'Invalid message type',
55
+ } as ZkProveWorkerResponse);
56
+ return;
57
+ }
58
+
59
+ try {
60
+ // Initialize TFHE if needed
61
+ await initTfhe();
62
+
63
+ if (!tfheModule) {
64
+ throw new Error('TFHE module not initialized');
65
+ }
66
+
67
+ // Deserialize FHE public key and CRS from hex strings
68
+ const fheKeyBytes = fromHexString(fheKeyHex);
69
+ const crsBytes = fromHexString(crsHex);
70
+
71
+ const fheKey = tfheModule.TfheCompactPublicKey.deserialize(fheKeyBytes);
72
+ const crs = tfheModule.CompactPkeCrs.deserialize(crsBytes);
73
+
74
+ // Create builder
75
+ const builder = tfheModule.ProvenCompactCiphertextList.builder(fheKey);
76
+
77
+ // Pack all items (duplicate of zkPack logic)
78
+ for (const item of items) {
79
+ switch (item.utype) {
80
+ case 'bool':
81
+ builder.push_boolean(Boolean(item.data));
82
+ break;
83
+ case 'uint8':
84
+ builder.push_u8(Number(item.data));
85
+ break;
86
+ case 'uint16':
87
+ builder.push_u16(Number(item.data));
88
+ break;
89
+ case 'uint32':
90
+ builder.push_u32(Number(item.data));
91
+ break;
92
+ case 'uint64':
93
+ builder.push_u64(BigInt(item.data));
94
+ break;
95
+ case 'uint128':
96
+ builder.push_u128(BigInt(item.data));
97
+ break;
98
+ case 'uint160':
99
+ builder.push_u160(BigInt(item.data));
100
+ break;
101
+ default:
102
+ throw new Error(`Unsupported type: ${item.utype}`);
103
+ }
104
+ }
105
+
106
+ // THE HEAVY OPERATION - but in worker thread!
107
+ const metadataBytes = new Uint8Array(metadata);
108
+ const compactList = builder.build_with_proof_packed(crs, metadataBytes, 1);
109
+
110
+ // Serialize result
111
+ const result = compactList.serialize();
112
+
113
+ // Send success response
114
+ self.postMessage({
115
+ id,
116
+ type: 'success',
117
+ result: Array.from(result),
118
+ } as ZkProveWorkerResponse);
119
+ } catch (error) {
120
+ // Send error response
121
+ self.postMessage({
122
+ id,
123
+ type: 'error',
124
+ error: error instanceof Error ? error.message : String(error),
125
+ } as ZkProveWorkerResponse);
126
+ }
127
+ };
128
+
129
+ // Signal ready - send proper message format
130
+ self.postMessage({
131
+ id: 'init',
132
+ type: 'ready',
133
+ } as ZkProveWorkerResponse);
@@ -1,180 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { ResultOk, ResultErr, ResultErrOrInternal, resultWrapper, resultWrapperSync, type Result } from './result.js';
3
- import { CofhesdkError, CofhesdkErrorCode } from './error.js';
4
-
5
- export const expectResultError = <T>(result: Result<T>, errorPartial: string) => {
6
- expect(result.success).to.eq(false, 'Result should be an error');
7
- expect(result.error!.message).to.include(errorPartial, `Error should contain error partial: ${errorPartial}`);
8
- };
9
-
10
- export const expectResultSuccess = <T>(result: Result<T>): T => {
11
- expect(result.success).to.eq(true, 'Result should be a success');
12
- return result.data!;
13
- };
14
-
15
- export const expectResultValue = <T>(result: Result<T>, value: T): T => {
16
- expect(result.success).to.eq(true, 'Result should be a success');
17
- expect(result.data).to.eq(value, `Result should have the expected value ${value}`);
18
- return result.data!;
19
- };
20
-
21
- describe('Result Type', () => {
22
- describe('ResultOk', () => {
23
- it('should create a successful result', () => {
24
- const result = ResultOk('test data');
25
- expect(result.success).toBe(true);
26
- expect(result.data).toBe('test data');
27
- expect(result.error).toBe(null);
28
- });
29
-
30
- it('should handle different data types', () => {
31
- const stringResult = ResultOk('string');
32
- const numberResult = ResultOk(42);
33
- const objectResult = ResultOk({ key: 'value' });
34
- const nullResult = ResultOk(null);
35
-
36
- expect(stringResult.data).toBe('string');
37
- expect(numberResult.data).toBe(42);
38
- expect(objectResult.data).toEqual({ key: 'value' });
39
- expect(nullResult.data).toBe(null);
40
- });
41
- });
42
-
43
- describe('ResultErr', () => {
44
- it('should create an error result', () => {
45
- const error = new CofhesdkError({
46
- code: CofhesdkErrorCode.InternalError,
47
- message: 'Test error',
48
- });
49
- const result = ResultErr(error);
50
-
51
- expect(result.success).toBe(false);
52
- expect(result.data).toBe(null);
53
- expect(result.error).toBe(error);
54
- });
55
- });
56
- });
57
-
58
- describe('Error Utilities', () => {
59
- describe('ResultErrOrInternal', () => {
60
- it('should wrap unknown errors as internal errors', () => {
61
- const result = ResultErrOrInternal(new Error('string error'));
62
- expect(result.success).toBe(false);
63
- expect(result.error!).toBeInstanceOf(CofhesdkError);
64
- expect(result.error!.code).toBe(CofhesdkErrorCode.InternalError);
65
- expect(result.error!.message).toBe('An internal error occurred | Caused by: string error');
66
- });
67
-
68
- it('should preserve CofhesdkError instances', () => {
69
- const originalError = new CofhesdkError({
70
- code: CofhesdkErrorCode.MissingPublicClient,
71
- message: 'Public client missing',
72
- });
73
- const result = ResultErrOrInternal(originalError);
74
- expect(result.success).toBe(false);
75
- expect(result.error!).toBe(originalError);
76
- });
77
-
78
- it('should handle Error instances', () => {
79
- const error = new Error('Standard error');
80
- const result = ResultErrOrInternal(error);
81
- expect(result.success).toBe(false);
82
- expect(result.error!).toBeInstanceOf(CofhesdkError);
83
- expect(result.error!.cause).toBe(error);
84
- });
85
- });
86
- });
87
-
88
- describe('Result Wrappers', () => {
89
- describe('resultWrapperSync', () => {
90
- it('should wrap successful sync function', () => {
91
- const result = resultWrapperSync(() => 'success');
92
- expect(result.success).toBe(true);
93
- expect(result.data).toBe('success');
94
- });
95
-
96
- it('should wrap failing sync function', () => {
97
- const result = resultWrapperSync(() => {
98
- throw new Error('Sync error');
99
- });
100
- expect(result.success).toBe(false);
101
- expect(result.error).toBeInstanceOf(CofhesdkError);
102
- });
103
- });
104
-
105
- describe('resultWrapper', () => {
106
- it('should wrap successful async function', async () => {
107
- const result = await resultWrapper(async () => 'async success');
108
- expect(result.success).toBe(true);
109
- expect(result.data).toBe('async success');
110
- });
111
-
112
- it('should wrap failing async function', async () => {
113
- const result = await resultWrapper(async () => {
114
- throw new Error('Async error');
115
- });
116
- expect(result.success).toBe(false);
117
- expect(result.error).toBeInstanceOf(CofhesdkError);
118
- });
119
-
120
- it('should handle async operations', async () => {
121
- const result = await resultWrapper(async () => {
122
- await new Promise((resolve) => setTimeout(resolve, 10));
123
- return 'delayed result';
124
- });
125
- expect(result.success).toBe(true);
126
- expect(result.data).toBe('delayed result');
127
- });
128
-
129
- it('should handle Promise rejections', async () => {
130
- const result = await resultWrapper(async () => {
131
- return Promise.reject(new Error('Promise rejection'));
132
- });
133
- expect(result.success).toBe(false);
134
- expect(result.error).toBeInstanceOf(CofhesdkError);
135
- });
136
- });
137
- });
138
-
139
- describe('Result Type Guards', () => {
140
- it('should correctly identify success results', () => {
141
- const successResult = ResultOk('data');
142
- expect(successResult.success).toBe(true);
143
- expect(successResult.data).toBe('data');
144
- expect(successResult.error).toBe(null);
145
- });
146
-
147
- it('should correctly identify error results', () => {
148
- const errorResult = ResultErr(
149
- new CofhesdkError({
150
- code: CofhesdkErrorCode.InternalError,
151
- message: 'Test error',
152
- })
153
- );
154
- expect(errorResult.success).toBe(false);
155
- expect(errorResult.data).toBe(null);
156
- expect(errorResult.error).toBeInstanceOf(CofhesdkError);
157
- });
158
- });
159
-
160
- describe('Result Test Utilities', () => {
161
- it('expectResultSuccess should return data for success', () => {
162
- const result = ResultOk('data');
163
- expect(expectResultSuccess(result)).toBe('data');
164
- });
165
-
166
- it('expectResultValue should validate and return matching data', () => {
167
- const result = ResultOk('expected');
168
- expect(expectResultValue(result, 'expected')).toBe('expected');
169
- });
170
-
171
- it('expectResultError should validate error messages', () => {
172
- const result = ResultErr(
173
- new CofhesdkError({
174
- code: CofhesdkErrorCode.InternalError,
175
- message: 'Test error message',
176
- })
177
- );
178
- expectResultError(result, 'Test error');
179
- });
180
- });
package/core/result.ts DELETED
@@ -1,67 +0,0 @@
1
- /* eslint-disable no-unused-vars */
2
- import { CofhesdkError, CofhesdkErrorCode } from './error.js';
3
-
4
- export type Result<T> = { success: true; data: T; error: null } | { success: false; data: null; error: CofhesdkError };
5
-
6
- export const ResultErr = <T>(error: CofhesdkError): Result<T> => ({
7
- success: false,
8
- data: null,
9
- error,
10
- });
11
-
12
- export const ResultOk = <T>(data: T): Result<T> => ({
13
- success: true,
14
- data,
15
- error: null,
16
- });
17
-
18
- export const ResultErrOrInternal = <T>(error: unknown): Result<T> => {
19
- return ResultErr(CofhesdkError.fromError(error));
20
- };
21
-
22
- export const ResultHttpError = (error: unknown, url: string, status?: number): CofhesdkError => {
23
- if (error instanceof CofhesdkError) return error;
24
-
25
- const message = status ? `HTTP error ${status} from ${url}` : `HTTP request failed for ${url}`;
26
-
27
- return new CofhesdkError({
28
- code: CofhesdkErrorCode.InternalError,
29
- message,
30
- cause: error instanceof Error ? error : undefined,
31
- });
32
- };
33
-
34
- export const ResultValidationError = (message: string): CofhesdkError => {
35
- return new CofhesdkError({
36
- code: CofhesdkErrorCode.InvalidPermitData,
37
- message,
38
- });
39
- };
40
-
41
- // Async resultWrapper
42
- export const resultWrapper = async <T>(
43
- tryFn: () => Promise<T>,
44
- catchFn?: (error: CofhesdkError) => void,
45
- finallyFn?: () => void
46
- ): Promise<Result<T>> => {
47
- try {
48
- const result = await tryFn();
49
- return ResultOk(result);
50
- } catch (error) {
51
- const result = ResultErrOrInternal(error);
52
- catchFn?.(result.error!);
53
- return result as Result<T>;
54
- } finally {
55
- finallyFn?.();
56
- }
57
- };
58
-
59
- // Sync resultWrapper
60
- export const resultWrapperSync = <T>(fn: () => T): Result<T> => {
61
- try {
62
- const result = fn();
63
- return ResultOk(result);
64
- } catch (error) {
65
- return ResultErrOrInternal(error);
66
- }
67
- };
@@ -1,45 +0,0 @@
1
- import { expect } from 'vitest';
2
- import { type Result } from './result.js';
3
- import { CofhesdkError, CofhesdkErrorCode } from './error.js';
4
-
5
- /**
6
- * Assert that a Result is successful and return its data
7
- * Useful for type narrowing in tests
8
- */
9
- export const expectResultSuccess = <T>(result: Result<T>): NonNullable<T> => {
10
- expect(result.error, `Result error: ${result.error?.toString()}`).toBe(null);
11
- expect(result.success, `Result: ${bigintSafeJsonStringify(result)}`).toBe(true);
12
- expect(result.data, `Result: ${bigintSafeJsonStringify(result)}`).not.toBe(null);
13
- return result.data!;
14
- };
15
-
16
- /**
17
- * Assert that a Result is an error and optionally verify the error details
18
- */
19
- export const expectResultError = <T>(
20
- result: Result<T>,
21
- errorCode?: CofhesdkErrorCode,
22
- errorMessage?: string
23
- ): CofhesdkError => {
24
- expect(result.success, `Result: ${bigintSafeJsonStringify(result)}`).toBe(false);
25
- expect(result.data, `Result: ${bigintSafeJsonStringify(result)}`).toBe(null);
26
- expect(result.error, `Result: ${bigintSafeJsonStringify(result)}`).not.toBe(null);
27
- const error = result.error as CofhesdkError;
28
- expect(error, `Result error: ${result.error?.toString()}`).toBeInstanceOf(CofhesdkError);
29
- if (errorCode) {
30
- expect(error.code, `Result error: ${result.error?.toString()}`).toBe(errorCode);
31
- }
32
- if (errorMessage) {
33
- expect(error.message, `Result error: ${result.error?.toString()}`).toBe(errorMessage);
34
- }
35
- return error;
36
- };
37
-
38
- const bigintSafeJsonStringify = (value: unknown): string => {
39
- return JSON.stringify(value, (key, value) => {
40
- if (typeof value === 'bigint') {
41
- return `${value}n`;
42
- }
43
- return value;
44
- });
45
- };