@cofhe/sdk 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/CHANGELOG.md +22 -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/defineChain.ts +2 -2
  11. package/chains/index.ts +3 -1
  12. package/chains/types.ts +3 -3
  13. package/core/baseBuilder.ts +30 -49
  14. package/core/client.test.ts +200 -72
  15. package/core/client.ts +152 -148
  16. package/core/clientTypes.ts +114 -0
  17. package/core/config.test.ts +30 -11
  18. package/core/config.ts +26 -13
  19. package/core/consts.ts +18 -0
  20. package/core/decrypt/cofheMocksSealOutput.ts +2 -4
  21. package/core/decrypt/decryptHandleBuilder.ts +51 -45
  22. package/core/decrypt/{tnSealOutput.ts → tnSealOutputV1.ts} +1 -1
  23. package/core/decrypt/tnSealOutputV2.ts +298 -0
  24. package/core/encrypt/cofheMocksZkVerifySign.ts +15 -16
  25. package/core/encrypt/encryptInputsBuilder.test.ts +132 -116
  26. package/core/encrypt/encryptInputsBuilder.ts +159 -111
  27. package/core/encrypt/encryptUtils.ts +6 -3
  28. package/core/encrypt/zkPackProveVerify.ts +70 -8
  29. package/core/error.ts +0 -2
  30. package/core/fetchKeys.test.ts +1 -18
  31. package/core/fetchKeys.ts +0 -26
  32. package/core/index.ts +37 -17
  33. package/core/keyStore.ts +65 -38
  34. package/core/permits.test.ts +255 -4
  35. package/core/permits.ts +83 -18
  36. package/core/types.ts +198 -152
  37. package/core/utils.ts +43 -1
  38. package/dist/adapters.d.cts +38 -20
  39. package/dist/adapters.d.ts +38 -20
  40. package/dist/chains.cjs +18 -8
  41. package/dist/chains.d.cts +31 -9
  42. package/dist/chains.d.ts +31 -9
  43. package/dist/chains.js +1 -1
  44. package/dist/{chunk-KFGPTJ6X.js → chunk-I5WFEYXX.js} +1768 -1526
  45. package/dist/{chunk-LU7BMUUT.js → chunk-R3B5TMVX.js} +330 -197
  46. package/dist/{chunk-GZCQQYVI.js → chunk-TBLR7NNE.js} +18 -9
  47. package/dist/{types-PhwGgQvs.d.ts → clientTypes-RqkgkV2i.d.ts} +331 -429
  48. package/dist/{types-bB7wLj0q.d.cts → clientTypes-e4filDzK.d.cts} +331 -429
  49. package/dist/core.cjs +3000 -2625
  50. package/dist/core.d.cts +113 -7
  51. package/dist/core.d.ts +113 -7
  52. package/dist/core.js +3 -3
  53. package/dist/node.cjs +2851 -2526
  54. package/dist/node.d.cts +4 -4
  55. package/dist/node.d.ts +4 -4
  56. package/dist/node.js +4 -3
  57. package/dist/{permit-S9CnI6MF.d.cts → permit-MZ502UBl.d.cts} +54 -41
  58. package/dist/{permit-S9CnI6MF.d.ts → permit-MZ502UBl.d.ts} +54 -41
  59. package/dist/permits.cjs +328 -195
  60. package/dist/permits.d.cts +113 -825
  61. package/dist/permits.d.ts +113 -825
  62. package/dist/permits.js +1 -1
  63. package/dist/types-YiAC4gig.d.cts +33 -0
  64. package/dist/types-YiAC4gig.d.ts +33 -0
  65. package/dist/web.cjs +3067 -2527
  66. package/dist/web.d.cts +22 -6
  67. package/dist/web.d.ts +22 -6
  68. package/dist/web.js +185 -9
  69. package/dist/zkProve.worker.cjs +93 -0
  70. package/dist/zkProve.worker.d.cts +2 -0
  71. package/dist/zkProve.worker.d.ts +2 -0
  72. package/dist/zkProve.worker.js +91 -0
  73. package/node/client.test.ts +20 -25
  74. package/node/encryptInputs.test.ts +18 -38
  75. package/node/index.ts +1 -0
  76. package/package.json +15 -15
  77. package/permits/index.ts +1 -0
  78. package/permits/localstorage.test.ts +9 -14
  79. package/permits/onchain-utils.ts +221 -0
  80. package/permits/permit.test.ts +76 -27
  81. package/permits/permit.ts +58 -95
  82. package/permits/sealing.test.ts +3 -3
  83. package/permits/sealing.ts +2 -2
  84. package/permits/store.test.ts +10 -50
  85. package/permits/store.ts +9 -21
  86. package/permits/test-utils.ts +11 -3
  87. package/permits/types.ts +39 -9
  88. package/permits/utils.ts +0 -5
  89. package/permits/validation.test.ts +29 -32
  90. package/permits/validation.ts +114 -176
  91. package/web/client.web.test.ts +20 -25
  92. package/web/config.web.test.ts +0 -2
  93. package/web/encryptInputs.web.test.ts +31 -54
  94. package/web/index.ts +65 -1
  95. package/web/storage.ts +19 -5
  96. package/web/worker.builder.web.test.ts +148 -0
  97. package/web/worker.config.web.test.ts +329 -0
  98. package/web/worker.output.web.test.ts +84 -0
  99. package/web/workerManager.test.ts +80 -0
  100. package/web/workerManager.ts +214 -0
  101. package/web/workerManager.web.test.ts +114 -0
  102. package/web/zkProve.worker.ts +133 -0
  103. package/core/result.test.ts +0 -180
  104. package/core/result.ts +0 -67
  105. package/core/test-utils.ts +0 -45
  106. package/dist/types-KImPrEIe.d.cts +0 -48
  107. package/dist/types-KImPrEIe.d.ts +0 -48
package/core/client.ts CHANGED
@@ -1,59 +1,61 @@
1
- /* eslint-disable no-unused-vars */
2
1
  import type { CreateSelfPermitOptions, CreateSharingPermitOptions, ImportSharedPermitOptions } from '@/permits';
3
2
 
4
3
  import { createStore } from 'zustand/vanilla';
5
4
  import { type PublicClient, type WalletClient } from 'viem';
6
- import { fetchMultichainKeys } from './fetchKeys.js';
7
5
  import { CofhesdkError, CofhesdkErrorCode } from './error.js';
8
6
  import { EncryptInputsBuilder } from './encrypt/encryptInputsBuilder.js';
9
- import { type Result, ResultOk, resultWrapper } from './result.js';
10
7
  import { createKeysStore } from './keyStore.js';
11
8
  import { permits } from './permits.js';
12
9
  import { DecryptHandlesBuilder } from './decrypt/decryptHandleBuilder.js';
13
- import {
14
- type CofhesdkClient,
15
- type CofhesdkClientParams,
16
- type CofhesdkClientConnectionState,
17
- type EncryptableItem,
18
- type FheTypes,
19
- type CofhesdkClientPermits,
20
- } from './types.js';
21
10
  import { getPublicClientChainID, getWalletClientAccount } from './utils.js';
11
+ import type {
12
+ CofhesdkClientConnectionState,
13
+ CofhesdkClientParams,
14
+ CofhesdkClient,
15
+ CofhesdkClientPermits,
16
+ } from './clientTypes.js';
17
+ import type { EncryptableItem, FheTypes } from './types.js';
18
+ import type { CofhesdkConfig } from './config.js';
19
+
20
+ export const InitialConnectStore: CofhesdkClientConnectionState = {
21
+ connected: false,
22
+ connecting: false,
23
+ connectError: undefined,
24
+ chainId: undefined,
25
+ account: undefined,
26
+ publicClient: undefined,
27
+ walletClient: undefined,
28
+ };
22
29
 
23
30
  /**
24
31
  * Creates a CoFHE SDK client instance (base implementation)
25
32
  * @param {CofhesdkClientParams} opts - Initialization options including config and platform-specific serializers
26
33
  * @returns {CofhesdkClient} - The CoFHE SDK client instance
27
34
  */
28
- export function createCofhesdkClientBase(opts: CofhesdkClientParams): CofhesdkClient {
35
+ export function createCofhesdkClientBase<TConfig extends CofhesdkConfig>(
36
+ opts: CofhesdkClientParams<TConfig>
37
+ ): CofhesdkClient<TConfig> {
29
38
  // Create keysStorage instance using configured storage
30
39
  const keysStorage = createKeysStore(opts.config.fheKeyStorage);
31
40
 
32
- // refs captured in closure
33
- let _publicClient: PublicClient | undefined = undefined;
34
- let _walletClient: WalletClient | undefined = undefined;
35
-
36
41
  // Zustand store for reactive state management
37
- const connectStore = createStore<CofhesdkClientConnectionState>(() => ({
38
- connected: false,
39
- connecting: false,
40
- connectError: undefined,
41
- chainId: undefined,
42
- account: undefined,
43
- }));
42
+
43
+ const connectStore = createStore<CofhesdkClientConnectionState>(() => InitialConnectStore);
44
+
45
+ // Minimal cancellation mechanism: incremented on each connect/disconnect.
46
+ // If a connect finishes after a disconnect, it must not overwrite the disconnected state.
47
+ let connectAttemptId = 0;
44
48
 
45
49
  // Helper to update state
46
50
  const updateConnectState = (partial: Partial<CofhesdkClientConnectionState>) => {
47
51
  connectStore.setState((state) => ({ ...state, ...partial }));
48
52
  };
49
53
 
50
- // single-flight + abortable warmup
51
- let _connectPromise: Promise<Result<boolean>> | undefined = undefined;
52
-
53
54
  // Called before any operation, throws of connection not yet established
54
55
  const _requireConnected = () => {
55
56
  const state = connectStore.getState();
56
- const notConnected = !state.connected || !_publicClient || !_walletClient || !state.account || !state.chainId;
57
+ const notConnected =
58
+ !state.connected || !state.account || !state.chainId || !state.publicClient || !state.walletClient;
57
59
  if (notConnected) {
58
60
  throw new CofhesdkError({
59
61
  code: CofhesdkErrorCode.NotConnected,
@@ -63,74 +65,62 @@ export function createCofhesdkClientBase(opts: CofhesdkClientParams): CofhesdkCl
63
65
  connected: state.connected,
64
66
  account: state.account,
65
67
  chainId: state.chainId,
66
- publicClient: _publicClient,
67
- walletClient: _walletClient,
68
+ publicClient: state.publicClient,
69
+ walletClient: state.walletClient,
68
70
  },
69
71
  });
70
72
  }
71
73
  };
72
74
 
73
- // INITIALIZATION
74
-
75
- const keyFetchResult = resultWrapper(async () => {
76
- // If configured, fetch keys for all supported chains
77
- if (opts.config.fheKeysPrefetching === 'SUPPORTED_CHAINS') {
78
- await fetchMultichainKeys(
79
- opts.config,
80
- 0,
81
- opts.tfhePublicKeyDeserializer,
82
- opts.compactPkeCrsDeserializer,
83
- keysStorage
84
- );
85
- return true;
86
- }
87
-
88
- return false;
89
- });
90
-
91
75
  // LIFECYCLE
92
76
 
93
77
  async function connect(publicClient: PublicClient, walletClient: WalletClient) {
94
78
  const state = connectStore.getState();
95
79
 
96
80
  // Exit if already connected and clients are the same
97
- if (state.connected && _publicClient === publicClient && _walletClient === walletClient) {
98
- return Promise.resolve(ResultOk(true));
99
- }
81
+ if (state.connected && state.publicClient === publicClient && state.walletClient === walletClient) return;
100
82
 
101
- // Exit if already connecting
102
- if (_connectPromise && _publicClient === publicClient && _walletClient === walletClient) {
103
- return _connectPromise;
104
- }
83
+ connectAttemptId += 1;
84
+ const localAttemptId = connectAttemptId;
105
85
 
106
86
  // Set connecting state
107
- updateConnectState({ connecting: true, connectError: null, connected: false });
108
-
109
- _connectPromise = resultWrapper(
110
- // try
111
- async () => {
112
- _publicClient = publicClient;
113
- _walletClient = walletClient;
114
-
115
- const chainId = await getPublicClientChainID(publicClient);
116
- const account = await getWalletClientAccount(walletClient);
117
-
118
- updateConnectState({ connecting: false, connected: true, chainId, account });
119
-
120
- return true;
121
- },
122
- // catch
123
- (e) => {
124
- updateConnectState({ connecting: false, connected: false, connectError: e });
125
- return false;
126
- },
127
- // finally
128
- () => {
129
- _connectPromise = undefined;
130
- }
131
- );
132
-
133
- return _connectPromise;
87
+ updateConnectState({
88
+ ...InitialConnectStore,
89
+ connecting: true,
90
+ });
91
+
92
+ // Fetch chainId and account
93
+ try {
94
+ const chainId = await getPublicClientChainID(publicClient);
95
+ const account = await getWalletClientAccount(walletClient);
96
+
97
+ // If a disconnect (or a newer connect) happened while awaiting, ignore this completion.
98
+ if (localAttemptId !== connectAttemptId) return;
99
+
100
+ updateConnectState({
101
+ connected: true,
102
+ connecting: false,
103
+ connectError: undefined,
104
+ chainId,
105
+ account,
106
+ publicClient,
107
+ walletClient,
108
+ });
109
+ } catch (e) {
110
+ // Ignore stale errors too.
111
+ if (localAttemptId !== connectAttemptId) return;
112
+
113
+ updateConnectState({
114
+ ...InitialConnectStore,
115
+ connectError: e,
116
+ });
117
+ throw e;
118
+ }
119
+ }
120
+
121
+ function disconnect() {
122
+ connectAttemptId += 1;
123
+ updateConnectState({ ...InitialConnectStore });
134
124
  }
135
125
 
136
126
  // CLIENT OPERATIONS
@@ -144,14 +134,15 @@ export function createCofhesdkClientBase(opts: CofhesdkClientParams): CofhesdkCl
144
134
  chainId: state.chainId ?? undefined,
145
135
 
146
136
  config: opts.config,
147
- publicClient: _publicClient ?? undefined,
148
- walletClient: _walletClient ?? undefined,
137
+ publicClient: state.publicClient ?? undefined,
138
+ walletClient: state.walletClient ?? undefined,
149
139
  zkvWalletClient: opts.config._internal?.zkvWalletClient,
150
140
 
151
141
  tfhePublicKeyDeserializer: opts.tfhePublicKeyDeserializer,
152
142
  compactPkeCrsDeserializer: opts.compactPkeCrsDeserializer,
153
143
  zkBuilderAndCrsGenerator: opts.zkBuilderAndCrsGenerator,
154
144
  initTfhe: opts.initTfhe,
145
+ zkProveWorkerFn: opts.zkProveWorkerFn,
155
146
 
156
147
  keysStorage,
157
148
 
@@ -169,8 +160,8 @@ export function createCofhesdkClientBase(opts: CofhesdkClientParams): CofhesdkCl
169
160
  account: state.account ?? undefined,
170
161
 
171
162
  config: opts.config,
172
- publicClient: _publicClient ?? undefined,
173
- walletClient: _walletClient ?? undefined,
163
+ publicClient: state.publicClient ?? undefined,
164
+ walletClient: state.walletClient ?? undefined,
174
165
 
175
166
  requireConnected: _requireConnected,
176
167
  });
@@ -204,67 +195,84 @@ export function createCofhesdkClientBase(opts: CofhesdkClientParams): CofhesdkCl
204
195
  subscribe: permits.subscribe,
205
196
 
206
197
  // Creation methods (require connection)
207
- createSelf: async (options: CreateSelfPermitOptions) =>
208
- resultWrapper(async () => {
209
- _requireConnected();
210
- return permits.createSelf(options, _publicClient!, _walletClient!);
211
- }),
212
-
213
- createSharing: async (options: CreateSharingPermitOptions) =>
214
- resultWrapper(async () => {
215
- _requireConnected();
216
- return permits.createSharing(options, _publicClient!, _walletClient!);
217
- }),
218
-
219
- importShared: async (options: ImportSharedPermitOptions | any | string) =>
220
- resultWrapper(async () => {
221
- _requireConnected();
222
- return permits.importShared(options, _publicClient!, _walletClient!);
223
- }),
198
+ createSelf: async (
199
+ options: CreateSelfPermitOptions,
200
+ clients?: { publicClient: PublicClient; walletClient: WalletClient }
201
+ ) => {
202
+ _requireConnected();
203
+ const { publicClient, walletClient } = clients ?? connectStore.getState();
204
+ return permits.createSelf(options, publicClient!, walletClient!);
205
+ },
206
+
207
+ createSharing: async (
208
+ options: CreateSharingPermitOptions,
209
+ clients?: { publicClient: PublicClient; walletClient: WalletClient }
210
+ ) => {
211
+ _requireConnected();
212
+ const { publicClient, walletClient } = clients ?? connectStore.getState();
213
+ return permits.createSharing(options, publicClient!, walletClient!);
214
+ },
215
+
216
+ importShared: async (
217
+ options: ImportSharedPermitOptions | string,
218
+ clients?: { publicClient: PublicClient; walletClient: WalletClient }
219
+ ) => {
220
+ _requireConnected();
221
+ const { publicClient, walletClient } = clients ?? connectStore.getState();
222
+ return permits.importShared(options, publicClient!, walletClient!);
223
+ },
224
+
225
+ // Get or create methods (require connection)
226
+ getOrCreateSelfPermit: async (chainId?: number, account?: string, options?: CreateSelfPermitOptions) => {
227
+ _requireConnected();
228
+ const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
229
+ const { publicClient, walletClient } = connectStore.getState();
230
+ return permits.getOrCreateSelfPermit(publicClient!, walletClient!, _chainId, _account, options);
231
+ },
232
+
233
+ getOrCreateSharingPermit: async (options: CreateSharingPermitOptions, chainId?: number, account?: string) => {
234
+ _requireConnected();
235
+ const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
236
+ const { publicClient, walletClient } = connectStore.getState();
237
+ return permits.getOrCreateSharingPermit(publicClient!, walletClient!, options, _chainId, _account);
238
+ },
224
239
 
225
240
  // Retrieval methods (auto-fill chainId/account)
226
- getPermit: async (hash: string, chainId?: number, account?: string) =>
227
- resultWrapper(async () => {
228
- const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
229
- return permits.getPermit(_chainId, _account, hash);
230
- }),
231
-
232
- getPermits: async (chainId?: number, account?: string) =>
233
- resultWrapper(async () => {
234
- const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
235
- return permits.getPermits(_chainId, _account);
236
- }),
237
-
238
- getActivePermit: async (chainId?: number, account?: string) =>
239
- resultWrapper(async () => {
240
- const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
241
- return permits.getActivePermit(_chainId, _account);
242
- }),
243
-
244
- getActivePermitHash: async (chainId?: number, account?: string) =>
245
- resultWrapper(async () => {
246
- const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
247
- return permits.getActivePermitHash(_chainId, _account);
248
- }),
241
+ getPermit: async (hash: string, chainId?: number, account?: string) => {
242
+ const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
243
+ return permits.getPermit(_chainId, _account, hash);
244
+ },
245
+
246
+ getPermits: async (chainId?: number, account?: string) => {
247
+ const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
248
+ return permits.getPermits(_chainId, _account);
249
+ },
250
+
251
+ getActivePermit: async (chainId?: number, account?: string) => {
252
+ const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
253
+ return permits.getActivePermit(_chainId, _account);
254
+ },
255
+
256
+ getActivePermitHash: async (chainId?: number, account?: string) => {
257
+ const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
258
+ return permits.getActivePermitHash(_chainId, _account);
259
+ },
249
260
 
250
261
  // Mutation methods (auto-fill chainId/account)
251
- selectActivePermit: async (hash: string, chainId?: number, account?: string) =>
252
- resultWrapper(async () => {
253
- const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
254
- return permits.selectActivePermit(_chainId, _account, hash);
255
- }),
256
-
257
- removePermit: async (hash: string, chainId?: number, account?: string) =>
258
- resultWrapper(async () => {
259
- const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
260
- return permits.removePermit(_chainId, _account, hash);
261
- }),
262
-
263
- removeActivePermit: async (chainId?: number, account?: string) =>
264
- resultWrapper(async () => {
265
- const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
266
- return permits.removeActivePermit(_chainId, _account);
267
- }),
262
+ selectActivePermit: (hash: string, chainId?: number, account?: string) => {
263
+ const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
264
+ return permits.selectActivePermit(_chainId, _account, hash);
265
+ },
266
+
267
+ removePermit: async (hash: string, chainId?: number, account?: string) => {
268
+ const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
269
+ return permits.removePermit(_chainId, _account, hash);
270
+ },
271
+
272
+ removeActivePermit: async (chainId?: number, account?: string) => {
273
+ const { chainId: _chainId, account: _account } = _getChainIdAndAccount(chainId, account);
274
+ return permits.removeActivePermit(_chainId, _account);
275
+ },
268
276
 
269
277
  // Utils (no context needed)
270
278
  getHash: permits.getHash,
@@ -277,11 +285,6 @@ export function createCofhesdkClientBase(opts: CofhesdkClientParams): CofhesdkCl
277
285
  getSnapshot: connectStore.getState,
278
286
  subscribe: connectStore.subscribe,
279
287
 
280
- // initialization results
281
- initializationResults: {
282
- keyFetchResult,
283
- },
284
-
285
288
  // flags (read-only: reflect snapshot)
286
289
  get connected() {
287
290
  return connectStore.getState().connected;
@@ -294,6 +297,7 @@ export function createCofhesdkClientBase(opts: CofhesdkClientParams): CofhesdkCl
294
297
  config: opts.config,
295
298
 
296
299
  connect,
300
+ disconnect,
297
301
  encryptInputs,
298
302
  decryptHandle,
299
303
  permits: clientPermits,
@@ -302,7 +306,7 @@ export function createCofhesdkClientBase(opts: CofhesdkClientParams): CofhesdkCl
302
306
  // Example:
303
307
  // async encryptData(data: unknown) {
304
308
  // requireConnected();
305
- // // Use _publicClient and _walletClient for implementation
309
+ // // Use state.publicClient and state.walletClient for implementation
306
310
  // },
307
311
  };
308
312
  }
@@ -0,0 +1,114 @@
1
+ // TODO: Extract client types to its own file, keep this one as primitives
2
+ import { type PublicClient, type WalletClient } from 'viem';
3
+ import { type CofhesdkConfig, type CofhesdkEnvironment } from './config.js';
4
+ import { type DecryptHandlesBuilder } from './decrypt/decryptHandleBuilder.js';
5
+ import { type EncryptInputsBuilder } from './encrypt/encryptInputsBuilder.js';
6
+ import { type ZkBuilderAndCrsGenerator, type ZkProveWorkerFunction } from './encrypt/zkPackProveVerify.js';
7
+ import { type FheKeyDeserializer } from './fetchKeys.js';
8
+ import { permits } from './permits.js';
9
+ import type { EncryptableItem, FheTypes, TfheInitializer } from './types.js';
10
+ import type { PermitUtils } from 'permits/permit.js';
11
+ import type {
12
+ CreateSelfPermitOptions,
13
+ Permit,
14
+ CreateSharingPermitOptions,
15
+ ImportSharedPermitOptions,
16
+ SharingPermit,
17
+ RecipientPermit,
18
+ SelfPermit,
19
+ } from 'permits/types.js';
20
+
21
+ // CLIENT
22
+
23
+ export type CofhesdkClient<TConfig extends CofhesdkConfig = CofhesdkConfig> = {
24
+ // --- state access ---
25
+ getSnapshot(): CofhesdkClientConnectionState;
26
+ subscribe(listener: Listener): () => void;
27
+
28
+ // --- convenience flags (read-only) ---
29
+ readonly connected: boolean;
30
+ readonly connecting: boolean;
31
+
32
+ // --- config & platform-specific ---
33
+ readonly config: TConfig;
34
+
35
+ connect(publicClient: PublicClient, walletClient: WalletClient): Promise<void>;
36
+ /**
37
+ * Clears the current connection state (account/chainId/clients) and marks the client as disconnected.
38
+ *
39
+ * This does not delete persisted permits or stored FHE keys; it only resets the in-memory connection.
40
+ */
41
+ disconnect(): void;
42
+ /**
43
+ * Types docstring
44
+ */
45
+ encryptInputs<T extends EncryptableItem[]>(inputs: [...T]): EncryptInputsBuilder<[...T]>;
46
+ decryptHandle<U extends FheTypes>(ctHash: bigint, utype: U): DecryptHandlesBuilder<U>;
47
+ permits: CofhesdkClientPermits;
48
+ };
49
+
50
+ export type CofhesdkClientConnectionState = {
51
+ connected: boolean;
52
+ connecting: boolean;
53
+ connectError: unknown | undefined;
54
+ chainId: number | undefined;
55
+ account: `0x${string}` | undefined;
56
+ publicClient: PublicClient | undefined;
57
+ walletClient: WalletClient | undefined;
58
+ };
59
+
60
+ type Listener = (snapshot: CofhesdkClientConnectionState) => void;
61
+
62
+ export type CofhesdkClientPermitsClients = {
63
+ publicClient: PublicClient;
64
+ walletClient: WalletClient;
65
+ };
66
+
67
+ export type CofhesdkClientPermits = {
68
+ getSnapshot: typeof permits.getSnapshot;
69
+ subscribe: typeof permits.subscribe;
70
+
71
+ // Creation methods (require connection, no params)
72
+ createSelf: (options: CreateSelfPermitOptions, clients?: CofhesdkClientPermitsClients) => Promise<SelfPermit>;
73
+ createSharing: (
74
+ options: CreateSharingPermitOptions,
75
+ clients?: CofhesdkClientPermitsClients
76
+ ) => Promise<SharingPermit>;
77
+ importShared: (
78
+ options: ImportSharedPermitOptions | string,
79
+ clients?: CofhesdkClientPermitsClients
80
+ ) => Promise<RecipientPermit>;
81
+
82
+ // Retrieval methods (chainId/account optional)
83
+ getPermit: (hash: string, chainId?: number, account?: string) => Promise<Permit | undefined>;
84
+ getPermits: (chainId?: number, account?: string) => Promise<Record<string, Permit>>;
85
+ getActivePermit: (chainId?: number, account?: string) => Promise<Permit | undefined>;
86
+ getActivePermitHash: (chainId?: number, account?: string) => Promise<string | undefined>;
87
+
88
+ // Get or create methods (get active or create new, chainId/account optional)
89
+ getOrCreateSelfPermit: (chainId?: number, account?: string, options?: CreateSelfPermitOptions) => Promise<Permit>;
90
+ getOrCreateSharingPermit: (
91
+ options: CreateSharingPermitOptions,
92
+ chainId?: number,
93
+ account?: string
94
+ ) => Promise<Permit>;
95
+
96
+ // Mutation methods (chainId/account optional)
97
+ selectActivePermit: (hash: string, chainId?: number, account?: string) => void;
98
+ removePermit: (hash: string, chainId?: number, account?: string) => void;
99
+ removeActivePermit: (chainId?: number, account?: string) => void;
100
+
101
+ // Utils
102
+ getHash: typeof PermitUtils.getHash;
103
+ serialize: typeof PermitUtils.serialize;
104
+ deserialize: typeof PermitUtils.deserialize;
105
+ };
106
+
107
+ export type CofhesdkClientParams<TConfig extends CofhesdkConfig> = {
108
+ config: TConfig;
109
+ zkBuilderAndCrsGenerator: ZkBuilderAndCrsGenerator;
110
+ tfhePublicKeyDeserializer: FheKeyDeserializer;
111
+ compactPkeCrsDeserializer: FheKeyDeserializer;
112
+ initTfhe: TfheInitializer;
113
+ zkProveWorkerFn?: ZkProveWorkerFunction;
114
+ };
@@ -1,4 +1,3 @@
1
- /* eslint-disable no-unused-vars */
2
1
  import { sepolia, hardhat } from '@/chains';
3
2
 
4
3
  import { describe, it, expect, vi } from 'vitest';
@@ -52,6 +51,17 @@ describe('createCofhesdkConfigBase', () => {
52
51
  expect(getNestedValue(result, path)).toEqual(expectedValue);
53
52
  };
54
53
 
54
+ it('environment', () => {
55
+ expectInvalidConfigItem('environment', 'not-a-valid-environment');
56
+ expectInvalidConfigItem('environment', 123);
57
+ expectInvalidConfigItem('environment', {});
58
+
59
+ expectValidConfigItem('environment', 'node', 'node');
60
+ expectValidConfigItem('environment', 'hardhat', 'hardhat');
61
+ expectValidConfigItem('environment', 'web', 'web');
62
+ expectValidConfigItem('environment', 'react', 'react');
63
+ });
64
+
55
65
  it('supportedChains', () => {
56
66
  expectInvalidConfigItem('supportedChains', {});
57
67
  expectInvalidConfigItem('supportedChains', 'not-an-array');
@@ -62,16 +72,6 @@ describe('createCofhesdkConfigBase', () => {
62
72
  expectValidConfigItem('supportedChains', [sepolia, hardhat], [sepolia, hardhat]);
63
73
  });
64
74
 
65
- it('fheKeysPrefetching', () => {
66
- expectInvalidConfigItem('fheKeysPrefetching', 'invalid-option');
67
- expectInvalidConfigItem('fheKeysPrefetching', 5);
68
-
69
- expectValidConfigItem('fheKeysPrefetching', 'CONNECTED_CHAIN', 'CONNECTED_CHAIN');
70
- expectValidConfigItem('fheKeysPrefetching', 'SUPPORTED_CHAINS', 'SUPPORTED_CHAINS');
71
- expectValidConfigItem('fheKeysPrefetching', 'OFF', 'OFF');
72
- expectValidConfigItem('fheKeysPrefetching', undefined, 'OFF');
73
- });
74
-
75
75
  it('permitGeneration', () => {
76
76
  expectInvalidConfigItem('permitGeneration', 'not-a-boolean');
77
77
  expectInvalidConfigItem('permitGeneration', null);
@@ -126,6 +126,14 @@ describe('createCofhesdkConfigBase', () => {
126
126
  expect(getItemCalled).toBe(true);
127
127
  expect(setItemCalled).toBe(true);
128
128
  expect(removeItemCalled).toBe(true);
129
+
130
+ const invalidStorageNotAFunction = {
131
+ getItem: 'not-a-function',
132
+ setItem: 'not-a-function',
133
+ removeItem: 'not-a-function',
134
+ };
135
+
136
+ expectInvalidConfigItem('fheKeyStorage', invalidStorageNotAFunction);
129
137
  });
130
138
 
131
139
  it('mocks', () => {
@@ -144,6 +152,17 @@ describe('createCofhesdkConfigBase', () => {
144
152
  expectValidConfigItem('mocks.sealOutputDelay', 1000, 1000);
145
153
  });
146
154
 
155
+ it('useWorkers', () => {
156
+ expectInvalidConfigItem('useWorkers', 'not-a-boolean');
157
+ expectInvalidConfigItem('useWorkers', null);
158
+ expectInvalidConfigItem('useWorkers', 123);
159
+ expectInvalidConfigItem('useWorkers', {});
160
+
161
+ expectValidConfigItem('useWorkers', true, true);
162
+ expectValidConfigItem('useWorkers', false, false);
163
+ expectValidConfigItem('useWorkers', undefined, true); // defaults to true
164
+ });
165
+
147
166
  it('should get config item', () => {
148
167
  const config: CofhesdkInputConfig = {
149
168
  supportedChains: [sepolia],